<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/"><channel><title>Appontes Blog</title><link>https://appontes.de/blog/</link><description>Fachwissen zu Sage 100, Warenwirtschaft, Rechnungswesen und IT-Infrastruktur aus der Praxis der Appontes GmbH in Rottweil.</description><language>de</language><copyright>Appontes GmbH</copyright><generator>Hugo</generator><lastBuildDate>Wed, 30 Sep 2026 00:00:00 +0000</lastBuildDate><image><url>https://appontes.de/img/og-image.png</url><title>Appontes Blog</title><link>https://appontes.de/blog/</link></image><atom:link href="https://appontes.de/blog/index.xml" rel="self" type="application/rss+xml"/><item><title>Wenn die Maske verschwindet: Was Sprachmodelle mit dem ERP machen werden</title><link>https://appontes.de/blog/llm-erp-zukunft-sage-100/</link><guid isPermaLink="true">https://appontes.de/blog/llm-erp-zukunft-sage-100/</guid><pubDate>Wed, 30 Sep 2026 00:00:00 +0000</pubDate><dc:creator>Thomas Falkner</dc:creator><category>Sage 100</category><category>Schnittstellen</category><category>Strategie</category><category>KI</category><description>Warum eine Sage 100 in ein paar Jahren vielleicht ohne klassische Oberfläche auskommt, warum sie trotzdem die entscheidende Basis liefert, und was Du heute schon tun kannst, damit Dein ERP für Sprachmodelle ansprechbar ist.</description><content:encoded>&lt;p&gt;&lt;img src="https://appontes.de/img/blog/llm-erp-sage-100.svg" alt="Wenn die Maske verschwindet: Was Sprachmodelle mit dem ERP machen werden"&gt;&lt;/p&gt;
&lt;p&gt;
Eine Frage aus dem Alltag: „Wie viel haben wir letztes Jahr bei diesem Lieferanten gekauft, was ist davon noch offen, und wie hat sich sein Preisniveau entwickelt?" In der Sage 100 ist das kein großer Akt, aber auch keine Sache von zehn Sekunden. Du gehst in den Kreditor, wechselst in die Umsätze, öffnest eine Auswertung, filterst auf das Jahr, wechselst in die Belege, suchst die offenen heraus und vergleichst dann in einer dritten Maske die Einkaufspreise. Vier, fünf Masken, ein paar Filter, am Ende eine Zahl im Kopf.
&lt;/p&gt;
&lt;p&gt;
Dieselbe Frage an ein Sprachmodell, das Zugriff auf dieselben Daten hat, dauert einen Satz. Und das ist keine Zukunftsmusik, das läuft. Wir haben so etwas gebaut: Einen schmalen Dienst vor der Sage, der ein paar klar umrissene Fragen beantwortet, tokengesichert, ohne dass jemand die Datenbank aufmacht.
&lt;/p&gt;
&lt;p&gt;
Genau an dieser Stelle wird es für die Zukunft von ERP-Systemen interessant. Denn wenn Fragen so beantwortet werden können, stellt sich eine unbequeme Frage: Wofür brauchen wir dann eigentlich noch die Maske?
&lt;/p&gt;
&lt;h2&gt;Was eine Maske eigentlich ist&lt;/h2&gt;
&lt;p&gt;
Eine ERP-Maske ist eine eingefrorene Antwort auf eine Frage, die irgendwann einmal jemand hatte. Jemand hat festgelegt, welche Felder zusammengehören, in welcher Reihenfolge man sie sieht, welche Auswertung daneben liegt und welche nicht. Das Ergebnis ist eine Navigation, die stellvertretend für Dich denkt.
&lt;/p&gt;
&lt;p&gt;
Technisch steckt dahinter mehr, als man vermutet. Eine typische Maske der Sage 100 bringt grob zwischen zwanzig und siebzig Abfragen mit, die sie je nach Register und Aktion abfeuert. Das ist eine Menge vorgedachter Arbeit, und sie ist wertvoll. Sie ist aber eben auch eine Annahme darüber, was Du wissen willst.
&lt;/p&gt;
&lt;p&gt;
Solange Deine Frage in dieser Annahme vorkommt, ist die Maske schneller als jedes Gespräch. Sobald sie danebenliegt, fängt die Klickarbeit an. Und die meisten Fragen, die im Alltag wirklich nerven, liegen daneben.
&lt;/p&gt;
&lt;h2&gt;Was Sprachmodelle daran verändern&lt;/h2&gt;
&lt;p&gt;
Ein Sprachmodell braucht keine Navigation. Es braucht Struktur und Bedeutung. Wenn es weiß, dass in einer Tabelle Kreditoren stehen, in einer anderen deren Belege, und wie beides zusammenhängt, dann muss ihm niemand einen Weg durch fünf Masken bauen. Drei Dinge verschieben sich damit:
&lt;/p&gt;
&lt;ul class="icon-list"&gt;
&lt;li&gt;&lt;strong&gt;Fragen statt Klicken.&lt;/strong&gt; Auswertungen, die heute ein Ticket oder eine Individualabfrage auslösen, werden zur Rückfrage im Gespräch. Der Aufwand für eine einmalige Frage sinkt auf nahezu null, und damit stellen Leute plötzlich Fragen, die sie sich vorher gespart haben.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vorgänge statt Einzelmasken.&lt;/strong&gt; Ein Vorgang wie „Angebot aus dieser Anfrage bauen, Preise aus der aktuellen Staffel ziehen, Liefertermin beim Lieferanten prüfen" berührt heute mehrere Programmteile. Für ein Modell ist das eine Abfolge von Werkzeugaufrufen.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ausnahmen statt Standard.&lt;/strong&gt; Der Standardfall läuft in jedem ERP gut. Geld kostet der Rest: Die Sonderkonstellation, für die es keine Maske gibt und bei der heute jemand angerufen wird, der sich auskennt. Genau dort sind Modelle stark, weil sie Zusammenhänge herstellen, statt einem festen Pfad zu folgen.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Warum die Maske trotzdem nicht einfach verschwindet&lt;/h2&gt;
&lt;p&gt;
Jetzt der Teil, den die meisten Beiträge zu diesem Thema weglassen. Es gibt gute Gründe, warum die klassische Oberfläche so schnell nicht abgeschafft wird, und sie sind nicht nostalgisch.
&lt;/p&gt;
&lt;ul class="icon-list"&gt;
&lt;li&gt;&lt;strong&gt;Eine Buchung muss reproduzierbar sein.&lt;/strong&gt; Ein Sprachmodell ist von Natur aus nicht deterministisch. Zweimal dieselbe Frage kann zwei Formulierungen ergeben. Für eine Auswertung ist das egal, für eine Buchung nicht. Steuerlich und handelsrechtlich musst Du belegen können, auf welchem Weg ein Wert zustande gekommen ist.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Masseneingabe ist heute Tastaturarbeit.&lt;/strong&gt; Wer den ganzen Tag Belege erfasst, ist mit Tabulator und Zehnerblock schneller als mit jeder Konversation. Dieses Argument hat allerdings ein Verfallsdatum, und das sollte man dazusagen: Ob Belege in einigen Jahren überhaupt noch von Hand erfasst werden, steht auf einem ganz anderen Blatt. &lt;a href="https://appontes.de/blog/e-rechnung-sage-100/"&gt;E-Rechnung&lt;/a&gt;, EDI und Belegerkennung nehmen genau diese Arbeit gerade weg. Wo nichts mehr getippt wird, braucht es auch keine schnelle Erfassungsmaske.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Die Maske ist auch eine Berechtigungsgrenze.&lt;/strong&gt; Wer keinen Zugriff auf die Maske hat, sieht die Daten nicht. Diese Grenze musst Du bei einem freien Zugang komplett neu ziehen, und zwar sauberer als vorher.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vertrauen entsteht über Wiedererkennung.&lt;/strong&gt; Ein Sachbearbeiter, der seit zwölf Jahren dieselbe Erfassungsmaske bedient, arbeitet darin schnell und fehlerarm. Das gibt man nicht leichtfertig auf.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Diese vier Gründe sind unterschiedlich haltbar, und das ist der interessante Teil. Die Masseneingabe erledigt sich vermutlich von selbst, nur eben nicht durch ein Sprachmodell, sondern durch Formate und Automatisierung. Die Reproduzierbarkeit einer Buchung und die Frage, wer was sehen und auslösen darf, verschwinden dagegen nicht. Die werden eher wichtiger, je mehr Wege in das System führen.
&lt;/p&gt;
&lt;p&gt;
Meine These ist deshalb nicht, dass die Oberfläche verschwindet. Sie verliert ihr Monopol. Aus „die Maske ist das System" wird „die Maske ist einer von mehreren Wegen in das System". Das ist ein Unterschied, aber ein folgenreicher.
&lt;/p&gt;
&lt;h2&gt;Warum die Sage 100 dafür eine gute Basis ist&lt;/h2&gt;
&lt;p&gt;
Und jetzt kommt der Punkt, der mich an dieser Entwicklung wirklich interessiert: Eine gewachsene Sage 100 ist für so eine Zukunft besser vorbereitet als manche moderne Cloud-Lösung mit hübscher Oberfläche und dünnem Unterbau.
&lt;/p&gt;
&lt;h3&gt;Ein Datenmodell, das man erklären kann&lt;/h3&gt;
&lt;p&gt;
Der eigentliche Wert der Sage 100 liegt nicht in der Oberfläche, sondern darunter: Ein relationales Modell, in dem Artikel, Kontokorrente, Belege, Buchungen und Lagerbewegungen sauber getrennt sind und über nachvollziehbare Schlüssel zusammenhängen. Genau das ist das Futter, das ein Modell braucht. Man kann einem Sprachmodell dieses Schema beibringen. Man kann ihm nicht beibringen, was in einem Datentopf ohne Struktur steht.
&lt;/p&gt;
&lt;h3&gt;Geschäftslogik, die nicht in der Maske klebt&lt;/h3&gt;
&lt;p&gt;
Das ist der entscheidende Teil, und er wird oft übersehen. Die Regeln der Sage 100 stecken nicht ausschließlich in der Oberfläche, sondern in einer Objektschicht dahinter, die über den Applikationsserver erreichbar ist. Wer einen Beleg über diese Objekte anlegt und speichert, bekommt dieselben Prüfungen, dieselbe Nummernvergabe und dieselbe Transaktionsklammer wie ein Anwender, der in der Maske auf Speichern drückt.
&lt;/p&gt;
&lt;p&gt;
Das klingt technisch, ist aber der Unterschied zwischen einer tragfähigen Anbindung und einer Zeitbombe. Ein Beispiel: Belegnummern und Schlüssel vergibt die Sage über einen zentralen Mechanismus. Wer stattdessen direkt in die Tabelle schreibt und sich seine Nummer selbst ausdenkt, bekommt keine Fehlermeldung, sondern irgendwann doppelte Schlüssel, und das merkt niemand am selben Tag.
&lt;/p&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;
&lt;strong&gt;Die Faustregel bleibt dieselbe wie bei jeder Schnittstelle:&lt;/strong&gt; Lesen darfst Du aus der Datenbank, schreiben nur über die Objekte. Daran ändert ein Sprachmodell gar nichts, es macht die Regel nur wichtiger, weil deutlich mehr Schreibzugriffe automatisiert angestoßen werden.
&lt;/p&gt;
&lt;/div&gt;
&lt;h3&gt;Metadaten sind maschinenlesbares Wissen&lt;/h3&gt;
&lt;p&gt;
Die Sage 100 beschreibt sich selbst. Masken, Abfragen, Sichten und Felddefinitionen liegen in der Datenbank. Das ist im Alltag eher Ballast, für diesen Zweck aber Gold: Du kannst maschinell auslesen, wie Dein System aufgebaut ist, welche Felder es gibt und was eine Individualentwicklung ergänzt hat. Wer ein Modell anlernen will, hat hier einen sehr guten Ausgangspunkt, und zwar ohne dass jemand eine Dokumentation schreiben muss.
&lt;/p&gt;
&lt;h2&gt;Was heute schon geht&lt;/h2&gt;
&lt;p&gt;
Das ist kein Konzeptpapier, das lässt sich bauen. Wir haben genau diesen Weg ausprobiert und den Zugriff bewusst eng geschnitten:
&lt;/p&gt;
&lt;ul class="icon-list"&gt;
&lt;li&gt;&lt;strong&gt;Ein schmaler Dienst vor der Sage.&lt;/strong&gt; Kein Datenbankzugang nach außen, sondern ein Endpunkt, der eine Handvoll definierter Fragen beantwortet. Zugriff über Token, Aufrufe werden protokolliert.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Feste Abfragen statt freiem SQL.&lt;/strong&gt; Das Modell bekommt Werkzeuge mit Parametern, nicht eine Konsole. Es kann fragen „Kontenumsatz für Konto X im Zeitraum Y", aber es kann keine Abfrage erfinden, die einen Tabellenscan über Millionen Zeilen auslöst.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lesen zuerst, lange.&lt;/strong&gt; Auswertungen, Status, Verfügbarkeiten. Alles, was schiefgehen kann, ist eine falsche Antwort, und die fällt auf.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Schreiben nur über die Objektschicht.&lt;/strong&gt; Und zwar mit demselben Protokoll wie jede andere Automatik: Wer hat was über welches Werkzeug ausgelöst.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Der Unterschied zwischen „das Modell hat Zugriff auf die Datenbank" und „das Modell hat ein paar klar definierte Werkzeuge" ist der ganze Punkt. Im ersten Fall hast Du ein unkalkulierbares Risiko, im zweiten eine Schnittstelle, die sich genauso prüfen lässt wie jede andere.
&lt;/p&gt;
&lt;h2&gt;Wie ich vorgehen würde&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Sammle die Fragen, die heute Klickarbeit sind.&lt;/strong&gt; Nicht die Visionen, die echten Fragen aus dem Tagesgeschäft. Meist sind es fünf bis fünfzehn, die achtzig Prozent des Ärgers ausmachen.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Baue je Frage ein Werkzeug.&lt;/strong&gt; Eine klar definierte Abfrage mit Parametern, dokumentiertem Rückgabeformat und Berechtigungsprüfung. Genau so, wie Du auch eine Schnittstelle zu einem anderen System bauen würdest.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bleib monatelang beim Lesen.&lt;/strong&gt; Erst wenn die Antworten konstant stimmen und die Leute ihnen vertrauen, lohnt sich das Nachdenken über schreibende Vorgänge.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Schreib nur über die Objekte, und protokolliere alles.&lt;/strong&gt; Jeder Vorgang muss sich im Nachhinein einer Person und einem Werkzeug zuordnen lassen. Sonst bekommst Du bei der nächsten Prüfung ein Problem.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Was ich nicht glaube&lt;/h2&gt;
&lt;p&gt;
Ein paar Erwartungen halte ich für falsch, und die sollte man aussprechen, bevor jemand ein Budget darauf aufbaut.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Dass das ERP verschwindet.&lt;/strong&gt; Es wird unsichtbarer, aber jemand muss weiterhin Bestände führen, Belege nummerieren, Steuern richtig ausweisen und Bilanzen erzeugen. Diese Arbeit verschwindet nicht, sie wird nur seltener direkt angefasst.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Dass man sein Datenmodell nicht mehr verstehen muss.&lt;/strong&gt; Das Gegenteil trifft zu. Ein Modell ist nur so gut wie die Struktur, auf die Du es lässt. Schlechte Stammdaten werden durch ein Sprachmodell nicht besser, sie werden schneller falsch beantwortet, und zwar in ganzen Sätzen, die sehr überzeugend klingen. Wer heute doppelte Artikel, falsche Warengruppen und einen mittleren Einkaufspreis von Hand überschreibt, bekommt später eben eine eloquent formulierte falsche Auskunft.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Dass das eine Frage der Version ist.&lt;/strong&gt; Der begrenzende Faktor ist selten die Sage-Version, sondern die Frage, ob jemand die Geschäftslogik hinter der Oberfläche kennt und sauber ansprechen kann.
&lt;/p&gt;
&lt;h2&gt;Was daraus folgt&lt;/h2&gt;
&lt;p&gt;
Die Oberfläche ist nicht das Produkt. Das Datenmodell und die Geschäftslogik sind es. Wer beides sauber hält und über definierte Schnittstellen zugänglich macht, ist auf jede künftige Oberfläche vorbereitet, auch auf gar keine.
&lt;/p&gt;
&lt;p&gt;
Das ist die eigentlich gute Nachricht für alle, die seit Jahren mit einer gewachsenen Sage 100 arbeiten: Die Investition der letzten fünfzehn Jahre steckt nicht in den Masken, sondern darunter. Sie bleibt nutzbar, wenn die Bedienung sich ändert. Vorausgesetzt, man hat die Datenqualität und die Schnittstellen im Griff, und daran führt so oder so kein Weg vorbei.
&lt;/p&gt;
&lt;p&gt;
Wenn Du gerade überlegst, wie Du bei diesem Thema anfängst: Fang nicht beim Sprachmodell an. Fang bei den fünf Fragen an, die in Deinem Haus jede Woche Klickarbeit kosten, und bau dafür saubere Werkzeuge. Was am anderen Ende der Schnittstelle sitzt, kannst Du später immer noch austauschen.
&lt;/p&gt;</content:encoded></item><item><title>Der mittlere Einkaufspreis in der Sage 100: Berechnung, Stolperfallen, Korrektur</title><link>https://appontes.de/blog/mittlerer-einkaufspreis-mek-sage-100/</link><guid isPermaLink="true">https://appontes.de/blog/mittlerer-einkaufspreis-mek-sage-100/</guid><pubDate>Sun, 27 Sep 2026 00:00:00 +0000</pubDate><dc:creator>Thomas Falkner</dc:creator><category>Sage 100</category><category>Warenwirtschaft</category><category>Einkauf</category><category>Lager</category><description>Wie die Sage 100 den MEK berechnet, was er betriebswirtschaftlich steuert, warum ein von Hand überschriebener Wert im Artikelstamm nicht hält und wie Du einen falschen MEK dauerhaft korrigierst. Mit Deep Dive in Tabellen, Belegarten und Rechenablauf.</description><content:encoded>&lt;p&gt;&lt;img src="https://appontes.de/img/blog/mek-sage-100.svg" alt="Der mittlere Einkaufspreis in der Sage 100: Berechnung, Stolperfallen, Korrektur"&gt;&lt;/p&gt;
&lt;p&gt;
Ein Verkaufsbeleg zeigt einen Roherlös, der nicht stimmen kann. Der Blick in den Artikelstamm liefert die Erklärung: Der mittlere Einkaufspreis liegt weit neben dem, was der Artikel tatsächlich kostet. Irgendwann hat jemand beim Wareneingang den Palettenpreis als Stückpreis erfasst, oder ein Lagerzugang wurde ohne Gesamtpreis gebucht. Der naheliegende Griff ist schnell gemacht: Feld überschreiben, speichern, fertig.
&lt;/p&gt;
&lt;p&gt;
Zwei Wochen später kommt der nächste Wareneingang, und der alte Wert ist wieder da. Nicht exakt derselbe, aber nah dran. Genau an dieser Stelle setzen die meisten Supportanfragen zum MEK an. Dieser Beitrag erklärt, wie die Sage 100 den mittleren Einkaufspreis rechnet, warum das Feld im Artikelstamm nur ein Ergebnis anzeigt und nicht die Eingabe dafür ist, und wie Du einen falschen Wert so korrigierst, dass er auch nach dem nächsten Zugang noch stimmt.
&lt;/p&gt;
&lt;h2&gt;Drei Einkaufspreise, eine Entscheidung&lt;/h2&gt;
&lt;p&gt;
Die Sage 100 führt je Artikel drei Einkaufspreise nebeneinander. Sie stehen in derselben Maske, werden aber völlig unterschiedlich befüllt:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a class="glossar-term" href="https://appontes.de/glossar/mek/"&gt;Mittlerer Einkaufspreis (MEK)&lt;span class="glossar-tip" aria-hidden="true"&gt;&lt;strong&gt;MEK (Mittlerer Einkaufspreis)&lt;/strong&gt;Der mengengewichtete Durchschnittspreis des Lagerbestands eines Artikels. Die Sage 100 berechnet ihn bei jedem Lagerzugang neu und nutzt ihn für Roherlös, Lagerbewertung und Inventur.&lt;em&gt;Mehr im Glossar &amp;#8594;&lt;/em&gt;&lt;/span&gt;&lt;/a&gt;:&lt;/strong&gt; Ein gewichteter Durchschnitt über den Lagerbestand. Das Programm rechnet ihn bei jedem Lagerzugang neu.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Letzter Einkaufspreis (LEK):&lt;/strong&gt; Der Nettopreis aus dem jüngsten Wareneingang oder Rechnungseingang, umgerechnet in Eigenwährung.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Kalkulatorischer Einkaufspreis (KEK):&lt;/strong&gt; Der Preis, mit dem die Warenwirtschaft kalkuliert. Im Register Kalkulation des Artikelstamms legst Du je Artikel über den Schalter „Preispflege kalk. EK" fest, ob er manuell gepflegt, vom LEK übernommen oder vom MEK übernommen wird.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Welcher der drei Preise in die Roherlösermittlung der Verkaufsbelege einfließt, legst Du in den Mandanteneinstellungen der Warenwirtschaft fest, im Register Verkaufsbelege. Der Demomandant Mustermann &amp;amp; Söhne steht zum Beispiel auf dem kalkulatorischen EK, viele Kundeninstallationen auf dem mittleren. Beim Anlegen einer Verkaufsposition liest die Sage den gewählten Preis aus dem Artikelstamm und friert ihn auf der Position ein. Sage selbst gibt zwei Einschränkungen mit: Über den LEK sollte der Roherlös nicht ermittelt werden, und bei Artikeln ohne Lagerführung funktioniert der MEK nicht, weil ohne Bestand nichts zu mitteln ist. Für solche Artikel bleibt nur der KEK.
&lt;/p&gt;
&lt;figure class="blog-figure"&gt;
&lt;img src="https://appontes.de/img/blog/mek/mandanteneinstellungen-verkaufsbelege-roherloes.png" alt="Mandanteneinstellungen der Sage 100, Register Verkaufsbelege, mit dem hervorgehobenen Feld Roherlösberechnung auf der Einstellung Über kalkulatorischen EK" width="1453" height="593" loading="lazy"&gt;
&lt;figcaption&gt;Register Verkaufsbelege: Hier legst Du fest, welcher der drei Einkaufspreise in den Roherlös eingeht. Der Demomandant steht auf dem kalkulatorischen EK&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2&gt;Warum dieser Preis betriebswirtschaftlich zählt&lt;/h2&gt;
&lt;p&gt;
Der Einkaufspreis im Artikelstamm wirkt unscheinbar, er steuert aber mehrere Zahlen, an denen im Unternehmen Entscheidungen hängen:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Roherlös je Position.&lt;/strong&gt; Verkaufspreis minus eingefrorener Einkaufspreis mal Menge. Das ist der Deckungsbeitrag, den der Vertrieb im Beleg sieht, bevor er einen Rabatt gibt. Ein zu niedriger MEK macht jeden Auftrag schöner, als er ist.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Provisionen.&lt;/strong&gt; Wer Provisionen vom Roherlös rechnet, bezahlt seine Außendienstler auf Basis dieses Felds. Wird der Roherlös bei positivem Umsatz negativ, setzt die Sage die Provision auf null.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Wareneinsatz in der Finanzbuchhaltung.&lt;/strong&gt; Bei der Übergabe einer Verkaufsrechnung ist der Wareneinsatz der eingefrorene Positionspreis mal Menge. Mit erweiterter Lagerlizenz gehen dazu Wareneinsatz- und Warenbestandskonto aus dem Artikelstamm mit.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lagerbewertung und Inventur.&lt;/strong&gt; Der Lagerwert ist Menge mal gewähltem Preis mal Bewertungssatz. Als Preisgrundlage stehen MEK, kalkulatorischer EK oder ein Verkaufspreis zur Wahl, der LEK nicht. Bestandsdifferenzen aus der Inventur werden mit dem MEK bewertet.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fertigung.&lt;/strong&gt; Der Einstand einer Fertigmeldung kann je nach Einstellung der MEK, der kalkulatorische EK, der LEK oder die Auftragskosten sein. Damit landet der Preis auch im Wert der Eigenfertigung.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Der MEK und der kalkulatorische EK beantworten dabei unterschiedliche Fragen. Der MEK sagt, was die Ware im Lager tatsächlich gekostet hat, als gleitender Durchschnitt über alle Zugänge. Das glättet Preisschwankungen und passt zu einem Handelsbestand, der laufend nachgekauft wird. Er hat aber zwei Schwächen: Er hinkt bei steigenden Einkaufspreisen hinterher, weil alte, günstige Bestände den Schnitt drücken, und er enthält nur, was auf der Einkaufsposition stand. Fracht, Zoll oder Verpackung als eigene Belegposition sind nicht drin.
&lt;/p&gt;
&lt;p&gt;
Der kalkulatorische EK ist dagegen der Preis, mit dem Du rechnen willst. Wiederbeschaffungspreis statt historischem Einstand, Bezugsnebenkosten eingerechnet, Abwertung für Ladenhüter, oder einfach ein stabiler Wert, den nicht jeder Wareneingang verschiebt. Deshalb stellen viele Betriebe die Roherlösermittlung auf den KEK und lassen ihn für Standardartikel automatisch aus dem MEK übernehmen. Nur die Artikel, bei denen der Durchschnitt nicht taugt, werden von Hand gepflegt.
&lt;/p&gt;
&lt;p&gt;
Für die Bilanz gilt der gleitende Durchschnitt als gängiges Vereinfachungsverfahren bei der Bewertung des Vorratsvermögens. Ob der MEK aus der Sage in Deinem Fall so übernommen werden kann oder ob Abschläge für Gängigkeit und Niederstwert dazukommen, klärst Du mit Deinem Steuerberater. Die Warenwirtschaft liefert den Ausgangswert, nicht die Bilanzposition.
&lt;/p&gt;
&lt;h2&gt;Die Formel&lt;/h2&gt;
&lt;p&gt;
Der MEK ist ein &lt;a class="glossar-term" href="https://appontes.de/glossar/gleitender-durchschnitt/"&gt;gleitender Durchschnitt&lt;span class="glossar-tip" aria-hidden="true"&gt;&lt;strong&gt;Gleitender Durchschnitt&lt;/strong&gt;Bewertungsverfahren, bei dem der Durchschnittspreis eines Bestands nach jedem Zugang neu berechnet wird. Grundlage des MEK in der Sage 100 und ein gängiges Vereinfachungsverfahren für die Vorratsbewertung.&lt;em&gt;Mehr im Glossar &amp;#8594;&lt;/em&gt;&lt;/span&gt;&lt;/a&gt;, gewichtet nach Menge. Bei jedem Zugang wird der Wert des vorhandenen Bestands mit dem Wert des Zugangs zusammengerechnet und durch die neue Gesamtmenge geteilt. Bestand und MEK mit dem Index „alt" sind die Werte vor dem Zugang:
&lt;/p&gt;
&lt;div class="formula"&gt;
&lt;math display="block"&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mtext&gt;MEK&lt;/mtext&gt;&lt;mtext&gt;neu&lt;/mtext&gt;&lt;/msub&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mfrac&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mtext&gt;Bestand&lt;/mtext&gt;&lt;mtext&gt;alt&lt;/mtext&gt;&lt;/msub&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;msub&gt;&lt;mtext&gt;MEK&lt;/mtext&gt;&lt;mtext&gt;alt&lt;/mtext&gt;&lt;/msub&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mtext&gt;Zugangsmenge&lt;/mtext&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;mtext&gt;Einstandspreis&lt;/mtext&gt;&lt;/mrow&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mtext&gt;Bestand&lt;/mtext&gt;&lt;mtext&gt;alt&lt;/mtext&gt;&lt;/msub&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mtext&gt;Zugangsmenge&lt;/mtext&gt;&lt;/mrow&gt;&lt;/mfrac&gt;&lt;/mrow&gt;&lt;/math&gt;
&lt;/div&gt;
&lt;p&gt;
Ein Beispiel. Im Lager liegen 40 Stück eines Artikels mit einem MEK von 12,50 Euro. Ein Wareneingang bringt 10 Stück zu 15,00 Euro netto.
&lt;/p&gt;
&lt;table class="tech-table"&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Schritt&lt;/th&gt;
&lt;th&gt;Rechnung&lt;/th&gt;
&lt;th&gt;Ergebnis&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Wert des Bestands&lt;/td&gt;
&lt;td&gt;40 × 12,50&lt;/td&gt;
&lt;td&gt;500,00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wert des Zugangs&lt;/td&gt;
&lt;td&gt;10 × 15,00&lt;/td&gt;
&lt;td&gt;150,00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gesamtwert&lt;/td&gt;
&lt;td&gt;500,00 + 150,00&lt;/td&gt;
&lt;td&gt;650,00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Neuer MEK&lt;/td&gt;
&lt;td&gt;650,00 / 50&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;13,00&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;
Der &lt;a class="glossar-term" href="https://appontes.de/glossar/einstandspreis/"&gt;Einstandspreis&lt;span class="glossar-tip" aria-hidden="true"&gt;&lt;strong&gt;Einstandspreis&lt;/strong&gt;Der Preis, den eine Ware bis zur Einlagerung tatsächlich gekostet hat: Nettopreis nach Rabatten, in der Sage 100 auf Lagerbuchungen als Einstandspreis der Bewegung gespeichert.&lt;em&gt;Mehr im Glossar &amp;#8594;&lt;/em&gt;&lt;/span&gt;&lt;/a&gt;, der in die Formel eingeht, ist der Nettopreis der Position. Positionsrabatt und Belegrabatt sind bereits abgezogen, Fremdwährungen werden in Eigenwährung umgerechnet. Der MEK wird mit vier Nachkommastellen geführt, deshalb steht im Artikelstamm oft ein Wert wie 5,4762 und nicht 5,48.
&lt;/p&gt;
&lt;p&gt;
Ein paar Regeln rund um die Formel, die im Alltag regelmäßig für Verwirrung sorgen:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Verkäufe ändern den MEK nicht direkt.&lt;/strong&gt; Ein Lieferschein reduziert den Bestand, der Durchschnittspreis bleibt. Er geht aber beim nächsten Zugang als kleinerer „alter Bestand" in die Formel ein.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bei Bestand null bleibt der alte MEK stehen.&lt;/strong&gt; Der nächste Zugang bestimmt den MEK dann allein, weil der Bestandsanteil in der Formel null ist. Das ist gleichzeitig der Hebel für die Korrektur weiter unten.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bei negativem Bestand setzt die Sage den LEK an.&lt;/strong&gt; Ein negativer Bestand darf nicht in den Durchschnitt eingerechnet werden. Solange der Bestand unter null liegt, gilt der letzte Einkaufspreis, erst ab einem Bestand von null oder mehr greift die Formel wieder.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gutschriften und Stornorechnungen im Einkauf verändern den MEK nicht.&lt;/strong&gt; Eine Retoure mindert die Zugangsmenge des Wareneingangs, auf den sie sich bezieht, der Stückpreis dieser Bewegung bleibt aber derselbe. Wer Ware zurückschickt, bekommt keinen korrigierten Durchschnitt.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Der Rechnungseingang kann nachkorrigieren.&lt;/strong&gt; Weicht der Preis in der Eingangsrechnung vom Wareneingang ab, passt die Sage den MEK an, sofern die Mandanteneinstellung das vorsieht. Teilrechnungen wirken anteilig nach der berechneten Menge.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Wann die Sage rechnet&lt;/h2&gt;
&lt;p&gt;
Die MEK-Berechnung ist teurer, als sie aussieht. Für jede Position wird nicht nur der aktuelle MEK neu bestimmt, sondern auch die Historie fortgeschrieben, die für die historische Lagerbewertung gebraucht wird. Bei Belegen mit vielen Positionen dauert das Speichern dadurch spürbar länger. Sage bietet deshalb vier Varianten an, die Du in den Mandanteneinstellungen im Register Lagerwirtschaft im Feld MEK-Berechnung auswählst:
&lt;/p&gt;
&lt;table class="tech-table"&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Einstellung&lt;/th&gt;
&lt;th&gt;Verhalten&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sofort mit Berücksichtigung der RE&lt;/td&gt;
&lt;td&gt;Der MEK wird beim Speichern des Wareneingangs berechnet. Weicht der Preis im Rechnungseingang ab, wird zum Positionslieferdatum der Rechnung nachkorrigiert. Die vollständigste Variante.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sofort ohne Berücksichtigung der RE&lt;/td&gt;
&lt;td&gt;Nur Wareneingänge aktualisieren den MEK, Rechnungseingänge nicht. Sage empfiehlt das für Betriebe, die Einkaufsvorgänge mit dem Wareneingang abschließen.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Zeitversetzt&lt;/td&gt;
&lt;td&gt;Beim Speichern passiert nichts. Der MEK wird erst neu berechnet, wenn jemand unter Abschluss den Menüpunkt MEK-Aktualisierung aufruft. Bis dahin rechnen Verkaufsbelege mit dem alten Wert.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Zeitversetzt mit Aktualisierung nach WE&lt;/td&gt;
&lt;td&gt;Nach einem Wareneingang wird der MEK vereinfacht neu gerechnet, ohne Historie. Liefertermine, Belegänderungen, gelöschte Belege, Retouren und Buchungen aus dem Lagermodul fließen erst bei der manuellen MEK-Aktualisierung ein.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;
Die beiden zeitversetzten Varianten merken sich die betroffenen Artikel in der Tabelle &lt;code&gt;KHKArtikelMEKAktualisierung&lt;/code&gt; vor. Die MEK-Aktualisierung arbeitet diese Liste ab. Wenn bei Dir also Roherlöse auf Wochen alten Einkaufspreisen basieren, lohnt sich ein Blick auf diese Einstellung, bevor Du im Artikelstamm nach Fehlern suchst. Häufig ist der MEK gar nicht falsch, sondern nur noch nicht berechnet.
&lt;/p&gt;
&lt;figure class="blog-figure"&gt;
&lt;img src="https://appontes.de/img/blog/mek/mandanteneinstellungen-lagerwirtschaft-mek.png" alt="Mandanteneinstellungen der Sage 100, Register Lagerwirtschaft, mit aufgeklapptem Feld MEK-Berechnung und den vier Auswahlmöglichkeiten" width="1440" height="724" loading="lazy"&gt;
&lt;figcaption&gt;Register Lagerwirtschaft: Die vier Varianten stehen in einem einzigen Feld. Diese Einstellung entscheidet, wie aktuell Deine Roherlöse sind&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2&gt;Der Liefertermin bestimmt die Reihenfolge&lt;/h2&gt;
&lt;p&gt;
Entscheidend für die Berechnung ist nicht, in welcher Reihenfolge die Belege erfasst wurden, sondern der Liefertermin der einzelnen Position. Die Sage sortiert alle lagerrelevanten Bewegungen eines Artikels nach diesem Datum und rechnet die Formel entlang dieser Kette. Das führt zu Ergebnissen, die auf den ersten Blick nicht nachvollziehbar sind. Ein Beispiel mit vier Belegen, erfasst in der Reihenfolge a bis d:
&lt;/p&gt;
&lt;table class="tech-table"&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Beleg&lt;/th&gt;
&lt;th&gt;Liefertermin&lt;/th&gt;
&lt;th&gt;Bewegung&lt;/th&gt;
&lt;th&gt;MEK danach&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;a) Wareneingang&lt;/td&gt;
&lt;td&gt;01.03.&lt;/td&gt;
&lt;td&gt;10 Stück zu 8,00&lt;/td&gt;
&lt;td&gt;8,0000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;b) Lieferschein&lt;/td&gt;
&lt;td&gt;05.03.&lt;/td&gt;
&lt;td&gt;4 Stück Abgang&lt;/td&gt;
&lt;td&gt;8,0000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;c) Wareneingang&lt;/td&gt;
&lt;td&gt;03.03.&lt;/td&gt;
&lt;td&gt;20 Stück zu 9,50&lt;/td&gt;
&lt;td&gt;9,0000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;d) Wareneingang&lt;/td&gt;
&lt;td&gt;10.03.&lt;/td&gt;
&lt;td&gt;10 Stück zu 8,00&lt;/td&gt;
&lt;td&gt;8,7222&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;
Bei Beleg c rechnet die Sage mit einem Bestand von 10 Stück, obwohl der Lieferschein schon erfasst ist. Sein Liefertermin liegt nach dem des Wareneingangs, also zählt er an dieser Stelle noch nicht: (10 × 8,00 + 20 × 9,50) / 30 = 9,00. Bei Beleg d ist der Lieferschein dann durch, der alte Bestand beträgt 26 Stück: (26 × 9,00 + 10 × 8,00) / 36 = 8,7222.
&lt;/p&gt;
&lt;p&gt;
Aus dieser Logik ergeben sich zwei Folgen. Erstens: Wird ein Liefertermin, eine Menge oder ein Preis in einem bereits gespeicherten Beleg geändert, baut die Sage den MEK ab diesem Datum neu auf. Dasselbe gilt für einen lagerrelevanten Verkaufsbeleg mit Liefertermin in der Vergangenheit, weil er den Bestand zu diesem Zeitpunkt verändert. Der Verlauf steht in der Tabelle &lt;code&gt;KHKArtikelbewertungMEKHistorie&lt;/code&gt;, ein Eintrag je Artikel, Ausprägung und Datum. Zweitens: Bereits gespeicherte Verkaufsbelege behalten ihren Roherlös. Eine MEK-Aktualisierung schreibt keine neuen Werte in alte Belege. Erst bei der Belegübernahme, etwa vom Auftrag in den Lieferschein, kann der Preis neu aus dem Stamm gezogen werden, wenn die Mandanteneinstellung „Einkaufspreise" auf „aktuell aus dem Stamm" steht statt auf „aus dem Initialbeleg".
&lt;/p&gt;
&lt;h2&gt;Warum das Überschreiben im Artikelstamm nicht hält&lt;/h2&gt;
&lt;p&gt;
Das Feld mittlerer Einkaufspreis im Artikelstamm lässt sich editieren, und die Änderung wirkt auch. In der Preisfindung der Verkaufsposition erscheint der neue Wert als Einkaufspreis, der Roherlös wird damit gerechnet, und in Auswertungen wie der Warenbestandsliste oder der Inventurbewertung taucht er als Berechnungspreis auf. Für einen Moment sieht alles richtig aus.
&lt;/p&gt;
&lt;p&gt;
Der Wert steht allerdings nur in der Anzeigespalte. Technisch liegt der MEK in &lt;code&gt;KHKArtikelVarianten.MittlererEK&lt;/code&gt;, also je Ausprägung des Artikels, und dorthin schreibt die Berechnung ihr Ergebnis zurück. Als Rechengrundlage für den nächsten Zugang nimmt sie aber nicht dieses Feld, sondern den Verlauf aus der MEK-Historie und den Lagerplatzbuchungen. Dort ist jede Bewegung mit Bewegungsdatum, Einstandspreis und dem MEK zu diesem Zeitpunkt gespeichert. Der manuelle Wert kommt in dieser Kette nicht vor.
&lt;/p&gt;
&lt;p&gt;
Beim nächsten Wareneingang, Rechnungseingang oder manuellen Lagerzugang passiert deshalb Folgendes: Die Formel nimmt den letzten berechneten MEK als „alten MEK", rechnet den Zugang dazu und überschreibt das Feld im Artikelstamm. Der falsche Ausgangswert ist wieder da, lediglich mit dem neuen Zugang verdünnt. Je größer der Bestand im Verhältnis zum Zugang, desto weniger ändert sich, und desto länger schleppt sich der Fehler durch. Sage beschreibt das in der Supportinformation knapp: Ein manuell eingetragener MEK wird durch die MEK-Berechnung überschrieben.
&lt;/p&gt;
&lt;p&gt;
Eine Nebenwirkung, die gern übersehen wird: Steht der Artikel auf „MEK übernehmen", kopiert der Artikelstamm den von Hand geänderten MEK sofort in den kalkulatorischen EK. Bis zum nächsten Zugang rechnen dann beide Preise mit dem manuellen Wert, danach beide wieder mit dem berechneten.
&lt;/p&gt;
&lt;details class="deep-dive"&gt;
&lt;summary&gt;
&lt;span class="deep-dive-label"&gt;Deep Dive&lt;/span&gt;
&lt;span&gt;Wie die drei Preise in der Datenbank entstehen und weiterwirken&lt;/span&gt;
&lt;span class="deep-dive-chev"&gt;&lt;svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;&lt;path d="m6 9 6 6 6-6"/&gt;&lt;/svg&gt;&lt;/span&gt;
&lt;/summary&gt;
&lt;div class="deep-dive-body"&gt;
&lt;p&gt;
Für alle, die den Ablauf bis in die Tabellen nachvollziehen wollen. Grundlage sind die Datenbank und die Metadaten einer Sage 100 in Version 9.0.11 mit dem Demomandanten 123 in &lt;code&gt;OLDemoReweAbfD&lt;/code&gt;, gelesen am 27.09.2026. Alle drei Preise liegen in Eigenwährung mit vier Nachkommastellen.
&lt;/p&gt;
&lt;h3&gt;Wo die Preise liegen&lt;/h3&gt;
&lt;p&gt;
Die laufenden Werte stehen je Artikelvariante in &lt;code&gt;KHKArtikelVarianten&lt;/code&gt;, Primärschlüssel Artikelnummer, Mandant und AuspraegungID. Ein Artikel mit Farb- oder Größenausprägungen hat also je Ausprägung einen eigenen MEK. Die Pflegeart des kalkulatorischen EK hängt dagegen am Artikel, nicht an der Variante.
&lt;/p&gt;
&lt;table class="tech-table"&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Preis&lt;/th&gt;
&lt;th&gt;Spalte&lt;/th&gt;
&lt;th&gt;Wer schreibt&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Mittlerer EK&lt;/td&gt;
&lt;td&gt;&lt;code&gt;KHKArtikelVarianten.MittlererEK&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Die MEK-Berechnung nach Einkaufs- und Verkaufsbelegen, Lagerbuchungen, Inventur und Fertigmeldung. Zusätzlich der Artikelstamm bei manueller Änderung.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Letzter EK&lt;/td&gt;
&lt;td&gt;&lt;code&gt;KHKArtikelVarianten.LetzterEK&lt;/code&gt;&lt;br&gt;dazu &lt;code&gt;LetzterLieferant&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Das Speichern eines Einkaufsbelegs, dessen Belegart geliefert oder berechnet mit Wirkung +1 ist. Die Fertigmeldung kann ihn aus der letzten Lagerzugangsbuchung neu setzen.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kalkulatorischer EK&lt;/td&gt;
&lt;td&gt;&lt;code&gt;KHKArtikelVarianten.KalkulatorischerEK&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Artikelstamm und Schnelländerung bei manueller Pflege, sonst jeder neue LEK oder MEK, je nach &lt;code&gt;KHKArtikel.PreispflegeEK&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="tech-table"&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;PreispflegeEK&lt;/th&gt;
&lt;th&gt;Text in der Maske&lt;/th&gt;
&lt;th&gt;Wirkung&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;EK wird manuell gepflegt&lt;/td&gt;
&lt;td&gt;MEK- und LEK-Läufe lassen den kalkulatorischen EK stehen.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;LEK übernehmen&lt;/td&gt;
&lt;td&gt;Jeder neu geschriebene LEK wird in den kalkulatorischen EK kopiert.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;MEK übernehmen&lt;/td&gt;
&lt;td&gt;Jeder neu geschriebene MEK wird kopiert, auch ein von Hand geänderter.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;
Drei weitere Tabellen halten Verlauf und Warteschlange: &lt;code&gt;KHKArtikelbewertungMEKHistorie&lt;/code&gt; mit einem MEK je Artikel, Ausprägung und Tag, &lt;code&gt;KHKArtikelbewertungKEKHistorie&lt;/code&gt; in derselben Form für den kalkulatorischen EK, und &lt;code&gt;KHKArtikelMEKAktualisierung&lt;/code&gt; als Merker für die zeitversetzte Nachrechnung. Auf jeder Lagerbuchung in &lt;code&gt;KHKLagerplatzbuchungen&lt;/code&gt; stehen außerdem der Einstandspreis der Bewegung und der MEK zum Zeitpunkt der Buchung. Die Trigger auf der Variantentabelle rechnen nichts, die Logik sitzt komplett im Programm.
&lt;/p&gt;
&lt;h3&gt;Was den MEK-Lauf anstößt&lt;/h3&gt;
&lt;p&gt;
Ob ein Beleg die MEK-Berechnung auslöst, entscheidet das Kennzeichen MEK-Berechnung an der Belegart in &lt;code&gt;KHKEKBelegarten&lt;/code&gt; beziehungsweise &lt;code&gt;KHKVKBelegarten&lt;/code&gt;. Im Auslieferungszustand sind das:
&lt;/p&gt;
&lt;table class="tech-table"&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Belegart&lt;/th&gt;
&lt;th&gt;MEK-Lauf&lt;/th&gt;
&lt;th&gt;Lagerwirkung&lt;/th&gt;
&lt;th&gt;Setzt den LEK&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Wareneingang (ELL)&lt;/td&gt;
&lt;td&gt;ja&lt;/td&gt;
&lt;td&gt;+1&lt;/td&gt;
&lt;td&gt;ja, über Lieferung&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rechnungseingang (ERR)&lt;/td&gt;
&lt;td&gt;ja&lt;/td&gt;
&lt;td&gt;keine&lt;/td&gt;
&lt;td&gt;ja, über Rechnung&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Direkt- und Sofortrechnung (ERD, ERS)&lt;/td&gt;
&lt;td&gt;ja&lt;/td&gt;
&lt;td&gt;+1&lt;/td&gt;
&lt;td&gt;ja&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Retoure (ELR)&lt;/td&gt;
&lt;td&gt;ja&lt;/td&gt;
&lt;td&gt;−1&lt;/td&gt;
&lt;td&gt;nein&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gutschrift, Stornorechnung, Bestellung&lt;/td&gt;
&lt;td&gt;nein&lt;/td&gt;
&lt;td&gt;keine&lt;/td&gt;
&lt;td&gt;nein&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lieferschein, Rücklieferschein, Sofortbelege im Verkauf (VLL, VLR, VSD, VSL, VSS)&lt;/td&gt;
&lt;td&gt;ja&lt;/td&gt;
&lt;td&gt;−1 bzw. +1&lt;/td&gt;
&lt;td&gt;nein&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Angebot, Auftrag, Rechnung im Verkauf&lt;/td&gt;
&lt;td&gt;nein&lt;/td&gt;
&lt;td&gt;keine&lt;/td&gt;
&lt;td&gt;nein&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;
Der Rechnungseingang stößt den Lauf an, obwohl er nicht lagert. Bei der Einstellung „Sofort mit Berücksichtigung der RE" wertet er den bereits vereinnahmten Mengenanteil auf den Rechnungspreis um. Verkaufsrechnungen rechnen zwar einen Roherlös, der MEK-Lauf hängt aber am Lieferschein oder am Sofortbeleg, weil erst dort die Lagerbewegung stattfindet.
&lt;/p&gt;
&lt;h3&gt;Der Stückpreis eines Zugangs&lt;/h3&gt;
&lt;p&gt;
In die Formel geht nicht der Einzelpreis aus der Maske ein, sondern der interne Gesamtpreis der Position in Eigenwährung geteilt durch die Menge in Basismengeneinheit. Rabatte sind darin schon abgezogen, Zuschläge als eigene Belegposition nicht enthalten. Retouren mindern die Zugangsmenge, ein Rechnungseingang mit anderem Preis bewertet den berechneten Anteil neu:
&lt;/p&gt;
&lt;div class="formula"&gt;
&lt;math display="block"&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mtext&gt;Menge&lt;/mtext&gt;&lt;mtext&gt;Rest&lt;/mtext&gt;&lt;/msub&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;msub&gt;&lt;mtext&gt;Menge&lt;/mtext&gt;&lt;mtext&gt;Zugang&lt;/mtext&gt;&lt;/msub&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;msub&gt;&lt;mtext&gt;Menge&lt;/mtext&gt;&lt;mtext&gt;Retoure&lt;/mtext&gt;&lt;/msub&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;msub&gt;&lt;mtext&gt;Menge&lt;/mtext&gt;&lt;mtext&gt;berechnet&lt;/mtext&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;/math&gt;
&lt;math display="block"&gt;&lt;mrow&gt;&lt;mtext&gt;Wert des Zugangs&lt;/mtext&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;msub&gt;&lt;mtext&gt;Menge&lt;/mtext&gt;&lt;mtext&gt;Rest&lt;/mtext&gt;&lt;/msub&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;msub&gt;&lt;mtext&gt;Stückpreis&lt;/mtext&gt;&lt;mtext&gt;WE&lt;/mtext&gt;&lt;/msub&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;msub&gt;&lt;mtext&gt;Menge&lt;/mtext&gt;&lt;mtext&gt;berechnet&lt;/mtext&gt;&lt;/msub&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;msub&gt;&lt;mtext&gt;Stückpreis&lt;/mtext&gt;&lt;mtext&gt;RE&lt;/mtext&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;/math&gt;
&lt;math display="block"&gt;&lt;mrow&gt;&lt;mtext&gt;Stückpreis der Bewegung&lt;/mtext&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mfrac&gt;&lt;mrow&gt;&lt;mtext&gt;Wert des Zugangs&lt;/mtext&gt;&lt;/mrow&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mtext&gt;Menge&lt;/mtext&gt;&lt;mtext&gt;Rest&lt;/mtext&gt;&lt;/msub&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;msub&gt;&lt;mtext&gt;Menge&lt;/mtext&gt;&lt;mtext&gt;berechnet&lt;/mtext&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;/mfrac&gt;&lt;/mrow&gt;&lt;/math&gt;
&lt;/div&gt;
&lt;p&gt;
Bei „Sofort ohne Berücksichtigung der RE" entfällt der zweite Summand, der Wareneingangspreis bleibt stehen.
&lt;/p&gt;
&lt;h3&gt;Die taggenaue Neuberechnung&lt;/h3&gt;
&lt;p&gt;
Bei den beiden Sofort-Einstellungen und im Abschluss-Lauf der MEK-Aktualisierung baut die Sage die Historie ab dem letzten Stützpunkt vor dem Bewegungsdatum neu auf. Der Ablauf:
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Der historische Bestand am Stützpunkt wird aus dem heutigen Bestand rückwärts gerechnet: Heutiger Bestand in Basismenge minus alle seitherigen Zugänge plus alle seitherigen Abgänge.&lt;/li&gt;
&lt;li&gt;Der Start-MEK kommt aus der Historie. Fehlt sie, aus dem MEK der ersten Lagerbuchung, und wenn auch die fehlt, aus dem Artikelstamm. Das ist der einzige Moment, in dem das Stammfeld als Eingabe dient.&lt;/li&gt;
&lt;li&gt;Gelesen werden lagerwirksame Einkaufszugänge mit echter Lagerbuchung, lagerwirksame Verkaufsabgänge und Verkaufszugänge, manuelle Lagerbuchungen und Inventurbuchungen sowie Abgänge interner Fertigungsaufträge.&lt;/li&gt;
&lt;li&gt;Alle Bewegungen laufen in Datums- und Buchungsreihenfolge durch. Bewegungen desselben Tages und derselben Richtung werden zu einer Historienzeile zusammengefasst.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="formula"&gt;
&lt;div class="formula-case"&gt;
&lt;span class="formula-case-label"&gt;Startwert&lt;/span&gt;
&lt;math display="block"&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mtext&gt;Wert&lt;/mtext&gt;&lt;mtext&gt;0&lt;/mtext&gt;&lt;/msub&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mtext&gt;historischer Bestand&lt;/mtext&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;msub&gt;&lt;mtext&gt;MEK&lt;/mtext&gt;&lt;mtext&gt;alt&lt;/mtext&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;/math&gt;
&lt;/div&gt;
&lt;div class="formula-case"&gt;
&lt;span class="formula-case-label"&gt;Zugang, Bestand danach kleiner oder gleich Zugangsmenge&lt;/span&gt;
&lt;math display="block"&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mtext&gt;MEK&lt;/mtext&gt;&lt;mtext&gt;neu&lt;/mtext&gt;&lt;/msub&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mtext&gt;Stückpreis dieses Zugangs&lt;/mtext&gt;&lt;/mrow&gt;&lt;/math&gt;
&lt;math display="block"&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mtext&gt;Wert&lt;/mtext&gt;&lt;mtext&gt;neu&lt;/mtext&gt;&lt;/msub&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;msub&gt;&lt;mtext&gt;MEK&lt;/mtext&gt;&lt;mtext&gt;neu&lt;/mtext&gt;&lt;/msub&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;msub&gt;&lt;mtext&gt;Bestand&lt;/mtext&gt;&lt;mtext&gt;danach&lt;/mtext&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;/math&gt;
&lt;/div&gt;
&lt;div class="formula-case"&gt;
&lt;span class="formula-case-label"&gt;Zugang, Bestand danach größer als Zugangsmenge&lt;/span&gt;
&lt;math display="block"&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mtext&gt;Wert&lt;/mtext&gt;&lt;mtext&gt;neu&lt;/mtext&gt;&lt;/msub&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;msub&gt;&lt;mtext&gt;Wert&lt;/mtext&gt;&lt;mtext&gt;alt&lt;/mtext&gt;&lt;/msub&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mtext&gt;Einstand des Zugangs&lt;/mtext&gt;&lt;/mrow&gt;&lt;/math&gt;
&lt;math display="block"&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mtext&gt;MEK&lt;/mtext&gt;&lt;mtext&gt;neu&lt;/mtext&gt;&lt;/msub&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mfrac&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mtext&gt;Wert&lt;/mtext&gt;&lt;mtext&gt;neu&lt;/mtext&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mtext&gt;Bestand&lt;/mtext&gt;&lt;mtext&gt;danach&lt;/mtext&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;/mfrac&gt;&lt;/mrow&gt;&lt;/math&gt;
&lt;/div&gt;
&lt;div class="formula-case"&gt;
&lt;span class="formula-case-label"&gt;Abgang&lt;/span&gt;
&lt;math display="block"&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mtext&gt;Bestand&lt;/mtext&gt;&lt;mtext&gt;neu&lt;/mtext&gt;&lt;/msub&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;msub&gt;&lt;mtext&gt;Bestand&lt;/mtext&gt;&lt;mtext&gt;alt&lt;/mtext&gt;&lt;/msub&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mtext&gt;Menge&lt;/mtext&gt;&lt;/mrow&gt;&lt;/math&gt;
&lt;math display="block"&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mtext&gt;Wert&lt;/mtext&gt;&lt;mtext&gt;neu&lt;/mtext&gt;&lt;/msub&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;msub&gt;&lt;mtext&gt;Wert&lt;/mtext&gt;&lt;mtext&gt;alt&lt;/mtext&gt;&lt;/msub&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mtext&gt;Menge&lt;/mtext&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;msub&gt;&lt;mtext&gt;MEK&lt;/mtext&gt;&lt;mtext&gt;alt&lt;/mtext&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;/math&gt;
&lt;math display="block"&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mtext&gt;MEK&lt;/mtext&gt;&lt;mtext&gt;neu&lt;/mtext&gt;&lt;/msub&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;msub&gt;&lt;mtext&gt;MEK&lt;/mtext&gt;&lt;mtext&gt;alt&lt;/mtext&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;/math&gt;
&lt;span class="formula-note"&gt;Der Stückpreis bleibt, nur Menge und Wert sinken.&lt;/span&gt;
&lt;/div&gt;
&lt;div class="formula-case"&gt;
&lt;span class="formula-case-label"&gt;Interne Bestandsmehrung ohne neuen Preis&lt;/span&gt;
&lt;math display="block"&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mtext&gt;Wert&lt;/mtext&gt;&lt;mtext&gt;neu&lt;/mtext&gt;&lt;/msub&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;msub&gt;&lt;mtext&gt;Wert&lt;/mtext&gt;&lt;mtext&gt;alt&lt;/mtext&gt;&lt;/msub&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mtext&gt;Menge&lt;/mtext&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;msub&gt;&lt;mtext&gt;MEK&lt;/mtext&gt;&lt;mtext&gt;alt&lt;/mtext&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;/math&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
Die erste Zugangsregel erklärt, warum Bestand null oder negativ den alten Durchschnitt löscht: War vor dem Zugang nichts oder weniger als nichts da, gilt der Preis des Zugangs komplett. Jeder Tagespreis wird auf vier Stellen gerundet und in die MEK-Historie geschrieben. Der jüngste Historiensatz wird zum neuen Stammwert, und bei Pflegeart 2 gleichzeitig zum kalkulatorischen EK.
&lt;/p&gt;
&lt;p&gt;
Ein reiner Verkaufsabgang ändert den Stückpreis nicht. Neu gerechnet wird nach einem Verkaufsbeleg nur, wenn hinter seinem Liefertermin noch ein Zugang liegt, denn dann verschiebt sich der Bestandssockel, in den sich dieser Zugang mischt. Bei zeitversetzter Einstellung wird der Artikel nur vorgemerkt.
&lt;/p&gt;
&lt;h3&gt;Die vereinfachte Formel nach Wareneingang&lt;/h3&gt;
&lt;p&gt;
Die Einstellung „Zeitversetzt mit Aktualisierung nach WE" rechnet ohne Historie, nur beim echten Wareneingang und mit dem aktuellen Bestand, in dem der gerade gespeicherte Beleg schon enthalten ist:
&lt;/p&gt;
&lt;div class="formula"&gt;
&lt;math display="block"&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mtext&gt;Bestand&lt;/mtext&gt;&lt;mtext&gt;neu&lt;/mtext&gt;&lt;/msub&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mtext&gt;Lagerbestand&lt;/mtext&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;mtext&gt;Umrechnungsfaktor LME&lt;/mtext&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mtext&gt;Menge dieses Belegs&lt;/mtext&gt;&lt;/mrow&gt;&lt;/math&gt;
&lt;math display="block"&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mtext&gt;Bestand&lt;/mtext&gt;&lt;mtext&gt;alt&lt;/mtext&gt;&lt;/msub&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;msub&gt;&lt;mtext&gt;Bestand&lt;/mtext&gt;&lt;mtext&gt;neu&lt;/mtext&gt;&lt;/msub&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mtext&gt;Zugangsmenge&lt;/mtext&gt;&lt;/mrow&gt;&lt;/math&gt;
&lt;math display="block"&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mtext&gt;MEK&lt;/mtext&gt;&lt;mtext&gt;neu&lt;/mtext&gt;&lt;/msub&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mfrac&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mtext&gt;Bestand&lt;/mtext&gt;&lt;mtext&gt;alt&lt;/mtext&gt;&lt;/msub&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;msub&gt;&lt;mtext&gt;MEK&lt;/mtext&gt;&lt;mtext&gt;alt&lt;/mtext&gt;&lt;/msub&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mtext&gt;Gesamtpreis intern EW&lt;/mtext&gt;&lt;/mrow&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mtext&gt;Bestand&lt;/mtext&gt;&lt;mtext&gt;neu&lt;/mtext&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;/mfrac&gt;&lt;/mrow&gt;&lt;/math&gt;
&lt;/div&gt;
&lt;p&gt;
Ist die Zugangsmenge nicht positiv, der Gesamtpreis negativ, der Bestand vor dem Zugang negativ oder der neue Bestand nicht positiv, wird die Rechnung verworfen und der Stamm bleibt unverändert. Liefertermine, Belegänderungen und Retouren holt erst die MEK-Aktualisierung nach.
&lt;/p&gt;
&lt;h3&gt;Wie der LEK entsteht&lt;/h3&gt;
&lt;p&gt;
Beim Speichern eines passenden Einkaufsbelegs sucht die Sage je Artikelposition die jüngste Einkaufsposition mit positiver Basismenge, deren Belegart geliefert oder berechnet mit Wirkung +1 ist und deren Belegdatum größer oder gleich dem Datum des gerade gespeicherten Belegs ist. Sortiert wird nach Belegdatum und dann nach Beleg-ID absteigend. Der LEK ist der interne Gesamtpreis dieser Position geteilt durch ihre Basismenge, der Lieferant wandert nach &lt;code&gt;LetzterLieferant&lt;/code&gt;. Ein nachträglich erfasster älterer Beleg überschreibt deshalb keinen jüngeren LEK, und Retouren fallen durch die Mengenbedingung heraus.
&lt;/p&gt;
&lt;h3&gt;Was im Verkauf passiert&lt;/h3&gt;
&lt;p&gt;
Beim Anlegen einer Verkaufsposition liest die Sage die Mandanteneigenschaft Roherlösberechnung (0 mittlerer EK, 1 kalkulatorischer EK, 2 letzter EK) und schreibt den passenden Stammpreis nach &lt;code&gt;KHKVKBelegePositionen.MittlererEK&lt;/code&gt;. Der Spaltenname bleibt immer derselbe, auch wenn der kalkulatorische EK drinsteht. Das Verfahren steht daneben in &lt;code&gt;Roherloesberechnung&lt;/code&gt;, eine manuelle Übersteuerung im Preisnachweis in &lt;code&gt;MittlererEKManuell&lt;/code&gt;. Bei einer Handelsstückliste ist der Preis die Summe der Komponentenpreise mal Stücklistenmenge.
&lt;/p&gt;
&lt;p&gt;
Der Roherlös selbst hängt vom Roherlösmodus der Verkaufsbelegart ab. Angebot, Auftrag, Lieferschein, Rechnung und die Sofortbelege rechnen Gesamtpreis intern minus gerundete Menge mal Positionspreis. Anzahlung, Proforma und Rahmenvertrag liefern null. Die Gutschrift setzt den Roherlös auf den Gesamtpreis. Die Mandanteneigenschaft Einkaufspreise entscheidet, ob bei der Belegübernahme der Preis aus dem ersten Beleg der Kette bleibt oder neu aus dem Stamm kommt. Neu gezogen wird nur, wenn die Position nicht manuell gekennzeichnet ist, der Beleg keine Stornorechnung ist und kein Projekt-EK auf der Position liegt.
&lt;/p&gt;
&lt;h3&gt;Lagerbewertung, Inventur, Fertigung&lt;/h3&gt;
&lt;p&gt;
Die Lagerbewertung rechnet Menge mal Preis mal Bewertungssatz durch 100, der Bewertungssatz kommt über &lt;code&gt;KHKArtikel.Bewertungssatz&lt;/code&gt; aus &lt;code&gt;KHKBewertungssaetze&lt;/code&gt;. Preisgrundlage ist wahlweise der MEK, der kalkulatorische EK oder ein Verkaufspreis aus einer Preisliste. Die Inventur kopiert beim Aufbau der Zählliste alle drei Preise nach &lt;code&gt;KHKIVBelegePositionen&lt;/code&gt;, bewertet Differenzen mit dem MEK der Zählposition und ruft nach der Verbuchung die MEK-Berechnung mit Menge und Einstand der Differenzbuchung auf. Die Fertigmeldung hat eine eigene Preiswahl über drei Mandanteneigenschaften: Ob die Auftragskosten als Einstand gelten, und falls nicht, ob MEK, kalkulatorischer EK oder LEK genommen wird. Anschließend setzt sie den LEK aus der letzten Lagerzugangsbuchung und stößt die MEK-Berechnung mit dem Einstand der Rückmeldung an.
&lt;/p&gt;
&lt;h3&gt;Nachsehen im eigenen Mandanten&lt;/h3&gt;
&lt;p&gt;
Die drei Mandanteneinstellungen stehen als Eigenschaften in &lt;code&gt;KHKMandanten&lt;/code&gt;: 40004 ist die MEK-Berechnung (−1 zeitversetzt, 0 sofort mit RE, 1 zeitversetzt mit Aktualisierung nach WE, 2 sofort ohne RE), 40034 die Roherlösberechnung und 40046 die Übernahme der Einkaufspreise (0 Initialbeleg, 1 Stamm).
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT Eigenschaft, Wert
FROM KHKMandanten
WHERE Mandant = 123
AND Eigenschaft IN (40004, 40034, 40046)
SELECT PreispflegeEK, COUNT(*) AS Artikel
FROM KHKArtikel
WHERE Mandant = 123
GROUP BY PreispflegeEK
SELECT TOP 20 Datum, MittlererEK
FROM KHKArtikelbewertungMEKHistorie
WHERE Mandant = 123 AND Artikelnummer = '00200050' AND AuspraegungID = 0
ORDER BY Datum DESC&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Im Demomandanten steht die MEK-Berechnung auf sofort mit RE und die Roherlösberechnung auf dem kalkulatorischen EK. Von 151 Artikeln werden 122 manuell gepflegt, 6 übernehmen den LEK und 23 den MEK. Von 19 311 Verkaufspositionen tragen 19 267 das Verfahren kalkulatorischer EK. Ein Beispiel, das die Zusammenhänge zeigt: Die Stehleuchte 00200050 steht auf „MEK übernehmen". Ihr MEK ist 10,3767, der kalkulatorische EK ebenfalls, der LEK dagegen 133,0000, weil er der Stückpreis eines einzelnen späteren Einkaufsbelegs ist und den gewichteten Lagerwert nicht ersetzt. Die MEK-Historie bestätigt den Stammwert mit dem jüngsten Satz vom 25.01.2021, davor stand am 04.09.2018 ein Wert von 9,5804. Das Antennenkabel 00250012 steht dagegen auf manueller Pflege: MEK 0,0263, LEK 0,0291, kalkulatorischer EK 0,0301. Hier hält der KEK einen eigenen Wert, den weder Beleg noch Durchschnitt überschrieben haben.
&lt;/p&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;
&lt;strong&gt;Grenzen:&lt;/strong&gt; Die Abläufe wurden an Datenbank und Metadaten der Version 9.0.11 nachvollzogen, die Zahlen stammen aus dem Demomandanten. Ein einzelner Wareneingang wurde dafür nicht in der Oberfläche neu gebucht. In anderen Versionen können Eigenschaftsnummern und Belegartenkennzeichen abweichen.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;h2&gt;Den MEK dauerhaft korrigieren&lt;/h2&gt;
&lt;p&gt;
Es gibt zwei saubere Wege, und welcher passt, hängt davon ab, wo der Fehler herkommt.
&lt;/p&gt;
&lt;h3&gt;Weg 1: Den Beleg korrigieren, der den Fehler verursacht hat&lt;/h3&gt;
&lt;p&gt;
Wenn ein einzelner Wareneingang mit falschem Preis oder falscher Menge schuld ist, korrigiere den Beleg selbst, sofern er noch änderbar ist. Weil die Sage den MEK entlang der Liefertermine neu aufbaut, sobald sich ein Beleg ändert, wird der Verlauf ab diesem Datum korrigiert, inklusive aller späteren Zugänge. Bei zeitversetzter Berechnung musst Du danach die MEK-Aktualisierung anstoßen. Das ist der Weg, der auch die historische Lagerbewertung richtig stellt.
&lt;/p&gt;
&lt;h3&gt;Weg 2: Bestand auf null und neu einlagern&lt;/h3&gt;
&lt;p&gt;
Wenn sich der Fehler nicht mehr auf einen Beleg zurückführen lässt oder mehrere Bewegungen betroffen sind, nutzt Du die Regel, dass bei Bestand null der nächste Zugang den MEK allein bestimmt:
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Bestand über alle Lagerorte ermitteln.&lt;/strong&gt; Der MEK gilt je Artikel und Ausprägung, nicht je Lager. Solange in irgendeinem Lager noch Bestand liegt, geht dieser mit dem alten MEK in die Formel ein.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Den gesamten Bestand auslagern.&lt;/strong&gt; Über eine manuelle Lagerbuchung (Abgang) in jedem betroffenen Lager, bis der Gesamtbestand null ist.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dieselbe Menge wieder einlagern, mit Gesamtpreis.&lt;/strong&gt; Der Lagerzugang verlangt einen Gesamtpreis, also Menge mal gewünschter Einstandspreis. Wer das Feld leer lässt, bekommt den bisherigen MEK vorgeschlagen, und die Korrektur verpufft. Für 6 Stück und einen Zielwert von 125,00 Euro trägst Du 750,00 Euro ein.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ergebnis prüfen.&lt;/strong&gt; Die Formel liefert (0 × alter MEK + 750,00) / 6 = 125,0000. Bei zeitversetzter Einstellung erst nach der MEK-Aktualisierung.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
Ein paar Dinge solltest Du vorher bedenken. Beide Buchungen erscheinen in Lagerjournal, Bestandshistorie und in der Inventurbewertung als Bewegungen, das gehört dokumentiert. Bei chargen- oder seriennummernpflichtigen Artikeln müssen die Nummern beim Aus- und Einlagern mitgeführt werden, sonst verlierst Du die Zuordnung. Wenn die Lagerbuchungen an die Finanzbuchhaltung übergeben werden, sprich das vorher mit der Buchhaltung ab. Und lege das Bewegungsdatum bewusst fest: Rückdatierte Buchungen bauen die Historie ab diesem Datum neu auf, Buchungen am Tag eines Abschlusses sorgen für Diskussionen.
&lt;/p&gt;
&lt;h2&gt;Wenn Du den Einkaufspreis regelmäßig selbst bestimmen willst&lt;/h2&gt;
&lt;p&gt;
Manche Betriebe wollen den Preis, mit dem der Roherlös gerechnet wird, bewusst steuern. Etwa weil Abwertungen eingerechnet werden sollen oder weil der Einstand über Bezugsnebenkosten anders aussieht als der Belegpreis. Dann ist der MEK das falsche Feld, und der Kampf gegen die Neuberechnung ist nicht zu gewinnen.
&lt;/p&gt;
&lt;p&gt;
Sage empfiehlt für diesen Fall den kalkulatorischen Einkaufspreis. Im Register Kalkulation des Artikelstamms stellst Du je Artikel über „Preispflege kalk. EK" ein, ob der KEK manuell gepflegt, vom LEK oder vom MEK übernommen wird. Artikel mit automatischem Einstand laufen weiter über den Durchschnitt, Artikel mit bewusst gesetztem Preis behalten Deinen Wert. Anschließend stellst Du die Roherlösermittlung in den Mandanteneinstellungen auf den kalkulatorischen EK um. Auch der KEK wird in einer eigenen Historie mitgeführt, allerdings erst ab dem Zeitpunkt der Umstellung. Für ältere Bestände fehlt dann in der historischen Lagerbewertung ein KEK-Wert.
&lt;/p&gt;
&lt;p&gt;
Was diese Umstellung nicht ändert: Auswertungen, Reports oder BI-Anbindungen, die direkt auf den MEK zugreifen, zeigen weiterhin den berechneten Durchschnitt. Wer dort den gesteuerten Preis sehen will, muss die Abfragen anpassen.
&lt;/p&gt;
&lt;h2&gt;Kurzcheck, wenn der Roherlös nicht plausibel ist&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Welcher Einkaufspreis ist in den Mandanteneinstellungen für den Roherlös hinterlegt, und passt das zum Artikel?&lt;/li&gt;
&lt;li&gt;Steht die MEK-Berechnung auf zeitversetzt, und wann lief die MEK-Aktualisierung zuletzt?&lt;/li&gt;
&lt;li&gt;Ist der Artikel lagerführend? Ohne Lagerführung gibt es keinen berechneten MEK.&lt;/li&gt;
&lt;li&gt;War der Bestand zwischenzeitlich negativ? Dann galt in dieser Zeit der LEK.&lt;/li&gt;
&lt;li&gt;Gibt es einen Wareneingang oder Lagerzugang mit auffälligem Preis oder Liefertermin?&lt;/li&gt;
&lt;li&gt;Hat jemand den MEK im Artikelstamm von Hand geändert, und wurde er beim nächsten Zugang überschrieben?&lt;/li&gt;
&lt;li&gt;Stammt der Preis auf der Position noch aus dem Auftrag von vor drei Monaten? Die Einstellung „Einkaufspreise" entscheidet, ob bei der Belegübernahme neu gelesen wird.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Fazit&lt;/h2&gt;
&lt;p&gt;
Der mittlere Einkaufspreis ist ein Rechenergebnis, kein Stammdatum. Wer ihn im Artikelstamm überschreibt, ändert eine Anzeige, nicht die Grundlage. Dauerhaft korrigieren lässt er sich nur über die Bewegungen, die ihn erzeugen: Durch die Korrektur des verursachenden Belegs oder durch Auslagern und Wiedereinlagern mit dem richtigen Gesamtpreis. Und wer den Einkaufspreis regelmäßig selbst festlegen will, ist mit dem kalkulatorischen EK besser bedient als mit einem Feld, das die Sage bei jedem Wareneingang neu berechnet.
&lt;/p&gt;
&lt;p&gt;
Wenn bei Dir Roherlöse oder Bestandsbewertungen nicht zusammenpassen, schauen wir uns gern gemeinsam an, wo der MEK herkommt. Meist steckt die Ursache in einem einzelnen Beleg oder in einer Mandanteneinstellung, die seit Jahren niemand mehr geprüft hat.
&lt;/p&gt;
&lt;div style="text-align: center; margin: 3rem 0;"&gt;
&lt;a href="https://appontes.de/kontakt/?betreff=anfrage-sage" class="btn btn-primary"&gt;Fragen zur Sage 100 Warenwirtschaft stellen&lt;/a&gt;
&lt;/div&gt;</content:encoded></item><item><title>Sage 100: Der Server wurde umbenannt und nichts läuft mehr</title><link>https://appontes.de/blog/servername-geaendert-sage-100-startet-nicht/</link><guid isPermaLink="true">https://appontes.de/blog/servername-geaendert-sage-100-startet-nicht/</guid><pubDate>Sat, 26 Sep 2026 00:00:00 +0000</pubDate><dc:creator>Thomas Falkner</dc:creator><category>Sage 100</category><category>Applikationsserver</category><category>Mehrbenutzerdienst</category><category>BlobStorage</category><category>IT-Infrastruktur</category><description>Ein Administrator benennt den Sage-Server um, am Samstag meldet er sich über die Notfallhotline, weil der Applikationsserver nicht mehr startet. Warum ein neuer Computername für die Sage 100 nicht reicht, an welchen Stellen die vier Dienste den alten Namen lesen und in welcher Reihenfolge Du das reparierst.</description><content:encoded>&lt;p&gt;&lt;img src="https://appontes.de/img/blog/servername-sage-100.svg" alt="Sage 100: Der Server wurde umbenannt und nichts läuft mehr"&gt;&lt;/p&gt;
&lt;p&gt;
Freitagnachmittag, der Administrator räumt die Namenskonventionen im Netz auf. Der Server, auf dem die Sage 100 läuft, heißt seit Jahren &lt;code&gt;ALTSERVER&lt;/code&gt;, jetzt soll er &lt;code&gt;SAGE01&lt;/code&gt; heißen. Systemsteuerung, Computername ändern, Neustart, DNS stimmt, Ping antwortet. Fertig, Wochenende.
&lt;/p&gt;
&lt;p&gt;
Samstagvormittag klingelt unsere Notfallhotline. Beim Kunden startet die Sage 100 nicht mehr. Der Smart Client zeigt „Es ist kein Application Gateway erreichbar", in der Diensteverwaltung steht der Sage Applikationsserver auf „Beendet", und wer ihn von Hand startet, sieht ihn nach wenigen Sekunden wieder stehen. Der BlobStorage-Dienst ist ebenfalls aus. Der Mehrbenutzerdienst dagegen läuft, und genau das macht die Sache verwirrend.
&lt;/p&gt;
&lt;figure class="blog-figure"&gt;
&lt;img src="https://appontes.de/img/blog/servername/smart-client-kein-gateway.png" alt="Fehlerdialog der Sage 100 Warenwirtschaft mit rotem Symbol und der Meldung Es ist kein Application Gateway erreichbar, darunter die Schaltflächen Wiederholen und Schließen" width="648" height="363" loading="lazy"&gt;
&lt;figcaption&gt;Der Smart Client bricht beim Start ab. Wiederholen ändert nichts, solange der Server den alten Namen sucht.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;
Die Empfehlung, die der Kunde bis dahin bekommen hatte, lautete: Applikationsserver und BlobStorage deinstallieren, Registry bereinigen, alles neu installieren. Bei einem Produktivsystem, das am Montag wieder laufen muss, wollten wir diesen Weg vermeiden. Eine komplette Neuinstallation hätte den Ausfall unnötig verlängert. Wir haben stattdessen die Stellen gesucht, an denen der alte Name noch stand, und die Dienste ohne Neuinstallation wieder in Betrieb genommen. Dieser Beitrag beschreibt, warum die Sage 100 auf eine Umbenennung so empfindlich reagiert, wo der Name überall hinterlegt ist und in welcher Reihenfolge die Umstellung gelingt.
&lt;/p&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;
&lt;strong&gt;Hinweis zur Version:&lt;/strong&gt; Die folgenden Erkenntnisse und Schritte beziehen sich auf Sage 100 Version 9.0.11.5. Die beschriebenen Dienstnamen, Registry-Pfade, Konfigurationsdateien, Ports und Abläufe wurden in dieser Version im Rahmen konkreter Debug-Sessions nachvollzogen. In anderen Versionen können einzelne Bezeichnungen, Pfade oder Abläufe abweichen.
&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;Vier Dienste, vier Stellen für denselben Namen&lt;/h2&gt;
&lt;p&gt;
In der von uns untersuchten Installation liefen Applikationsserver, BlobStorage, Mehrbenutzerdienst und Application Gateway auf derselben Maschine. Man könnte annehmen, dass sie einfach den Windows-Computernamen verwenden. Tun sie nicht. Jeder der vier Dienste liest den Namen an einer eigenen Stelle, und keine davon ändert sich, wenn Du den Rechner umbenennst.
&lt;/p&gt;
&lt;table class="tech-table"&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dienst&lt;/th&gt;
&lt;th&gt;Woran der Name hängt&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sage Applikationsserver&lt;br&gt;&lt;code&gt;SagedeApplicationServerService90&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Startet den Token-Dienst (STS) und die SData-Endpunkte. Liest den Namen des Mehrbenutzerservers aus der Office-Line-Konfiguration. Sein Registry-Schlüssel heißt wie der Computername.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sage BlobStorageServer&lt;br&gt;&lt;code&gt;SagedeBlobStorageServer90&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Ports 4000 bis 4030. Muss den STS unter dem Host erreichen, den der Applikationsserver anbietet.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sage Mehrbenutzerdienst&lt;br&gt;&lt;code&gt;SageMultiUserService40&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Lauscht auf einer lokalen &lt;a class="glossar-term" href="https://appontes.de/glossar/named-pipes/"&gt;Named Pipe&lt;span class="glossar-tip" aria-hidden="true"&gt;&lt;strong&gt;Named Pipes&lt;/strong&gt;Windows-Mechanismus für die Kommunikation zwischen Prozessen über benannte Kanäle, lokal oder über das Netzwerk per Servername angesprochen.&lt;em&gt;Mehr im Glossar &amp;#8594;&lt;/em&gt;&lt;/span&gt;&lt;/a&gt;. Die Clients, auch der Applikationsserver, suchen ihn aber unter dem Namen aus der Office-Line-Konfiguration.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Application Gateway&lt;br&gt;&lt;code&gt;SagedeApplicationGateway&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Endpunkt &lt;code&gt;https://&amp;lt;Name&amp;gt;:4337/api&lt;/code&gt;. Der Smart Client nimmt nur einen Registry-Schlüssel, dessen State auf Started steht. Das TLS-Zertifikat auf dem Port muss zum Hostnamen passen.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;
Alle vier Dienste laufen als LocalSystem. Ihre Konfiguration liegt im 32-Bit-Zweig der Registry unter &lt;code&gt;HKLM\SOFTWARE\WOW6432Node\Sage\Office Line\9.0&lt;/code&gt;, weil die Sage-Prozesse 32-Bit-Anwendungen sind. Wer nur im 64-Bit-Zweig unter &lt;code&gt;HKLM\SOFTWARE&lt;/code&gt; sucht, findet die Einträge deshalb nicht.
&lt;/p&gt;
&lt;h2&gt;Das Fehlerbild im Ereignisprotokoll&lt;/h2&gt;
&lt;p&gt;
Auf dem Client gibt es zunächst nur die Meldung, dass kein Application Gateway erreichbar ist. Die technischen Details dahinter zeigen, dass der Client in &lt;code&gt;Bootstrapper.IsApplicationGatewayAvailable&lt;/code&gt; scheitert. Das bestätigt, wo der Fehler sichtbar wird, aber nicht, wo er entsteht:
&lt;/p&gt;
&lt;figure class="blog-figure"&gt;
&lt;img src="https://appontes.de/img/blog/servername/meldung-technische-details.png" alt="Meldungsfenster der Sage 100 mit Applikation Sagede.Officeline.Client.exe, Komponente Sagede.Shell.Core.dll und dem Text Es ist kein Application Gateway erreichbar, darunter die technischen Details mit System.Runtime.Remoting.ServerException ApplicationGateway ist nicht erreichbar bei Sagede.OfficeLine.Client.Bootstrapper.IsApplicationGatewayAvailable" width="713" height="585" loading="lazy"&gt;
&lt;figcaption&gt;Die technischen Details auf dem Client: Eine ServerException aus dem Bootstrapper, mehr nicht. Die Ursache steht auf dem Server.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;
Das Windows-Ereignis 1026 zeigt nur den äußeren Ausnahmetyp. Die eigentliche Aussage steht im Sage-Protokoll des Applikationsservers unter der Ereignisquelle &lt;code&gt;SagedeApplicationServerService90&lt;/code&gt;:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Sagede.ApplicationServer.HostedApplicationException
Der Server kann nicht gestartet werden. Applikation lehnt den Start ab.
Sagede.Core.MultiUser.MultiUserException
Es ist ein Fehler im Client des Mehrbenutzerdienstes aufgetreten.
Grund: Es kann keine Verbindung zum Mehrbenutzerdienst auf '\\ALTSERVER'
hergestellt werden.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Das erklärt den scheinbaren Widerspruch. Der Mehrbenutzerdienst läuft, seine &lt;a class="glossar-term" href="https://appontes.de/glossar/named-pipes/"&gt;Named Pipe&lt;span class="glossar-tip" aria-hidden="true"&gt;&lt;strong&gt;Named Pipes&lt;/strong&gt;Windows-Mechanismus für die Kommunikation zwischen Prozessen über benannte Kanäle, lokal oder über das Netzwerk per Servername angesprochen.&lt;em&gt;Mehr im Glossar &amp;#8594;&lt;/em&gt;&lt;/span&gt;&lt;/a&gt; &lt;code&gt;\\.\pipe\SageMultiUserService&lt;/code&gt; existiert lokal. Die Analyse des Startvorgangs zeigte aber, dass der Applikationsserver den Mehrbenutzerdienst nicht einfach lokal anspricht. Er liest in &lt;code&gt;CommonSettings.get_ServerName&lt;/code&gt; den Servernamen aus der Office-Line-Konfiguration und verbindet sich mit &lt;code&gt;\\ALTSERVER&lt;/code&gt;. Diesen Namen gibt es nicht mehr, die Namensauflösung scheitert, der Applikationsserver lehnt den Start ab. Damit steht auch der STS nicht zur Verfügung, und der BlobStorage kommt danach gar nicht mehr an die Reihe. Seine eigene Konfiguration kann dabei völlig in Ordnung sein. Die Meldung des Smart Clients beschreibt also nur das letzte Glied dieser Kette, nicht ihre Ursache.
&lt;/p&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;
&lt;strong&gt;Abgrenzung:&lt;/strong&gt; Endet der BlobStorage dagegen mit einer &lt;code&gt;ArgumentNullException&lt;/code&gt; in &lt;code&gt;StsAuthenticationClient&lt;/code&gt; für den Parameter &lt;code&gt;configuration.Host&lt;/code&gt;, handelt es sich um ein anderes Fehlerbild. Dann fehlt ihm der &lt;code&gt;stsClient&lt;/code&gt;-Knoten in der Konfiguration, meist nach einem Setup-Lauf. Wie Du das behebst, steht im Beitrag &lt;a href="https://appontes.de/blog/blobstorage-startet-nicht-sage-100/"&gt;Wenn der BlobStorage nach einem Update nicht mehr startet&lt;/a&gt;. Beide Fehler können gleichzeitig auftreten.
&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;Die naheliegende Abkürzung, die nicht funktioniert&lt;/h2&gt;
&lt;p&gt;
In diesem Zusammenhang wird oft empfohlen, den alten Namen zunächst per Alias wieder erreichbar zu machen. Ein Eintrag in der hosts-Datei, &lt;code&gt;127.0.0.1 ALTSERVER&lt;/code&gt;, und die Sage findet ihren alten Server wieder.
&lt;/p&gt;
&lt;p&gt;
Der Applikationsserver kommt damit tatsächlich ein Stück weiter. In unserem Fall scheiterte anschließend jedoch die Anmeldung am SQL Server mit Fehler 18452: „Die Anmeldung stammt aus einer nicht vertrauenswürdigen Domäne und kann nicht mit der Windows-Authentifizierung verwendet werden." Die Sage-Dienste greifen mit integrierter Windows-Authentifizierung auf den SQL Server zu. Über den tatsächlichen Computernamen und über &lt;code&gt;localhost&lt;/code&gt; gelang die Anmeldung, über den Alias nicht. Wird für die Windows-Authentifizierung ein Alias anstelle des Rechnernamens verwendet, entstehen zusätzliche Abhängigkeiten, insbesondere bei SPNs, Kerberos, dem Rückfall auf NTLM und der &lt;a href="https://learn.microsoft.com/en-us/troubleshoot/windows-server/networking/accessing-server-locally-with-fqdn-cname-alias-denied" target="_blank" rel="noopener"&gt;Loopback-Prüfung von Windows&lt;/a&gt;. Welche davon hier griff, haben wir nicht weiter eingegrenzt.
&lt;/p&gt;
&lt;p&gt;
Man könnte diese Alias-Konfiguration technisch weiterführen, etwa über &lt;code&gt;BackConnectionHostNames&lt;/code&gt;. Damit würde man jedoch einen nicht mehr gültigen Servernamen künstlich am Leben halten. Sauberer ist es, den alten Namen an den tatsächlichen Konfigurationsstellen der Sage zu ersetzen.
&lt;/p&gt;
&lt;h2&gt;Was Sage selbst empfiehlt&lt;/h2&gt;
&lt;p&gt;
Für den Fall, dass nur die Domäne wechselt und der Servername bleibt, reicht nach Auskunft von Sage der Sage Server Manager: Reparatur, Applikationsserver, „Neue URLs erzeugen". Ändert sich der Servername selbst, müssen zusätzlich alle Clients auf den neuen Mehrbenutzerdienst umgestellt werden. Der übliche Rat für diesen Fall lautet, Applikationsserver und BlobStorage zu deinstallieren, die Registry-Zweige &lt;code&gt;Application Server&lt;/code&gt;, &lt;code&gt;Blobstorage Server&lt;/code&gt; und &lt;code&gt;Identity Server&lt;/code&gt; zu löschen und die Serverkomponenten neu zu installieren.
&lt;/p&gt;
&lt;p&gt;
Genau diese Empfehlung lag unserem Kunden vor. Sie ist nicht falsch, und in einer geplanten Wartung ist die Neuinstallation ein sauberer Weg. Sie kostet allerdings mehrere Stunden, und danach sind Client-Registrierungen am STS, Zertifikate und eventuelle Sonderkonfigurationen neu zu erzeugen. An einem Samstag über die Notfallhotline, mit einem Produktivsystem, das am Montag laufen muss, war das keine Option. Nachdem die relevanten Konfigurationsstellen identifiziert waren, ließ sich die Umgebung in unserem Fall ohne Neuinstallation in weniger als einer Stunde wieder in Betrieb nehmen. Die folgenden Schritte sind der Weg, den wir an diesem Samstag gegangen sind.
&lt;/p&gt;
&lt;h2&gt;Schritt 1: Namensauflösung prüfen&lt;/h2&gt;
&lt;p&gt;
Bevor Du irgendetwas an der Sage anfasst, muss der neue Name vom Server selbst und von den Clients aus auf diese Maschine zeigen. Die &lt;a href="https://onlinehilfe.sage.de/onlinehilfe/ol/80/abf/troubleshooting_applicationserver_doku.htm" target="_blank" rel="noopener"&gt;Sage-Onlinehilfe&lt;/a&gt; nennt dafür die zwei Befehle:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ping -4 SAGE01
ping -a &amp;lt;IP-Adresse aus dem ersten Befehl&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Der zweite Befehl muss den neuen Namen mit der richtigen Domäne zurückliefern. Liefert er noch den alten Namen, stimmt der Reverse-Lookup im DNS nicht. Das führt später zu Zertifikatsfehlern, deren Ursache nicht im Zertifikat liegt.
&lt;/p&gt;
&lt;h2&gt;Schritt 2: Der Name des Mehrbenutzerservers&lt;/h2&gt;
&lt;p&gt;
Das ist die Stelle, an der der Applikationsserver stirbt. Er liest den Namen aus der XML-Konfiguration der Office Line, nicht aus der Registry:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;C:\ProgramData\Sage\Office Line\9.0\Office Line.Config
&amp;lt;server&amp;gt;
&amp;lt;add name="Name" value="\\SAGE01" type="string" /&amp;gt;
&amp;lt;/server&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Dieselbe Zeile steht in &lt;code&gt;officeLine90.config.template&lt;/code&gt; im selben Ordner. Beide Dateien anpassen, sonst schreibt eine spätere Neuanlage der Konfiguration den alten Namen zurück. Die Registry führt eine zweite Kopie, die denselben Wert tragen muss:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HKLM\SOFTWARE\WOW6432Node\Sage\Office Line\9.0\Server
Name = \\SAGE01&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Der Mehrbenutzerdienst selbst bleibt installiert und läuft weiter. Er hat mit der Umbenennung kein Problem, seine Clients haben eins. Auf den Arbeitsplätzen erledigt das die &lt;code&gt;Sagede.OfficeLine.ClientAdmin.exe&lt;/code&gt; aus dem Shared-Ordner der Sage-Installation. Sie ändert nichts anderes als diese eine Zeile in der lokalen Office Line.Config.
&lt;/p&gt;
&lt;h2&gt;Schritt 3: Der SQL-Servername in den Datenquellen&lt;/h2&gt;
&lt;p&gt;
Die Datenquellen der Sage zeigen auf den SQL Server, und nach der Umbenennung muss dort der neue Computername stehen. Ein Alias reicht aus dem oben genannten Grund nicht.
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Registry: Unter &lt;code&gt;…\9.0\Admin\Datasources\&lt;/code&gt; gibt es pro Datenquelle einen Schlüssel mit dem Wert &lt;code&gt;ServerName&lt;/code&gt;, bei einigen zusätzlich &lt;code&gt;Station&lt;/code&gt;. Bei allen lokalen Datenquellen den neuen Namen eintragen.&lt;/li&gt;
&lt;li&gt;Datenbank: In &lt;code&gt;OLGlobal.dbo.LSInfoDatenbanken&lt;/code&gt; steht pro Mandantendatenbank der &lt;code&gt;Servername&lt;/code&gt;. Nur die Zeilen ändern, deren Datenbank tatsächlich auf diesem SQL Server liegt. Einträge, die auf andere SQL Server zeigen, bleiben wie sie sind.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Nach der Umbenennung und dem Neustart ist die SQL-Instanz grundsätzlich auch über den neuen Computernamen erreichbar. Die internen Metadaten des SQL Servers werden dadurch jedoch nicht angepasst. &lt;code&gt;SELECT @@SERVERNAME&lt;/code&gt; liefert deshalb zunächst weiterhin &lt;code&gt;ALTSERVER&lt;/code&gt;. Für den Start der Sage-Dienste spielt das keine Rolle. Angleichen solltest Du ihn trotzdem, in einem eigenen Wartungsfenster, weil der SQL-Dienst danach neu starten muss. Das Vorgehen beschreibt Microsoft unter &lt;a href="https://learn.microsoft.com/en-us/sql/database-engine/install-windows/rename-a-computer-that-hosts-a-stand-alone-instance-of-sql-server" target="_blank" rel="noopener"&gt;Rename a Computer That Hosts a Stand-Alone Instance of SQL Server&lt;/a&gt;:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;EXEC sp_dropserver 'ALTSERVER';
EXEC sp_addserver 'SAGE01', 'local';&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Bei einer benannten Instanz gehört der Instanzname mit dazu, also &lt;code&gt;ALTSERVER\SAGE&lt;/code&gt;. Linked Server, Replikation und Datenbankspiegelung haben eigene Regeln, die Microsoft-Seite listet sie auf.
&lt;/p&gt;
&lt;h2&gt;Schritt 4: Die Instanzschlüssel in der Registry&lt;/h2&gt;
&lt;p&gt;
Jetzt kommt der Teil, der üblicherweise zur Empfehlung führt, neu zu installieren. Sage legt pro Dienst einen Registry-Schlüssel an, der wie der Computername heißt. Im Debugger war zu erkennen, dass der laufende Dienst den Instanzschlüssel erwartet, der zu &lt;code&gt;%COMPUTERNAME%&lt;/code&gt; passt. Nach der Umbenennung existiert der nicht, und der Dienst startet ohne Konfiguration oder gar nicht.
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HKLM\SOFTWARE\WOW6432Node\Sage\Office Line\9.0\
Application Server\ALTSERVER
Application Gateway\ALTSERVER
Blobstorage Server\ALTSERVER
Identity Server\ALTSERVER
Connectivity Server\ALTSERVER&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Den alten Schlüssel kopierst Du unter dem neuen Namen, statt nur die URLs darin umzuschreiben:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;reg copy "HKLM\SOFTWARE\WOW6432Node\Sage\Office Line\9.0\Application Server\ALTSERVER" ^
"HKLM\SOFTWARE\WOW6432Node\Sage\Office Line\9.0\Application Server\SAGE01" /s /f&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Danach im neuen Schlüssel alle Werte mit &lt;code&gt;Address&lt;/code&gt;, &lt;code&gt;Endpoint&lt;/code&gt; oder &lt;code&gt;Host&lt;/code&gt; im Namen durchgehen und den Hostnamen in den URLs ersetzen. Port und Pfad bleiben. Aus &lt;code&gt;https://altserver:5493/sdata&lt;/code&gt; wird &lt;code&gt;https://sage01:5493/sdata&lt;/code&gt;. Erst wenn der neue Schlüssel vollständig ist und der Dienst ihn verwendet, löschst Du den alten. Beim Application Gateway ist das besonders wichtig. Bei der Analyse des Smart-Client-Startvorgangs zeigte sich, dass der laufende Windows-Dienst allein nicht ausreicht. Der Client liest in &lt;code&gt;TryGetApplicationGatewayBaseUrl&lt;/code&gt; die unter &lt;code&gt;Application Gateway&lt;/code&gt; registrierten Instanzen auf dem Server aus, der in &lt;code&gt;Server\Name&lt;/code&gt; steht, und nimmt den ersten Eintrag, dessen &lt;code&gt;State&lt;/code&gt; auf Started steht. Bleibt der alte Instanzschlüssel mit einem alten Endpunkt bestehen, kann der Client zuerst den erwischen. Hat kein Schlüssel den erwarteten Status, läuft der Windows-Dienst des Gateways, während der Anwender in der Warenwirtschaft trotzdem diese Meldung sieht:
&lt;/p&gt;
&lt;figure class="blog-figure"&gt;
&lt;img src="https://appontes.de/img/blog/servername/warenwirtschaft-anwendungsdienste.png" alt="Dialog der Sage 100 Warenwirtschaft mit Warnsymbol und dem Text Anwendungsdienste konnten nicht gestartet werden, es konnte keine aktive Applikationgateway-Instanz gefunden werden, mögliche Ursachen Applikationgateway-Dienst ist nicht gestartet" width="556" height="374" loading="lazy"&gt;
&lt;figcaption&gt;Keine aktive Instanz gefunden heißt hier: Kein Registry-Schlüssel unter Application Gateway hat den State Started.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2&gt;Schritt 5: Die Konfigurationsdateien der Dienste&lt;/h2&gt;
&lt;p&gt;
Dieselben Hostnamen stehen noch einmal in den XML-Konfigurationen der Programmordner. Auch hier nur den Host tauschen:
&lt;/p&gt;
&lt;table class="tech-table"&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Datei&lt;/th&gt;
&lt;th&gt;Element&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Application Server\9.0\Sagede.ApplicationServer.Core.config&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;stsServer&lt;/code&gt;, Attribut &lt;code&gt;host&lt;/code&gt;. Der &lt;code&gt;certificateThumbprint&lt;/code&gt; bleibt unverändert.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Application Server\9.0\Sagede.ApplicationServer.SData.config&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sdataEndpoint&lt;/code&gt; für jeden Port.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Blobstorage Server\9.0\Sagede.BlobStorageServer.exe.config&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Die &lt;code&gt;EndPoint&lt;/code&gt;-Einträge für die Ports 4000 bis 4030 und der &lt;code&gt;stsClient&lt;/code&gt;, dessen &lt;code&gt;host&lt;/code&gt; auf den STS des Applikationsservers zeigt. &lt;code&gt;clientId&lt;/code&gt; und &lt;code&gt;clientSecret&lt;/code&gt; bleiben.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Application Server\9.0\StsClientRegistry.xml&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Die registrierten Clients behalten ihre Kennungen. Hostnamen darin, falls vorhanden, ebenfalls umstellen.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;
In der BlobStorage-Konfiguration liegt ein zweiter &lt;code&gt;StsClient&lt;/code&gt;-Block mit &lt;code&gt;http://localhost:3333/&lt;/code&gt; im auskommentierten Beispiel. Der ist nicht aktiv und bleibt, wie er ist.
&lt;/p&gt;
&lt;h2&gt;Schritt 6: Zertifikate und TLS-Bindungen&lt;/h2&gt;
&lt;p&gt;
Die Umbenennung ändert kein Zertifikat. Auf dem Server gibt es mindestens zwei mit verschiedenen Aufgaben, und die musst Du auseinanderhalten:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Das &lt;strong&gt;STS-Signaturzertifikat&lt;/strong&gt;, Betreff &lt;code&gt;CN=SageSTS.&amp;lt;alter Name&amp;gt;&lt;/code&gt;. Sein Thumbprint steht im &lt;code&gt;stsServer&lt;/code&gt;-Knoten. Es dient der Signierung der ausgegebenen Tokens, sein Subject muss daher nicht mit dem Hostnamen übereinstimmen. Ein alter Rechnername im Zertifikatsnamen ist für sich genommen kein Grund, dieses Zertifikat auszutauschen.&lt;/li&gt;
&lt;li&gt;Die &lt;strong&gt;TLS-Zertifikate&lt;/strong&gt;, die HTTP.sys an die Ports bindet. Hier zählt der Name. Auf dem Gateway-Port 4337 prüft der Smart Client den Hostnamen gegen das Zertifikat. Hängt dort noch &lt;code&gt;CN=altserver&lt;/code&gt;, bricht die Verbindung mit &lt;code&gt;RemoteCertificateNameMismatch&lt;/code&gt; ab, und der Client meldet, dass kein Application Gateway erreichbar sei. Der Windows-Dienst läuft dabei einwandfrei.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Was aktuell gebunden ist, zeigt Dir:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;netsh http show sslcert&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Ein Zertifikat mit dem neuen Namen stellt Windows in der Domäne über die Zertifizierungsstelle aus, alternativ ein selbstsigniertes für den internen Gebrauch. Die Bindung tauschst Du pro Port, die &lt;code&gt;appid&lt;/code&gt; übernimmst Du aus der Ausgabe des vorigen Befehls:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;netsh http delete sslcert ipport=0.0.0.0:4337
netsh http add sslcert ipport=0.0.0.0:4337 certhash=&amp;lt;Thumbprint neues Zertifikat&amp;gt; ^
appid={&amp;lt;appid aus show sslcert&amp;gt;} certstorename=MY&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Ein neues STS-Zertifikat mit dem neuen Namen erzeugt bei Bedarf &lt;code&gt;ASADMIN /command:stsconfig /action:create /all&lt;/code&gt;. Das ist ein eigener Schritt mit eigenem Risiko, denn danach müssen alle Dienste den neuen Thumbprint kennen. Für den Start der Dienste ist er nicht erforderlich.
&lt;/p&gt;
&lt;h2&gt;Schritt 7: Dienste in der richtigen Reihenfolge starten&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Der Mehrbenutzerdienst läuft bereits und bleibt es.&lt;/li&gt;
&lt;li&gt;Applikationsserver starten. Er muss im Status „Wird ausgeführt" bleiben. Kommt die &lt;code&gt;HostedApplicationException&lt;/code&gt; sofort wieder, steht in der Office Line.Config noch der alte Name.&lt;/li&gt;
&lt;li&gt;BlobStorage starten. Er bleibt nur oben, wenn der STS auf dem konfigurierten Host antwortet.&lt;/li&gt;
&lt;li&gt;Application Gateway neu starten, nachdem der Registry-Schlüssel mit dem neuen Namen existiert und der Port das passende Zertifikat trägt. Der Dienst setzt &lt;code&gt;State&lt;/code&gt; dann selbst auf Started.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Zur Kontrolle ein paar Aufrufe von einem Client aus. Ein 401 vom STS ist dabei die richtige Antwort, er verlangt eine Anmeldung, mehr sagt der Code nicht aus:
&lt;/p&gt;
&lt;table class="tech-table"&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Port&lt;/th&gt;
&lt;th&gt;Dienst&lt;/th&gt;
&lt;th&gt;Erwartete Antwort&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;5468&lt;/td&gt;
&lt;td&gt;STS des Applikationsservers&lt;/td&gt;
&lt;td&gt;HTTP 401 ohne Anmeldung&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5493, 5486, 5494, 5501&lt;/td&gt;
&lt;td&gt;SData&lt;/td&gt;
&lt;td&gt;Port belegt&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4000 bis 4030&lt;/td&gt;
&lt;td&gt;BlobStorage&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://sage01:4000/BlobStorage&lt;/code&gt; liefert HTTP 200&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4337&lt;/td&gt;
&lt;td&gt;Application Gateway&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://sage01:4337/api&lt;/code&gt; antwortet, Zertifikat ohne Namensfehler&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;
In &lt;code&gt;netstat&lt;/code&gt; gehören diese Ports dem Prozess System mit PID 4. Das ist kein Fehler, HTTP.sys lauscht für die Sage-Dienste im Kernel.
&lt;/p&gt;
&lt;p&gt;
Der belastbare Test bleibt aber ein echter Vorgang aus der Sage 100: Anmelden am Smart Client, einen Beleg öffnen, ein Dokument in der Dateiablage hochladen. Erst dann sind Mehrbenutzerdienst, STS, SData, BlobStorage und Gateway gemeinsam geprüft.
&lt;/p&gt;
&lt;h2&gt;Was bewusst stehen bleiben darf&lt;/h2&gt;
&lt;p&gt;
Nicht jeder Rest des alten Namens ist ein Fehler. Diese Punkte haben beim Kunden den Betrieb nicht gestört und wurden bewusst zurückgestellt:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Der Betreff des STS-Signaturzertifikats mit dem alten Namen.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@@SERVERNAME&lt;/code&gt; mit dem alten Wert, solange &lt;code&gt;sp_addserver&lt;/code&gt; noch nicht gelaufen ist.&lt;/li&gt;
&lt;li&gt;Datenquellen, deren SQL Server auf einer anderen Maschine läuft.&lt;/li&gt;
&lt;li&gt;Der Schlüssel des Connectivity Servers, wenn der Kommunikationsdienst nicht im Einsatz ist.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Vorbeugen&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Einen Sage-Server benennt man nicht nebenbei um. Wenn es sein muss, dann mit Wartungsfenster, Sicherung und der Liste aus diesem Beitrag. Bei einem ohnehin anstehenden Hardwarewechsel ist ein neuer Server mit dem gewünschten Namen und eine saubere Migration oft der weniger riskante Weg.&lt;/li&gt;
&lt;li&gt;Vorher den Registry-Zweig &lt;code&gt;HKLM\SOFTWARE\WOW6432Node\Sage&lt;/code&gt; exportieren und die Konfigurationsdateien aller Sage-Dienste an einen Ort außerhalb der Programmordner kopieren.&lt;/li&gt;
&lt;li&gt;Thumbprints, Ports, &lt;code&gt;clientId&lt;/code&gt;/&lt;code&gt;clientSecret&lt;/code&gt;-Paare und die Namen der Datenquellen in der Systemdokumentation festhalten. Das ist die Liste, die Du bei jeder Reparatur brauchst.&lt;/li&gt;
&lt;li&gt;Änderungen am Server, die nichts mit der Sage zu tun haben, mit dem Sage-Betreuer abstimmen. Umbenennung, Domänenwechsel, neues Maschinenzertifikat, Härtung von TLS: Alles davon trifft die Sage-Dienste, und zwar oft erst Tage später. Wie so eine Verzögerung aussieht, zeigt der Beitrag zur &lt;a href="https://appontes.de/blog/sage-100-tls12-mehrbenutzerdienst/"&gt;Lizenzprüfung ohne TLS 1.2&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Fazit&lt;/h2&gt;
&lt;p&gt;
Ein neuer Computername ist für Windows eine Kleinigkeit und für die Sage 100 ein Umzug. Der Name steht in der Office Line.Config, in der Registry der einzelnen Dienste, in den Datenquellen, in den XML-Konfigurationen und in den TLS-Bindungen.
&lt;/p&gt;
&lt;p&gt;
In unserem Fall ließ sich die Sage 100 nach Identifikation dieser Abhängigkeiten ohne Neuinstallation in weniger als einer Stunde wieder in Betrieb nehmen. Ein Alias für den alten Rechnernamen hätte dagegen nur einen Teil der eigentlichen Konfigurationsfehler verdeckt. Entscheidend ist deshalb nicht, den alten Namen irgendwie wieder erreichbar zu machen, sondern die Stellen zu finden, an denen die Sage ihn tatsächlich verwendet.
&lt;/p&gt;
&lt;p&gt;
Wenn Deine Sage 100 nach einer Änderung am Server nicht mehr startet, melde Dich bei uns. Wir finden die Stelle, an der der alte Name noch steht.
&lt;/p&gt;
&lt;div style="text-align: center; margin: 3rem 0;"&gt;
&lt;a href="https://appontes.de/kontakt/?betreff=anfrage-sage" class="btn btn-primary"&gt;Hilfe bei Sage 100 Serverproblemen anfragen&lt;/a&gt;
&lt;/div&gt;</content:encoded></item><item><title>SQL-Timeouts in der Sage 100: Wenn eine einzige offene Transaktion alle blockiert</title><link>https://appontes.de/blog/sql-blocking-sage-100-offene-transaktion/</link><guid isPermaLink="true">https://appontes.de/blog/sql-blocking-sage-100-offene-transaktion/</guid><pubDate>Mon, 21 Sep 2026 08:00:00 +0200</pubDate><dc:creator>Thomas Falkner</dc:creator><category>Sage 100</category><category>SQL Server</category><category>Performance</category><category>Datenbank</category><description>Masken hängen, Belege lassen sich nicht speichern, die Sage 100 meldet Timeouts. Oft ist die Datenbank gar nicht langsam, sondern eine Session hält seit Minuten eine Transaktion offen. Wie Du den Root Blocker findest, warum ein höherer Timeout nichts bringt und wie Dienste, AddIns und DCMs das Problem gar nicht erst erzeugen.</description><content:encoded>&lt;p&gt;&lt;img src="https://appontes.de/img/blog/sql-blocking-root-blocker.svg" alt="SQL-Timeouts in der Sage 100: Wenn eine einzige offene Transaktion alle blockiert"&gt;&lt;/p&gt;
&lt;p&gt;
Freitagmittag, die Belegerfassung steht. In der Warenwirtschaft hängt die Maske beim Speichern, im Rechnungswesen lässt sich kein Beleg mehr öffnen, ein Importlauf im Hintergrund kommt nicht weiter. Nach einer halben Minute meldet die Sage 100: „Timeout abgelaufen. Das Timeout ist vor dem Beenden des Vorgangs eingetreten, oder der Server reagiert nicht." Der Server hat aber weder viel CPU-Last noch tut sich auf der Platte etwas. Er wartet. Und zwar auf eine einzige Session, die seit zehn Minuten nichts mehr tut.
&lt;/p&gt;
&lt;p&gt;
Genau dieses Muster sehen wir regelmäßig, und fast immer läuft der erste Reflex in die falsche Richtung: Timeout hochsetzen, Server neu starten, Index neu aufbauen. In diesem Beitrag zeige ich Dir an einem Importdienst auf Basis des Sage 100 SDK, wie ein einziger fehlender Aufruf eine ganze Sage-100-Umgebung lahmlegt, wie Du den Verursacher in wenigen Minuten findest und was in eigener Programmierung anders laufen muss.
&lt;/p&gt;
&lt;h2&gt;Was ein Timeout wirklich bedeutet&lt;/h2&gt;
&lt;p&gt;
Der Timeout ist keine Entscheidung des SQL Servers. Er ist eine Entscheidung der Anwendung. Sie schickt einen Befehl, wartet die eingestellte Zeit (bei den meisten Datenzugriffsbibliotheken 30 Sekunden) und bricht dann ab. Der SQL Server bekommt davon nur ein sogenanntes Attention-Ereignis mit und beendet die Abfrage. Microsoft beschreibt den Ablauf in der Anleitung zum &lt;a href="https://learn.microsoft.com/de-de/troubleshoot/sql/database-engine/performance/troubleshoot-query-timeouts" target="_blank" rel="noopener"&gt;Behandeln von Abfragetimeoutfehlern&lt;/a&gt; und nennt dort als häufigsten Grund eine langsame Abfrage.
&lt;/p&gt;
&lt;p&gt;
Es gibt aber einen zweiten Grund, der von außen exakt gleich aussieht: Die Abfrage ist überhaupt nicht langsam. Sie darf nur nicht anfangen, weil die Zeilen, die sie braucht, von einer anderen Transaktion gesperrt sind. Der SQL Server nennt das Blocking. Eine Sekunde Arbeit, 29 Sekunden Warten, dann der Abbruch. Wer in diesem Fall den Timeout auf 120 Sekunden stellt, erreicht nur, dass der Anwender zwei Minuten statt einer halben auf dieselbe Sperre wartet.
&lt;/p&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;
Die entscheidende Frage bei Timeouts lautet deshalb nicht „Wie erhöhen wir das Zeitlimit?", sondern „Wer blockiert wen, und warum hält diese Session ihre Transaktion so lange offen?"
&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;Woran Du Blocking erkennst&lt;/h2&gt;
&lt;p&gt;
Ein Blick in die aktuell laufenden Anforderungen zeigt bei Blocking mehrere Sessions mit Wartetypen wie &lt;code&gt;LCK_M_S&lt;/code&gt; oder &lt;code&gt;LCK_M_IX&lt;/code&gt;. Die Bedeutung ist in der Doku zu &lt;a href="https://learn.microsoft.com/de-de/sql/relational-databases/system-dynamic-management-views/sys-dm-os-wait-stats-transact-sql" target="_blank" rel="noopener"&gt;sys.dm_os_wait_stats&lt;/a&gt; beschrieben: &lt;code&gt;LCK_M_S&lt;/code&gt; heißt, eine Session wartet auf eine Lesesperre (Shared Lock). &lt;code&gt;LCK_M_IX&lt;/code&gt; heißt, eine Session will schreiben und wartet auf eine Intent-Exclusive-Sperre. Beides bekommt sie nicht, solange eine andere Transaktion die exklusive Sperre auf denselben Zeilen hält.
&lt;/p&gt;
&lt;p&gt;
Und diese Sperren halten lange. Aus dem &lt;a href="https://learn.microsoft.com/de-de/sql/relational-databases/sql-server-transaction-locking-and-row-versioning-guide" target="_blank" rel="noopener"&gt;Handbuch zu Sperren und Zeilenversionsverwaltung&lt;/a&gt;: Eine Transaktion hält für jede Datenänderung eine exklusive Sperre, und zwar bis die Transaktion abgeschlossen ist, unabhängig von der Isolationsstufe. Solange also kein COMMIT oder ROLLBACK kommt, bleibt jede geänderte Zeile für alle anderen tabu. Lesen inklusive.
&lt;/p&gt;
&lt;p&gt;Aus den Wartenden entsteht dann eine Kette, die sich bis zu einem Verursacher zurückverfolgen lässt:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Session 233 &amp;lt;-- Root Blocker
├── Session 199 Belegerfassung, wartet LCK_M_S
├── Session 332 Artikelsuche, wartet LCK_M_S
├── Session 369 Schlüsselvergabe sysTan, wartet LCK_M_IX
│ └── Session 165
├── Session 377 Übergabe Rechnungswesen
└── Session 475 Importlauf
└── Session 365&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Session 233 ist der Root Blocker. Sie wartet selbst auf niemanden. Die anderen warten alle, direkt oder über einen Zwischenschritt, auf sie. Wer 369 oder 475 abschießt, hat nichts gewonnen, denn die Sperren liegen bei 233.
&lt;/p&gt;
&lt;h2&gt;Der Fall: Ein Auftragsimport bleibt mitten in der Transaktion hängen&lt;/h2&gt;
&lt;p&gt;
Das Beispiel ist an die Schulungsbeispiele aus dem Sage Developer-Programm angelehnt, mit denen Sage das Objektmodell des SDK erklärt. Ein Windows-Dienst holt Bestellungen aus dem Webshop als XML-Dateien ab und legt daraus Verkaufsaufträge in der Sage 100 an. Dazu meldet er sich beim Start einmal an der Sage 100 an und behält Session und Mandant, bis er beendet wird:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var session = ApplicationEngine.CreateSession("OLDemo", ApplicationToken.AddOn,
null, new NamePasswordCredential("Import", passwort));
var mandant = session.CreateMandant(123);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Pro Bestellung erzeugt er über die BelegEngine einen Auftrag, schreibt danach die Shop-Bestellnummer mit der neuen BelID in eine eigene Zuordnungstabelle, hängt einen Protokolleintrag an und meldet die Auftragsnummer per REST an den Shop zurück. Damit Beleg und Zuordnung nur gemeinsam gespeichert werden, klammert der Entwickler alles in eine Transaktion auf der Verbindung des Mandanten. Genau das machen auch die Sage-Beispiele beim Lagerbuchungsimport, dort mit dem Kommentar „Transaktion pro Datei":
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public void ImportiereBestellung(Mandant mandant, XMLBeleg xml)
{
var conn = mandant.MainDevice.GenericConnection;
conn.BeginTransaction();
try
{
using (var beleg = new Beleg(mandant, Erfassungsart.Verkauf))
{
var jahr = (short)mandant.PeriodenManager.Perioden
.Date2Periode(xml.Belegdatum).Jahr;
beleg.Initialize("VVA", xml.Belegdatum, jahr);
beleg.SetKonto(xml.EmpfaengerKonto, false);
foreach (var p in xml.Positionen)
{
var pos = new BelegPosition(beleg);
pos.Initialize(Positionstyp.Artikel);
pos.SetArtikel(p.Artikelnummer, 0);
pos.Menge = p.Menge;
pos.Calculate();
beleg.Positionen.Add(pos);
}
beleg.Calculate(true);
beleg.Renumber();
if (!beleg.Validate(true) || !beleg.Save(false))
throw new BelegImportException(beleg.Errors.GetDescriptionSummary());
SchreibeShopZuordnung(conn, xml.Bestellnummer, beleg.Handle);
ProtokollHelper.AppendProtokollItem(mandant, ImportLog, beleg.Handle, ...);
// REST-Aufruf an den Shop, noch innerhalb der Transaktion
MeldeAuftragAnShop(xml.Bestellnummer, beleg.BelegnummerFormatiert);
}
conn.CommitTransaction();
}
catch (Exception ex)
{
TraceLog.LogException(ex);
// Fehlt: conn.RollbackTransaction();
}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Der catch-Block ist wörtlich aus dem Belegimport der Sage-Beispiele übernommen: Loggen und mit der nächsten Datei weitermachen. Dort ist das richtig, weil der Beispielimport keine eigene Transaktion aufmacht und die BelegEngine ihre Speicherung selbst absichert. Sobald aber eine eigene Klammer mit &lt;code&gt;BeginTransaction&lt;/code&gt; dazukommt, fehlt in diesem catch der &lt;code&gt;RollbackTransaction&lt;/code&gt;. Im Lagerbuchungsbeispiel von Sage steht er drin. Hier nicht.
&lt;/p&gt;
&lt;p&gt;
Monatelang fällt das nicht auf. Dann ist der Shop eines Vormittags für zwanzig Minuten nicht erreichbar, der REST-Aufruf wirft eine Exception, sie wird geloggt, der Dienst nimmt sich die nächste Datei. Die Verbindung gehört dem Mandanten und lebt so lange wie der Dienst. Die Transaktion bleibt offen, weil niemand sie zurückrollt. Und der Auftrag ist zu diesem Zeitpunkt bereits vollständig geschrieben: &lt;code&gt;Beleg.Save&lt;/code&gt; hat Belegkopf, Positionen und Vorgang angelegt und die Schlüssel dafür über &lt;code&gt;sysTan&lt;/code&gt; aus &lt;code&gt;KHKTan&lt;/code&gt; geholt. Alles gesperrt, nichts committet.
&lt;/p&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;
Zur Abgrenzung: Die Sage 100 hat eigene Sperren auf Anwendungsebene. Wer einen Beleg in der Erfassung offen hat, hält über den Mehrbenutzerdienst eine Semaphore, und der nächste bekommt „Beleg in Bearbeitung" angezeigt. Das ist gewollt und sichtbar. SQL-Blocking dagegen zeigt keine Meldung. Die Maske steht einfach, bis der Timeout kommt.
&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;Was auf dem Server zurückbleibt&lt;/h2&gt;
&lt;p&gt;Auf dem SQL Server sieht Session 233 jetzt so aus:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;session_id 233
status sleeping
open_transaction_count 1
last_request_end_time 10:14:04&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Der Status &lt;code&gt;sleeping&lt;/code&gt; bedeutet laut Doku zu &lt;a href="https://learn.microsoft.com/de-de/sql/relational-databases/system-dynamic-management-views/sys-dm-exec-sessions-transact-sql" target="_blank" rel="noopener"&gt;sys.dm_exec_sessions&lt;/a&gt; schlicht, dass die Session gerade keine Anforderung ausführt. Sie verbraucht keine CPU, sie liest nichts, sie taucht in keiner Liste der laufenden Abfragen auf. Trotzdem hält sie exklusive Sperren auf jeder Zeile, die sie in der offenen Transaktion geändert hat: &lt;code&gt;KHKVKBelege&lt;/code&gt;, &lt;code&gt;KHKVKBelegePositionen&lt;/code&gt;, &lt;code&gt;KHKVKVorgaenge&lt;/code&gt;, &lt;code&gt;KHKVKVorgaengePositionen&lt;/code&gt;, die Zuordnungstabelle, das Protokoll und die Schlüsselzeilen in &lt;code&gt;KHKTan&lt;/code&gt;.
&lt;/p&gt;
&lt;p&gt;
&lt;code&gt;KHKTan&lt;/code&gt; ist der Knackpunkt. Der einzelne Auftrag interessiert vielleicht nur den Vertrieb. Über &lt;code&gt;KHKTan&lt;/code&gt; vergibt die Sage 100 aber per &lt;code&gt;sysTan&lt;/code&gt; die Primärschlüssel für ihre Tabellen. Solange Session 233 die Zeilen für Belege und Positionen exklusiv hält, wartet jeder, der in diesem Mandanten einen Verkaufsbeleg anlegen will, auf sie. Und die tut nichts, außer zu schlafen.
&lt;/p&gt;
&lt;table class="tech-table"&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Uhrzeit&lt;/th&gt;
&lt;th&gt;Was passiert&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;10:14:02&lt;/td&gt;
&lt;td&gt;Der Importdienst (Session 233) beginnt die Transaktion. Beleg.Save schreibt Belegkopf, Positionen und Vorgang und holt die Schlüssel aus KHKTan. Auf allen Zeilen liegen jetzt exklusive Sperren.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10:14:04&lt;/td&gt;
&lt;td&gt;Der REST-Aufruf an den Shop wirft eine Exception. Wird geloggt, kein RollbackTransaction. Die Session bleibt mit offener Transaktion im Status sleeping.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10:14:20&lt;/td&gt;
&lt;td&gt;Ein Kollege sucht in der Auftragsübersicht. Sein SELECT auf KHKVKBelege wartet mit LCK_M_S.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10:14:25&lt;/td&gt;
&lt;td&gt;Die Belegerfassung braucht über sysTan einen neuen Primärschlüssel. Das UPDATE auf KHKTan wartet mit LCK_M_IX.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10:14:50&lt;/td&gt;
&lt;td&gt;Erster Anwender bekommt nach 30 Sekunden den Timeout.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10:16:00&lt;/td&gt;
&lt;td&gt;Der Admin schaut auf den Server und sieht viele wartende Abfragen. Auf den ersten Blick sieht alles nach „Datenbank langsam" aus.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10:16:30&lt;/td&gt;
&lt;td&gt;Blocking-Analyse: Alle Wartenden zeigen auf 233. Status sleeping, eine offene Transaktion seit zweieinhalb Minuten. Ursache gefunden.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;Warum der letzte Befehl so harmlos aussieht&lt;/h2&gt;
&lt;p&gt;
Hier tappen viele in eine Falle. Wer nachsieht, was Session 233 zuletzt geschickt hat, findet oft etwas völlig Harmloses. Der Dienst hat sich nach dem Fehler die nächste Datei vorgenommen, und das Erste, was die BelegEngine dafür auf derselben Verbindung tut, ist ein Lookup:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT ... FROM KHKKontokorrent WHERE Mandant = 123 AND Kto = 'D10001'&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Wie soll dieser SELECT sieben Tabellen sperren? Gar nicht. Die Sperren stammen von den INSERTs davor, die alle zur selben, noch offenen Transaktion gehören. Und es kommt schlimmer: Weil die Verbindung dieselbe ist, laufen auch alle folgenden Importe in dieser Transaktion weiter. Ein inneres COMMIT beendet in SQL Server keine äußere Transaktion, es zählt laut Doku zu &lt;a href="https://learn.microsoft.com/de-de/sql/t-sql/language-elements/commit-transaction-transact-sql" target="_blank" rel="noopener"&gt;COMMIT TRANSACTION&lt;/a&gt; nur &lt;code&gt;@@TRANCOUNT&lt;/code&gt; um eins herunter. Jeder weitere Auftrag vergrößert also den Berg an Sperren, statt ihn abzubauen. Der Eingabepuffer zeigt Dir nur den letzten Befehl der Session, nicht den, der die Sperren erzeugt hat. Für den Blick in den Puffer gibt es seit SQL Server 2014 SP2 die Funktion &lt;a href="https://learn.microsoft.com/de-de/sql/relational-databases/system-dynamic-management-views/sys-dm-exec-input-buffer-transact-sql" target="_blank" rel="noopener"&gt;sys.dm_exec_input_buffer&lt;/a&gt;, die das ältere &lt;code&gt;DBCC INPUTBUFFER&lt;/code&gt; ablöst und sich per CROSS APPLY mit den Sessions verbinden lässt. Nutze sie als Hinweis auf die Anwendung, nicht als Beweis für den Verursacher.
&lt;/p&gt;
&lt;h2&gt;So findest Du den Root Blocker&lt;/h2&gt;
&lt;p&gt;
Vier Fragen führen zum Ziel: Wer blockiert wen? Ist auf der blockierenden Session eine Transaktion offen? Seit wann? Und welche Sperren hält sie? Für alle vier reichen die Systemsichten des SQL Servers, Du brauchst nur die Berechtigung &lt;code&gt;VIEW SERVER STATE&lt;/code&gt;.
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Schritt 1, die Wartenden.&lt;/strong&gt; Alle Anforderungen, die auf eine andere Session warten, sortiert nach Wartezeit:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT r.session_id,
r.blocking_session_id,
r.wait_type,
r.wait_time / 1000 AS WartetSekunden,
DB_NAME(r.database_id) AS Datenbank,
t.text AS SqlText
FROM sys.dm_exec_requests AS r
OUTER APPLY sys.dm_exec_sql_text(r.sql_handle) AS t
WHERE r.blocking_session_id &amp;lt;&amp;gt; 0
ORDER BY r.wait_time DESC;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Die Spalte &lt;code&gt;blocking_session_id&lt;/code&gt; ist der Faden, an dem Du ziehst. Der Root Blocker ist die Session, die dort auftaucht, selbst aber auf niemanden wartet. Und jetzt der Punkt, an dem viele hängen bleiben: Session 233 steht in dieser Liste gar nicht drin. Sie führt keine Anforderung aus, also hat sie in &lt;code&gt;sys.dm_exec_requests&lt;/code&gt; keine Zeile. Du siehst nur ihre Nummer bei den anderen.
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Schritt 2, die Session dahinter.&lt;/strong&gt; Wer ist das, von welchem Rechner, mit welchem Programm, und steht eine Transaktion offen?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT s.session_id,
s.status,
s.login_name,
s.host_name,
s.program_name,
s.open_transaction_count,
s.last_request_start_time,
s.last_request_end_time,
c.client_net_address,
ib.event_info AS LetzterBefehl
FROM sys.dm_exec_sessions AS s
LEFT JOIN sys.dm_exec_connections AS c ON c.session_id = s.session_id
OUTER APPLY sys.dm_exec_input_buffer(s.session_id, NULL) AS ib
WHERE s.session_id = 233;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Die Kombination aus &lt;code&gt;status = sleeping&lt;/code&gt; und &lt;code&gt;open_transaction_count &amp;gt; 0&lt;/code&gt; ist das Signal. Eine Session, die nichts tut, aber eine Transaktion hält. Microsoft führt genau diese Suche als Beispiel in der Doku zu &lt;a href="https://learn.microsoft.com/de-de/sql/relational-databases/system-dynamic-management-views/sys-dm-exec-sessions-transact-sql" target="_blank" rel="noopener"&gt;sys.dm_exec_sessions&lt;/a&gt; unter „Find idle sessions that have open transactions". &lt;code&gt;host_name&lt;/code&gt; und &lt;code&gt;program_name&lt;/code&gt; verraten Dir, welcher Arbeitsplatz und welche Anwendung dahinterstecken. Bei einem Importdienst steht dort ein anderer Rechner und ein anderer Programmname als beim Sage-Client, das grenzt den Kreis der Verdächtigen sofort ein.
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Schritt 3, das Alter der Transaktion.&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT st.session_id,
at.transaction_id,
at.name,
at.transaction_begin_time,
DATEDIFF(SECOND, at.transaction_begin_time, GETDATE()) AS OffenSeitSekunden,
at.transaction_state
FROM sys.dm_tran_session_transactions AS st
JOIN sys.dm_tran_active_transactions AS at ON at.transaction_id = st.transaction_id
WHERE st.session_id = 233;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Ein &lt;code&gt;transaction_state&lt;/code&gt; von 2 heißt laut Doku zu &lt;a href="https://learn.microsoft.com/de-de/sql/relational-databases/system-dynamic-management-views/sys-dm-tran-active-transactions-transact-sql" target="_blank" rel="noopener"&gt;sys.dm_tran_active_transactions&lt;/a&gt;: Die Transaktion ist aktiv. Zusammen mit &lt;code&gt;transaction_begin_time&lt;/code&gt; weißt Du, ob es um Sekunden geht (normal) oder um Minuten (verwaist).
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Schritt 4, die gehaltenen Sperren.&lt;/strong&gt; Auf welchen Tabellen liegt die Session?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT DISTINCT
tl.resource_type,
tl.request_mode,
tl.request_status,
OBJECT_SCHEMA_NAME(p.object_id, tl.resource_database_id) AS Schema_,
OBJECT_NAME(p.object_id, tl.resource_database_id) AS Tabelle
FROM sys.dm_tran_locks AS tl
LEFT JOIN sys.partitions AS p ON p.hobt_id = tl.resource_associated_entity_id
WHERE tl.request_session_id = 233
AND tl.resource_database_id = DB_ID('OLDemo')
ORDER BY Tabelle, tl.request_mode;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Hier tauchen sie auf: KEY-Sperren im Modus X auf &lt;code&gt;KHKVKBelege&lt;/code&gt;, &lt;code&gt;KHKVKBelegePositionen&lt;/code&gt;, &lt;code&gt;KHKVKVorgaenge&lt;/code&gt;, &lt;code&gt;KHKVKVorgaengePositionen&lt;/code&gt;, &lt;code&gt;KHKTan&lt;/code&gt; und der Zuordnungstabelle des Importdienstes. Damit hast Du den Beweis, dass die Sperren nicht vom harmlosen letzten SELECT stammen, sondern von Schreibzugriffen davor.
&lt;/p&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;
Wer das nicht jedes Mal von Hand zusammensetzen will, nimmt &lt;a href="https://whoisactive.com/" target="_blank" rel="noopener"&gt;sp_WhoIsActive&lt;/a&gt; von Adam Machanic. Die Prozedur ist seit Jahren der Standard in der SQL-Server-Community, kostenlos, und zeigt Blocking-Ketten samt offenen Transaktionen in einem einzigen Aufruf.
&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;Akut: Die Session beenden&lt;/h2&gt;
&lt;p&gt;
Wenn klar ist, dass die Transaktion verwaist ist, löst ein &lt;code&gt;KILL 233&lt;/code&gt; die Blockade. Der SQL Server beendet dabei nicht einfach die Verbindung. Er rollt die offene Transaktion zurück, und das kann laut Doku zu &lt;a href="https://learn.microsoft.com/de-de/sql/t-sql/language-elements/kill-transact-sql" target="_blank" rel="noopener"&gt;KILL&lt;/a&gt; dauern, je nachdem, wie viel Arbeit rückgängig zu machen ist. Den Fortschritt siehst Du mit &lt;code&gt;KILL 233 WITH STATUSONLY&lt;/code&gt;, das nur den Stand des Rollbacks in Prozent anzeigt und selbst nichts beendet. Wiederhole niemals das nackte &lt;code&gt;KILL 233&lt;/code&gt;, um den Fortschritt zu prüfen: Sobald der Rollback fertig ist, kann die Session-Nummer an eine neue Verbindung vergeben werden, und Du triffst den Falschen. Auch das steht so in der Doku.
&lt;/p&gt;
&lt;p&gt;Vor dem KILL gehören drei Dinge geklärt, weil ein Rollback nicht rückgängig zu machen ist:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Welcher Anwender und welcher Arbeitsplatz stecken dahinter? Bei der Sage 100 hält der Client seine Verbindung dauerhaft. Ein KILL trifft also einen echten Menschen, dessen Sage 100 danach die Verbindung verliert.&lt;/li&gt;
&lt;li&gt;Welcher Geschäftsvorgang wird zurückgerollt? Im Beispiel verschwindet der halb erzeugte Beleg. Das ist hier gewollt, muss aber jemand wissen.&lt;/li&gt;
&lt;li&gt;Ist die Transaktion wirklich verwaist, oder läuft da ein legitimer, nur langer Vorgang wie ein Jahresabschluss oder ein Importlauf?&lt;/li&gt;
&lt;/ul&gt;
&lt;details class="deep-dive"&gt;
&lt;summary&gt;
&lt;span class="deep-dive-label"&gt;Deep Dive&lt;/span&gt;
&lt;span&gt;Warum die Verbindung im Beispiel nie geschlossen wird&lt;/span&gt;
&lt;span class="deep-dive-chev"&gt;&lt;svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;&lt;path d="m6 9 6 6 6-6"/&gt;&lt;/svg&gt;&lt;/span&gt;
&lt;/summary&gt;
&lt;div class="deep-dive-body"&gt;
&lt;p&gt;
Ein häufiger Einwand lautet: „Wenn die Verbindung geschlossen wird, rollt der SQL Server doch alles zurück." Das stimmt. Das Sperrhandbuch von Microsoft sagt ausdrücklich, dass bei einem Verbindungsabbruch, einem Absturz des Clients oder einem Neustart des Rechners alle ausstehenden Transaktionen zurückgerollt werden. Und die Doku zu &lt;a href="https://learn.microsoft.com/de-de/dotnet/api/microsoft.data.sqlclient.sqlconnection.close" target="_blank" rel="noopener"&gt;SqlConnection.Close&lt;/a&gt; ergänzt: Close rollt jede ausstehende Transaktion zurück und gibt die Verbindung dann an den Pool zurück. Bei aktivem Connection Pooling passiert der Rollback beim Zurücksetzen der Verbindung.
&lt;/p&gt;
&lt;p&gt;
Das Problem im Beispiel ist, dass keiner von beiden Fällen eintritt. Im Sage 100 SDK gehört die Verbindung nicht Deinem Code, sondern dem Mandanten. Du bekommst sie über &lt;code&gt;MainDevice.GenericConnection&lt;/code&gt; nur geliehen. Der Mandant lebt so lange wie die Session, und ein Dienst oder ein AddIn im Sage-Client meldet sich einmal an und erst beim Beenden wieder ab. Ein Rollback durch Verbindungsende kommt also erst, wenn jemand den Dienst neu startet. Das ist übrigens der Grund, warum „nach dem Neustart ging es wieder" so oft die einzige Beobachtung ist, die vom Vorfall übrig bleibt. Wer stattdessen eigene ADO.NET-Verbindungen aufmacht, hat die gleiche Pflicht in eigener Hand: Eine SqlConnection, die den Gültigkeitsbereich verlässt, wird laut Doku nicht geschlossen. Du musst Close oder Dispose selbst aufrufen.
&lt;/p&gt;
&lt;p&gt;
Es gibt noch eine zweite Wirkung nicht geschlossener Verbindungen, die gern mit dem Blocking verwechselt wird: Der Pool läuft voll. Laut Doku zum &lt;a href="https://learn.microsoft.com/de-de/sql/connect/ado-net/sql-server-connection-pooling" target="_blank" rel="noopener"&gt;Connection Pooling&lt;/a&gt; sind standardmäßig 100 Verbindungen pro Pool erlaubt. Werden sie nicht zurückgegeben, wartet der nächste Open-Aufruf 15 Sekunden und wirft dann ebenfalls einen Timeout, diesmal beim Verbinden statt beim Ausführen. Beide Fehler heißen für den Anwender „Timeout", haben aber verschiedene Ursachen. Der Beitrag von Microsoft zu Abfragetimeouts erklärt, wie Du die beiden auseinanderhältst.
&lt;/p&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;h2&gt;Wie es richtig geht&lt;/h2&gt;
&lt;p&gt;
Die Mindestanforderung: Jede begonnene Transaktion endet mit Commit oder Rollback, auch im Fehlerfall. Sages eigene Beispiele zeigen das Muster beim Löschen von Protokolleinträgen und beim Lagerbuchungsimport: &lt;code&gt;BeginTransaction&lt;/code&gt;, Arbeit, &lt;code&gt;CommitTransaction&lt;/code&gt;, und im catch zuerst &lt;code&gt;RollbackTransaction&lt;/code&gt;, dann loggen, dann die Exception weiterreichen. Der zweite Punkt ist genauso wichtig: Der REST-Aufruf gehört hinter das Commit.
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public void ImportiereBestellung(Mandant mandant, XMLBeleg xml)
{
var conn = mandant.MainDevice.GenericConnection;
string belegnummer;
conn.BeginTransaction();
try
{
using (var beleg = new Beleg(mandant, Erfassungsart.Verkauf))
{
// Initialize, SetKonto, Positionen, Calculate, Renumber wie oben
if (!beleg.Validate(true) || !beleg.Save(false))
throw new BelegImportException(beleg.Errors.GetDescriptionSummary());
SchreibeShopZuordnung(conn, xml.Bestellnummer, beleg.Handle);
ProtokollHelper.AppendProtokollItem(mandant, ImportLog, beleg.Handle, ...);
belegnummer = beleg.BelegnummerFormatiert;
}
conn.CommitTransaction();
}
catch
{
conn.RollbackTransaction();
throw;
}
// Ab hier sind alle Sperren frei.
MeldeAuftragAnShop(xml.Bestellnummer, belegnummer);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Innerhalb einer Datenbanktransaktion passiert nur Datenbankarbeit. Kein Webservice, kein PDF, kein Drucker, keine E-Mail, kein Dialog, der auf den Anwender wartet. Alles davon kann langsam sein oder scheitern, und jede Sekunde davon ist eine Sekunde, in der Deine Sperren die Kollegen aufhalten. Wenn der Shop nach dem Commit nicht erreichbar ist, merkst Du Dir die Rückmeldung als offen und holst sie beim nächsten Lauf nach. Das ist ein fachliches Problem, kein Sperrproblem.
&lt;/p&gt;
&lt;p&gt;
Der Unterschied ist nicht akademisch. Eine Variante, die wir in der Praxis gesehen haben: Ein Webservice-Aufruf mitten in der Transaktion, der normalerweise 200 Millisekunden dauert. An dem Tag, an dem der Anbieter Wartungsarbeiten hatte, dauerte er 90 Sekunden. 90 Sekunden, in denen jede Belegerfassung im Haus stand. Der SQL Server war dabei komplett unschuldig.
&lt;/p&gt;
&lt;h2&gt;Das gilt auch für DCMs in der Sage 100&lt;/h2&gt;
&lt;p&gt;
Der Importdienst arbeitet von außen gegen die BelegEngine. Wer die Belegerfassung stattdessen von innen erweitert, sitzt noch näher an der Transaktion: Das Ereignis wird im AppDesigner registriert, die Implementierung dahinter ist ein DCM. Die Sage-Doku zu den &lt;a href="https://sagegmbh.atlassian.net/wiki/spaces/S1/pages/121765912/Erweiterungen+der+Belegerfassung" target="_blank" rel="noopener"&gt;Erweiterungen der Belegerfassung&lt;/a&gt; ist da eindeutig: Die DCMs &lt;code&gt;VKBelegProxyBeforeSave&lt;/code&gt; und &lt;code&gt;VKBelegProxyAfterSave&lt;/code&gt; werden vor beziehungsweise nach der Transaktion ausgeführt. &lt;code&gt;VKBelegBeforeSave&lt;/code&gt; und &lt;code&gt;VKBelegSave&lt;/code&gt; laufen mittendrin. Dasselbe steht in der Doku zu den &lt;a href="https://sagegmbh.atlassian.net/wiki/spaces/S1/pages/51019815/Ereignisse" target="_blank" rel="noopener"&gt;Ereignissen&lt;/a&gt;, die im AppDesigner registriert werden: Das Ereignis vor Änderung eines Datensatzes wird serverseitig innerhalb der Transaktion ausgeführt.
&lt;/p&gt;
&lt;p&gt;
Für Dich heißt das: Alles, was ein DCM für &lt;code&gt;VKBelegSave&lt;/code&gt;, &lt;code&gt;VKBelegBeforeSave&lt;/code&gt; oder das Ereignis vor Änderung eines Datensatzes implementiert, verlängert die Zeit, in der die Sage 100 ihre Sperren auf Belegkopf, Positionen und &lt;code&gt;KHKTan&lt;/code&gt; hält. Ein Aufruf ins DMS, eine Adressprüfung bei einem Webdienst, ein Etikettendruck oder ein Mailversand an dieser Stelle bremst nicht nur diesen einen Anwender, sondern jeden, der gerade einen Beleg speichern will. Solche Dinge gehören in &lt;code&gt;VKBelegProxyAfterSave&lt;/code&gt;, wenn die Transaktion abgeschlossen ist. In der Transaktion bleibt nur, was wirklich mit dem Beleg zusammen gespeichert oder verworfen werden muss.
&lt;/p&gt;
&lt;details class="deep-dive"&gt;
&lt;summary&gt;
&lt;span class="deep-dive-label"&gt;Deep Dive&lt;/span&gt;
&lt;span&gt;Weitere Verursacher, die genauso aussehen&lt;/span&gt;
&lt;span class="deep-dive-chev"&gt;&lt;svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;&lt;path d="m6 9 6 6 6-6"/&gt;&lt;/svg&gt;&lt;/span&gt;
&lt;/summary&gt;
&lt;div class="deep-dive-body"&gt;
&lt;p&gt;
&lt;strong&gt;Das vergessene Query-Fenster.&lt;/strong&gt; Der Klassiker. Jemand testet im Management Studio ein UPDATE mit &lt;code&gt;BEGIN TRAN&lt;/code&gt;, um es notfalls zurückrollen zu können, geht in die Mittagspause und lässt das Fenster offen. Session sleeping, Transaktion offen, Programmname SQL Server Management Studio. Kommt öfter vor, als man denkt.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Implizite Transaktionen.&lt;/strong&gt; Mit &lt;a href="https://learn.microsoft.com/de-de/sql/t-sql/statements/set-implicit-transactions-transact-sql" target="_blank" rel="noopener"&gt;SET IMPLICIT_TRANSACTIONS ON&lt;/a&gt; startet der SQL Server bei jedem Datenzugriff automatisch eine Transaktion, die erst mit einem ausdrücklichen COMMIT endet. Manche Treiber und Tools setzen das ein, wenn Autocommit abgeschaltet wird. Die Anwendung glaubt, sie hätte gar keine Transaktion offen. Hat sie aber.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Trigger.&lt;/strong&gt; Ein einzelnes UPDATE auf eine Tabelle kann über Trigger weitere Tabellen ändern. Alle diese Änderungen gehören zur selben Transaktion und halten ihre Sperren genauso lange. Wer sich wundert, warum eine Session Sperren auf Tabellen hält, die sie nie direkt angefasst hat, sollte in &lt;code&gt;sys.triggers&lt;/code&gt; nachsehen. Bei der Sage 100 gilt das auch für Trigger, die Zusatzmodule oder Schnittstellen auf Sage-Tabellen legen.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Benutzerinteraktion in der Transaktion.&lt;/strong&gt; Transaktion starten, Datensatz ändern, Dialog anzeigen „Wirklich buchen?" und auf den Klick warten. Wenn der Anwender jetzt telefoniert, wartet die halbe Firma mit. Das Sperrhandbuch von Microsoft legt die Verantwortung dafür ausdrücklich in die Hand der Anwendung.
&lt;/p&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;h2&gt;Beim nächsten Mal nicht mehr suchen müssen&lt;/h2&gt;
&lt;p&gt;
Blocking hat eine unangenehme Eigenschaft: Wenn Du hinschaust, ist es oft schon vorbei. Der Anwender hat seine Sage 100 neu gestartet, die Verbindung ist weg, die Transaktion ist zurückgerollt, die Kette hat sich aufgelöst. Damit Du beim nächsten Mal nicht auf Verdacht suchen musst, kann der SQL Server Blocking selbst melden. Die Serveroption &lt;a href="https://learn.microsoft.com/de-de/sql/database-engine/configure-windows/blocked-process-threshold-server-configuration-option" target="_blank" rel="noopener"&gt;blocked process threshold&lt;/a&gt; legt fest, ab wie vielen Sekunden Wartezeit ein Bericht erzeugt wird. Zulässig sind 5 bis 86.400 Sekunden, standardmäßig ist die Option aus.
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;EXEC sp_configure 'show advanced options', 1;
RECONFIGURE;
EXEC sp_configure 'blocked process threshold', 20;
RECONFIGURE;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Den Bericht fängst Du mit einer Extended-Events-Sitzung auf das Ereignis &lt;code&gt;blocked_process_report&lt;/code&gt; ab. Er enthält beide Seiten, den Blockierten und den Blockierer, samt Eingabepuffer und offener Transaktionsdauer. Damit hast Du morgens die Antwort auf die Frage, was gestern Nachmittag los war, ohne dass jemand im richtigen Moment am Server sitzen musste. Wichtig aus der Doku: Der Sperrmonitor prüft nur alle fünf Sekunden, kürzere Blockaden werden nicht erkannt, und der Bericht ist nicht in Echtzeit garantiert. Für die Ursachensuche reicht das völlig.
&lt;/p&gt;
&lt;h2&gt;Fazit&lt;/h2&gt;
&lt;p&gt;
Ein Timeout ist ein Symptom. Ob dahinter eine langsame Abfrage oder eine blockierende Transaktion steckt, entscheidet über die Therapie, und die zweite Ursache ist tückischer, weil der Verursacher im Status sleeping unsichtbar bleibt. Vier Fragen bringen Dich hin: Wer blockiert wen, ist eine Transaktion offen, seit wann, und welche Sperren hält sie. Die Antworten stehen alle in den Systemsichten des SQL Servers.
&lt;/p&gt;
&lt;p&gt;
Passend dazu: Unser &lt;a href="https://appontes.de/blog/sage-100-sql-performance-messen/"&gt;SQL-Performance-Test für die Sage 100&lt;/a&gt; zeigt Dir mit den Lock-Hotspots, an welchen Tabellen sich Deine Anwender tatsächlich stauen. Und was passiert, wenn sich zwei Transaktionen gegenseitig blockieren, erklärt der Beitrag zu &lt;a href="https://appontes.de/blog/deadlocks-sql-server-verstehen-vermeiden/"&gt;Deadlocks im SQL Server&lt;/a&gt;.
&lt;/p&gt;
&lt;h2&gt;Anpassungen, die auch unter Last halten&lt;/h2&gt;
&lt;p&gt;
Wenn bei Dir gerade Belege hängen und niemand weiß, warum, finden wir den Root Blocker. Meist dauert das weniger lang als die Diskussion über den Timeout-Wert. Der eigentliche Wert liegt aber davor: Die meisten Blocking-Fälle, die wir sehen, stammen aus eigener Programmierung rund um die Sage 100, aus Diensten und AddIns, aus DCMs hinter registrierten Ereignissen, aus Schnittstellen zu Shop, DMS oder Zeiterfassung. Im Test mit zwei Anwendern läuft das alles. Mit vierzig Anwendern an einem Monatsende nicht mehr.
&lt;/p&gt;
&lt;p&gt;
Deshalb prüfen wir solche Anpassungen auf das, was im Produktivbetrieb zählt: Werden Transaktionen sauber beendet, auch im Fehlerfall? Sind sie so kurz wie möglich? Stecken externe Aufrufe oder Dialoge in einer offenen Transaktion oder in einem DCM, das innerhalb der Transaktion läuft? Werden Verbindungen zurückgegeben? Greifen alle Abläufe in derselben Reihenfolge auf die Sage-Tabellen zu? Und wir lassen das Ganze unter realistischer Last laufen, bevor es Deine Anwender tun. Egal ob die Anpassung von uns stammt, von einem anderen Partner oder aus dem eigenen Haus.
&lt;/p&gt;
&lt;div style="text-align: center; margin: 3rem 0;"&gt;
&lt;a href="https://appontes.de/kontakt/?betreff=anfrage-sage" class="btn btn-primary"&gt;Blocking-Analyse oder Code-Review anfragen&lt;/a&gt;
&lt;/div&gt;</content:encoded></item><item><title>Einmalkunden und Einmallieferanten in der Sage 100: Wann sie sich lohnen und was Du an Auswertbarkeit verlierst</title><link>https://appontes.de/blog/einmalkunden-einmallieferanten-sage-100/</link><guid isPermaLink="true">https://appontes.de/blog/einmalkunden-einmallieferanten-sage-100/</guid><pubDate>Sun, 20 Sep 2026 00:00:00 +0000</pubDate><dc:creator>Thomas Falkner</dc:creator><category>Sage 100</category><category>Warenwirtschaft</category><category>Rechnungswesen</category><category>Stammdaten</category><description>Die Sonderfunktion Einmalvorgänge hält den Kundenstamm der Sage 100 schlank, wenn jemand nur einmal kauft. Wie Du Einmalkunden und Einmallieferanten einrichtest, was bei der Übergabe ins Rechnungswesen passiert, für welche Fälle sich das Modell eignet und welche Statistiken und Auskünfte Du damit aufgibst.</description><content:encoded>&lt;p&gt;&lt;img src="https://appontes.de/img/blog/einmalkunden-sage-100.svg" alt="Einmalkunden und Einmallieferanten in der Sage 100: Wann sie sich lohnen und was Du an Auswertbarkeit verlierst"&gt;&lt;/p&gt;
&lt;p&gt;
Ein Messebesucher nimmt ein Ersatzteil mit und zahlt bar. Ein Privatkunde bestellt einmal über die Website und meldet sich nie wieder. Der Hausmeisterservice stellt eine einzige Rechnung für die Reparatur des Rolltors. In jedem dieser Fälle steht die Frage im Raum, ob dafür wirklich ein vollständiger Kunde oder Lieferant im Stamm angelegt werden soll. Mit Kontokorrent, Zahlungskondition, Kreditlimit, Vertreter und all den Feldern, die für einen Geschäftspartner gedacht sind, mit dem man länger zu tun hat.
&lt;/p&gt;
&lt;p&gt;
Die Sage 100 hat für genau diese Situation die &lt;strong&gt;Sonderfunktion Einmalvorgänge&lt;/strong&gt;. Ein einziger Stammsatz dient als Sammelkunde, die eigentliche Anschrift wird erst im Beleg erfasst. In der Praxis nutzen das erstaunlich wenige Anwender, und wenn, dann oft ohne zu wissen, was hinten im Rechnungswesen und in den Auswertungen daraus wird. Dieser Beitrag zeigt Dir die Einrichtung, den Weg des Belegs bis zum Offenen Posten und vor allem die Frage, die vor der Entscheidung stehen sollte: Für welche Fälle lohnt sich das Modell, und was gibst Du dafür auf?
&lt;/p&gt;
&lt;h2&gt;Was ein Einmalkunde technisch ist&lt;/h2&gt;
&lt;p&gt;
Ein Einmalkunde ist ein ganz normaler Kunde im Kundenstamm, bei dem im Feld &lt;em&gt;Vorlage&lt;/em&gt; der Wert &lt;em&gt;Für Einmalvorgänge&lt;/em&gt; steht. Die Onlinehilfe spricht von der Sonderfunktion Einmalvorgänge, in den Masken heißt das Feld schlicht Vorlage. Er hat eine Kundennummer, einen &lt;a class="glossar-term" href="https://appontes.de/glossar/matchcode/"&gt;Matchcode&lt;span class="glossar-tip" aria-hidden="true"&gt;&lt;strong&gt;Matchcode&lt;/strong&gt;Frei wählbarer Suchbegriff zu einem Datensatz in der Sage 100, über den sich Adressen, Kunden, Lieferanten oder Artikel schnell finden lassen.&lt;em&gt;Mehr im Glossar &amp;#8594;&lt;/em&gt;&lt;/span&gt;&lt;/a&gt; und ein &lt;a class="glossar-term" href="https://appontes.de/glossar/kontokorrent/"&gt;Kontokorrent&lt;span class="glossar-tip" aria-hidden="true"&gt;&lt;strong&gt;Kontokorrent&lt;/strong&gt;Sammelbegriff für die Personenkonten der Buchhaltung: Debitoren (Kunden) und Kreditoren (Lieferanten) mit ihren Stammdaten wie Zahlungskonditionen und Besteuerungsart.&lt;em&gt;Mehr im Glossar &amp;#8594;&lt;/em&gt;&lt;/span&gt;&lt;/a&gt;, aber bewusst keine Anschrift. Straße, Postleitzahl und Ort bleiben leer, weil sie bei jedem Beleg anders lauten und nichts vorbelegen sollen. Was Du hinterlegen kannst und solltest, sind die Vorgaben, die im Beleg als Vorschlag dienen: Steuergebiet, Preisliste, Zahlungskondition, Vertreter, Erlöscode.
&lt;/p&gt;
&lt;p&gt;
Für Einmallieferanten gilt dasselbe im Lieferantenstamm. Das Feld Vorlage sitzt an derselben Stelle, der Ablauf im Einkauf ist spiegelbildlich. Im Folgenden beschreibe ich die Kundenseite, der Rest überträgt sich.
&lt;/p&gt;
&lt;p&gt;
Das Gegenstück im selben Feld ist der Wert &lt;em&gt;Für die Anlage neuer Kunden&lt;/em&gt;. Ein so markierter Kunde ist ein Musterkunde, dessen Bedingungen bei der Neuanlage eines echten Kunden übernommen werden. Sie erzeugt also weitere Stammsätze und ist jederzeit änderbar. Der Einmalkunde macht das Gegenteil: Er vermeidet neue Stammsätze und ist nach dem ersten Beleg nicht mehr umstellbar. Beides in einem Datensatz zu kombinieren geht nicht, das Feld kennt genau einen Wert.
&lt;/p&gt;
&lt;h2&gt;Wann Einmalvorgänge sinnvoll sind und wann nicht&lt;/h2&gt;
&lt;p&gt;
Die Entscheidung hängt weniger von der Sage-Technik ab als von Deinem Geschäft. Die Leitfrage lautet: Wirst Du zu diesem Geschäftspartner jemals eine Auskunft brauchen, die über den einzelnen Beleg hinausgeht? Wenn die Antwort nein ist, ist der Einmalkunde richtig.
&lt;/p&gt;
&lt;table class="tech-table"&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Geeignet für Einmalvorgänge&lt;/th&gt;
&lt;th&gt;Besser als eigener Stammsatz&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Laufkundschaft und Barverkauf, etwa am Werksverkauf, auf Messen oder im Ladenlokal&lt;/td&gt;
&lt;td&gt;Jeder Kunde, der ein zweites Mal kauft oder bei dem Du das erwartest&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Privatkunden, die einmalig über einen Shop oder ein Portal bestellen und keine Kundenbeziehung wollen&lt;/td&gt;
&lt;td&gt;Kunden mit Preisliste, Rabattstaffel, Rahmenvertrag oder Kreditlimit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gutschriften und Rückerstattungen an Personen, die sonst nie im System auftauchen&lt;/td&gt;
&lt;td&gt;Kunden, deren Umsatz einem Vertreter zugerechnet oder provisioniert werden soll&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Einmalige Fremdleistungen im Einkauf, zum Beispiel ein Handwerker, ein Caterer oder eine Auslagenerstattung an einen Mitarbeiter&lt;/td&gt;
&lt;td&gt;Lieferanten mit Bestellvorschlag, Wiederbeschaffungszeit oder Rahmenabruf&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Testmandanten und Schulungen, in denen niemand echte Stammdaten pflegen soll&lt;/td&gt;
&lt;td&gt;Geschäftspartner im EU-Ausland, bei denen die Umsatzsteuer-Identifikationsnummer sauber am Stamm hängen muss&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;
Die letzte Zeile verdient ein Wort mehr. Innergemeinschaftliche Lieferungen brauchen die Umsatzsteuer-Identifikationsnummer des Abnehmers, und die &lt;a href="https://appontes.de/blog/zusammenfassende-meldung-zm-sage-100/"&gt;Zusammenfassende Meldung&lt;/a&gt; wird je Nummer aufgebaut. Das lässt sich technisch auch über einen Einmalkunden abbilden, weil die Nummer im Beleg erfasst werden kann. Ich würde es trotzdem nicht empfehlen. Sobald eine Prüfung nachvollziehen will, an wen steuerfrei geliefert wurde, ist ein eigener Stammsatz mit geprüfter Nummer der deutlich stabilere Nachweis. Ähnlich sieht es bei Kunden aus, die per E-Rechnung beliefert werden wollen: Leitweg-ID, Bestellnummernpflicht und Zustellweg gehören an einen echten Kunden.
&lt;/p&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;
&lt;strong&gt;Faustregel aus Projekten:&lt;/strong&gt; Ein Einmalkunde ist eine Aussage über die Zukunft, nicht über die Vergangenheit. Wer zum zweiten Mal bestellt, bekommt einen Stammsatz. Wer das konsequent macht, hat einen Kundenstamm, der nur Beziehungen enthält, und einen Einmalkunden, der wirklich nur Einmaliges sammelt.
&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;Einmalkunde anlegen&lt;/h2&gt;
&lt;p&gt;
Der Stammsatz entsteht wie jeder andere Kunde unter &lt;em&gt;Stammdaten&lt;/em&gt; und &lt;em&gt;Kunden&lt;/em&gt;. Vergib eine Nummer, die man sofort erkennt, zum Beispiel am Ende des Nummernkreises, und einen sprechenden Matchcode. Im Demomandanten ist das der Kunde D400000 mit dem Matchcode &lt;em&gt;Diverse&lt;/em&gt;. Die Anschriftsfelder bleiben leer. In den Bedingungen stellst Du dann das Feld &lt;em&gt;Vorlage&lt;/em&gt; auf &lt;em&gt;Für Einmalvorgänge&lt;/em&gt;.
&lt;/p&gt;
&lt;figure class="blog-figure"&gt;
&lt;img src="https://appontes.de/img/blog/einmalkunden/kundenstamm-vorlage-einmalvorgaenge.png" alt="Kundenstamm der Sage 100 mit dem Kunden D400000 Diverse, Anschrift leer, im Bereich Bedingungen ist das Feld Vorlage geöffnet und zeigt die Auswahl für die Anlage neuer Kunden, für Einmalvorgänge und Nein" width="2336" height="649" loading="lazy"&gt;
&lt;figcaption&gt;Der Sammelkunde D400000 Diverse aus dem Demomandanten: Anschrift leer, Zahlungskondition Sofort, Vorlage auf Für Einmalvorgänge&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;
Zwei Dinge solltest Du dabei wissen. Erstens lässt sich das Feld Vorlage nur setzen und ändern, solange der Kunde noch nirgends verwendet wurde, weder in einem Beleg der Warenwirtschaft noch in einer Buchung des Rechnungswesens. Ein bestehender Kunde mit Historie kann also nicht nachträglich zum Einmalkunden werden. Zweitens braucht der Einmalkunde ein Kontokorrent, also eine Debitorennummer. Darauf landen später alle Buchungen, egal an wen die Rechnung ging.
&lt;/p&gt;
&lt;p&gt;
Aus dem zweiten Punkt folgt eine Empfehlung: Lege nicht einen, sondern mehrere Einmalkunden an, wenn sich Deine Einmalgeschäfte in Gruppen mit unterschiedlichen Vorgaben teilen. Typisch sind ein Einmalkunde für Inland, einer für EU-Ausland und einer für Drittland, weil sich das Steuergebiet unterscheidet. Manche Unternehmen trennen zusätzlich Barverkauf und Rechnungskauf, weil der Barverkauf eine andere Zahlungskondition und ein anderes Erlöskonto bekommt. Jeder dieser Einmalkunden ist später ein eigenes Sammelkonto in der Buchhaltung und eine eigene Zeile in der Statistik, und genau das macht die Auswertung hinterher erträglicher.
&lt;/p&gt;
&lt;h2&gt;Verkaufsbeleg an einen Einmalkunden erfassen&lt;/h2&gt;
&lt;p&gt;
In der Belegerfassung wählst Du als Empfänger den Einmalkunden. Die Sage 100 füllt daraufhin die Vorgaben aus dem Stammsatz, Steuergebiet, Preisliste, Vertreter und Zahlungskondition. Die Anschriftsfelder sind leer und warten auf die Daten des tatsächlichen Käufers. Name, Straße, Postleitzahl, Ort und Land trägst Du direkt im Beleg ein.
&lt;/p&gt;
&lt;figure class="blog-figure"&gt;
&lt;img src="https://appontes.de/img/blog/einmalkunden/belegerfassung-matchcode-einmalkunde.png" alt="Belegkopf der Verkaufsbelegerfassung mit Kunde D400000 Diverse, darunter das Feld Matchcode Einmalkunde und die von Hand erfasste Anschrift Radwerk Rottweil GmbH, Neckar Str. 43, 78628 Rottweil" width="870" height="443" loading="lazy" style="display: block; margin: 0 auto;"&gt;
&lt;figcaption&gt;Der Einmalkunde liefert die Vorgaben, Name und Anschrift des Käufers kommen von Hand in den Beleg&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;
Wichtig für das Verständnis: Alles, was Du hier eingibst, gehört zum Beleg und nur zum Beleg. Der Stammsatz bleibt unverändert, auch wenn Du das Steuergebiet oder die Preisliste im Beleg überschreibst. Beim nächsten Beleg an den Einmalkunden startest Du wieder mit den Vorgaben aus dem Stamm.
&lt;/p&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;
&lt;strong&gt;Tipp:&lt;/strong&gt; Bei der Übergabe ins Rechnungswesen legt die Sage 100 für den Käufer eine Adresse im Adressenstamm an, dazu gleich mehr. Als Matchcode dieser Adresse verwendet sie standardmäßig den Matchcode des Einmalkunden. Das Ergebnis ist ein Adressenstamm voller Einträge, die alle &lt;em&gt;Diverse&lt;/em&gt; heißen, und eine Offene-Posten-Liste, in der Du den Käufer nur über die Belegnummer findest.
&lt;/p&gt;
&lt;p&gt;
Die Belegerfassung hat dafür das Feld &lt;em&gt;Matchcode Einmalkunde&lt;/em&gt;, das im Standardlayout ausgeblendet ist. Über die Layoutanpassung ziehst Du es aus den ausgeblendeten Elementen in den Adressbereich, im Screenshot oben ist es bereits eingeblendet. Wer den Beleg erfasst, trägt dort den Namen des Käufers ein, und die Adresse im Rechnungswesen bekommt genau diesen Matchcode. Ein Muss ist das nicht, aber eine echte Vereinfachung für alle, die später mit den Offenen Posten arbeiten. Sprich mit dem Team ab, wie das Feld gefüllt wird, Firma und Ort oder Nachname und Vorname, immer in derselben Reihenfolge. Sonst steht dieselbe Person nach drei Käufen als drei unterschiedlich geschriebene Adressen im Stamm.
&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;Was bei der Übergabe ins Rechnungswesen passiert&lt;/h2&gt;
&lt;p&gt;
Solange der Beleg ein Angebot, eine Auftragsbestätigung oder ein Lieferschein ist, bleibt alles in der Warenwirtschaft. Interessant wird es mit der Rechnung, Sofortrechnung oder Direktrechnung, also mit jedem Beleg, der ins Rechnungswesen übergeben wird. Bei dieser Übergabe passieren drei Dinge gleichzeitig.
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Die Buchung landet auf dem Konto des Einmalkunden.&lt;/strong&gt; Der Debitor des Sammelkunden bekommt den Umsatz, so wie bei jedem anderen Kunden auch. Sein Saldo ist die Summe aller offenen Einmalgeschäfte.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Eine neue Adresse entsteht im Adressenstamm.&lt;/strong&gt; Die im Beleg erfasste Anschrift wird als eigenständiger Datensatz unter &lt;em&gt;Stammdaten&lt;/em&gt; und &lt;em&gt;Adressen&lt;/em&gt; angelegt. Diese Adresse hat kein Kontokorrent und keine Belege in ihrer Sammelmappe. Sie ist eine reine Anschrift.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Der &lt;a class="glossar-term" href="https://appontes.de/glossar/offene-posten/"&gt;Offene Posten&lt;span class="glossar-tip" aria-hidden="true"&gt;&lt;strong&gt;Offene Posten&lt;/strong&gt;Noch nicht ausgeglichene Forderungen und Verbindlichkeiten. Die Offene-Posten-Verwaltung zeigt, welche Rechnungen noch nicht bezahlt oder verrechnet sind.&lt;em&gt;Mehr im Glossar &amp;#8594;&lt;/em&gt;&lt;/span&gt;&lt;/a&gt; wird an die Adresse gehängt.&lt;/strong&gt; Der Offene Posten gehört buchhalterisch zum Konto des Einmalkunden, trägt aber den Verweis auf die neue Adresse. Über diese Adresse laufen Mahnwesen und Zahlungsverkehr, dort steht die Anschrift für den Mahnbrief und, wenn Du sie hinterlegst, die Bankverbindung für den Zahlungslauf.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Wer nachvollziehen will, welche Adresse zu welchem Einmalkunden gehört, findet die Verbindung im Adressenstamm über das Hamburgermenü unter &lt;em&gt;Extras&lt;/em&gt; und &lt;em&gt;Verwendungsnachweis&lt;/em&gt;. Dort zeigt die Sage 100 die Kundennummer, unter der die Adresse in Offenen Posten verwendet wird. Denselben Verwendungsnachweis kennst Du vielleicht schon von den &lt;a href="https://appontes.de/blog/abweichende-lieferadressen-sage-100/"&gt;abweichenden Lieferadressen&lt;/a&gt;, die auf dieselbe Weise als reine Anschriften gespeichert werden.
&lt;/p&gt;
&lt;h3&gt;Sonderfall abweichender Rechnungsempfänger&lt;/h3&gt;
&lt;p&gt;
Seit Version 9.0 verhält sich die Kombination aus Einmalkunde und abweichendem Rechnungsempfänger klar definiert. Geht eine Rechnung an einen echten Debitor, der als abweichenden Rechnungsempfänger einen Einmalkunden hat, wird bei der Übergabe die Adresse angelegt. Umgekehrt, also Beleg an den Einmalkunden mit einem bestehenden Debitor als abweichendem Rechnungsempfänger, wird kein Einmalvorgang erzeugt, sondern der bestehende Debitor gebucht. Das ist der Weg, wenn beispielsweise ein Händler für seinen Endkunden bestellt und selbst die Rechnung bekommt.
&lt;/p&gt;
&lt;details class="deep-dive"&gt;
&lt;summary&gt;
&lt;span class="deep-dive-label"&gt;Deep Dive&lt;/span&gt;
&lt;span&gt;Wo die Sage 100 den Einmalkunden wirklich speichert&lt;/span&gt;
&lt;span class="deep-dive-chev"&gt;&lt;svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"&gt;&lt;path d="m6 9 6 6 6-6"/&gt;&lt;/svg&gt;&lt;/span&gt;
&lt;/summary&gt;
&lt;div class="deep-dive-body"&gt;
&lt;p&gt;
Für alle, die es genau wissen wollen: Die Sonderfunktion ist kein Merkmal des Kunden im Sinne der Adresse und auch kein Merkmal des Belegs. Sie hängt am Personenkonto. Ein Debitor wird in der Tabelle &lt;code&gt;KHKKontokorrent&lt;/code&gt; über die Spalte &lt;code&gt;KtoTyp&lt;/code&gt; als Konto für Einmalvorgänge markiert.
&lt;/p&gt;
&lt;table class="tech-table"&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;KtoTyp&lt;/th&gt;
&lt;th&gt;Bedeutung&lt;/th&gt;
&lt;th&gt;Auswahl in der Maske&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Standardkunde&lt;/td&gt;
&lt;td&gt;Nein&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Einmalkonto&lt;/td&gt;
&lt;td&gt;Für Einmalvorgänge&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Vorlage&lt;/td&gt;
&lt;td&gt;Für die Anlage neuer Kunden&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;
Dazu muss &lt;code&gt;KtoArt&lt;/code&gt; auf &lt;em&gt;D&lt;/em&gt; stehen, es geht also um einen Debitor. Im Demomandanten ist das Konto D400000 mit dem Matchcode &lt;em&gt;Diverse&lt;/em&gt; so markiert. Für Einmallieferanten gilt dasselbe mit &lt;code&gt;KtoArt&lt;/code&gt; gleich &lt;em&gt;K&lt;/em&gt;.
&lt;/p&gt;
&lt;p&gt;
Die Engine liest genau dieses Feld. Ein Konto gilt als Einmalkonto, wenn &lt;code&gt;KtoTyp&lt;/code&gt; den Wert 1 hat, im Quelltext der Engine ist die Eigenschaft als Personenkonto beschrieben, auf dem Einmalvorgänge gebucht werden. In der Maske erreichst Du die Spalte im Kundenstamm über das Register &lt;em&gt;Kunde&lt;/em&gt;, Gruppe &lt;em&gt;Bedingungen&lt;/em&gt;, unter dem Feldtitel &lt;em&gt;Vorlage&lt;/em&gt;. Die Auswahlliste bietet die drei Werte aus der Tabelle. Sobald auf dem Konto einmal gebucht wurde, schaltet die Maske das Feld schreibgeschützt, deshalb lässt sich die Sonderfunktion nachträglich nicht mehr ändern.
&lt;/p&gt;
&lt;p&gt;
In der Belegerfassung wird ein Auftraggeber mit &lt;code&gt;KtoTyp&lt;/code&gt; gleich 1 von der Belegengine als Einmalkunde behandelt. Anschrift und Matchcode laufen dann belegbezogen. Am Verkaufsbelegkopf in &lt;code&gt;KHKVKBelege&lt;/code&gt; stehen dafür zwei zusätzliche Felder: &lt;code&gt;A0Einmalkunde&lt;/code&gt; als Kennzeichen und &lt;code&gt;A0EinmalkundeAdrNr&lt;/code&gt; mit der Nummer der Adresse, die bei der Übergabe ins Rechnungswesen entsteht. Diese Adresse bekommt die Adresskategorie 11 für Einmalkunden, daran erkennst Du sie im Adressenstamm auch ohne Verwendungsnachweis.
&lt;/p&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;
&lt;strong&gt;Nicht verwechseln:&lt;/strong&gt; Im Buchungsjournal gibt es ebenfalls eine Spalte &lt;code&gt;KtoTyp&lt;/code&gt;. Dort bezeichnet sie die Kontoart der Buchungszeile, also Debitor, Kreditor oder Sachkonto, und hat mit dem Stammdatenkennzeichen aus &lt;code&gt;KHKKontokorrent&lt;/code&gt; nichts zu tun.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;h2&gt;Einmalkunden direkt in der Buchungserfassung&lt;/h2&gt;
&lt;p&gt;
Der Einmalkunde funktioniert auch ohne Warenwirtschaft. Buchst Du im Rechnungswesen auf sein Konto, verlangt die Buchungserfassung zwingend eine Adresse zum Offenen Posten. Du kannst entweder eine neue Adresse anlegen oder eine bestehende aus dem Adressenstamm auswählen. Hier fragt die Sage 100 den Matchcode direkt ab, das Layoutthema aus der Warenwirtschaft stellt sich also nicht. Die Adresse ist anschließend im Detailbereich der Buchung und im Buchungsnachweis unter den Details des Offenen Postens sichtbar und dort auch änderbar.
&lt;/p&gt;
&lt;p&gt;
Für Einmallieferanten ist das der häufigere Weg. Die Handwerkerrechnung wird nicht über eine Bestellung im Einkauf abgewickelt, sondern direkt gebucht. Denk daran, dass die Vorsteuer den Rechnungsaussteller braucht, und dass die Adresse zum Offenen Posten genau diese Angabe trägt. Für den Zahlungslauf hinterlegst Du die Bankverbindung an der Adresse, nicht am Sammelkonto.
&lt;/p&gt;
&lt;h2&gt;Was Du an Auswertbarkeit verlierst&lt;/h2&gt;
&lt;p&gt;
Jetzt zum Teil, den die Onlinehilfe nur mit einem Halbsatz erwähnt. Alle Statistiken der Sage 100 laufen über das Kontokorrent. Beim Einmalkunden ist das Kontokorrent der Sammelkunde, und der weiß nichts von den Menschen und Firmen dahinter. Konkret bedeutet das:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Kundenstatistik und Umsatzauswertung.&lt;/strong&gt; Der Umsatz erscheint als eine Zeile für den Einmalkunden. Eine Frage wie &lt;em&gt;Was hat Firma Müller im letzten Jahr gekauft?&lt;/em&gt; beantwortet keine Standardauswertung, weil Firma Müller in der Statistik nicht existiert.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sammelmappe.&lt;/strong&gt; Die Belege liegen in der Sammelmappe des Einmalkunden, nicht bei der Adresse. Wer im Adressenstamm die Adresse von Firma Müller öffnet, sieht dort keinen einzigen Beleg. Umgekehrt enthält die Sammelmappe des Einmalkunden nach zwei Jahren Betrieb tausende Belege an tausende Empfänger.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Preis- und Belegehistorie.&lt;/strong&gt; Die Funktionen, die beim Erfassen den letzten Preis oder die letzte Bestellung dieses Kunden anzeigen, beziehen sich auf den Sammelkunden. Der Vorschlag ist damit wertlos.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Kreditlimit und Bonität.&lt;/strong&gt; Ein Kreditlimit am Einmalkunden gilt für die Summe aller Einmalgeschäfte, nicht für den Einzelnen. Eine Kreditlimitprüfung ist damit praktisch abgeschaltet. Das ist auch der Grund, warum Einmalvorgänge fast immer Vorkasse, Barzahlung oder Kleinbeträge sind.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mahnhistorie.&lt;/strong&gt; Mahnungen gehen zwar korrekt an die Adresse, die Mahnstufen und die Mahnhistorie hängen aber am Offenen Posten. Ob jemand schon beim letzten Kauf schlecht gezahlt hat, siehst Du nicht auf einen Blick.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Saldenbestätigung und Kontoauszug.&lt;/strong&gt; Ein Kontoauszug des Einmalkunden vermischt alle Käufer. Für eine Saldenbestätigung an einen einzelnen Käufer musst Du auf Ebene der Offenen Posten nach der Adresse filtern.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Offene-Posten-Liste.&lt;/strong&gt; In der Liste nach Kunden steht der Einmalkunde als Block, darin die einzelnen Posten mit der Kurzbezeichnung der Adresse als Matchcode. Das funktioniert, sofern das Feld Matchcode Einmalkunde gepflegt wurde. Ohne diese Pflege heißt jeder Posten gleich.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Dazu kommt ein Effekt, den man erst nach einer Weile bemerkt: Das Aufblähen verschwindet nicht, es verlagert sich. Jede Rechnung an einen Einmalkunden erzeugt eine Adresse im Adressenstamm. Statt tausend Debitoren hast Du nach einer Weile tausend Adressen ohne Kontokorrent, darunter Dubletten, wenn dieselbe Person mehrfach gekauft hat. Für die Buchhaltung ist das der geringere Ballast, weil diese Adressen keine Konten sind und in keiner Saldenliste auftauchen. Für ein Löschkonzept nach DSGVO ist es aber ein Posten, den Du im Blick behalten solltest, denn diese Adressen enthalten personenbezogene Daten und werden von niemandem gepflegt.
&lt;/p&gt;
&lt;h3&gt;Wenn Du trotzdem wissen willst, wer gekauft hat&lt;/h3&gt;
&lt;p&gt;
Die Anschrift des Käufers steht im Belegkopf, und Belege verschwinden nicht. Wer eine Auswertung nach Beleganschrift braucht, kommt mit einer Abfrage auf die Belegtabelle weiter. Welche Konten Einmalkunden sind, musst Du dabei nicht von Hand aufzählen, das Kennzeichen steht am Personenkonto in &lt;code&gt;KHKKontokorrent&lt;/code&gt;, siehe Deep Dive weiter oben. Vereinfacht sieht das so aus:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT b.A0Empfaenger, b.A0Name1, b.A0PLZ, b.A0Ort,
COUNT(*) AS Belege,
SUM(b.Nettobetrag) AS Nettoumsatz
FROM dbo.KHKVKBelege b
JOIN dbo.KHKKontokorrent k
ON k.Mandant = b.Mandant
AND k.Kto = b.A0Empfaenger
WHERE b.Mandant = 123
AND k.KtoArt = 'D'
AND k.KtoTyp = 1 -- Sonderfunktion Einmalvorgänge
AND b.Belegart IN ('Rechnung', 'Sofortrechnung')
AND b.Belegdatum &gt;= '2026-01-01'
GROUP BY b.A0Empfaenger, b.A0Name1, b.A0PLZ, b.A0Ort
ORDER BY Nettoumsatz DESC;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Das liefert eine Umsatzliste je Einmalkunde und Anschrift über alle Konten mit der Sonderfunktion. Wer lieber am Beleg filtert, nimmt statt des Joins das Kennzeichen &lt;code&gt;A0Einmalkunde&lt;/code&gt; im Belegkopf. Das Ergebnis hat alle Schwächen, die eine Gruppierung nach freiem Text hat. &lt;em&gt;Müller GmbH&lt;/em&gt; und &lt;em&gt;Mueller GmbH&lt;/em&gt; sind zwei Zeilen. Auch Gutschriften und Stornos musst Du je nach Belegart getrennt behandeln. Als Kontrolle, ob sich hinter dem Einmalkunden längst Stammkunden verstecken, ist die Abfrage trotzdem Gold wert. Wer in dieser Liste mit drei oder mehr Belegen auftaucht, gehört in den Kundenstamm.
&lt;/p&gt;
&lt;h2&gt;Aus der Einmaladresse einen Kunden machen&lt;/h2&gt;
&lt;p&gt;
Der Wechsel ist einfacher als gedacht. Du öffnest die Adresse im Adressenstamm und legst im Register &lt;em&gt;Kontokorrent&lt;/em&gt; eine Debitorennummer an. Ab diesem Moment ist die Adresse ein regulärer Kunde mit allen Bedingungen und einer eigenen Sammelmappe. Was nicht passiert: Die bisherigen Belege und Buchungen wandern nicht mit. Sie bleiben beim Einmalkunden und auf dessen Konto. Die Historie beginnt für den neuen Kunden also bei null, und die alten Rechnungen findest Du weiterhin nur über die Beleganschrift.
&lt;/p&gt;
&lt;p&gt;
Das ist ein weiteres Argument für die Regel, beim zweiten Kauf umzustellen und nicht beim fünften. Je länger jemand als Einmalkunde geführt wird, desto mehr Historie liegt am Ende auf dem falschen Konto.
&lt;/p&gt;
&lt;h2&gt;Fazit&lt;/h2&gt;
&lt;p&gt;
Einmalkunden und Einmallieferanten sind ein sauberes Werkzeug gegen einen Kundenstamm, in dem die Hälfte der Einträge seit Jahren keinen Umsatz gemacht hat. Die Einrichtung dauert zehn Minuten, im Beleg ändert sich für die Erfassung wenig, und das Rechnungswesen kommt mit der Konstruktion gut zurecht, weil Mahnwesen und Zahlungsverkehr über die Adresse zum Offenen Posten laufen.
&lt;/p&gt;
&lt;p&gt;
Der Preis ist die Auswertbarkeit. Alles, was die Sage 100 über einen Kunden weiß, weiß sie über das Kontokorrent, und beim Einmalkunden ist das Kontokorrent ein Sammelbecken. Wenn Du das Modell einführst, dann mit drei Entscheidungen im Gepäck: getrennte Einmalkunden für unterschiedliche Steuergebiete und Zahlungsarten, das Feld Matchcode Einmalkunde im Beleglayout und eine feste Regel, ab wann jemand einen eigenen Stammsatz bekommt.
&lt;/p&gt;
&lt;p&gt;
Wenn Du Deinen Kundenstamm aufräumen willst oder unsicher bist, welche Kunden eigentlich Einmalgeschäfte sind, schauen wir gemeinsam in Deine Belegdaten. Die Abfrage oben ist ein guter Anfang.
&lt;/p&gt;
&lt;div style="text-align: center; margin: 3rem 0;"&gt;
&lt;a href="https://appontes.de/kontakt/?betreff=anfrage-sage" class="btn btn-primary"&gt;Kostenlose Erstberatung vereinbaren&lt;/a&gt;
&lt;/div&gt;</content:encoded></item><item><title>Sage 100: Warum die Lizenzprüfung ohne TLS 1.2 scheitert</title><link>https://appontes.de/blog/sage-100-tls12-mehrbenutzerdienst/</link><guid isPermaLink="true">https://appontes.de/blog/sage-100-tls12-mehrbenutzerdienst/</guid><pubDate>Thu, 17 Sep 2026 00:00:00 +0000</pubDate><dc:creator>Thomas Falkner</dc:creator><category>Sage 100</category><category>Mehrbenutzerdienst</category><category>Lizenzierung</category><category>TLS</category><category>IT-Infrastruktur</category><description>Subskriptions-Lizenzen der Sage 100 werden online beim Sage-Lizenz-Service geprüft. Läuft der Mehrbenutzerdienst ohne TLS 1.2, bricht der Handshake ab. Warum ein aktuelles Windows dafür nicht reicht, was die Registry-Keys wirklich tun und wie Du das sauber prüfst.</description><content:encoded>&lt;p&gt;&lt;img src="https://appontes.de/img/blog/sage-100-tls12.svg" alt="Sage 100: Warum die Lizenzprüfung ohne TLS 1.2 scheitert"&gt;&lt;/p&gt;
&lt;p&gt;
Das Fehlerbild ist unspektakulär und deswegen ärgerlich. Die Sage 100 läuft seit Jahren, am Server hat niemand etwas geändert, und plötzlich meldet der zentrale Mehrbenutzerdienst, dass er die Lizenz nicht prüfen kann. Im Ereignisprotokoll steht irgendetwas von einer fehlgeschlagenen Verbindung. Der Admin pingt den Sage-Server an, kommt durch, schaut in die Firewall, findet nichts Auffälliges, und steht dann davor.
&lt;/p&gt;
&lt;p&gt;
Die Ursache liegt fast immer eine Schicht tiefer, als man sie sucht: Der Dienst erreicht den Sage-Lizenz-Service durchaus, er scheitert erst an der Verschlüsselungsaushandlung. Und zwar nicht, weil Windows kein TLS 1.2 könnte, sondern weil die Anwendung gar nicht erst danach fragt.
&lt;/p&gt;
&lt;h2&gt;Was der Mehrbenutzerdienst mit Lizenzen zu tun hat&lt;/h2&gt;
&lt;p&gt;
Klassische Sage-100-Lizenzen waren eine lokale Angelegenheit. Eine Lizenzdatei wurde eingespielt, der Mehrbenutzerdienst verteilte die Arbeitsplätze daraus, fertig. Mit den Subskriptions-Lizenzen ist eine Online-Komponente dazugekommen. Die Berechtigung hat eine begrenzte Gültigkeit und wird in regelmäßigen Abständen beim Sage-Lizenz-Service, kurz SLS, erneuert.
&lt;/p&gt;
&lt;p&gt;
Diesen Abgleich macht der zentrale Mehrbenutzerdienst. Er ist die einzige Komponente im System, die dafür nach außen telefoniert, und zwar per HTTPS an &lt;code&gt;https://licensing2.services.sage.com&lt;/code&gt;. Kein Client, kein Applikationsserver, nur der eine Dienst auf dem einen Rechner.
&lt;/p&gt;
&lt;p&gt;
Das erklärt den zeitlichen Verlauf, der die Diagnose so oft in die Irre führt. Am Tag, an dem die Voraussetzungen auf dem Server wegbrechen, passiert erst einmal gar nichts. Die vorhandene Berechtigung läuft weiter. Erst wenn der nächste Abgleich fällig wäre und wiederholt scheitert, kippt das System. Zwischen Ursache und Symptom können Tage liegen, und die Änderung, die man dann sucht, war ein Windows-Update oder eine Härtungsmaßnahme, an die längst niemand mehr denkt.
&lt;/p&gt;
&lt;h2&gt;Der eigentliche Punkt: Wer entscheidet über die TLS-Version&lt;/h2&gt;
&lt;p&gt;
Beim Aufbau einer TLS-Verbindung schickt der Client als Erstes ein ClientHello. Darin steht, welche Protokollversionen und welche Verschlüsselungsverfahren er anbietet. Der Server sucht sich daraus etwas aus, das er ebenfalls beherrscht, und antwortet mit seiner Wahl. Gibt es keine Schnittmenge, endet die Sache mit einem Handshake-Failure-Alert oder einem schlicht geschlossenen Socket.
&lt;/p&gt;
&lt;p&gt;
Der Sage-Lizenz-Service akzeptiert nur noch TLS 1.2 und neuer. Das ist kein Sage-Sonderweg. TLS 1.0 stammt von 1999, TLS 1.1 von 2006, und beide haben eine unerfreuliche Geschichte. Der &lt;a href="https://de.wikipedia.org/wiki/Transport_Layer_Security#BEAST" target="_blank" rel="noopener"&gt;BEAST-Angriff&lt;/a&gt; nutzt den vorhersagbaren Initialisierungsvektor im CBC-Modus aus, &lt;a href="https://www.isg.rhul.ac.uk/tls/Lucky13.html" target="_blank" rel="noopener"&gt;Lucky Thirteen&lt;/a&gt; holt über Laufzeitunterschiede beim Padding Klartext heraus. Dazu kommt die Abhängigkeit von SHA-1 für die Handshake-Integrität. Der PCI-Standard hat die Abschaltung &lt;a href="https://blog.pcisecuritystandards.org/are-you-ready-for-30-june-2018-sayin-goodbye-to-ssl-early-tls" target="_blank" rel="noopener"&gt;zum 30. Juni 2018&lt;/a&gt; verlangt, die Browserhersteller sind 2020 nachgezogen, und seit 2021 ist die Sache mit &lt;a href="https://www.rfc-editor.org/rfc/rfc8996" target="_blank" rel="noopener"&gt;RFC 8996&lt;/a&gt; auch offiziell erledigt. Dort steht wörtlich, dass TLS 1.0 und TLS 1.1 nicht mehr verwendet werden dürfen.
&lt;/p&gt;
&lt;p&gt;
Interessant wird es auf der Client-Seite. Man nimmt intuitiv an, dass ein Windows Server, der TLS 1.2 unterstützt, dieses Protokoll dann auch benutzt. Das stimmt für die TLS-Implementierung von Windows, die Microsoft offiziell &lt;a href="https://learn.microsoft.com/de-de/windows/win32/secauthn/secure-channel" target="_blank" rel="noopener"&gt;Secure Channel, kurz Schannel&lt;/a&gt;, nennt. Es stimmt nicht für eine .NET-Framework-Anwendung, die darauf aufsetzt.
&lt;/p&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;
&lt;strong&gt;Der Kern des Problems:&lt;/strong&gt; Das .NET Framework gibt Schannel explizit vor, welche Protokolle im ClientHello landen dürfen. Der Standardwert dieser Vorgabe war jahrelang SSL 3.0 und TLS 1.0. Windows könnte also TLS 1.2 sprechen, aber die Anwendung untersagt es ihm aktiv. Der Server auf der Gegenseite sieht ein ClientHello mit maximal TLS 1.0 und legt auf.
&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;
Ab .NET Framework 4.6 hat Microsoft die Voreinstellung geändert. Nur greift die neue Voreinstellung an einer Bedingung, die im Alltag gern übersehen wird: Sie hängt am Ziel-Framework, gegen das die Anwendung kompiliert wurde, nicht an der Version, die auf dem Server installiert ist. Eine Binärdatei, die gegen 4.5 gebaut wurde, bekommt weiterhin das alte Verhalten, auch auf einem Server mit .NET 4.8. Das ist Absicht und nennt sich Kompatibilitäts-Quirk. Microsoft beschreibt das in den &lt;a href="https://learn.microsoft.com/de-de/dotnet/framework/network-programming/tls" target="_blank" rel="noopener"&gt;bewährten Methoden für TLS mit dem .NET Framework&lt;/a&gt; recht deutlich, inklusive des Hinweises, dass &lt;code&gt;SslProtocols.Default&lt;/code&gt; bis heute für SSL 3.0 und TLS 1.0 steht.
&lt;/p&gt;
&lt;p&gt;
Deshalb ist der Satz „Auf dem Server ist doch .NET 4.8 installiert" kein Gegenargument. Und deshalb braucht es die Registry-Schalter.
&lt;/p&gt;
&lt;h2&gt;Was die Registry-Keys tatsächlich bewirken&lt;/h2&gt;
&lt;p&gt;
Die beiden Werte liegen unter den Framework-Zweigen und wirken prozessübergreifend für alle .NET-Anwendungen der jeweiligen Version.
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;SchUseStrongCrypto = 1&lt;/code&gt;&lt;/strong&gt; nimmt SSL 3.0 und TLS 1.0 aus der Standardliste heraus. Technisch übergibt .NET damit das Kennzeichen &lt;a href="https://learn.microsoft.com/de-de/windows/win32/api/schannel/ns-schannel-schannel_cred" target="_blank" rel="noopener"&gt;&lt;code&gt;SCH_USE_STRONG_CRYPTO&lt;/code&gt;&lt;/a&gt; an Schannel, das bekannt schwache Algorithmen, Cipher Suites und Protokollversionen abschaltet. Das ist der historisch ältere Schalter und derjenige, den die Sage-Hinweise nennen.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;SystemDefaultTlsVersions = 1&lt;/code&gt;&lt;/strong&gt; geht einen Schritt weiter und ist der sauberere Weg. Damit gibt .NET überhaupt keine Protokollliste mehr vor, sondern überlässt die Entscheidung dem Betriebssystem. Windows wählt dann nach seiner eigenen Schannel-Konfiguration. Das hat den angenehmen Nebeneffekt, dass ein künftiges TLS 1.3 ohne erneuten Eingriff funktioniert.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Beide zusammen zu setzen ist die von Microsoft dokumentierte Kombination. Sie widersprechen sich nicht, sondern greifen an unterschiedlichen Stellen der Auswahl.
&lt;/p&gt;
&lt;p&gt;
Der dritte Wert betrifft eine andere Baustelle. Unter &lt;code&gt;Internet Settings\WinHttp&lt;/code&gt; steuert &lt;code&gt;DefaultSecureProtocols&lt;/code&gt; nicht .NET, sondern native Komponenten, die WinHTTP direkt verwenden. Setups, Update-Routinen und manche Dienste gehören dazu. Der übliche Wert &lt;code&gt;0x0AA0&lt;/code&gt; ist eine Bitmaske und ergibt sich aus TLS 1.2 (0x800), TLS 1.1 (0x200), TLS 1.0 (0x080) und SSL 3.0 (0x020).
&lt;/p&gt;
&lt;h2&gt;Warum ausgerechnet WOW6432Node&lt;/h2&gt;
&lt;p&gt;
Der Punkt, an dem die meisten Umstellungen scheitern, ist der Registry-Zweig. Die Sage-Anleitung betont ihn zu Recht.
&lt;/p&gt;
&lt;p&gt;
Auf einem 64-Bit-Windows gibt es zwei getrennte Ablagen unterhalb von &lt;code&gt;HKEY_LOCAL_MACHINE\SOFTWARE&lt;/code&gt;. Der sichtbare Zweig gehört den 64-Bit-Prozessen. Für 32-Bit-Prozesse schaltet die WOW64-Schicht beim Öffnen von &lt;code&gt;SOFTWARE&lt;/code&gt; unbemerkt nach &lt;code&gt;SOFTWARE\WOW6432Node&lt;/code&gt; um. Die Anwendung bekommt davon nichts mit, sie glaubt, sie läse den normalen Pfad.
&lt;/p&gt;
&lt;p&gt;
Der zentrale Mehrbenutzerdienst der Sage 100 ist ein 32-Bit-Prozess. Ein Eintrag ausschließlich im 64-Bit-Zweig geht für ihn ins Leere. Genau das ist der Grund, warum eine Umstellung scheinbar korrekt durchgeführt wurde und trotzdem nichts bringt.
&lt;/p&gt;
&lt;p&gt;
Beim Setzen der Werte gilt dieselbe Mechanik. Eine 64-Bit-PowerShell muss &lt;code&gt;WOW6432Node&lt;/code&gt; wörtlich im Pfad stehen haben. Eine 32-Bit-PowerShell landet automatisch dort, auch wenn der Pfad anders aussieht. Wer es in beiden Zweigen setzt, umgeht die Frage. Genau das tut auch die Registry-Datei weiter unten.
&lt;/p&gt;
&lt;h2&gt;Was auf dem Server vorhanden sein muss&lt;/h2&gt;
&lt;p&gt;Bevor Du an der Registry drehst, sollten die Grundlagen stimmen:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Aktuelle Windows-Updates. TLS 1.2 ist auf älteren Serverständen nachgerüstet worden, nicht von Anfang an vorhanden gewesen.&lt;/li&gt;
&lt;li&gt;.NET Framework 4.7.2 oder höher. Ab dieser Version ist das Verhalten ohnehin auf die Systemvorgabe umgestellt, was die Sache deutlich entspannter macht.&lt;/li&gt;
&lt;li&gt;Visual C++ Redistributable 2017, also die Runtime-Version 14.1x beziehungsweise Toolset 141. Die aktualisierten Dienst-Binärdateien sind dagegen gelinkt.&lt;/li&gt;
&lt;li&gt;Firewall-Freigabe für &lt;code&gt;https://licensing2.services.sage.com&lt;/code&gt; auf Port 443, ausgehend vom Server des Mehrbenutzerdienstes.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Der Weg zum aktualisierten Dienst&lt;/h2&gt;
&lt;p&gt;
Für die &lt;strong&gt;Sage 100 Version 9.0&lt;/strong&gt; genügt ein Live-Update auf &lt;strong&gt;9.0.3.4&lt;/strong&gt;. Dabei wird der zentrale Mehrbenutzerdienst mit aktualisiert. Die Windows-Anpassungen sind trotzdem fällig, das Live-Update fasst die Registry nicht an.
&lt;/p&gt;
&lt;p&gt;
Für alle Stände vor 9.0.3.4 stellt Sage ein separates Setup bereit, das der Support auf Anfrage herausgibt. Es deckt auch die Versionen 7.1, 8.0 und 8.1 ab. Dafür gelten drei Regeln:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Das Setup wird ausschließlich auf dem Rechner des zentralen Mehrbenutzerdienstes installiert, nicht auf Clients und nicht auf weiteren Servern.&lt;/li&gt;
&lt;li&gt;Vor dem Start müssen sich alle Anwender der Sage 100 abmelden.&lt;/li&gt;
&lt;li&gt;Die Ausführung erfolgt mit Administrationsrechten.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Die TLS-1.2-Aktivierung in Windows gehört zusätzlich auf die Standort-Server und die Remote-Standortsysteme. Der Mehrbenutzerdienst ist der Auslöser, aber er ist nicht der einzige .NET-Prozess in der Landschaft, der nach außen spricht.
&lt;/p&gt;
&lt;h2&gt;Die Registry-Datei&lt;/h2&gt;
&lt;p&gt;
Wir haben die Werte in einer Registry-Datei zusammengefasst, die beide Framework-Versionen und beide Registry-Zweige abdeckt, dazu die WinHTTP-Einstellung. Der Kern sieht so aus:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\.NETFramework\v4.0.30319]
"SystemDefaultTlsVersions"=dword:00000001
"SchUseStrongCrypto"=dword:00000001
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\v4.0.30319]
"SystemDefaultTlsVersions"=dword:00000001
"SchUseStrongCrypto"=dword:00000001&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Die vollständige Datei setzt dieselben Werte zusätzlich für &lt;code&gt;v2.0.50727&lt;/code&gt; und trägt &lt;code&gt;DefaultSecureProtocols&lt;/code&gt; unter WinHttp ein. Sie fügt nur hinzu und entfernt nichts. Andere Werte, die in diesen Schlüsseln stehen, bleiben unangetastet, was auch ausdrücklich so sein soll.
&lt;/p&gt;
&lt;div style="text-align: center; margin: 2rem 0;"&gt;
&lt;a href="https://appontes.de/download/sage-100-tls12-fix" class="btn btn-primary"&gt;Registry-Fix herunterladen&lt;/a&gt;
&lt;p style="margin-top: .75rem; font-size: .9rem; color: #6b7785;"&gt;ZIP mit .reg-Datei und Kurzanleitung. Zusammenführen als Administrator, danach Server neu starten.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;
Eine Sicherung der betroffenen Schlüssel vorab ist trotzdem guter Stil. &lt;code&gt;reg export&lt;/code&gt; auf die vier Framework-Pfade dauert eine halbe Minute.
&lt;/p&gt;
&lt;h2&gt;Prüfen statt hoffen&lt;/h2&gt;
&lt;p&gt;
Nach dem Eingriff will man wissen, ob es gewirkt hat, und zwar bevor am Montagmorgen vierzig Anwender vor einer Meldung sitzen. Drei Tests, die unterschiedliche Fragen beantworten.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Erstens: Kommt der Server netzwerkseitig überhaupt raus und beherrscht die Gegenstelle TLS 1.2?&lt;/strong&gt; Der folgende Aufruf erzwingt TLS 1.2 unabhängig von den Prozess-Voreinstellungen.
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$h = 'licensing2.services.sage.com'
$c = New-Object Net.Sockets.TcpClient($h, 443)
$s = New-Object Net.Security.SslStream($c.GetStream())
$s.AuthenticateAsClient($h, $null, [Net.SecurityProtocolType]::Tls12, $false)
"Protokoll: $($s.SslProtocol)"
"Zertifikat: $($s.RemoteCertificate.Subject)"
$s.Dispose(); $c.Close()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Läuft das durch, sind Firewall und Namensauflösung in Ordnung. Schau Dir dabei den Zertifikatsnamen an. Steht dort nicht Sage, sondern der Name Deiner Firewall oder Deines Proxys, hast Du eine TLS-Inspection im Weg. Dazu gleich mehr.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Zweitens: Was bietet ein .NET-Prozess von sich aus an?&lt;/strong&gt; Derselbe Test mit &lt;code&gt;SystemDefault&lt;/code&gt; statt &lt;code&gt;Tls12&lt;/code&gt; lässt die Voreinstellungen entscheiden und zeigt in &lt;code&gt;$s.SslProtocol&lt;/code&gt;, was dabei herauskommt.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Drittens: Stehen die Werte in beiden Zweigen?&lt;/strong&gt;
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;'HKLM:\SOFTWARE\Microsoft\.NETFramework\v4.0.30319',
'HKLM:\SOFTWARE\WOW6432Node\Microsoft\.NETFramework\v4.0.30319' | ForEach-Object {
$p = Get-ItemProperty $_ -ErrorAction SilentlyContinue
[PSCustomObject]@{
Zweig = $_
SystemDefaultTlsVersions = $p.SystemDefaultTlsVersions
SchUseStrongCrypto = $p.SchUseStrongCrypto
}
} | Format-List&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Ein leeres Feld beim WOW6432Node-Eintrag ist der häufigste Befund bei einer Umstellung, die angeblich schon gemacht wurde.
&lt;/p&gt;
&lt;h2&gt;Stolperfallen&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PowerShell testet sich selbst.&lt;/strong&gt; Die Windows PowerShell 5.1 ist eine .NET-Framework-Anwendung und unterliegt denselben Voreinstellungen. Ein &lt;code&gt;Invoke-WebRequest&lt;/code&gt;, das ohne explizit gesetztes &lt;code&gt;SecurityProtocol&lt;/code&gt; scheitert, belegt das Problem sehr schön. Ein &lt;code&gt;Invoke-WebRequest&lt;/code&gt;, das mit explizit gesetztem &lt;code&gt;SecurityProtocol&lt;/code&gt; gelingt, belegt dagegen überhaupt nichts über den Sage-Dienst. Die beiden Varianten dürfen nicht durcheinandergeraten.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Neustart.&lt;/strong&gt; Die Werte werden beim Prozessstart gelesen. Ein Dienstneustart reicht in der Regel, ein Serverneustart ist die sicherere Variante, weil auch die WinHTTP-Änderung greifen soll.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TLS-Inspection.&lt;/strong&gt; Firewalls, die HTTPS aufbrechen, präsentieren dem Client ihr eigenes Zertifikat. Fehlt deren Aussteller im Zertifikatsspeicher des Computerkontos, scheitert die Validierung, obwohl TLS 1.2 einwandfrei ausgehandelt wurde. Das Fehlerbild ähnelt sich, die Ursache ist eine andere. Eine Ausnahme für den Lizenzhost im Proxy ist der ruhigere Weg.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Proxy mit Anmeldung.&lt;/strong&gt; Der Mehrbenutzerdienst läuft unter einem Dienstkonto. Was im Browser des angemeldeten Administrators funktioniert, funktioniert für dieses Konto noch lange nicht.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Härtungstools.&lt;/strong&gt; Werkzeuge wie IIS Crypto schalten Protokolle getrennt nach Server- und Client-Rolle. Es kommt vor, dass TLS 1.2 serverseitig aktiv ist und clientseitig unter &lt;code&gt;SCHANNEL\Protocols\TLS 1.2\Client&lt;/code&gt; auf &lt;code&gt;Enabled = 0&lt;/code&gt; beziehungsweise &lt;code&gt;DisabledByDefault = 1&lt;/code&gt; steht. Dann nützt die schönste .NET-Einstellung nichts, weil Schannel das Protokoll gar nicht erst anbietet. Welche Werte dort zulässig sind, steht in den &lt;a href="https://learn.microsoft.com/de-de/windows-server/security/tls/tls-registry-settings" target="_blank" rel="noopener"&gt;TLS-Registrierungseinstellungen für Schannel&lt;/a&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Der Workaround und seine Grenzen&lt;/h2&gt;
&lt;p&gt;
Wenn es brennt und der Betrieb gerade steht, verschafft das Einspielen einer neuen Lizenz Luft. Die Gültigkeit beginnt von vorn, die Anwender können arbeiten. Als Lösung taugt das nicht. Der nächste fällige Abgleich läuft in denselben Fehler, und dann steht die Umstellung wieder an, nur unter mehr Zeitdruck.
&lt;/p&gt;
&lt;h2&gt;Fazit&lt;/h2&gt;
&lt;p&gt;
Die Aktualisierung des Mehrbenutzerdienstes auf TLS 1.2 ist für den Betrieb von Subskriptions-Lizenzen nicht optional. Sie besteht aus zwei Teilen, die beide gemacht werden müssen: Der Dienst selbst über Live-Update 9.0.3.4 oder das Sage-Setup, und die Windows-Seite über die Registry. Der eine Punkt, an dem es in der Praxis hakt, ist der Zweig WOW6432Node.
&lt;/p&gt;
&lt;p&gt;
Weiterführend zum Thema TLS unter .NET gibt es eine ausführliche Seite bei Microsoft: &lt;a href="https://learn.microsoft.com/de-de/mem/configmgr/core/plan-design/security/enable-tls-1-2-server#bkmk_net" target="_blank" rel="noopener"&gt;TLS 1.2 auf Standortservern und Remotestandortsystemen aktivieren&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
Wenn Du nicht sicher bist, auf welchem Stand Dein Mehrbenutzerdienst ist oder ob die Umstellung vollständig gegriffen hat, schauen wir uns das gern gemeinsam an. Passend dazu auch unser Beitrag zum &lt;a href="https://appontes.de/blog/sage-100-applikationsserver-performance/"&gt;Applikationsserver der Sage 100&lt;/a&gt;.
&lt;/p&gt;
&lt;div style="text-align: center; margin: 3rem 0;"&gt;
&lt;a href="https://appontes.de/kontakt/?betreff=anfrage-sage" class="btn btn-primary"&gt;Unterstützung bei der TLS-Umstellung anfragen&lt;/a&gt;
&lt;/div&gt;</content:encoded></item><item><title>DBCC SHRINKFILE läuft, aber die Datei bleibt groß: Ursachen und Lösungen</title><link>https://appontes.de/blog/dbcc-shrinkfile-funktioniert-nicht/</link><guid isPermaLink="true">https://appontes.de/blog/dbcc-shrinkfile-funktioniert-nicht/</guid><pubDate>Fri, 11 Sep 2026 08:00:00 +0200</pubDate><dc:creator>Thomas Falkner</dc:creator><category>SQL Server</category><category>Sage 100</category><category>Wartung</category><category>Datenbank</category><description>Nach einer großen Löschaktion soll die MDF kleiner werden, doch der Shrink bringt nichts oder läuft stundenlang. Die häufigsten Gründe von Ghost Records über LOB-Daten und IAM-Sperren bis zum Transaktionsprotokoll, jeweils mit dem passenden Vorgehen und Belegen aus der Microsoft-Dokumentation.</description><content:encoded>&lt;p&gt;&lt;img src="https://appontes.de/img/blog/shrinkfile.svg" alt="DBCC SHRINKFILE läuft, aber die Datei bleibt groß: Ursachen und Lösungen"&gt;&lt;/p&gt;
&lt;p&gt;
Die Ausgangslage ist fast immer dieselbe: Es wurde einmalig richtig viel Platz frei. Ein Archivlauf, eine gelöschte Protokolltabelle oder wie in unserem &lt;a href="https://appontes.de/blog/xrm-dokumente-dateiablage-sage-100/"&gt;Beitrag zur xRM-Dateiablage&lt;/a&gt; ein Dokumentbestand, der aus der Datenbank in eine Dateiablage gewandert ist. Danach zeigt der SQL Server mehrere Gigabyte freien Platz in der Datei, aber die MDF auf der Platte ist unverändert groß. Also &lt;code&gt;DBCC SHRINKFILE&lt;/code&gt;, und dann passiert eines von drei Dingen: Es tut sich gar nichts, es wird nur ein Bruchteil frei, oder der Befehl läuft stundenlang und blockiert dabei die halbe Anwendung.
&lt;/p&gt;
&lt;p&gt;
Dieser Beitrag sammelt die Gründe dafür, jeweils mit dem, was Du dagegen tun kannst. Die Belege stammen aus der Dokumentation von Microsoft, nicht aus Forenwissen.
&lt;/p&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;
&lt;strong&gt;Vorweg, weil es die wichtigste Aussage ist:&lt;/strong&gt; Ein Shrink ist keine Wartungsaufgabe. Microsoft schreibt in der Doku zu &lt;a href="https://learn.microsoft.com/de-de/sql/t-sql/database-console-commands/dbcc-shrinkfile-transact-sql" target="_blank" rel="noopener"&gt;DBCC SHRINKFILE&lt;/a&gt; ausdrücklich, dass Dateien, die durch den normalen Geschäftsbetrieb wachsen, keinen Shrink brauchen. Wer regelmäßig schrumpft und dann zusieht, wie die Datei wieder wächst, verbrennt nur Rechenzeit und zerlegt sich die Indizes. Die Doku wird an dieser Stelle deutlich: Wächst die Datei nach dem Verkleinern wieder auf dieselbe Größe, war der Platz für den normalen Betrieb nötig, und jedes dieser Wachstumsereignisse kostet zusätzlich Zeit und E/A-Last. Ein Shrink, der sich alle paar Wochen wiederholt, macht die Datenbank also langsamer statt kleiner. &lt;code&gt;AUTO_SHRINK&lt;/code&gt; gehört aus demselben Grund auf &lt;code&gt;OFF&lt;/code&gt;. Sinnvoll ist ein Shrink nach einer einmaligen, großen Löschaktion, und danach nicht mehr.
&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;Schritt null: Nachsehen, wie viel überhaupt frei ist&lt;/h2&gt;
&lt;p&gt;
Bevor Du über Ursachen nachdenkst, klär die Zahlen. Die folgende Abfrage steht so in der Microsoft-Doku und zeigt Dir pro Datei den tatsächlich freien Platz:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT name,
size / 128.0 AS GroesseMB,
CAST(FILEPROPERTY(name, 'SpaceUsed') AS int) / 128.0 AS BelegtMB,
size / 128.0 - CAST(FILEPROPERTY(name, 'SpaceUsed') AS int) / 128.0 AS FreiMB
FROM sys.database_files;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Genauso aufschlussreich ist das Ergebnis, das &lt;code&gt;DBCC SHRINKFILE&lt;/code&gt; selbst ausgibt. Die Spalte &lt;code&gt;MinimumSize&lt;/code&gt; nennt die Untergrenze der Datei, &lt;code&gt;EstimatedPages&lt;/code&gt; die Größe, auf die der SQL Server die Datei realistisch schrumpfen zu können glaubt. Liegt &lt;code&gt;EstimatedPages&lt;/code&gt; nahe an &lt;code&gt;CurrentSize&lt;/code&gt;, brauchst Du über das Zielmaß nicht weiter zu diskutieren. Alle Werte sind 8-KB-Seiten, geteilt durch 128 ergibt Megabyte.
&lt;/p&gt;
&lt;h2&gt;Grund 1: Gelöscht heißt nicht freigegeben&lt;/h2&gt;
&lt;p&gt;
Wenn Du Zeilen löschst, verschwinden sie nicht sofort von der Seite. Der SQL Server markiert sie nur, das sind die sogenannten Ghost Records. Der &lt;a href="https://learn.microsoft.com/de-de/sql/relational-databases/ghost-row-cleanup-process-guide" target="_blank" rel="noopener"&gt;Ghost Cleanup&lt;/a&gt; räumt sie später im Hintergrund weg, und erst danach ist der Platz für den Shrink überhaupt verwertbar.
&lt;/p&gt;
&lt;p&gt;
Zwei Details aus der Doku erklären, warum das dauern kann. Erstens gibt es pro Instanz genau einen Ghost-Cleanup-Thread für alle Datenbanken. Zweitens überspringt der Prozess eine Datenbank, wenn er keine gemeinsame Sperre darauf bekommt, und versucht es erst im nächsten Durchlauf wieder. Nach dem Löschen von Millionen Zeilen ist die Aufräumarbeit also nichts, was in einer Minute erledigt ist.
&lt;/p&gt;
&lt;p&gt;Wie viel noch offen ist, zeigt Dir:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT DB_NAME(database_id) AS Datenbank,
SUM(ghost_record_count) AS Ghosts
FROM sys.dm_db_index_physical_stats(NULL, NULL, NULL, NULL, 'SAMPLED')
GROUP BY database_id
ORDER BY Ghosts DESC;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
&lt;strong&gt;Was hilft:&lt;/strong&gt; Abwarten und die Zahl beobachten. Wer nicht warten will, baut die Indizes der betroffenen Tabelle neu auf. Ein Rebuild erzeugt die Seiten neu und lässt die Ghosts dabei weg, das steht so in der Doku. Ein Rebuild braucht allerdings Platz in der Datei, insofern ist die Reihenfolge Rebuild zuerst und Shrink danach die richtige.
&lt;/p&gt;
&lt;h2&gt;Grund 2: Die Datei kann nicht unter ihre Mindestgröße&lt;/h2&gt;
&lt;p&gt;
Eine Datei lässt sich nicht kleiner machen als ihre Mindestgröße. Das ist entweder die Größe bei der Erstellung oder die letzte Größe, die per &lt;code&gt;ALTER DATABASE&lt;/code&gt; oder einem früheren Shrink ausdrücklich gesetzt wurde. Microsoft nennt das Beispiel einer Datenbank, die mit 10 MB angelegt wurde und auf 100 MB gewachsen ist: Kleiner als 10 MB wird sie nicht, auch wenn alle Daten gelöscht sind.
&lt;/p&gt;
&lt;p&gt;
Praktisch relevant wird das andersherum: Wurde die Datei irgendwann bewusst auf 80 GB gesetzt, ist das die Untergrenze, bis ein Shrink sie neu festlegt. Der Wert steht als &lt;code&gt;MinimumSize&lt;/code&gt; im Ergebnis des Shrink-Befehls.
&lt;/p&gt;
&lt;h2&gt;Grund 3: TRUNCATEONLY schneidet nur ab&lt;/h2&gt;
&lt;p&gt;
Hier liegt das häufigste Missverständnis. Die drei Varianten machen sehr unterschiedliche Dinge. Eines vorweg zur Schreibweise: Die Zielgröße wird in Megabyte angegeben und meint die Größe, die die Datei danach haben soll, nicht den Betrag, um den sie kleiner wird. &lt;code&gt;20000&lt;/code&gt; heißt also „verkleinere die Datei auf rund 20 GB". Lässt Du die Zahl weg oder setzt sie auf &lt;code&gt;0&lt;/code&gt;, geht der SQL Server auf die Erstellungsgröße der Datei zurück.
&lt;/p&gt;
&lt;table class="tech-table"&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aufruf&lt;/th&gt;
&lt;th&gt;Was passiert&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DBCC SHRINKFILE (datei, 20000)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Verschiebt belegte Seiten vom Ende der Datei in freie Bereiche am Anfang und gibt den Platz danach an das Betriebssystem zurück. Das ist der teure, aber wirksame Weg.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DBCC SHRINKFILE (datei, TRUNCATEONLY)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Gibt nur den freien Platz am Ende der Datei zurück und verschiebt nichts. Die Datei schrumpft exakt bis zum letzten belegten Block, also der Einheit aus acht zusammenhängenden Seiten. Liegt dort eine einzige belegte Seite, passiert praktisch nichts.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DBCC SHRINKFILE (datei, NOTRUNCATE)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Verschiebt die Seiten nach vorne, gibt den Platz aber nicht zurück. Die Datei sieht hinterher unverändert aus, laut Doku „scheint sie nicht zu schrumpfen". Sinnvoll nur als vorbereitender Schritt.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;
Wenn also &lt;code&gt;TRUNCATEONLY&lt;/code&gt; nichts bringt, ist das kein Fehler, sondern die dokumentierte Funktionsweise. Und noch ein Detail, das in der Doku ausdrücklich steht: Gibst Du zusätzlich eine Zielgröße zusammen mit &lt;code&gt;TRUNCATEONLY&lt;/code&gt; an, wird der freie Platz am Ende unter Umständen gar nicht freigegeben. Entweder Zielgröße oder &lt;code&gt;TRUNCATEONLY&lt;/code&gt;, nicht beides.
&lt;/p&gt;
&lt;h2&gt;Grund 4: LOB-Daten machen den Shrink zäh&lt;/h2&gt;
&lt;p&gt;
Genau der Fall, der nach einer Dokumentmigration auftritt. Inhalte aus &lt;code&gt;varbinary(max)&lt;/code&gt;, &lt;code&gt;nvarchar(max)&lt;/code&gt; oder &lt;code&gt;xml&lt;/code&gt; liegen nicht in der Datenzeile, sondern in eigenen LOB-Seiten, die über Verweisketten hängen. Ein Shrink muss diese Seiten einzeln verschieben, und das ist der langsamste Teil der Übung. Für komprimierte Columnstore-Segmente dokumentiert Microsoft sogar, dass LOB-Seiten vor SQL Server 2025 überhaupt nicht verschoben werden können.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Was hilft:&lt;/strong&gt; Die LOB-Daten vorher verdichten, statt sie vom Shrink einsammeln zu lassen. Dafür gibt es einen dokumentierten Weg, nämlich &lt;a href="https://learn.microsoft.com/de-de/sql/t-sql/statements/alter-index-transact-sql" target="_blank" rel="noopener"&gt;ALTER INDEX REORGANIZE&lt;/a&gt; mit &lt;code&gt;LOB_COMPACTION&lt;/code&gt;:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ALTER INDEX PK_BCSPjmDokumente ON dbo.BCSPjmDokumente
REORGANIZE WITH (LOB_COMPACTION = ON);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Laut Doku verdichtet die Option alle Seiten mit LOB-Daten und kann so die Datenmenge auf der Platte reduzieren. Bei einem gruppierten Index betrifft das alle LOB-Spalten der Tabelle. Der Standardwert ist ohnehin &lt;code&gt;ON&lt;/code&gt;, die ausdrückliche Angabe dient nur der Klarheit. Wichtig ist die Einschränkung am anderen Ende: Bei einem Heap, also einer Tabelle ohne gruppierten Index, läuft die LOB-Kompaktierung ins Leere. Tabellen, aus denen Du große Mengen LOB-Daten gelöscht hast, sollten deshalb einen gruppierten Index haben.
&lt;/p&gt;
&lt;h2&gt;Grund 5: Der Shrink wird blockiert&lt;/h2&gt;
&lt;p&gt;Drei Blockaden sind dokumentiert und begegnen einem regelmäßig.&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Snapshot-Transaktionen.&lt;/strong&gt; Läuft parallel eine Transaktion unter einer zeilenversionsbasierten Isolationsstufe, wartet der Shrink auf deren Ende. Der SQL Server schreibt dazu die Meldung 5203 ins Fehlerprotokoll, in der ersten Stunde alle fünf Minuten, danach stündlich. Welche Transaktion es ist, zeigt &lt;code&gt;sys.dm_tran_active_snapshot_database_transactions&lt;/code&gt;. Du hast dann drei Möglichkeiten: Die blockierende Transaktion beenden, den Shrink beenden oder warten.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Sperren auf IAM-Seiten.&lt;/strong&gt; Der Shrink braucht beim Verschieben oder Löschen von Index Allocation Maps eine Schemaänderungssperre, während normale Abfragen darauf eine Schemastabilitätssperre halten. Das Ergebnis beschreibt Microsoft deutlich: Lang laufende Abfragen blockieren den Shrink, und neue Abfragen stellen sich hinter dem Shrink an. In einer aktiven Sage-Umgebung reicht dafür eine einzige große Auswertung.
&lt;/p&gt;
&lt;p&gt;
Seit SQL Server 2022 gibt es dafür einen Schalter. Er lässt den Shrink im Zweifel abbrechen, statt die Anwender warten zu lassen:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DBCC SHRINKFILE (datei, 20000) WITH WAIT_AT_LOW_PRIORITY (ABORT_AFTER_WAIT = SELF);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Bekommt der Shrink die Sperre binnen einer Minute nicht, bricht er mit Fehler 49516 ab. Die Alternative &lt;code&gt;ABORT_AFTER_WAIT = BLOCKERS&lt;/code&gt; beendet stattdessen die blockierenden Transaktionen der Anwender. Das willst Du in einer produktiven Warenwirtschaft eher nicht.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Eine laufende Sicherung.&lt;/strong&gt; Kurz und bündig aus der Doku: Du kannst eine Datenbank nicht schrumpfen, während sie gesichert wird, und umgekehrt nicht sichern, während ein Shrink läuft. Wer den Shrink abends startet und um 22 Uhr die Vollsicherung anspringen lässt, hat die Ursache damit schon gefunden. Auch Dateien hinzufügen oder entfernen geht während einer Sicherung nicht.
&lt;/p&gt;
&lt;p&gt;
Ein Sonderfall noch: Eine schreibgeschützte Datenbank lässt sich nicht schrumpfen. Das steht bei den Dateigruppenoptionen von &lt;code&gt;ALTER DATABASE&lt;/code&gt;.
&lt;/p&gt;
&lt;h2&gt;Grund 6: Beim Protokoll gelten eigene Regeln&lt;/h2&gt;
&lt;p&gt;
Wenn die LDF nicht kleiner wird, ist die Ursache fast nie der Shrink selbst. Verkürzen und Schrumpfen sind zwei verschiedene Dinge. Das Abschneiden gibt Platz innerhalb der Datei frei, die physische Datei wird dadurch nicht kleiner. Schrumpfen kann nur, was vorher abgeschnitten wurde, und laut Doku nur, solange mindestens eine virtuelle Protokolldatei frei ist.
&lt;/p&gt;
&lt;p&gt;Warum das Abschneiden ausbleibt, verrät eine einzige Abfrage. Microsoft führt die möglichen Werte unter &lt;a href="https://learn.microsoft.com/de-de/sql/relational-databases/logs/the-transaction-log-sql-server" target="_blank" rel="noopener"&gt;Faktoren, die das Abschneiden des Protokolls verzögern können&lt;/a&gt; auf:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT name, recovery_model_desc, log_reuse_wait_desc
FROM sys.databases
WHERE name = 'MeineDatenbank';&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Die häufigsten Werte und was sie bedeuten:&lt;/p&gt;
&lt;table class="tech-table"&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;log_reuse_wait_desc&lt;/th&gt;
&lt;th&gt;Bedeutung&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;LOG_BACKUP&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Es fehlt eine Protokollsicherung. Der Dauerbrenner bei Datenbanken im vollständigen Wiederherstellungsmodell, bei denen nur die Vollsicherung eingerichtet wurde. Entweder Du sicherst das Protokoll regelmäßig, oder das Wiederherstellungsmodell passt nicht zu dem, was Du tatsächlich brauchst.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ACTIVE_TRANSACTION&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Eine Transaktion ist offen. Das verhindert das Abschneiden in jedem Wiederherstellungsmodell, auch im einfachen. Dazu zählen auch zurückgestellte Transaktionen, deren Rollback an einer fehlenden Ressource hängt.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ACTIVE_BACKUP_OR_RESTORE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Eine Sicherung oder Wiederherstellung läuft gerade.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;REPLICATION&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Transaktionen sind noch nicht an die Verteilungsdatenbank übergeben. Relevant überall dort, wo Replikation im Spiel ist.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;AVAILABILITY_REPLICA&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Ein sekundäres Replikat einer Verfügbarkeitsgruppe hängt hinterher.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CHECKPOINT&lt;/code&gt; und &lt;code&gt;OLDEST_PAGE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Routinefälle rund um Prüfpunkte. Meist kurzlebig, bei indirekten Prüfpunkten kann die älteste Seite das Abschneiden verzögern.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;
Und selbst wenn alles stimmt, schrumpft das Protokoll nur bis zur Grenze einer virtuellen Protokolldatei. Kleiner als eine solche Einheit geht nicht, und liegt der aktive Teil des Protokolls hinten in der Datei, gibt der SQL Server frei, was geht, und sagt Dir in einer Meldung, was zu tun ist. Nach der nächsten Sicherung klappt es dann. Zwei Läufe sind hier normal, kein Fehler.
&lt;/p&gt;
&lt;h2&gt;Grund 7: EMPTYFILE auf der falschen Datei&lt;/h2&gt;
&lt;p&gt;
Wer eine Datei ganz loswerden will, nutzt &lt;code&gt;DBCC SHRINKFILE (datei, EMPTYFILE)&lt;/code&gt;. Die Option verschiebt die Daten in die anderen Dateien &lt;strong&gt;derselben Dateigruppe&lt;/strong&gt; und markiert die Datei so, dass nichts Neues mehr hineingeschrieben wird. Anschließend lässt sie sich per &lt;code&gt;ALTER DATABASE ... REMOVE FILE&lt;/code&gt; entfernen, und zwar laut Doku nur dann, wenn sie leer ist.
&lt;/p&gt;
&lt;p&gt;Zwei Stolperfallen dabei:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Gibt es in der Dateigruppe keine zweite Datei mit genug Platz, hat der Inhalt kein Ziel und der Lauf scheitert. In der Praxis quittiert der SQL Server das mit der Meldung 2555, dass sich der Inhalt der Datei nicht an einen anderen Ort verschieben lässt. Auf der primären Datendatei scheitert es ohnehin, dort liegen Systeminformationen der Datenbank.&lt;/li&gt;
&lt;li&gt;Brichst Du einen &lt;code&gt;EMPTYFILE&lt;/code&gt;-Lauf ab, bleibt die Datei nicht gesperrt. Die Doku weist ausdrücklich darauf hin, dass sie in dem Fall nicht markiert bleibt und wieder Daten aufnehmen kann. Ein abgebrochener Lauf ist also kein Halbzustand, auf den Du Dich verlassen kannst.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Der Shrink läuft ewig: Fortschritt sichtbar machen&lt;/h2&gt;
&lt;p&gt;
Ein Shrink über eine große Datei dauert Stunden, und das ist normal. Blind warten musst Du trotzdem nicht, denn der Fortschritt wird in &lt;code&gt;sys.dm_exec_requests&lt;/code&gt; gemeldet. Die Spalte &lt;code&gt;percent_complete&lt;/code&gt; ist laut Doku unter anderem für &lt;code&gt;DBCC SHRINKFILE&lt;/code&gt; und &lt;code&gt;DBCC SHRINKDATABASE&lt;/code&gt; gefüllt:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT session_id, command, percent_complete,
total_elapsed_time / 1000 AS SekundenGesamt,
wait_type, blocking_session_id
FROM sys.dm_exec_requests
WHERE command LIKE 'DBCC%';&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Gut zu wissen: Du darfst jederzeit abbrechen. Die bereits geleistete Arbeit bleibt erhalten, das garantiert die Doku für Shrink-Operationen ausdrücklich. Ein Shrink in mehreren Etappen über mehrere Wartungsfenster ist deshalb ein völlig legitimes Vorgehen. In kleinen Schritten vorzugehen, also von 100 GB auf 90, dann auf 80, ist bei großen Dateien ohnehin angenehmer als ein einziger großer Sprung, weil Du nach jeder Etappe entscheiden kannst.
&lt;/p&gt;
&lt;p&gt;
Für wirklich große Datenbanken empfiehlt Microsoft in den Best Practices inzwischen das &lt;a href="https://github.com/microsoft/sql-server-samples/tree/master/samples/features/shrink/shrink-driver" target="_blank" rel="noopener"&gt;ShrinkDriver-Skript&lt;/a&gt; aus den offiziellen Beispielen. Es macht aus dem Shrink einen einzigen beobachtbaren Vorgang, der mehrere Dateien parallel bearbeitet und nach einer Unterbrechung wieder aufsetzt.
&lt;/p&gt;
&lt;h2&gt;Die Alternative, wenn gar nichts geht&lt;/h2&gt;
&lt;p&gt;
Manchmal ist der sauberere Weg, gar nicht erst zu schrumpfen, sondern umzuziehen. Du legst eine neue Dateigruppe mit einer neuen Datei an, verschiebst die großen Tabellen dorthin, indem Du deren gruppierten Index mit &lt;code&gt;CREATE INDEX ... WITH (DROP_EXISTING = ON) ON [NeueDateigruppe]&lt;/code&gt; neu erstellst, und leerst die alte Datei anschließend mit &lt;code&gt;EMPTYFILE&lt;/code&gt;. Das Ergebnis ist eine kompakte, frisch aufgebaute Struktur statt eines fragmentierten Rests.
&lt;/p&gt;
&lt;p&gt;
Der Preis ist hoch: Du brauchst zwischenzeitlich Platz für beide Stände, die Aktion gehört in ein Wartungsfenster, und bei einer Herstellerdatenbank wie der Sage 100 solltest Du vorher klären, ob eine eigene Dateigruppe unterstützt wird. Für Datenbanken jenseits weniger hundert Gigabyte ist es trotzdem oft der planbarere Weg.
&lt;/p&gt;
&lt;h2&gt;Nach dem Shrink: Die Indizes sind hinüber&lt;/h2&gt;
&lt;p&gt;
Das ist keine Nebenwirkung, sondern eine Garantie. Microsoft formuliert es in der &lt;a href="https://learn.microsoft.com/de-de/sql/relational-databases/databases/shrink-a-database" target="_blank" rel="noopener"&gt;Anleitung zum Verkleinern einer Datenbank&lt;/a&gt; so: Die verschobenen Daten können an jeder beliebigen freien Stelle in der Datei landen, das erzeugt Indexfragmentierung und bremst Abfragen, die größere Bereiche lesen. Ein Shrink erhält den Fragmentierungsgrad nicht, er verschlechtert ihn.
&lt;/p&gt;
&lt;p&gt;
Nach dem Shrink gehört deshalb eine Indexpflege dazu. Und weil ein Rebuild Platz in der Datei braucht, wächst die Datei dabei womöglich wieder ein Stück. Genau davor warnt die Doku auch. Rechne also nicht mit dem letzten Gigabyte, sondern lass bewusst Luft. Wer nach dem Shrink sofort wieder schrumpft, weil der Rebuild die Datei vergrößert hat, dreht sich im Kreis.
&lt;/p&gt;
&lt;h2&gt;Das Vorgehen in der richtigen Reihenfolge&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Freien Platz messen und ein realistisches Ziel festlegen, mit bewusster Reserve statt auf Kante.&lt;/li&gt;
&lt;li&gt;Ghost Records prüfen und der Aufräumarbeit Zeit geben.&lt;/li&gt;
&lt;li&gt;Bei großen Mengen LOB-Daten die betroffenen Indizes mit &lt;code&gt;LOB_COMPACTION&lt;/code&gt; reorganisieren.&lt;/li&gt;
&lt;li&gt;Beim Protokoll zuerst &lt;code&gt;log_reuse_wait_desc&lt;/code&gt; klären, nicht schrumpfen.&lt;/li&gt;
&lt;li&gt;Den Shrink in ein Fenster legen, in dem keine Sicherung und keine Indexpflege läuft, und in Etappen arbeiten.&lt;/li&gt;
&lt;li&gt;Ab SQL Server 2022 mit &lt;code&gt;WAIT_AT_LOW_PRIORITY&lt;/code&gt; arbeiten, damit der Shrink nachgibt und nicht die Anwender.&lt;/li&gt;
&lt;li&gt;Danach die Indizes neu aufbauen und die Dateigröße einmal bewusst setzen, statt sie wieder wachsen zu lassen.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Fazit&lt;/h2&gt;
&lt;p&gt;
Ein Shrink, der nichts bringt, ist selten ein Defekt. In den meisten Fällen ist der Platz noch nicht wirklich frei, liegt hinten in der Datei fest, hängt in LOB-Ketten oder wird von einer Sperre blockiert. Die Diagnose besteht aus drei Abfragen: freier Platz je Datei, &lt;code&gt;ghost_record_count&lt;/code&gt; und &lt;code&gt;log_reuse_wait_desc&lt;/code&gt;. Zusammen mit dem Ergebnis des Shrink-Befehls selbst erklären sie fast jeden Fall.
&lt;/p&gt;
&lt;p&gt;
Genauso wichtig ist die Erwartungshaltung. Ein Shrink ist eine einmalige Aufräumaktion nach einer einmaligen Löschaktion, er kostet Laufzeit, erzeugt Fragmentierung und braucht danach eine Indexpflege. Wenn Du das einplanst, ist es eine saubere Sache. Wenn Du es nebenbei im laufenden Betrieb versuchst, wird es eine lange Nacht.
&lt;/p&gt;
&lt;p&gt;
Wie es überhaupt so weit kommt, dass mehrere Gigabyte Dokumente in einer Sage-Datenbank liegen, steht in unserem Beitrag zur &lt;a href="https://appontes.de/blog/xrm-dokumente-dateiablage-sage-100/"&gt;xRM-Dateiablage&lt;/a&gt;. Wenn Du bei einer konkreten Datenbank nicht weiterkommst, schau Dir auch unseren &lt;a href="https://appontes.de/sage-100/health-check/"&gt;Sage 100 Health-Check&lt;/a&gt; an oder melde Dich direkt bei uns.
&lt;/p&gt;
&lt;div style="text-align: center; margin: 3rem 0;"&gt;
&lt;a href="https://appontes.de/kontakt/?betreff=anfrage-sage" class="btn btn-primary"&gt;Unterstützung bei SQL-Server-Wartung anfragen&lt;/a&gt;
&lt;/div&gt;</content:encoded></item><item><title>xRM-Dokumente in Sage 100: Warum eingebettete Dateien Deine Datenbank ausbremsen</title><link>https://appontes.de/blog/xrm-dokumente-dateiablage-sage-100/</link><guid isPermaLink="true">https://appontes.de/blog/xrm-dokumente-dateiablage-sage-100/</guid><pubDate>Fri, 11 Sep 2026 00:00:00 +0000</pubDate><dc:creator>Thomas Falkner</dc:creator><category>Sage 100</category><category>xRM</category><category>Dokumente</category><category>SQL Server</category><description>Eingebettete Dokumente landen in der Tabelle BCSPjmDokumente und blähen die Sage-100-Datenbank auf. Was das für Backup, Wartung und Kopien bedeutet, welche Speichermodelle das xRM kennt, wie Du die Dateiablage umstellst und wie Du bestehende Dokumente in ein Verzeichnis auslagerst.</description><content:encoded>&lt;p&gt;&lt;img src="https://appontes.de/img/blog/xrm-dateiablage.svg" alt="xRM-Dokumente in Sage 100: Warum eingebettete Dateien Deine Datenbank ausbremsen"&gt;&lt;/p&gt;
&lt;p&gt;
Im &lt;a class="glossar-term" href="https://appontes.de/glossar/xrm/"&gt;xRM&lt;span class="glossar-tip" aria-hidden="true"&gt;&lt;strong&gt;xRM&lt;/strong&gt;Das in die Sage 100 integrierte Beziehungsmanagement (Extended Relationship Management). Es verbindet Kunden, Verkaufschancen, Projekte, Service und Support direkt mit den ERP-Daten.&lt;em&gt;Mehr im Glossar &amp;#8594;&lt;/em&gt;&lt;/span&gt;&lt;/a&gt; der Sage 100 hängen an Kontakten, Vorgängen und Projekten Dokumente: Angebote, Serviceberichte, Fotos, vor allem aber E-Mails aus dem Outlook-Mailtracking. In den meisten Installationen landen die alle am selben Ort, nämlich direkt in der Datenbank. Das funktioniert jahrelang unauffällig, und irgendwann fällt jemandem auf, dass die Sage-Datenbank 40 GB groß ist und das Backup-Fenster nicht mehr reicht.
&lt;/p&gt;
&lt;p&gt;
Dieser Beitrag zeigt Dir, wo die Dokumente technisch liegen, welche Probleme das Einbetten mit sich bringt, welche Speichermodelle das xRM kennt und wie Du sowohl die Grundlagen als auch den vorhandenen Bestand umstellst.
&lt;/p&gt;
&lt;h2&gt;Wo die Dokumente wirklich liegen&lt;/h2&gt;
&lt;p&gt;
Alle xRM-Dokumente stehen in einer einzigen Tabelle, und die heißt &lt;code&gt;BCSPjmDokumente&lt;/code&gt;. Der Aufbau ist schnell erzählt:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CREATE TABLE [dbo].[BCSPjmDokumente](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Mandant] [smallint] NOT NULL,
[PosID] [int] NOT NULL,
[Typ] [smallint] NOT NULL,
[Dokument] [varbinary](max) NULL,
[SourceRoot] [varchar](512) NULL,
[SourceFile] [varchar](512) NULL,
[SourceExtension] [varchar](10) NULL,
[Beschreibung] [varchar](max) NULL,
[Erstellt] [datetime] NULL,
[Kategorie] [varchar](20) NULL,
[DocIDSageDMS] [varchar](60) NULL,
[Timestamp] [timestamp] NOT NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Interessant sind zwei Stellen. Die Spalte &lt;code&gt;Dokument&lt;/code&gt; ist ein &lt;code&gt;varbinary(max)&lt;/code&gt; und nimmt bei eingebetteten Dokumenten den kompletten Dateiinhalt auf. Bei verknüpften Dokumenten bleibt sie leer, stattdessen sind &lt;code&gt;SourceRoot&lt;/code&gt;, &lt;code&gt;SourceFile&lt;/code&gt; und &lt;code&gt;SourceExtension&lt;/code&gt; gefüllt. Dass der Wurzelpfad getrennt vom Dateinamen gespeichert wird, ist kein Zufall. Genau darauf setzt die Grundlageneinstellung für die Dateiablage auf, dazu gleich mehr.
&lt;/p&gt;
&lt;p&gt;
Die zweite Stelle ist das &lt;code&gt;TEXTIMAGE_ON [PRIMARY]&lt;/code&gt; am Ende. Die Dokumentinhalte liegen also in derselben Dateigruppe wie alle übrigen Sage-Daten. Es gibt keine getrennte Dateigruppe für Dokumente, die Du separat auf günstigen Speicher legen oder read-only schalten könntest, und auch kein FILESTREAM. Was eingebettet wird, ist damit Teil der operativen Datenbank und wird mit ihr zusammen gesichert, wiederhergestellt, kopiert und geprüft.
&lt;/p&gt;
&lt;p&gt;Wie viel das bei Dir ist, verrät eine kurze Abfrage auf dem Mandanten:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT COUNT(*) AS Dokumente,
SUM(CASE WHEN Dokument IS NOT NULL THEN 1 ELSE 0 END) AS Eingebettet,
SUM(CASE WHEN Dokument IS NULL THEN 1 ELSE 0 END) AS Verknuepft,
CAST(SUM(DATALENGTH(Dokument)) / 1048576.0 AS decimal(18,1)) AS MB
FROM dbo.BCSPjmDokumente;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
In der Praxis kommen dabei schnell einige Gigabyte zusammen. In dem Demobestand, an dem wir unser Tool getestet haben, waren es 8.729 Dokumente mit 2,3 GB. Bei Kunden mit aktivem Mailtracking über mehrere Jahre sehen wir deutlich größere Bestände, weil dort jede archivierte Mail samt Anhang in der Tabelle landet.
&lt;/p&gt;
&lt;h2&gt;Was eingebettete Dokumente im Betrieb kosten&lt;/h2&gt;
&lt;p&gt;
Das Problem ist nicht der Speicherplatz an sich. Plattenplatz ist billig geworden. Das Problem ist, dass diese Datenmenge in jedem einzelnen Vorgang mitläuft, der die Datenbank anfasst.
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Sicherung und Wiederherstellung.&lt;/strong&gt; Ein Vollbackup zieht die Dokumente jedes Mal komplett mit, obwohl sich an einem Angebot von 2019 nichts mehr ändert. Aus einem 20-Minuten-Backup wird eine Stunde, und im Ernstfall dauert die Wiederherstellung genauso lange. Die Zeit bis zur Wiederverfügbarkeit Deiner Warenwirtschaft hängt dann zu großen Teilen an Dateien, die im Tagesgeschäft niemand braucht.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mandanten- und Testkopien.&lt;/strong&gt; Jede Kopie für Schulung, Test oder eine Updateprobe vervielfacht die Dokumentmenge. Wer drei Testumgebungen betreibt, sichert und lagert seine Dokumente viermal.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Wartungsfenster.&lt;/strong&gt; Ein &lt;code&gt;DBCC CHECKDB&lt;/code&gt; und die Indexpflege laufen über eine größere Datenbank länger. Das ist keine Katastrophe, verschiebt aber jedes Wartungsfenster nach hinten.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Transaktionsprotokoll.&lt;/strong&gt; Wird ein 30-MB-Anhang eingebettet, geht er durch das Log. Bei vielen und großen Dokumenten wächst das Protokoll, und die Protokollsicherungen wachsen mit.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Zugriff nur über Sage.&lt;/strong&gt; Was in der Tabelle steckt, kann kein Explorer öffnen, kein Dokumentenmanagementsystem indizieren, keine Windows-Suche finden und kein Virenscanner prüfen. Ein Dokument aus dem xRM zu bekommen, heißt immer: Sage 100 starten, Eintrag suchen, Dokument extrahieren.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bearbeiten ist umständlich.&lt;/strong&gt; Ein eingebettetes Dokument wird beim Öffnen aus der Datenbank in eine temporäre Datei geschrieben und muss nach der Bearbeitung wieder zurück. Das ist der von Sage selbst genannte Nachteil des Modells und macht sich vor allem bei großen Dateien bemerkbar.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Doppelte Stände.&lt;/strong&gt; Bettest Du eine bestehende Datei ein, existiert sie danach zweimal, einmal im Dateisystem und einmal in der Datenbank. Änderungen musst Du in beiden nachziehen, und bei der nächsten Rückfrage weiß niemand mehr, welcher Stand der richtige war.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;
&lt;strong&gt;Fairerweise:&lt;/strong&gt; Eingebettete Dokumente haben gute Gründe. Sie können nicht verwaisen, weil niemand eine Datei verschiebt oder umbenennt. Sie brauchen keine Freigabe und keine Berechtigungspflege im Dateisystem. Und sie sind mit einem einzigen Datenbank-Backup vollständig gesichert, inklusive der Zuordnung zum Kontakt. Wer das Einbetten abschafft, übernimmt diese Aufgaben selbst. Genau darum geht es bei der Entscheidung, nicht um richtig oder falsch.
&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;Die Speichermodelle des xRM&lt;/h2&gt;
&lt;p&gt;
Das xRM kennt beim Anlegen eines Dokuments mehrere Speichermodelle. Praktisch relevant sind heute drei davon. Die früher ebenfalls angebotenen OLE-Dokumente spielen in aktuellen Installationen keine Rolle mehr.
&lt;/p&gt;
&lt;table class="tech-table"&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Modell&lt;/th&gt;
&lt;th&gt;Was passiert&lt;/th&gt;
&lt;th&gt;Wofür geeignet&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Datei-Dokument eingebettet&lt;/td&gt;
&lt;td&gt;Der binäre Dateiinhalt wandert in die Spalte &lt;code&gt;Dokument&lt;/code&gt;. Kein Platzbedarf im Dateisystem, kein Bedarf an Freigaben, dafür wächst die Datenbank um die volle Dateigröße.&lt;/td&gt;
&lt;td&gt;Kleine Dokumente, verteilte Standorte ohne gemeinsame Dateifreigabe, Umgebungen ohne gepflegte Berechtigungsstruktur.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Datei-Dokument verknüpft&lt;/td&gt;
&lt;td&gt;In der Datenbank stehen nur Pfad und Dateiname. Der Platzbedarf in der Datenbank ist minimal, dafür müssen Freigabe und Berechtigungen stimmen.&lt;/td&gt;
&lt;td&gt;Große Dokumente, große Bestände, Umgebungen mit sauberem Dateiserver und funktionierender Dateisicherung.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Strukturierte Dateiablage&lt;/td&gt;
&lt;td&gt;Wie verknüpft, aber das xRM legt die Dateien ausgehend vom Wurzelpfad automatisch in Unterordner nach Jahr und Monat ab. Gibt es am Kontakt oder Vorgang einen Projektverweis, kommt ein Ordner mit der Projektnummer dazu.&lt;/td&gt;
&lt;td&gt;Große Bestände, bei denen Du auch außerhalb von Sage eine nachvollziehbare Ordnerstruktur brauchst.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;
Als Faustregel gilt: Je größer ein Dokument, desto mehr überwiegen die Vorteile der Verknüpfung. Bei einer 40 KB großen Notiz ist die Diskussion müßig, bei einem 200-MB-Video nicht.
&lt;/p&gt;
&lt;h2&gt;Die Grundlagen umstellen&lt;/h2&gt;
&lt;p&gt;
Alles Weitere steuerst Du in den Grundlageneinstellungen. Zwei Einträge sind dafür wichtig.
&lt;/p&gt;
&lt;h3&gt;Speichermodell für neue Dokumente&lt;/h3&gt;
&lt;p&gt;
Unter &lt;em&gt;Kontakt- und Vertriebsmanagement&lt;/em&gt; findest Du im unteren Drittel vier Eigenschaften, die das Verhalten beim Anlegen festlegen.
&lt;/p&gt;
&lt;figure class="blog-figure"&gt;
&lt;img src="https://appontes.de/img/blog/xrm-dateiablage/speichermodelle-grundlagen.png" alt="Grundlageneinstellung Kontakt- und Vertriebsmanagement mit den hervorgehobenen Eigenschaften Bevorzugtes Speichermodell Dokumente, Großes Speichermodell Dokumente, Großes Speichermodell verwenden ab MB und Anwender kann Speichermodell auswählen" width="1350" height="1018" loading="lazy"&gt;
&lt;figcaption&gt;Die vier Schalter für das Speichermodell in der Grundlageneinstellung Kontakt- und Vertriebsmanagement&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Bevorzugtes Speichermodell Dokumente&lt;/strong&gt; ist die Voreinstellung, wenn ein Anwender ein Dokument zu einem Eintrag hinzufügt oder erstellt.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Großes Speichermodell Dokumente&lt;/strong&gt; greift ab einer bestimmten Dateigröße. Es gilt unter anderem dann, wenn eine bestehende Datei manuell angehängt wird und das Modell nicht geändert werden darf, wenn ein Dokument über &lt;em&gt;Dokument erstellen&lt;/em&gt; entsteht und wenn E-Mails über das Senden und Erstellen von Mails oder über das Outlook-Mailtracking an einem Eintrag landen.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Großes Speichermodell verwenden ab [MB]&lt;/strong&gt; legt die Schwelle fest, im Screenshot 10 MB.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Anwender kann Speichermodell auswählen&lt;/strong&gt; entscheidet, ob der Anwender im Dokumentdialog davon abweichen darf.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Die im Screenshot gezeigte Kombination ist ein brauchbarer Kompromiss für den Einstieg: Kleines wird eingebettet, alles ab 10 MB wird verknüpft. Wer die Datenbank konsequent schlank halten will, stellt beide Modelle auf verknüpft und setzt &lt;em&gt;Anwender kann Speichermodell auswählen&lt;/em&gt; auf Nein, damit niemand aus Gewohnheit wieder einbettet.
&lt;/p&gt;
&lt;h3&gt;Wurzelpfad für verknüpfte Dokumente&lt;/h3&gt;
&lt;p&gt;
Damit die Verknüpfung funktioniert, braucht das xRM ein Zielverzeichnis. Das steht in der Grundlageneinstellung &lt;em&gt;Dateiablage verknüpfte Dokumente&lt;/em&gt;.
&lt;/p&gt;
&lt;figure class="blog-figure"&gt;
&lt;img src="https://appontes.de/img/blog/xrm-dateiablage/dateiablage-verknuepfte-dokumente.png" alt="Grundlageneinstellung Dateiablage verknüpfte Dokumente mit einer Zeile, in der beim Anwender ein Stern steht und als Pfad eine UNC-Freigabe eingetragen ist" width="1352" height="1016" loading="lazy"&gt;
&lt;figcaption&gt;Der Wurzelpfad der Dateiablage, hier für alle Anwender über den Platzhalter Stern&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;
Der Stern in der Spalte &lt;em&gt;Anwender&lt;/em&gt; bedeutet, dass der Pfad für alle gilt. Du kannst darunter aber auch einzelne Anwender mit einem abweichenden Pfad eintragen, etwa wenn ein Standort dieselbe Ablage über einen anderen Servernamen erreicht.
&lt;/p&gt;
&lt;p&gt;
Das ist mehr als eine Bequemlichkeit. Weil in der Tabelle &lt;code&gt;SourceRoot&lt;/code&gt; und &lt;code&gt;SourceFile&lt;/code&gt; getrennt stehen, kann das xRM den Wurzelpfad zur Laufzeit ersetzen. Zieht die Ablage später auf einen anderen Server um, änderst Du hier eine Zeile statt zehntausende Verknüpfungen in der Datenbank. Genau das entschärft den klassischen Nachteil verknüpfter Dokumente, nämlich tote Pfade nach einem Serverumzug. Nutze deshalb immer einen UNC-Pfad auf eine Freigabe und keinen lokalen Laufwerksbuchstaben, den nur ein Rechner kennt.
&lt;/p&gt;
&lt;p&gt;
Wenn Du die strukturierte Dateiablage einsetzen willst, konfigurierst Du sie direkt darunter unter &lt;em&gt;Konfiguration der strukturierten Dateiablage&lt;/em&gt;. Der hinterlegte Pfad dient dann als Wurzelverzeichnis, unter dem die Ordner für Jahr, Monat und gegebenenfalls Projektnummer automatisch entstehen.
&lt;/p&gt;
&lt;h2&gt;Der Haken: Bestehende Dokumente ändern das Modell nicht&lt;/h2&gt;
&lt;p&gt;
Mit den Grundlagen hast Du geregelt, was künftig passiert. Für die Dokumente, die längst in der Datenbank stehen, ändert sich dadurch nichts. Das Speichermodell eines bestehenden Dokuments lässt sich im Dokumentdialog nicht umstellen, das Feld ist dort gesperrt.
&lt;/p&gt;
&lt;p&gt;
Der manuelle Weg wäre, jedes Dokument einzeln über das Optionsmenü als Datei zu speichern, das alte zu löschen und die Datei neu als Verknüpfung anzuhängen. Bei fünfzig Dokumenten ist das ein Nachmittag, bei achttausend ist es keine Option. Zumal dabei jedes Mal Erstellungsdatum, Beschreibung und Kategorie von Hand wieder gesetzt werden müssten.
&lt;/p&gt;
&lt;h2&gt;Bestand umstellen mit der xRM Dateiablage&lt;/h2&gt;
&lt;p&gt;
Für genau diesen Schritt haben wir ein kleines Tool gebaut. Die &lt;strong&gt;xRM Dateiablage&lt;/strong&gt; liest die eingebetteten Dokumente aus &lt;code&gt;BCSPjmDokumente&lt;/code&gt;, schreibt sie in ein Verzeichnis Deiner Wahl und stellt die zugehörigen Einträge in Sage anschließend auf die verknüpfte Ablage um. Die Zuordnung zum Kontakt oder Vorgang bleibt dabei erhalten, für die Anwender ändert sich an der Bedienung nichts.
&lt;/p&gt;
&lt;figure class="blog-figure"&gt;
&lt;img src="https://appontes.de/img/blog/xrm-dateiablage/xrm-dateiablage-tool.png" alt="Oberfläche des Tools xRM Dateiablage mit Feldern für SQL-Anmeldung, Server, Datenbank, Mandant und Ablagepfad sowie einem Protokoll der migrierten Dokumente" width="1413" height="1429" loading="lazy"&gt;
&lt;figcaption&gt;Nach dem Lauf: 8.729 Dokumente umgestellt, 2,3 GB aus der Datenbank in die Dateiablage verschoben&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Der Ablauf ist bewusst schlicht gehalten:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Anmeldung per Windows-Authentifizierung oder SQL-Anmeldung, dazu Server, Datenbank und Mandantennummer.&lt;/li&gt;
&lt;li&gt;Beim Feld &lt;em&gt;Ablagepfad&lt;/em&gt; hast Du die Wahl. Lässt Du es leer, übernimmt das Programm beim Prüfen den in Sage hinterlegten Standardpfad aus der Grundlageneinstellung. Trägst Du einen Pfad ein, gilt dieser.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Verbindung und Bestand prüfen&lt;/em&gt; zeigt Dir vorab, wie viele Dokumente betroffen sind und welches Volumen sie haben. Dieser Schritt ändert nichts.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Migration starten&lt;/em&gt; arbeitet die Dokumente einzeln ab. Jede Datei wird zuerst temporär geschrieben, auf Vollständigkeit geprüft und erst dann in der Datenbank umgehängt. Gleichzeitige Änderungen am selben Datensatz werden erkannt, sodass ein Dokument nicht verloren gehen kann, das jemand parallel bearbeitet.&lt;/li&gt;
&lt;li&gt;Bricht der Lauf ab, etwa weil das Netzwerk wegbricht, setzt ein erneuter Start an der Stelle auf, an der er aufgehört hat. Bereits umgestellte Dokumente werden nicht erneut angefasst.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Zum Ausprobieren: Die Freeware-Fassung&lt;/h2&gt;
&lt;p&gt;
Du musst uns nicht glauben, dass das funktioniert, Du kannst es selbst ausprobieren. Die xRM Dateiablage steht als Freeware zum Download bereit, ohne Anmeldung und ohne dass Du uns Deine Adresse dalassen musst. Ohne Lizenz lassen sich damit einmalig bis zu 25 Dokumente extrahieren. Das reicht, um an einer Kopie Deiner Datenbank zu sehen, wie der Ablauf aussieht, ob die Dateien sauber im Zielverzeichnis landen und ob die Anwender die Dokumente danach wie gewohnt im xRM öffnen können.
&lt;/p&gt;
&lt;p&gt;
Für die Umstellung eines kompletten Bestands brauchst Du eine Lizenz. Sprich uns dafür einfach an, wir schauen uns Deinen Bestand vorher ohnehin gemeinsam an.
&lt;/p&gt;
&lt;div style="text-align: center; margin: 2rem 0;"&gt;
&lt;a href="https://appontes.de/download/xrm-dateiablage" class="btn btn-primary"&gt;xRM Dateiablage herunterladen&lt;/a&gt;
&lt;p style="margin-top: .75rem; font-size: .9rem; color: #6b7785;"&gt;Windows, 64 Bit, rund 11 MB. Version 1.1.3, ohne Lizenz bis zu 25 Dokumente.&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;Was Du vorher klären solltest&lt;/h2&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;
&lt;strong&gt;Pflichtprogramm:&lt;/strong&gt; Vor einer produktiven Migration gehören ein vollständiges SQL-Backup und ein Testlauf mit einer Datenbankkopie dazu. Nicht weil wir mit Problemen rechnen, sondern weil Massenänderungen immer abgesichert sein sollten.
&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Darüber hinaus sind das die Punkte, die in Projekten regelmäßig aufkommen:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Berechtigungen.&lt;/strong&gt; Solange die Dokumente in der Datenbank stehen, kommt niemand ohne Sage 100 an sie heran. Nach der Umstellung entscheidet das Dateisystem. Die Freigabe muss so berechtigt sein, dass alle xRM-Anwender lesen und schreiben können, aber eben auch nicht mehr Leute als vorgesehen. Das ist der eine Punkt, an dem die Umstellung mehr ist als eine technische Übung.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Datensicherung.&lt;/strong&gt; Das Zielverzeichnis muss in das Sicherungskonzept, und zwar mit einem Rhythmus, der zur Datenbanksicherung passt. Sonst hast Du nach einer Wiederherstellung Verknüpfungen auf Dateien, die es nicht mehr gibt.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Kein Cloud-Sync-Ordner.&lt;/strong&gt; Ordner, die im Hintergrund synchronisiert werden, sind als Ziel ungeeignet. Umbenennungen, Platzhalterdateien und verzögerte Verfügbarkeit vertragen sich nicht mit fest gespeicherten Pfaden.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Virenscanner.&lt;/strong&gt; Ein Scanner, der Dateien beim Schreiben in Quarantäne schiebt, sorgt für genau die toten Verknüpfungen, die Du vermeiden willst. Die Ausnahmeregeln gehören vor den Lauf abgestimmt.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Die Datenbank schrumpft nicht von allein.&lt;/strong&gt; Nach der Migration ist der Platz in der Datei frei, die Datei selbst bleibt aber gleich groß. Wenn Du den Platz zurückgeben willst, brauchst Du ein &lt;code&gt;DBCC SHRINKFILE&lt;/code&gt; und danach eine Indexreorganisation, weil ein Shrink die Indizes zerlegt. Plane das ins Wartungsfenster ein und mach es einmal richtig statt regelmäßig. Dass dieser Shrink oft nicht so läuft wie erwartet, haben wir im Folgebeitrag &lt;a href="https://appontes.de/blog/dbcc-shrinkfile-funktioniert-nicht/"&gt;DBCC SHRINKFILE läuft, aber die Datei bleibt groß&lt;/a&gt; auseinandergenommen.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Testkopien.&lt;/strong&gt; Denk daran, dass Kopien der Datenbank auf denselben Ablagepfad zeigen. In einem Testmandanten willst Du in aller Regel ein anderes Verzeichnis hinterlegen, damit dort niemand versehentlich produktive Dateien überschreibt.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Fazit&lt;/h2&gt;
&lt;p&gt;
Eingebettete Dokumente sind bequem und in kleinen Installationen völlig in Ordnung. Ab einer gewissen Größe drehen sich die Vorzeichen aber: Die Datenbank trägt dann Ballast, der das Backup verlängert, jede Kopie aufbläht und im Ernstfall die Wiederherstellung verzögert. Die Trennung von strukturierten Sage-Daten und Dokumentdateien schafft an dieser Stelle Luft und gibt Dir die Freiheit, beides getrennt zu sichern und zu skalieren.
&lt;/p&gt;
&lt;p&gt;
Der Weg dorthin besteht aus zwei Teilen. Die Grundlageneinstellungen regeln, was künftig passiert, und sind in zehn Minuten gesetzt. Den vorhandenen Bestand bekommst Du damit nicht umgestellt, dafür braucht es einen kontrollierten Lauf über die Tabelle. Wichtig ist, dass Du die Umstellung nicht als reines Datenbankthema behandelst. Berechtigungen und Sicherung der neuen Ablage sind der Teil, der hinterher zählt.
&lt;/p&gt;
&lt;p&gt;
Wenn Du wissen willst, wie groß das Thema bei Dir überhaupt ist, fang mit der Abfrage oben an. Bei der Bewertung der Zahlen und der Umstellung helfen wir gerne. Passend dazu ist auch unser Beitrag zum &lt;a href="https://appontes.de/blog/backups-pruefen-sage-100/"&gt;Prüfen von Sage-100-Backups&lt;/a&gt;, und was das xRM sonst noch kann, steht auf unserer Seite zu &lt;a href="https://appontes.de/sage-100/xrm/"&gt;Sage 100 xRM&lt;/a&gt;.
&lt;/p&gt;
&lt;div style="text-align: center; margin: 3rem 0;"&gt;
&lt;a href="https://appontes.de/kontakt/?betreff=anfrage-sage" class="btn btn-primary"&gt;xRM-Dateiablage mit uns umstellen&lt;/a&gt;
&lt;/div&gt;</content:encoded></item><item><title>Belegnummern in der Sage 100 per SQL zusammensetzen und aufspalten</title><link>https://appontes.de/blog/belegnummern-zusammensetzen-aufspalten-sql/</link><guid isPermaLink="true">https://appontes.de/blog/belegnummern-zusammensetzen-aufspalten-sql/</guid><pubDate>Tue, 08 Sep 2026 00:00:00 +0000</pubDate><dc:creator>Sebastian Wandtke</dc:creator><category>SQL Server</category><category>Sage 100</category><category>Belege</category><category>SQL</category><description>Mal zeigt die Sage 100 Jahr und Nummer getrennt, mal als 2026-123456. Mit CONCAT(), LEFT(), RIGHT() und SUBSTRING() bringst Du Belegnummern per SQL in die Form, die Du gerade brauchst.</description><content:encoded>&lt;p&gt;&lt;img src="https://appontes.de/img/blog/belegnummern-zusammensetzen-aufspalten.svg" alt="Belegnummern in der Sage 100 per SQL zusammensetzen und aufspalten"&gt;&lt;/p&gt;
&lt;p&gt;Sage kennt zwei verschiedene Darstellungsarten der Belegnummer: zusammengesetzt und aufgespalten. Je nach Fall wird Dir für eine Rechnung mit der Nummer „123456“ aus dem Jahr „2026“ mal Jahr und Nummer getrennt angezeigt und mal zusammengesetzt als „2026-123456“.&lt;/p&gt;
&lt;p&gt;Diese unterschiedlichen Darstellungsarten findest Du nicht nur in der Oberfläche, sondern, je nach Tabelle, auch direkt in der Datenbank. Deswegen gehört es einfach dazu, je nach Fragestellung die Belegnummer in zusammengesetzter oder aufgespaltener Form ausgeben zu können. Und dafür reichen ein paar einfache SQL-Befehle.&lt;/p&gt;
&lt;h2&gt;Zusammensetzen von Belegnummern&lt;/h2&gt;
&lt;p&gt;Hier gibt es zwei Varianten: den Verkettungsoperator &lt;code&gt;+&lt;/code&gt; oder die SQL-Funktion &lt;code&gt;CONCAT()&lt;/code&gt;. In der Praxis funktionieren beide, Unterschiede gibt es in ihrem Verhalten, wenn Werte mal &lt;code&gt;NULL&lt;/code&gt; sind.&lt;/p&gt;
&lt;p&gt;Wird der Verkettungsoperator &lt;code&gt;+&lt;/code&gt; verwendet, müssen die beiden Bestandteile mit &lt;code&gt;CONVERT()&lt;/code&gt; oder &lt;code&gt;CAST()&lt;/code&gt; in reinen Text (also den &lt;code&gt;VARCHAR&lt;/code&gt;-Datentyp) umgewandelt werden. Sonst würde SQL Server die beiden Zahlen (im &lt;code&gt;INT&lt;/code&gt;-Datentyp) addieren, was natürlich nicht gewollt ist. Mit &lt;code&gt;CONVERT()&lt;/code&gt; zur Typumwandlung sieht das so aus:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CONVERT(VARCHAR(4), MeinJahr) + '-' + CONVERT(VARCHAR(6), MeineNummer)
-- Ergebnis: 2026-123456&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Und schon wird die zusammengesetzte Belegnummer in einer Zelle ausgegeben. Die Zahlen in Klammern hinter &lt;code&gt;VARCHAR&lt;/code&gt; geben übrigens die Länge des Textes an, der erhalten werden soll. Also 4 Zeichen für das Jahr und 6 Zeichen für die Nummer.&lt;/p&gt;
&lt;p&gt;Variante 2 nutzt die &lt;code&gt;CONCAT()&lt;/code&gt;-Funktion und kommt mit weniger Schreibaufwand aus:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CONCAT(MeinJahr, '-', MeineNummer)
-- Ergebnis: 2026-123456&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Hier ist keine aufwändige Typumwandlung nötig, weil die &lt;code&gt;CONCAT()&lt;/code&gt;-Funktion das direkt mit übernimmt. Meistens reicht für das Zusammensetzen von Belegnummern diese kürzere Variante aus.&lt;/p&gt;
&lt;p&gt;Unterschiede weisen die beiden Varianten in der Behandlung von &lt;code&gt;NULL&lt;/code&gt;-Werten auf. Ist eine Nummer oder ein Jahr mal &lt;code&gt;NULL&lt;/code&gt;, so ist mit dem Verkettungsoperator &lt;code&gt;+&lt;/code&gt; auch das gesamte Ergebnis &lt;code&gt;NULL&lt;/code&gt;. Dagegen liefert die &lt;code&gt;CONCAT()&lt;/code&gt;-Funktion den Teil zurück, der nicht &lt;code&gt;NULL&lt;/code&gt; ist:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CONCAT(NULL, '-', MeineNummer)
-- Ergebnis: -123456&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Welche Ausgabe gewünscht ist, hängt von den Anforderungen ab. Manchmal ist es hilfreich, dass das Ergebnis einfach &lt;code&gt;NULL&lt;/code&gt; ist, wenn ein Teil der zusammengesetzten Belegnummer fehlt.&lt;/p&gt;
&lt;h2&gt;Aufspalten von Belegnummern&lt;/h2&gt;
&lt;p&gt;Findet man die zusammengesetzte Belegnummer in einer Tabellenspalte vor und möchte das Belegjahr einzeln ausgeben, bietet sich die &lt;code&gt;LEFT()&lt;/code&gt;-Funktion an:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;LEFT(ZusammengesetzteNummer, 4)
-- Ergebnis: 2026&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Die &lt;code&gt;LEFT()&lt;/code&gt;-Funktion gibt vom Anfang des Ausdruckes Zeichen zurück, wobei hier mit der 4 die Anzahl der zurückgegebenen Zeichen festgelegt wird. Analog kann mit der &lt;code&gt;RIGHT()&lt;/code&gt;-Funktion vom Ende eines Ausdruckes aus eine definierte Anzahl von Zeichen erhalten werden, was sich für das Herauslösen der Nummer aus der zusammengesetzten Belegnummer anbietet:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;RIGHT(ZusammengesetzteNummer, 6)
-- Ergebnis: 123456&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In den meisten Fällen lässt sich so bereits die Belegnummer aufspalten. Ab und zu benötigt man jedoch die &lt;code&gt;SUBSTRING()&lt;/code&gt;-Funktion, wenn man etwas aus der Mitte eines zusammengesetzten Ausdruckes entnehmen möchte. Das kann zum Beispiel bei offenen Posten (OPs) der Fall sein, wenn eine OP-Nummer aus Belegnummer und einer angefügten Zahl besteht (z. B. Teilung in 2026-123456.1 und 2026-123456.2):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SUBSTRING('2026-123456.1', 6, 6)
-- Ergebnis: 123456&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Der &lt;code&gt;SUBSTRING()&lt;/code&gt;-Funktion wird erst der Ausdruck angegeben, dem ein Teil entnommen werden soll, dann die Startposition der Entnahme und dann die Anzahl der zu entnehmenden Zeichen. Hier sollen ab einschließlich der 6. Position 6 Zeichen entnommen werden. Die &lt;code&gt;SUBSTRING()&lt;/code&gt;-Funktion ist also vielseitiger, aber auch ein wenig komplexer als die &lt;code&gt;LEFT()&lt;/code&gt;- und &lt;code&gt;RIGHT()&lt;/code&gt;-Funktionen.&lt;/p&gt;
&lt;h2&gt;Fazit&lt;/h2&gt;
&lt;p&gt;Das Zusammensetzen und Aufspalten von Belegnummern lässt sich mit wenigen SQL-Ausdrücken erreichen. Mit &lt;code&gt;CONCAT()&lt;/code&gt; ist das Zusammensetzen von Belegnummern schnell gemacht, und wenn die aufzuspaltende Belegnummer einen festen Aufbau hat, lässt sich mit &lt;code&gt;LEFT()&lt;/code&gt; oder &lt;code&gt;RIGHT()&lt;/code&gt; der gewünschte Teil direkt entnehmen. Und sollte man mal einen etwas komplizierteren Aufbau haben, hilft die vielseitige &lt;code&gt;SUBSTRING()&lt;/code&gt;-Funktion.&lt;/p&gt;</content:encoded></item><item><title>Saldenvortrag in der Sage 100: Sauber ins neue Geschäftsjahr starten</title><link>https://appontes.de/blog/saldenvortrag-sage-100/</link><guid isPermaLink="true">https://appontes.de/blog/saldenvortrag-sage-100/</guid><pubDate>Sat, 29 Aug 2026 00:00:00 +0000</pubDate><dc:creator>Thomas Falkner</dc:creator><category>Sage 100</category><category>Rechnungswesen</category><category>Jahresabschluss</category><description>Wann und wie überträgst Du die Salden ins neue Geschäftsjahr? So funktioniert der Saldenvortrag im Sage 100 Rechnungswesen, von den Festkonten bis zum Praxistipp für ein aufgeräumtes Kontenblatt.</description><content:encoded>&lt;p&gt;&lt;img src="https://appontes.de/img/blog/saldenvortrag-sage-100.svg" alt="Saldenvortrag in der Sage 100: Sauber ins neue Geschäftsjahr starten"&gt;&lt;/p&gt;
&lt;p&gt;
Mit jedem Jahreswechsel tauchen in der Buchhaltung dieselben Fragen auf: Wann übernehme ich die Salden ins neue Geschäftsjahr, und was muss ich dabei beachten? Die gute Nachricht vorweg: Ist Dein Sage 100 Rechnungswesen richtig eingerichtet, kann beim Saldenvortrag kaum etwas schiefgehen. An ein paar Stellen kannst Du Dir die Arbeit aber deutlich erleichtern. In diesem Beitrag gehen wir den kompletten Ablauf durch.
&lt;/p&gt;
&lt;h2&gt;Drei Grundsätze vorab&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Der Saldenvortrag setzt voraus, dass das neue Geschäftsjahr bereits angelegt ist. Fehlt es, bietet Dir die Sage 100 beim Aufruf direkt an, es anzulegen.&lt;/li&gt;
&lt;li&gt;Du kannst den Saldenvortrag beliebig oft wiederholen, solange im Folgejahr mindestens eine Periode offen ist. Bei jedem weiteren Lauf werden nur die Differenzen als neue Buchungen übergeben, nichts wird doppelt vorgetragen.&lt;/li&gt;
&lt;li&gt;Offene Posten wandern nicht per Saldenvortrag ins neue Jahr. Sie sind im Gegensatz zum Kontokorrent ohnehin jahresübergreifend und brauchen keine Übernahme.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Wann ist der richtige Zeitpunkt?&lt;/h2&gt;
&lt;p&gt;
Jede Buchhaltung hat hier ihre eigenen Gewohnheiten, und die Sage 100 lässt Dir alle Freiheiten: Ein Saldenvortrag ist zu jedem Zeitpunkt möglich. Bewährt hat sich die erste Übergabe direkt zum Wechsel des Geschäftsjahres. Auch wenn im alten Jahr noch gebucht wird, stehen damit die wesentlichen Buchhaltungsdaten schon im neuen Jahr zur Verfügung. Gerade Kontokorrent- und Finanzkonten solltest Du gleich zum Jahresbeginn vortragen, damit Kontenblätter und Auswertungen von Anfang an stimmen. Spätere Läufe gleichen dann nur noch die Differenzen aus.
&lt;/p&gt;
&lt;h2&gt;Die Saldenvortragskonten&lt;/h2&gt;
&lt;p&gt;
Als Gegenkonten für die Vortragsbuchungen dienen eigene Sachkonten. Diese hinterlegst Du in den &lt;strong&gt;Grundlagen&lt;/strong&gt; unter &lt;em&gt;Festkonten Diverse&lt;/em&gt; im Register &lt;em&gt;Diverse&lt;/em&gt;. Dort gibt es getrennte Konten für Sachkonten, Debitoren, Kreditoren und Statistikkonten. Einmal sauber eingerichtet, musst Du hier in der Regel nie wieder ran.
&lt;/p&gt;
&lt;!--
TODO Screenshot: Grundlagen, Festkonten Diverse, Register Diverse mit den hinterlegten Saldenvortragskonten
&lt;figure class="blog-figure"&gt;
&lt;img src="https://appontes.de/img/blog/saldenvortrag/festkonten-diverse.png" alt="Festkonten Diverse in den Grundlagen der Sage 100 mit den hinterlegten Saldenvortragskonten" loading="lazy"&gt;
&lt;figcaption&gt;Die Saldenvortragskonten pflegst Du zentral in den Grundlagen unter Festkonten Diverse&lt;/figcaption&gt;
&lt;/figure&gt;
--&gt;
&lt;h2&gt;Der Dialog Jahresabschluss/Saldovortrag&lt;/h2&gt;
&lt;p&gt;
Den eigentlichen Vortrag startest Du im &lt;strong&gt;alten Geschäftsjahr&lt;/strong&gt; über den Menüpunkt &lt;em&gt;Jahresabschluss/Saldovortrag&lt;/em&gt;. Im Dialog legst Du zunächst die Buchungsangaben fest:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Buchungsdatum:&lt;/strong&gt; Hier empfiehlt sich der erste Tag des neuen Geschäftsjahres. Kontenblätter sind nach Buchungsdatum sortiert, mit diesem Datum beginnt jedes Kontenblatt sauber mit dem Saldenvortrag. Das macht die Auswertungen deutlich besser lesbar.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Buchungsperiode:&lt;/strong&gt; Die Sage 100 schlägt die erste Periode des neuen Geschäftsjahres vor. Dabei kannst Du es in aller Regel belassen.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Belegnummer:&lt;/strong&gt; Sie wird für alle Vortragsbuchungen gemeinsam vergeben. Der Saldenvortrag funktioniert auch ohne Belegnummer, mit einer eindeutigen Nummer findest Du die Buchungen später aber leichter wieder.&lt;/li&gt;
&lt;/ul&gt;
&lt;!--
TODO Screenshot: Dialog Jahresabschluss/Saldovortrag mit Buchungsdatum, Buchungsperiode und Belegnummer
&lt;figure class="blog-figure"&gt;
&lt;img src="https://appontes.de/img/blog/saldenvortrag/dialog-buchungsangaben.png" alt="Dialog Saldovortrag in der Sage 100 mit Buchungsdatum, Buchungsperiode und Belegnummer" loading="lazy"&gt;
&lt;figcaption&gt;Buchungsdatum, Periode und Belegnummer gelten für alle Vortragsbuchungen des Laufs&lt;/figcaption&gt;
&lt;/figure&gt;
--&gt;
&lt;h3&gt;Welche Bereiche überträgst Du?&lt;/h3&gt;
&lt;p&gt;
Im nächsten Schritt wählst Du aus, welche Bereiche vorgetragen werden: Kunden, Lieferanten, Anlagen, Statistikkonten, Kostenstellen/Kostenarten, Kostenträger/Kostenarten und Bilanzkonten. Die Auswahl hängt vom Zeitpunkt ab und lässt sich bei jedem Lauf neu treffen. Kunden, Lieferanten und Anlagen gehören möglichst früh ins neue Jahr, den Rest kannst Du auch später nachziehen.
&lt;/p&gt;
&lt;p&gt;
Für die Bilanzkonten gibt es zwei zusätzliche Eingrenzungen: Mit dem Kennzeichen &lt;em&gt;Nur Finanz-/Kassenkonten&lt;/em&gt; überträgst Du aus der Menge der Bilanzkonten zunächst nur Bank und Kasse. Und mit &lt;em&gt;Nur Konten mit Abstimmkennzeichen&lt;/em&gt; beschränkst Du den Vortrag auf Bilanzkonten, die das Abstimmkennzeichen (Akz) tragen.
&lt;/p&gt;
&lt;p&gt;
Die Optionen zu Kostenstellen/Kostenarten und Kostenträger/Kostenarten beziehen sich auf die Teilnahme der Saldenvortragskonten an der Kostenrechnung. Nehmen Deine Vortragskonten an der Kostenrechnung teil, werden bei aktivierter Option auch diese Werte übernommen.
&lt;/p&gt;
&lt;!--
TODO Screenshot: Bereichsauswahl im Saldovortrag-Dialog mit den Eingrenzungen für Bilanzkonten
&lt;figure class="blog-figure"&gt;
&lt;img src="https://appontes.de/img/blog/saldenvortrag/dialog-bereiche.png" alt="Bereichsauswahl im Saldovortrag-Dialog der Sage 100 mit Kunden, Lieferanten, Anlagen und Bilanzkonten samt Eingrenzungen" loading="lazy"&gt;
&lt;figcaption&gt;Die Bereichsauswahl kannst Du bei jedem Saldenvortrag neu treffen&lt;/figcaption&gt;
&lt;/figure&gt;
--&gt;
&lt;p&gt;Mit OK startet die Übernahme und die Salden stehen im neuen Geschäftsjahr bereit.&lt;/p&gt;
&lt;h2&gt;Was dabei im Hintergrund passiert&lt;/h2&gt;
&lt;p&gt;
Der Saldenvortrag legt in der Buchungserfassung des neuen Geschäftsjahres eine eigene Sitzung mit der Bezeichnung &lt;em&gt;Automatischer Saldovortrag&lt;/em&gt; an. Die Buchungen darin sind bereits verarbeitet. Bearbeiten kannst Du sie nicht, löschen dagegen schon. Beachte dabei: Gelöschte Vortragsbuchungen werden beim nächsten Saldenvortrag wieder übernommen, die Salden gehen also nicht verloren.
&lt;/p&gt;
&lt;!--
TODO Screenshot: Buchungserfassung im neuen Geschäftsjahr mit der Sitzung Automatischer Saldovortrag
&lt;figure class="blog-figure"&gt;
&lt;img src="https://appontes.de/img/blog/saldenvortrag/sitzung-saldovortrag.png" alt="Buchungserfassung der Sage 100 mit der automatisch angelegten Sitzung Automatischer Saldovortrag" loading="lazy"&gt;
&lt;figcaption&gt;Jeder Lauf landet als eigene Sitzung in der Buchungserfassung des neuen Jahres&lt;/figcaption&gt;
&lt;/figure&gt;
--&gt;
&lt;h2&gt;Manuelle Saldenvorträge&lt;/h2&gt;
&lt;p&gt;
Beim Start mit einem neuen Mandanten führt kein Weg an manuellen Saldenvorträgen vorbei. Bank-, Kassen- und Anlagenbestände sowie die offenen Posten Deiner Kunden und Lieferanten erfasst Du dann als normale Buchungen gegen die Saldenvortragskonten. Bei Debitoren und Kreditoren gehört zu jeder Position auch die Anlage des offenen Postens mit OP-Nummer, OP-Datum und Betrag, denn aus dem OP-Datum ermittelt die Sage 100 die Fälligkeit für Skonto und Mahnwesen.
&lt;/p&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;Nutze manuelle Saldenvorträge wirklich nur zur Einrichtung und nicht in der laufenden Buchhaltung. Sonst riskierst Du, dass Abschlusssalden und Anfangssalden nicht mehr zusammenpassen.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;
Praktisch dabei: Die Sage 100 berücksichtigt manuelle Vorträge beim automatischen Saldenvortrag. Stößt Du nach manuellen Buchungen den automatischen Lauf an, werden nur die Differenzen übertragen. Doppelte Werte landen nicht im neuen Geschäftsjahr.
&lt;/p&gt;
&lt;h2&gt;Praxistipp: Nur eine Vortragsbuchung pro Konto&lt;/h2&gt;
&lt;p&gt;
Eine Frage aus unserem Support: Wie kann man während des Jahres laufend Saldenvorträge fahren und trotzdem nach der Bilanzierung nur eine einzige Vortragsbuchung pro Konto auf dem Kontenblatt haben?
&lt;/p&gt;
&lt;p&gt;
Die Antwort ist einfacher als gedacht. Sobald die Bilanz fertig ist, löschst Du die Sitzungen des automatischen Saldenvortrags im neuen Jahr und stößt den Saldenvortrag aus dem alten Geschäftsjahr noch einmal an. Ein einziger Lauf über die endgültigen Salden, und jedes Konto beginnt mit genau einer Vortragsbuchung.
&lt;/p&gt;
&lt;h2&gt;Fazit&lt;/h2&gt;
&lt;p&gt;
Der Saldenvortrag in der Sage 100 ist unkompliziert, wenn man die Mechanik einmal verstanden hat: früh und ruhig mehrfach vortragen, die Differenzlogik arbeiten lassen und nach der Bilanzierung mit einem letzten Lauf aufräumen. So startet jedes Kontenblatt sauber ins neue Jahr.
&lt;/p&gt;
&lt;p&gt;
Du hast Fragen zum Jahresabschluss in Deiner Sage 100 oder möchtest Deine Buchhaltungsprozesse insgesamt auf den Prüfstand stellen? Dann sprich uns an.
&lt;/p&gt;
&lt;div style="text-align: center; margin: 3rem 0;"&gt;
&lt;a href="https://appontes.de/kontakt/?betreff=anfrage-sage" class="btn btn-primary"&gt;Kostenlose Erstberatung vereinbaren&lt;/a&gt;
&lt;/div&gt;</content:encoded></item><item><title>Von Sage Office Line zu Sage 100: Was aus Anpassungen, Belegen und Schnittstellen wird</title><link>https://appontes.de/blog/office-line-zu-sage-100/</link><guid isPermaLink="true">https://appontes.de/blog/office-line-zu-sage-100/</guid><pubDate>Tue, 11 Aug 2026 00:00:00 +0000</pubDate><dc:creator>Thomas Falkner</dc:creator><category>Sage 100</category><category>Office Line</category><category>Migration</category><category>ERP</category><description>Deine Office Line läuft seit Jahren stabil, aber Updates gibt es keine mehr. Warum der Umstieg auf Sage 100 kein Systemwechsel ist, was aus Access-Anpassungen, Belegdruck und Schnittstellen wird und in welcher Reihenfolge Du das Thema angehst.</description><content:encoded>&lt;p&gt;&lt;img src="https://appontes.de/img/blog/office-line-zu-sage-100.svg" alt="Von Sage Office Line zu Sage 100: Was aus Anpassungen, Belegen und Schnittstellen wird"&gt;&lt;/p&gt;
&lt;p&gt;
Es gibt eine Sorte Sage-Installation, die uns immer wieder begegnet: Eine Office Line, die seit zehn oder fünfzehn Jahren zuverlässig ihren Dienst tut. Über die Jahre sind individuelle Belege dazugekommen, ein paar angepasste Masken, eine Schnittstelle zum Webshop, eine zweite zum Hochregallager. Alles läuft. Und genau deshalb hat niemand den Umstieg angepackt. Bis irgendetwas Druck macht: Der Server soll erneuert werden, die E-Rechnung steht im Haus, der langjährige Betreuer hat aufgehört oder der aktuelle Partner meldet sich nur noch bei der Rechnungsstellung. Dann kommt die Frage, die dieser Beitrag beantwortet: Was passiert beim Umstieg auf Sage 100 eigentlich mit all dem, was wir uns über die Jahre aufgebaut haben?
&lt;/p&gt;
&lt;h2&gt;Gleiche Linie, neuer Name&lt;/h2&gt;
&lt;p&gt;
Zuerst die wichtigste Einordnung, weil sie viele Sorgen relativiert: Office Line und Sage 100 sind keine zwei verschiedenen Produkte. Es ist dieselbe Produktlinie, die seit 1995 kontinuierlich weiterentwickelt wird. Gestartet ist sie beim deutschen Hersteller KHK auf Basis von Microsoft Access. 1997 übernahm Sage das Produkt, ab 2008 begann mit der "Office Line Evolution" der schrittweise Umbau auf das .NET-Framework. 2016 folgte mit Version 7.1 die Umbenennung in Sage 100, verbunden mit einer neuen Belegerfassung und dem AppDesigner als zentralem Anpassungswerkzeug. Heute steht die Linie bei Version 9.0, die von Sage laufend mit Service Packs weiterentwickelt wird.
&lt;/p&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;
Ein Umstieg von der Office Line auf Sage 100 ist deshalb &lt;strong&gt;kein Wechsel auf ein fremdes System&lt;/strong&gt;, sondern ein Update innerhalb derselben Produktfamilie. Deine Datenbank, Deine Stammdaten, Deine Belege und Deine Historie werden dabei übernommen und nicht in ein neues System hinübermigriert. Je nach Ausgangsversion läuft das Update in mehreren Stufen, aber es bleibt ein Update.
&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;Warum gerade jetzt Bewegung in das Thema kommt&lt;/h2&gt;
&lt;p&gt;
Dass sich viele Unternehmen ausgerechnet jetzt mit dem Umstieg beschäftigen, hat handfeste Gründe, und die wichtigsten davon sind Termine:
&lt;/p&gt;
&lt;ul class="icon-list arrow"&gt;
&lt;li&gt;Für die alten &lt;strong&gt;Office-Line-Versionen&lt;/strong&gt; liefert Sage seit dem 1. Juli 2022 keine Software-Aktualisierungen und keinen personalisierten Support mehr.&lt;/li&gt;
&lt;li&gt;Auch die &lt;strong&gt;Sage 100 Desktop&lt;/strong&gt;, also das klassische Kauflizenz-Modell, ist seit dem 1. Januar 2025 im Extended Support: keine Updates, kein personalisierter Support. Neue Module oder zusätzliche User gibt es dafür schon seit Oktober 2023 nicht mehr, Erweiterungen setzen den Wechsel auf das Subscription-Modell Sage 100 Connected voraus.&lt;/li&gt;
&lt;li&gt;Die &lt;strong&gt;E-Rechnungspflicht&lt;/strong&gt; ist seit 2025 Realität. Funktionen dafür bekommen nur aktuelle Versionen, alte Installationen bleiben außen vor.&lt;/li&gt;
&lt;li&gt;Neue &lt;strong&gt;Windows- und SQL-Server-Versionen&lt;/strong&gt; werden nur noch für die aktuelle Sage 100 freigegeben. Wer den Server erneuern will oder muss, kommt an der Softwarefrage nicht vorbei.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Anders gesagt: Eine alte Office Line läuft nicht plötzlich schlechter. Aber jedes Infrastrukturthema, jede gesetzliche Änderung und jeder Erweiterungswunsch führt früher oder später auf denselben Punkt zu. Wer den Zeitpunkt selbst wählt, ist klar im Vorteil gegenüber dem, den ein Serverausfall oder eine Frist zum Handeln zwingt.
&lt;/p&gt;
&lt;h2&gt;Was wird aus den Anpassungen?&lt;/h2&gt;
&lt;p&gt;
Das ist die Frage, an der die meisten Umstiegsprojekte hängen, und die ehrliche Antwort lautet: Es kommt darauf an, womit die Anpassungen gebaut wurden. In gewachsenen Office-Line-Installationen finden sich typischerweise drei Sorten.
&lt;/p&gt;
&lt;h3&gt;1. Anpassungen aus der Access-Welt&lt;/h3&gt;
&lt;p&gt;
Die alte Office Line basierte im Frontend auf Microsoft Access. Entsprechend wurden Masken erweitert, Formulare verändert und Logik in VBA hinterlegt. Sage löst Access seit Jahren Schritt für Schritt ab. Seit Version 9.0.7 gibt es mit der &lt;strong&gt;Sage 100 Smart Edition&lt;/strong&gt; einen Client, der komplett ohne Access auskommt und die Zukunft der Produktlinie darstellt. Access-basierte Anpassungen laufen im klassischen Client vielfach noch mit, haben aber ein absehbares Ende. Beim Umstieg gehören sie deshalb auf den Tisch: Was davon wird noch gebraucht, was kann der heutige Standard längst von allein und was bauen wir gezielt mit dem AppDesigner neu?
&lt;/p&gt;
&lt;h3&gt;2. Anpassungen mit Bordmitteln&lt;/h3&gt;
&lt;p&gt;
Benutzerfelder, angepasste Auskünfte, eigene Abfragen und Einstellungen überstehen ein Update in aller Regel gut, weil sie in der Datenbank und nicht im alten Frontend leben. Sie werden im Projekt geprüft und mitgenommen.
&lt;/p&gt;
&lt;h3&gt;3. Individuell entwickelte Erweiterungen&lt;/h3&gt;
&lt;p&gt;
Hier lohnt der genaueste Blick. Manche Erweiterung von damals ist heute Standardfunktion und kann ersatzlos entfallen. Manche läuft nach einer Anpassung an die aktuelle Version weiter. Und manche ist so geschäftskritisch und speziell, dass sie sauber auf die heutige Technik gehoben wird. Genau diese Bewertung ist der Kern einer guten Bestandsaufnahme: nicht alles blind nachbauen, sondern erst prüfen, was der Standard inzwischen abdeckt.
&lt;/p&gt;
&lt;h2&gt;Was wird aus den Belegen?&lt;/h2&gt;
&lt;p&gt;
Individuelle Auftragsbestätigungen, Lieferscheine und Rechnungen wurden in der Office Line über Jahre mit dem Access-basierten Print-AddIn angepasst. Dieses Kapitel ist abgeschlossen: Seit Version 8.1 gibt es das Print-AddIn nicht mehr, der Belegdruck wird seitdem über den AppDesigner angepasst.
&lt;/p&gt;
&lt;p&gt;
Für den Umstieg heißt das konkret: Individuelle Beleglayouts aus der Access-Zeit werden einmalig im AppDesigner nachgebaut. Das ist planbarer Aufwand und zugleich eine gute Gelegenheit zum Aufräumen. In fast jedem Altsystem finden sich Beleg-Varianten, die seit Jahren niemand mehr druckt, und Sonderfälle, die längst keiner mehr erklären kann. Wer beim Umstieg nur das nachbaut, was wirklich im Einsatz ist, spart Geld und bekommt einen sauberen Stand für die E-Rechnung gleich mit.
&lt;/p&gt;
&lt;h2&gt;Was wird aus den Schnittstellen?&lt;/h2&gt;
&lt;p&gt;
Webshop, Lager, Versand, DATEV, Zeiterfassung: Gewachsene Installationen hängen selten allein im Raum. Bei Schnittstellen hilft die gleiche Sortierung wie bei den Anpassungen.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Zukaufte Zusatzlösungen&lt;/strong&gt; von Sage-Partnern gibt es meist in versionskompatiblen Ständen für die aktuelle Sage 100. Hier ist zu klären, ob der Hersteller die Lösung noch pflegt und was das Update kostet. &lt;strong&gt;Direkte Datenbankzugriffe&lt;/strong&gt;, etwa lesende SQL-Auswertungen, funktionieren oft weiter, weil das Datenmodell der Produktlinie über die Versionen hinweg erstaunlich stabil geblieben ist. Verlassen sollte man sich darauf trotzdem nicht ungeprüft, gerade schreibende Zugriffe gehören auf den Prüfstand. &lt;strong&gt;Eigenentwickelte Schnittstellen&lt;/strong&gt; aus der COM- und VBA-Zeit schließlich werden bewertet und bei Bedarf auf die heute unterstützten Wege gehoben. Das ist unser Tagesgeschäft, und häufig wird die Schnittstelle dabei nicht nur kompatibel, sondern auch robuster als vorher.
&lt;/p&gt;
&lt;h2&gt;Kauflizenz oder Subscription?&lt;/h2&gt;
&lt;p&gt;
Eine Frage stellt sich beim Umstieg automatisch mit: das Lizenzmodell. Die klassische Kauflizenz (Sage 100 Desktop) wird von Sage nicht mehr ausgebaut, Erweiterungen und aktuelle Updates gibt es im Subscription-Modell Sage 100 Connected. Für die Kalkulation heißt das: Statt Kaufpreis plus Wartungsvertrag gibt es eine monatliche Nutzungsgebühr. Ob und wann sich der Wechsel für Dich rechnet, hängt von Modulumfang, Userzahl und Planungshorizont ab. Das rechnen wir im Erstgespräch transparent durch, bevor irgendetwas unterschrieben wird.
&lt;/p&gt;
&lt;h2&gt;Wie wir so einen Umstieg angehen&lt;/h2&gt;
&lt;p&gt;
Kein Umstiegsprojekt beginnt bei uns mit einem Installationsmedium. Es beginnt mit einer Bestandsaufnahme: Welche Version läuft, welche Module, welche Anpassungen, welche Schnittstellen, wie steht es um &lt;a href="https://appontes.de/blog/sage-100-sql-performance-messen/"&gt;Datenbank und Performance&lt;/a&gt;? Daraus entsteht eine Liste mit drei Spalten: läuft einfach mit, muss angefasst werden, kann weg. Erst dann wird geplant.
&lt;/p&gt;
&lt;p&gt;
Das eigentliche Update proben wir in einer Testumgebung mit einer Kopie Deiner Datenbank. Dort zeigt sich, ob der Updatepfad sauber durchläuft, welche Anpassungen sich wie verhalten und wie die nachgebauten Belege aussehen. Deine Anwender testen ihre echten Abläufe am Testsystem, bevor der Stichtag festgelegt wird. So wird aus dem gefürchteten Großprojekt eine Abfolge kontrollierter Schritte, und das Tagesgeschäft läuft nebenher weiter.
&lt;/p&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;
Übrigens: Für den Umstieg musst Du nicht bei Deinem bisherigen Partner bleiben. Die Betreuung einer Sage-Installation lässt sich formlos auf einen anderen zertifizierten Partner übertragen, Lizenzen und Daten bleiben davon unberührt. Wie das abläuft, steht in unserem Beitrag zum &lt;a href="https://appontes.de/sage-100/betreuungswechsel/"&gt;Sage 100 Betreuungswechsel&lt;/a&gt;.
&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;Fazit&lt;/h2&gt;
&lt;p&gt;
Der Umstieg von der Office Line auf Sage 100 ist kein Sprung ins Ungewisse, sondern ein Update innerhalb derselben Produktlinie, mit Deinen Daten und Deiner Historie. Die eigentliche Arbeit steckt nicht im Update selbst, sondern in der ehrlichen Bewertung der gewachsenen Anpassungen, Belege und Schnittstellen. Genau dafür braucht es einen Partner, der sowohl die alte Access-Welt als auch die heutige Sage-100-Technik kennt und der auch entwickeln kann, wenn eine Speziallösung mitgenommen werden muss.
&lt;/p&gt;
&lt;p&gt;
Wie eine modern aufgestellte Sage 100 im Handel aussieht, zeigen wir übrigens auf unseren Branchenseiten für den &lt;a href="https://appontes.de/sage-100/technischer-grosshandel/"&gt;technischen Großhandel&lt;/a&gt; und den &lt;a href="https://appontes.de/sage-100/maschinen-anlagen-geraetehandel/"&gt;Maschinen-, Anlagen- und Gerätehandel mit Service&lt;/a&gt;. Und wenn bei Dir eine gewachsene Office Line oder eine ältere Sage 100 läuft und Du wissen willst, wo Du stehst: Meld Dich einfach. Die Bestandsaufnahme ist der einfachste erste Schritt.
&lt;/p&gt;
&lt;p class="text-center mt-4"&gt;
&lt;a href="https://appontes.de/kontakt/?betreff=anfrage-sage" class="btn btn-primary"&gt;Bestehende Sage-Umgebung besprechen&lt;/a&gt;
&lt;/p&gt;</content:encoded></item><item><title>Sage 100 langsam? So messen wir, woran es wirklich liegt</title><link>https://appontes.de/blog/sage-100-sql-performance-messen/</link><guid isPermaLink="true">https://appontes.de/blog/sage-100-sql-performance-messen/</guid><pubDate>Tue, 11 Aug 2026 00:00:00 +0000</pubDate><dc:creator>Thomas Falkner</dc:creator><category>Sage 100</category><category>Performance</category><category>SQL Server</category><category>IT-Infrastruktur</category><description>Statt zu raten, messen wir: Unser PowerShell-Script prüft Netzwerk, SQL Server und die echten Sage 100 Tabellen in einem Durchlauf. Wir erklären Dir alle Indikatoren, ihre Referenzwerte und was sie über Dein System verraten.</description><content:encoded>&lt;p&gt;&lt;img src="https://appontes.de/img/blog/sql-performance-test.svg" alt="Sage 100 langsam? So messen wir, woran es wirklich liegt"&gt;&lt;/p&gt;
&lt;p&gt;
„Die Sage 100 ist langsam." Diesen Satz hören wir oft. Und er ist völlig berechtigt, nur leider auch völlig unpräzise. Liegt es am Netzwerk? Am SQL Server? Am Client? An fehlender Wartung? Jeder im Unternehmen hat eine Vermutung, und meistens wird dann erstmal neue Hardware gekauft. Manchmal hilft das sogar. Oft aber nicht, weil das eigentliche Problem woanders lag.
&lt;/p&gt;
&lt;p&gt;
Deshalb raten wir nicht, sondern messen. Dafür haben wir ein PowerShell-Script entwickelt, das in wenigen Minuten die komplette Kette vom Client bis zum SQL Server durchleuchtet: Netzwerk, Verbindungsaufbau, echte Sage-Abfragen, Server-Gesundheit, Konfiguration, Wartung und Sicherheit. Am Ende steht ein Bericht mit klaren Bewertungen und einer Diagnose, wo die Ursache liegt. In diesem Beitrag zeigen wir Dir, wie das Script funktioniert und was die einzelnen Indikatoren bedeuten.
&lt;/p&gt;
&lt;h2&gt;So funktioniert der Test&lt;/h2&gt;
&lt;p&gt;
Das Script &lt;code&gt;Test-SagePerformance.ps1&lt;/code&gt; läuft auf einem beliebigen Windows-Rechner mit Zugriff auf den SQL Server. Idealerweise startest Du es genau dort, wo die Anwender arbeiten, denn dann misst es exakt die Strecke, die auch die Sage 100 nimmt. Es braucht nur vier Angaben: Server, Datenbank, Anmeldung und die Sage-Mandantennummer.
&lt;/p&gt;
&lt;p&gt;Drei Dinge sind uns dabei wichtig:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Es misst unter realen Bedingungen.&lt;/strong&gt; Das Script simuliert die Artikelsuche, das Öffnen eines Artikels und den Listenaufbau direkt auf den echten Sage-Tabellen wie KHKArtikel, KHKAdressen und KHKVKBelege. Kundenindividuelle USER_-Felder werden dabei ignoriert, damit die Messung vergleichbar bleibt.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Es verändert nichts an Deinen Daten.&lt;/strong&gt; Alle Abfragen sind lesend. Nur der Schreib-Benchmark nutzt eine temporäre Tabelle in der TempDB, die danach wieder verschwindet.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Jeder Messwert wird bewertet.&lt;/strong&gt; Für jeden Indikator gibt es einen Referenzwert aus gesunden Systemen. Das Ergebnis ist immer &lt;span class="verdict verdict-ok"&gt;OK&lt;/span&gt;, &lt;span class="verdict verdict-warn"&gt;WARNUNG&lt;/span&gt; oder &lt;span class="verdict verdict-crit"&gt;KRITISCH&lt;/span&gt;. So muss niemand interpretieren, ob 12 Millisekunden nun gut oder schlecht sind.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Jeder Abfrage-Test läuft in mehreren Runden, damit einzelne Ausreißer das Ergebnis nicht verfälschen. Am Ende schreibt das Script auf Wunsch einen formatierten HTML-Bericht mit allen Messwerten, den Auffälligkeiten und einem Fazit. Den bekommst Du von uns nach jeder Messung, verständlich aufbereitet und ohne Fachchinesisch.
&lt;/p&gt;
&lt;figure class="blog-figure"&gt;
&lt;img src="https://appontes.de/img/blog/sql-performance-bericht.png" alt="Der HTML-Bericht des Performance-Tests mit Zusammenfassung, Messergebnissen und Bewertungen als farbige Badges" loading="lazy"&gt;
&lt;figcaption&gt;Der HTML-Bericht: Oben die Zusammenfassung, darunter jeder Messwert mit Referenz und Bewertung&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2&gt;Warum Latenz bei der Sage 100 alles ist&lt;/h2&gt;
&lt;p&gt;
Bevor wir in die Indikatoren einsteigen, ein wichtiger Hintergrund: Die Sage 100 stellt pro Maske nicht eine große Abfrage an den SQL Server, sondern viele kleine, je nach Maske etwa 20 bis 70. Deshalb multipliziert sich jede Verzögerung im Netzwerk.
&lt;/p&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;Rechenbeispiel: Ein Maskenwechsel löst 50 kleine Abfragen aus. Bei 1 Millisekunde Roundtrip-Latenz beträgt der Netzwerkanteil 50 Millisekunden, das fühlt sich sofort an. Bei 10 Millisekunden, etwa über ein VPN, wartet der Anwender schon eine halbe Sekunde. Und zwar bei jedem einzelnen Klick, den ganzen Tag. Am Server hat sich dabei nichts geändert, und trotzdem fühlt sich die Anwendung wie ausgetauscht an.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;
Genau deshalb ist die Roundtrip-Latenz für uns der wichtigste Einzelwert des ganzen Tests. Und genau deshalb bringt ein schnellerer Server nichts, wenn das Problem zwischen Client und Server liegt.
&lt;/p&gt;
&lt;h2&gt;Die Netzwerk-Indikatoren&lt;/h2&gt;
&lt;table class="tech-table"&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Indikator&lt;/th&gt;
&lt;th&gt;Referenzwert&lt;/th&gt;
&lt;th&gt;Was er verrät&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;DNS-Auflösung&lt;/td&gt;
&lt;td&gt;unter 50 ms&lt;/td&gt;
&lt;td&gt;Langsames DNS oder Active Directory verzögert jeden Verbindungsaufbau und jeden Login.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ICMP-Ping&lt;/td&gt;
&lt;td&gt;unter 1 ms im LAN&lt;/td&gt;
&lt;td&gt;Die Grundlatenz des Netzwerks. Höhere Werte deuten auf WLAN, VPN oder Routing-Probleme hin.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Paketverlust&lt;/td&gt;
&lt;td&gt;0 von 10&lt;/td&gt;
&lt;td&gt;Schon einzelne verlorene Pakete sind für die Sage 100 fatal, weil jede Übertragung wiederholt werden muss.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SQL-Roundtrip&lt;/td&gt;
&lt;td&gt;unter 2 ms&lt;/td&gt;
&lt;td&gt;Der wichtigste Wert: Wie lange braucht eine minimale Abfrage vom Absenden bis zur Antwort?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jitter&lt;/td&gt;
&lt;td&gt;unter 3 ms&lt;/td&gt;
&lt;td&gt;Die Schwankung der Latenz. Ein instabiles Netz fühlt sich für Anwender wie zufälliges Ruckeln an.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Roundtrip unter Last&lt;/td&gt;
&lt;td&gt;höchstens doppelter Einzelwert&lt;/td&gt;
&lt;td&gt;8 parallele Verbindungen simulieren mehrere Anwender. Bricht der Wert ein, gibt es einen Engpass, den ein Einzeltest nie sieht.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Durchsatz&lt;/td&gt;
&lt;td&gt;über 50 MB/s im GBit-LAN&lt;/td&gt;
&lt;td&gt;Wie schnell große Datenmengen fließen, etwa beim Aufbau von Ergebnislisten oder Auswertungen.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;
Dazu kommen einige Prüfungen, die klassische Stolperfallen aufdecken. Der MTU-Test erkennt, ob große Pakete fragmentiert werden. Das ist ein typisches VPN-Problem: Der Ping sieht gut aus, aber der Durchsatz ist miserabel. Das Script prüft außerdem, ob die Verbindung über TCP oder über die deutlich langsameren Named Pipes läuft, und ob die Windows-Anmeldung Kerberos nutzt oder in den NTLM-Fallback rutscht. Letzteres ist ein Hinweis auf einen fehlenden SPN und eine häufige Ursache für zähe Logins.
&lt;/p&gt;
&lt;p&gt;
Optional gibt es noch einen Langzeit-Stabilitätstest. Der feuert über einen wählbaren Zeitraum durchgehend Abfragen ab und zählt Ausreißer über 50 Millisekunden. Damit fangen wir die Fälle, in denen der Durchschnitt gut aussieht, aber alle paar Sekunden ein Hänger auftritt. Dahinter stecken oft Virenscanner, Backups oder WLAN-Roaming.
&lt;/p&gt;
&lt;h2&gt;Die Sage-Praxistests&lt;/h2&gt;
&lt;p&gt;
Der spannendste Teil: Das Script macht genau das, was Deine Anwender den ganzen Tag tun, und stoppt die Zeit dabei.
&lt;/p&gt;
&lt;table class="tech-table"&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Test&lt;/th&gt;
&lt;th&gt;Referenzwert&lt;/th&gt;
&lt;th&gt;Was er verrät&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Artikelsuche „beginnt mit"&lt;/td&gt;
&lt;td&gt;unter 100 ms&lt;/td&gt;
&lt;td&gt;Diese Suche kann einen Index nutzen. Ist sie langsam, stimmt etwas mit Indizes oder Statistiken nicht.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Artikelsuche „enthält"&lt;/td&gt;
&lt;td&gt;unter 300 ms&lt;/td&gt;
&lt;td&gt;So sucht die Sage 100 im Standard. Ein Index hilft hier nicht, die Tabelle wird komplett gelesen. Das ist die Suche, die Deine Anwender als langsam erleben.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Artikel öffnen&lt;/td&gt;
&lt;td&gt;unter 20 ms&lt;/td&gt;
&lt;td&gt;Ein einzelner Datensatz mit allen Spalten. Bei einem gesunden System praktisch sofort da.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ergebnisliste mit 1000 Artikeln&lt;/td&gt;
&lt;td&gt;unter 500 ms&lt;/td&gt;
&lt;td&gt;Der Listenaufbau kombiniert Server-Leistung und Netzwerk-Durchsatz.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;
Der Unterschied zwischen den beiden Suchvarianten ist diagnostisches Gold. Ist „beginnt mit" schnell und „enthält" langsam, arbeitet der Server grundsätzlich sauber und die Tabelle passt nur nicht komplett in den RAM oder das Storage bremst beim Lesen. Sind beide langsam, obwohl das Netzwerk gut aussieht, liegt ein grundsätzliches Serverproblem vor.
&lt;/p&gt;
&lt;p&gt;
Dieselben Tests laufen anschließend auf den Adressen, den Verkaufs- und Einkaufsbelegen und der Buchungserfassung. Als Suchbegriff nimmt das Script entweder einen Begriff, mit dem der Kunde tatsächlich sucht, oder es ermittelt automatisch einen aus den echten Daten. Ein Schreib-Benchmark mit 1000 Einfüge-, Änderungs- und Löschvorgängen misst zusätzlich den Schreibpfad des Servers, wie er auch beim Buchen und Speichern gefordert ist.
&lt;/p&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;Wichtig für Dich: Der Schreib-Benchmark fasst keine einzige Sage-Tabelle an. Er legt eine temporäre Tabelle (&lt;code&gt;#SagePerfWrite&lt;/code&gt;) in der TempDB an, der Arbeitsdatenbank des SQL Servers, schreibt dort seine 1000 Testzeilen und räumt sie am Ende wieder weg. Spätestens beim Trennen der Verbindung ist die Tabelle automatisch verschwunden. Auf Deine Sage-Datenbank greift das Script ausschließlich lesend zu, es wird also kein Artikel, kein Beleg und keine Buchung verändert.&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;Der Blick in den SQL Server&lt;/h2&gt;
&lt;p&gt;
Bis hierhin haben wir gemessen, was der Anwender erlebt. Jetzt schauen wir hinein, warum. Der SQL Server protokolliert intern sehr genau, worauf er wartet, und genau diese Werte liest das Script aus.
&lt;/p&gt;
&lt;table class="tech-table"&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Indikator&lt;/th&gt;
&lt;th&gt;Referenzwert&lt;/th&gt;
&lt;th&gt;Was er verrät&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Page Life Expectancy&lt;/td&gt;
&lt;td&gt;über 3600 s&lt;/td&gt;
&lt;td&gt;Wie lange Daten im RAM bleiben, bevor sie verdrängt werden. Niedrige Werte heißen: Der RAM reicht nicht, der Server liest ständig von der Platte.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IO-Latenz Daten lesen&lt;/td&gt;
&lt;td&gt;unter 10 ms&lt;/td&gt;
&lt;td&gt;Der direkteste Storage-Nachweis. Wie lange dauert ein Lesezugriff auf die Datendateien wirklich?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IO-Latenz Log schreiben&lt;/td&gt;
&lt;td&gt;unter 5 ms&lt;/td&gt;
&lt;td&gt;Das Transaktionslog wird bei jeder Buchung geschrieben. Ist es langsam, ist jedes Speichern in der Sage träge.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WRITELOG-Wartezeit&lt;/td&gt;
&lt;td&gt;unter 2 ms&lt;/td&gt;
&lt;td&gt;Wie lange jeder Commit auf das Log wartet. Der Wert, den Anwender beim Buchen direkt spüren.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Signal Waits&lt;/td&gt;
&lt;td&gt;unter 15 %&lt;/td&gt;
&lt;td&gt;Der Anteil der Wartezeit, in der Abfragen auf einen freien CPU-Kern warten. Hohe Werte heißen: Die CPU ist der Engpass.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Memory Grants Pending&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Abfragen, die gerade auf Arbeitsspeicher warten. Der deutlichste Indikator für akuten RAM-Mangel.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Blockierte Sessions&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Anwender, die gerade von anderen Anwendern oder Prozessen ausgesperrt werden.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Statistiken-Alter&lt;/td&gt;
&lt;td&gt;unter 7 Tage&lt;/td&gt;
&lt;td&gt;Veraltete Statistiken führen zu schlechten Ausführungsplänen. Ein klares Zeichen für fehlende Wartung.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;
Besonders aufschlussreich sind zwei weitere Auswertungen. Die &lt;strong&gt;Lock-Hotspots&lt;/strong&gt; zeigen, an welchen Sage-Tabellen sich die Anwender gegenseitig blockieren, umgerechnet in Wartesekunden pro Tag. Und der Anteil von &lt;strong&gt;ASYNC_NETWORK_IO&lt;/strong&gt; verrät, wie viel Zeit der Server damit verbringt, auf die Clients zu warten. Ein hoher Wert dreht die Verdachtsrichtung komplett um: Nicht der Server ist langsam, sondern die Gegenseite nimmt die Daten nicht schnell genug ab, etwa ein überlasteter Terminalserver.
&lt;/p&gt;
&lt;p&gt;
Das Script schaut außerdem ins Errorlog des SQL Servers. Meldungen wie „I/O requests taking longer than 15 seconds" sind Selbstanzeigen des Servers, dass das Storage massive Aussetzer hatte. Solche Einträge nehmen wir sehr ernst.
&lt;/p&gt;
&lt;h2&gt;Konfiguration, Wartung und Sicherheit&lt;/h2&gt;
&lt;p&gt;
Zum Abschluss prüft das Script gut 30 Einstellungen gegen bewährte Praxiswerte. Ein paar Klassiker, die wir auf vielen Kundensystemen finden:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;AUTO_CLOSE aktiviert:&lt;/strong&gt; Die Datenbank wird nach jeder Verbindung geschlossen und muss neu geöffnet werden. Der Klassiker hinter „die erste Abfrage morgens dauert ewig".&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;max server memory unbegrenzt:&lt;/strong&gt; Der SQL Server nimmt dem Betriebssystem und dem Applikationsserver den RAM weg, wenn beide auf derselben Maschine laufen.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RAM kleiner als die Datenbank:&lt;/strong&gt; Passt die Datenbank nicht in den Speicher, wird ständig von der Platte gelesen. Mehr RAM ist hier fast immer die wirksamste Einzelmaßnahme.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Keine Wartung:&lt;/strong&gt; Fragmentierte Indizes, uralte Statistiken, nie ein DBCC CHECKDB. Das System wird schleichend langsamer, und Korruption würde erst beim Restore auffallen.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Backup-Lücken:&lt;/strong&gt; Recovery Model FULL ohne Log-Sicherungen lässt das Transaktionslog wachsen, bis die Platte voll ist. Das ist dann kein Performance-Problem mehr, sondern ein Stillstand mit Ansage.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;&lt;strong&gt;Was macht eigentlich DBCC CHECKDB?&lt;/strong&gt; Der Befehl ist die Konsistenzprüfung des SQL Servers: Er liest jede einzelne Seite der Datenbank und prüft, ob die physische Struktur und die logischen Verknüpfungen noch stimmen, also Prüfsummen, Indizes, Systemtabellen und die Verkettung der Datenseiten. So fallen schleichende Schäden auf, die zum Beispiel ein Storage-Controller verursacht hat, lange bevor ein Anwender auf die defekte Stelle zugreift. Die Prüfung ist rein lesend und läuft intern über einen Datenbank-Snapshot, sie verändert also nichts. Sie ist aber IO-intensiv und gehört deshalb ins Wartungsfenster. Warum das so wichtig ist: Ein Backup sichert Korruption einfach mit. Wer nie prüft, merkt den Schaden im schlimmsten Fall erst beim Restore, und dann sind auch die Sicherungen der letzten Wochen betroffen.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;
Der Sicherheits-Teil prüft unter anderem den Support-Status der SQL-Server-Version, aktive sa-Konten, triviale Passwörter und riskante Serveroptionen. Das hat mit Performance nichts zu tun, aber wenn wir schon einmal messen, sagen wir Dir auch, wenn dort etwas im Argen liegt.
&lt;/p&gt;
&lt;h2&gt;Die Diagnose: Netzwerk oder Server?&lt;/h2&gt;
&lt;p&gt;
Am Ende verdichtet das Script alle Messwerte zu einer klaren Aussage. Sind die Netzwerkwerte auffällig und die Serverwerte gut, liegt die Ursache auf der Strecke. Ist es umgekehrt, gehört die Aufmerksamkeit dem Server, also RAM, Storage und Wartung. Sind beide Seiten unauffällig und die Sage trotzdem langsam, suchen wir beim Client weiter, etwa beim Virenscanner oder bei AppDesigner-Anpassungen.
&lt;/p&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;Unser Lieblingstrick: Wir führen den Test einmal direkt auf dem SQL Server aus und einmal von einem Sage-Client. Die Differenz der Roundtrip-Latenz ist der reine Netzwerkanteil, sauber isoliert und schwarz auf weiß. Damit ist die Diskussion „Netzwerk oder Server" in zwei Minuten beendet.&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;Start per GUI, Kommandozeile oder Aufgabenplanung&lt;/h2&gt;
&lt;h3&gt;Die grafische Oberfläche&lt;/h3&gt;
&lt;p&gt;
Für alle, die nicht auf der Konsole arbeiten wollen, gibt es eine kleine grafische Oberfläche. Verbindungsdaten eintragen, Mandant wählen, auf „Test starten" klicken, fertig. Die Ausgabe läuft live und farbig mit: OK in Grün, WARNUNG in Gelb, KRITISCH in Rot. Der eigentliche Test läuft dabei in einem eigenen Prozess, die Oberfläche bleibt also jederzeit bedienbar und der Lauf lässt sich abbrechen. Deine Eingaben (außer dem Passwort) merkt sich die GUI für den nächsten Start, und am Ende speicherst Du den fertigen HTML-Bericht mit einem Klick oder öffnest ihn direkt im Browser.
&lt;/p&gt;
&lt;figure class="blog-figure"&gt;
&lt;img src="https://appontes.de/img/blog/sql-performance-gui.png" alt="Die grafische Oberfläche des Sage 100 SQL-Performance-Tests mit Verbindungsdaten und farbiger Live-Ausgabe eines laufenden Tests" loading="lazy"&gt;
&lt;figcaption&gt;Die grafische Oberfläche: Verbindungsdaten oben, darunter die farbige Live-Ausgabe des laufenden Tests&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3&gt;Start über die Kommandozeile&lt;/h3&gt;
&lt;p&gt;
Wer es direkt mag, startet das Script in einer PowerShell. Ein typischer Aufruf mit SQL-Anmeldung sieht so aus:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.\Test-SagePerformance.ps1 -Server "SQLSRV01\SAGE" -Database OLReweAbfDE `
-User sa -Password "geheim" -Mandant 123 `
-HtmlReport C:\Temp\SagePerf.html&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Mit Windows-Anmeldung entfallen Benutzer und Passwort, stattdessen kommt der Schalter &lt;code&gt;-WindowsAuth&lt;/code&gt; dazu. Nützliche optionale Parameter: &lt;code&gt;-SearchTerm&lt;/code&gt; übergibt einen Suchbegriff, mit dem Deine Anwender wirklich suchen, &lt;code&gt;-Rounds&lt;/code&gt; erhöht die Zahl der Messrunden für glattere Werte, &lt;code&gt;-StabilitySeconds 60&lt;/code&gt; aktiviert den Langzeit-Stabilitätstest und &lt;code&gt;-NoAudit&lt;/code&gt; lässt die Audit-Sektionen weg, wenn es nur um die reine Performance geht. Blockiert die Ausführungsrichtlinie den Start, hilft der Aufruf über &lt;code&gt;powershell -ExecutionPolicy Bypass -File .\Test-SagePerformance.ps1 ...&lt;/code&gt;
&lt;/p&gt;
&lt;h3&gt;Automatisch messen mit der Windows-Aufgabenplanung&lt;/h3&gt;
&lt;p&gt;
Richtig wertvoll wird der Test, wenn er regelmäßig läuft. Eine einzelne Messung ist eine Momentaufnahme, eine Messreihe zeigt Trends: Wird die Artikelsuche seit Wochen schleichend langsamer? Bricht die Latenz immer dienstags ein, wenn das Backup läuft? Dafür richtest Du in der Windows-Aufgabenplanung eine Aufgabe ein, die das Script zum Beispiel jeden Werktag um 10 Uhr startet, also mitten in der echten Last.
&lt;/p&gt;
&lt;p&gt;Als Programm trägst Du &lt;code&gt;powershell.exe&lt;/code&gt; ein, als Argumente:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-NoProfile -ExecutionPolicy Bypass -Command "&amp; 'C:\Tools\SQLPerformance\Test-SagePerformance.ps1' -Server 'SQLSRV01\SAGE' -Database OLReweAbfDE -WindowsAuth -Mandant 123 -HtmlReport ('C:\SagePerf\Bericht_{0:yyyy-MM-dd_HHmm}.html' -f (Get-Date))"&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Der Kniff steckt am Ende: Der Zeitstempel wird beim Start in den Dateinamen eingesetzt, jeder Lauf speichert seinen Bericht also automatisch unter einem eigenen Namen. So sammelt sich in &lt;code&gt;C:\SagePerf&lt;/code&gt; eine lückenlose Historie, die Du jederzeit vergleichen kannst. Zwei Hinweise dazu: Lass die Aufgabe unter einem Dienstkonto mit Windows-Anmeldung laufen, dann steht nirgendwo ein Passwort im Klartext. Und aktiviere in der Aufgabe „Unabhängig von der Benutzeranmeldung ausführen", damit die Messung auch ohne angemeldeten Benutzer läuft.
&lt;/p&gt;
&lt;h2&gt;Wofür wir das Script einsetzen&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Erstdiagnose:&lt;/strong&gt; Wenn ein Kunde über eine langsame Sage 100 klagt, ist der Test unser erster Schritt. Nach wenigen Minuten wissen wir, in welcher Ecke wir suchen müssen.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vorher-Nachher-Vergleich:&lt;/strong&gt; Nach einer Optimierung messen wir erneut. So sieht jeder schwarz auf weiß, was die Maßnahme gebracht hat.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gesundheitscheck:&lt;/strong&gt; Bei Neuinstallationen und Serverumzügen prüfen wir, ob die Umgebung sauber konfiguriert ist, bevor die Anwender darauf arbeiten.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Objektive Grundlage:&lt;/strong&gt; Wenn mehrere Dienstleister beteiligt sind, ersetzt der Bericht das gegenseitige Fingerzeigen durch Messwerte.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Deine Sage 100 ist langsam? Lass uns messen.&lt;/h2&gt;
&lt;p&gt;
Wenn sich Deine Sage 100 zäh anfühlt, musst Du das nicht hinnehmen. Und Du musst auch nicht auf Verdacht in neue Hardware investieren. Wir führen den Performance-Test bei Dir aus, besprechen den Bericht gemeinsam und sagen Dir konkret, welche Maßnahmen sich lohnen und welche Du Dir sparen kannst. Oft stecken hinter einem quälend langsamen System nur zwei oder drei Einstellungen.
&lt;/p&gt;
&lt;p&gt;
Auch bei allen anderen Datenbankthemen rund um die Sage 100 helfen wir Dir gern: Langsame Auswertungen, wachsende Transaktionslogs, Blockierungen, Wartungspläne oder ein Backupkonzept, das den Namen verdient. Melde Dich einfach, die Erstanalyse ist unkompliziert und schnell terminiert.
&lt;/p&gt;
&lt;div style="text-align: center; margin: 3rem 0;"&gt;
&lt;a href="https://appontes.de/kontakt/?betreff=anfrage-sage" class="btn btn-primary"&gt;Performance-Check anfragen&lt;/a&gt;
&lt;/div&gt;</content:encoded></item><item><title>Deadlocks im SQL Server: Was da wirklich passiert und wie Du sie loswirst</title><link>https://appontes.de/blog/deadlocks-sql-server-verstehen-vermeiden/</link><guid isPermaLink="true">https://appontes.de/blog/deadlocks-sql-server-verstehen-vermeiden/</guid><pubDate>Tue, 11 Aug 2026 00:00:00 +0000</pubDate><dc:creator>Thomas Falkner</dc:creator><category>Sage 100</category><category>SQL Server</category><category>Performance</category><category>IT-Infrastruktur</category><description>Die Transaktion wurde als Deadlockopfer ausgewählt: Was hinter Fehler 1205 steckt, wie Du Deadlocks mit zwei Query-Fenstern selbst nachstellst und mit welchen Maßnahmen Du sie dauerhaft vermeidest.</description><content:encoded>&lt;p&gt;&lt;img src="https://appontes.de/img/blog/sql-deadlocks.svg" alt="Deadlocks im SQL Server: Was da wirklich passiert und wie Du sie loswirst"&gt;&lt;/p&gt;
&lt;p&gt;
„Die Transaktion (Prozess-ID 52) befand sich in einer Deadlocksituation und wurde als Deadlockopfer ausgewählt. Führen Sie die Transaktion erneut aus." Wenn Deine Anwender diese Meldung sehen, ist gerade ein Vorgang mittendrin abgebrochen worden, eine Buchung, eine Belegerfassung, ein Importlauf oder auch nur eine Auswertung. Die Eingabe ist weg, der Frust ist da. Und weil der Fehler scheinbar zufällig auftritt, mal beim Buchen, mal beim Drucken, mal wochenlang gar nicht, wird er gern als Mysterium abgetan.
&lt;/p&gt;
&lt;p&gt;
Kleiner Service für die Comic-Fans vorweg: Mit Deathlok, dem Cyborg aus dem Marvel-Universum, hat der Deadlock nichts zu tun. Völlig abwegig ist die Verwechslung aber auch nicht, denn in beiden Geschichten taucht am Ende ein gnadenloser Vollstrecker auf und terminiert einen Prozess. Unserer trägt nur den deutlich unscheinbareren Namen Deadlock-Monitor, dazu gleich mehr.
&lt;/p&gt;
&lt;p&gt;
Dabei ist ein Deadlock nichts Mysteriöses. Er ist ein völlig logisches Ergebnis aus zwei Abläufen, die sich gegenseitig blockieren. In diesem Beitrag zeige ich Dir, was dabei wirklich passiert, wie Du einen Deadlock mit zwei Query-Fenstern selbst nachstellst (ganz ohne Sage 100, nur mit SQL Server Management Studio) und mit welchen Maßnahmen Du das Problem dauerhaft in den Griff bekommst.
&lt;/p&gt;
&lt;h2&gt;Was ein Deadlock ist, und was er nicht ist&lt;/h2&gt;
&lt;p&gt;
Zuerst die wichtige Abgrenzung: Eine &lt;strong&gt;Blockierung&lt;/strong&gt; ist normal. Wenn Transaktion A eine Zeile sperrt und Transaktion B dieselbe Zeile ändern will, wartet B einfach, bis A fertig ist. Das dauert vielleicht einen Moment, löst sich aber von selbst auf. Sperren sind kein Fehler, sie sind der Mechanismus, mit dem der SQL Server Deine Daten konsistent hält.
&lt;/p&gt;
&lt;p&gt;
Ein &lt;strong&gt;Deadlock&lt;/strong&gt; ist die Sackgasse daraus: Transaktion A hält Sperre 1 und wartet auf Sperre 2. Transaktion B hält Sperre 2 und wartet auf Sperre 1. Keine der beiden kann jemals weitermachen, egal wie lange sie warten. Der SQL Server erkennt solche Zyklen mit einem eigenen Überwachungsprozess, der standardmäßig alle 5 Sekunden nach ihnen sucht. Findet er einen, beendet er eine der beteiligten Transaktionen zwangsweise, in der Regel die, deren Rollback am billigsten ist. Diese Transaktion ist das „Deadlockopfer" und bekommt den Fehler 1205. Die andere läuft weiter, als wäre nichts gewesen.
&lt;/p&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;Das Wichtigste vorab: Der Abbruch ist kein Bug des SQL Servers, sondern seine Rettungsmaßnahme. Ohne sie würden beide Transaktionen für immer stehen und nach und nach alle anderen Anwender mit in den Stau ziehen. Die eigentliche Ursache liegt immer in den Zugriffsmustern der Anwendungen.&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;Beispiel 1: Der klassische überkreuzte Zugriff&lt;/h2&gt;
&lt;p&gt;
Das stellst Du in fünf Minuten selbst nach. Du brauchst nur eine Testdatenbank und zwei Query-Fenster im Management Studio. Zuerst die Spielwiese:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CREATE TABLE dbo.DemoKonten (
KontoNr INT PRIMARY KEY,
Saldo DECIMAL(18,2) NOT NULL
);
INSERT INTO dbo.DemoKonten (KontoNr, Saldo)
VALUES (1000, 500.00), (2000, 750.00);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Jetzt simulieren wir zwei Umbuchungen, die in entgegengesetzter Reihenfolge auf die Konten zugreifen. In &lt;strong&gt;Fenster 1&lt;/strong&gt; startest Du diese Transaktion (das WAITFOR gibt Dir Zeit, das zweite Fenster zu starten, in echten Anwendungen ist das einfach die Zeit zwischen zwei Statements):
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-- Fenster 1: bucht von Konto 1000 nach 2000
BEGIN TRAN;
UPDATE dbo.DemoKonten SET Saldo = Saldo - 100 WHERE KontoNr = 1000;
WAITFOR DELAY '00:00:10';
UPDATE dbo.DemoKonten SET Saldo = Saldo + 100 WHERE KontoNr = 2000;
COMMIT;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Und während die 10 Sekunden laufen, in &lt;strong&gt;Fenster 2&lt;/strong&gt; die Gegenrichtung:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-- Fenster 2: bucht von Konto 2000 nach 1000
BEGIN TRAN;
UPDATE dbo.DemoKonten SET Saldo = Saldo - 50 WHERE KontoNr = 2000;
UPDATE dbo.DemoKonten SET Saldo = Saldo + 50 WHERE KontoNr = 1000;
COMMIT;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Was passiert: Fenster 1 sperrt die Zeile von Konto 1000. Fenster 2 sperrt die Zeile von Konto 2000 und bleibt dann beim Zugriff auf Konto 1000 hängen, das gehört ja gerade Fenster 1. Nach Ablauf der 10 Sekunden will Fenster 1 an Konto 2000, das Fenster 2 hält. Der Kreis ist geschlossen, keiner kommt mehr weiter. Wenige Sekunden später schlägt der Deadlock-Monitor zu und eines der beiden Fenster zeigt:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Meldung 1205, Ebene 13, Status 51
Die Transaktion (Prozess-ID xx) befand sich in einer Deadlocksituation
und wurde als Deadlockopfer ausgewählt.
Führen Sie die Transaktion erneut aus.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Das andere Fenster läuft sauber durch. Genau dieses Muster steckt hinter den meisten Deadlocks in der Praxis: Zwei Abläufe fassen dieselben Ressourcen in unterschiedlicher Reihenfolge an.
&lt;/p&gt;
&lt;h2&gt;Beispiel 2: Erst lesen, dann schreiben&lt;/h2&gt;
&lt;p&gt;
Das zweite Muster ist heimtückischer, weil beide Sitzungen scheinbar dasselbe Richtige tun. Ein typischer Ablauf in Anwendungen: Erst den aktuellen Stand lesen und prüfen, dann ändern. Führe dieses Skript in &lt;strong&gt;beiden&lt;/strong&gt; Fenstern kurz nacheinander aus:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-- In BEIDEN Fenstern kurz nacheinander starten
BEGIN TRAN;
SELECT Saldo
FROM dbo.DemoKonten WITH (HOLDLOCK)
WHERE KontoNr = 1000;
WAITFOR DELAY '00:00:05';
UPDATE dbo.DemoKonten SET Saldo = Saldo + 10 WHERE KontoNr = 1000;
COMMIT;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Beide Sitzungen bekommen für ihr SELECT eine Lesesperre auf dieselbe Zeile, das ist erlaubt, Lesesperren vertragen sich untereinander. Dann wollen beide auf eine Schreibsperre aufwerten. Und dafür muss jeweils die Lesesperre des anderen verschwinden, was nie passieren wird. Wieder ein perfekter Kreis, wieder Fehler 1205. Man nennt das einen Konvertierungs-Deadlock.
&lt;/p&gt;
&lt;p&gt;
Die Lösung für dieses Muster ist ein Klassiker: Wer liest, um gleich danach zu schreiben, sollte das dem SQL Server sagen. Mit &lt;code&gt;WITH (UPDLOCK)&lt;/code&gt; statt &lt;code&gt;HOLDLOCK&lt;/code&gt; holt sich das SELECT von vornherein eine Update-Sperre. Die zweite Sitzung wartet dann einfach brav, bis die erste fertig ist, aus dem Deadlock wird eine harmlose kurze Blockierung.
&lt;/p&gt;
&lt;p&gt;Zum Aufräumen danach: &lt;code&gt;DROP TABLE dbo.DemoKonten;&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;Woher weiß ich, wer sich verklemmt hat?&lt;/h2&gt;
&lt;p&gt;
Der SQL Server protokolliert jeden Deadlock automatisch, Du musst nichts einschalten. Die Extended-Events-Sitzung &lt;code&gt;system_health&lt;/code&gt; läuft ab Werk mit und zeichnet zu jedem Deadlock einen kompletten Graphen auf: Welche Sitzungen beteiligt waren, welche Statements liefen, welche Sperren auf welchen Objekten sie hielten und wer das Opfer war. So holst Du die letzten Deadlock-Graphen heraus:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT CAST(event_data AS XML).query('(event/data/value/deadlock)[1]') AS DeadlockGraph
FROM sys.fn_xe_file_target_read_file('system_health*.xel', NULL, NULL, NULL)
WHERE object_name = 'xml_deadlock_report';&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Im XML siehst Du unter &lt;code&gt;process&lt;/code&gt; die beteiligten Statements und unter &lt;code&gt;resource-list&lt;/code&gt; die umkämpften Objekte. In Management Studio kannst Du die XML-Datei auch als &lt;code&gt;.xdl&lt;/code&gt; speichern und grafisch öffnen, dann zeigt Dir SSMS die beiden Kontrahenten als Diagramm mit dem Opfer durchgestrichen. Für die Frage „wie oft passiert das bei uns überhaupt" reicht ein Blick auf den Leistungsindikator, den auch unser Performance-Script auswertet, dazu gleich mehr.
&lt;/p&gt;
&lt;h2&gt;Maßnahmen: So wirst Du Deadlocks los&lt;/h2&gt;
&lt;p&gt;
Deadlocks komplett auszuschließen ist in einem System mit vielen gleichzeitigen Anwendern unrealistisch. Aber Du kannst sie von „mehrmals täglich" auf „praktisch nie" drücken. Die Maßnahmen, sortiert nach Wirkung:
&lt;/p&gt;
&lt;table class="tech-table"&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Maßnahme&lt;/th&gt;
&lt;th&gt;Warum sie wirkt&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Gleiche Zugriffsreihenfolge&lt;/td&gt;
&lt;td&gt;Wenn alle Abläufe Tabellen und Zeilen in derselben Reihenfolge anfassen, kann kein Kreis entstehen. Das ist die einzige Maßnahme, die Deadlocks strukturell unmöglich macht. Relevant vor allem für eigene Entwicklungen und Schnittstellen.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Transaktionen kurz halten&lt;/td&gt;
&lt;td&gt;Je kürzer eine Transaktion Sperren hält, desto kleiner das Zeitfenster für eine Verklemmung. Keine Benutzereingaben, keine externen Aufrufe, keine langen Berechnungen innerhalb einer offenen Transaktion.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Passende Indizes&lt;/td&gt;
&lt;td&gt;Fehlt der Index, muss der SQL Server für ein UPDATE die halbe Tabelle durchsuchen und sperrt dabei weit mehr Zeilen als nötig. Jede unnötig gesperrte Zeile ist eine potenzielle Kollisionsfläche. Mehr als einmal haben wir Deadlock-Serien allein durch einen fehlenden Index erklärt.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;UPDLOCK beim Lesen vor dem Schreiben&lt;/td&gt;
&lt;td&gt;Verhindert Konvertierungs-Deadlocks wie in Beispiel 2. Gilt für eigene Prozeduren und Integrationen, die erst prüfen und dann ändern.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Aktuelle Statistiken und Wartung&lt;/td&gt;
&lt;td&gt;Veraltete Statistiken führen zu schlechten Ausführungsplänen, schlechte Pläne zu Scans, Scans zu breiten Sperren. Regelmäßige Wartung ist auch Deadlock-Vorbeugung.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wiederholungslogik in eigener Software&lt;/td&gt;
&lt;td&gt;Fehler 1205 sagt es wörtlich: „Führen Sie die Transaktion erneut aus." Eigene Anwendungen und Schnittstellen sollten den Fehler abfangen und die Transaktion nach kurzer Wartezeit automatisch wiederholen, statt dem Anwender eine Fehlermeldung zu zeigen.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;Ein Wort zu Snapshot-Isolation (RCSI): Damit lesen SELECTs eine Versionskopie statt zu sperren, was Lese-Schreib-Konflikte deutlich entschärft. Bei Standardsoftware wie der Sage 100 ist das aber keine Einstellung zum einfach mal Umlegen. Sie verändert das Sperrverhalten der gesamten Datenbank und gehört vorher mit dem Hersteller beziehungsweise Deinem Sage-Betreuer abgestimmt und getestet.&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;Und in der Sage 100?&lt;/h2&gt;
&lt;p&gt;
In der Sage 100 kannst Du die Abfragen des Standards natürlich nicht umschreiben. Trotzdem bist Du Deadlocks dort nicht ausgeliefert, denn die drei größten Hebel liegen in Deiner Hand: kurze Sperrzeiten durch einen schnellen Server (RAM, Storage, Wartung), gesunde Indizes und Statistiken durch einen ordentlichen Wartungsplan, und saubere Zugriffsmuster in allem, was Ihr selbst an Schnittstellen, AppDesigner-Anpassungen und Zusatztools betreibt. Ein träger Server verlängert jede Transaktion, und je länger die Sperren stehen, desto öfter verklemmen sie sich. Deadlock-Häufigkeit ist damit auch ein Performance-Symptom.
&lt;/p&gt;
&lt;p&gt;
Genau deshalb misst unser &lt;a href="https://appontes.de/blog/sage-100-sql-performance-messen/"&gt;SQL-Performance-Test&lt;/a&gt; beides mit: Er liest die Deadlock-Rate seit dem letzten Serverstart aus (als Wert pro Tag, bewertet mit OK, WARNUNG oder KRITISCH) und zeigt Dir mit den Lock-Hotspots, an welchen Sage-Tabellen sich Deine Anwender tatsächlich stauen, in Wartesekunden pro Tag. Damit siehst Du auf einen Blick, ob Du ein Deadlock-Problem hast und wo Du ansetzen musst.
&lt;/p&gt;
&lt;h2&gt;Das Tool kostenlos herunterladen&lt;/h2&gt;
&lt;p&gt;
Das komplette Performance-Script inklusive grafischer Oberfläche bekommst Du kostenlos gegen eine Newsletter-Anmeldung. Was alle Messwerte im Einzelnen bedeuten, erklärt der &lt;a href="https://appontes.de/blog/sage-100-sql-performance-messen/"&gt;ausführliche Beitrag zum Tool&lt;/a&gt;.
&lt;/p&gt;
&lt;div class="newsletter-box" data-source="blog-deadlocks" data-file="sqlperf"&gt;
&lt;div class="newsletter-box-header"&gt;Kostenloser Download: Sage 100 SQL-Performance-Test&lt;/div&gt;
&lt;div class="newsletter-box-body"&gt;
&lt;p&gt;
Trage Deine E-Mail-Adresse ein und Du bekommst den Download-Link direkt zugeschickt,
zusammen mit unserem Newsletter rund um Sage 100, SQL Server und Praxis-Tools.
Kein Spam, jederzeit mit einem Klick abbestellbar.
&lt;/p&gt;
&lt;form class="newsletter-form" novalidate&gt;
&lt;div class="newsletter-form-grid"&gt;
&lt;div&gt;
&lt;label for="nl-firstname"&gt;Vorname &lt;span class="nl-opt"&gt;(optional)&lt;/span&gt;&lt;/label&gt;
&lt;input type="text" id="nl-firstname" name="first_name" autocomplete="given-name" maxlength="100"&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;label for="nl-lastname"&gt;Nachname &lt;span class="nl-opt"&gt;(optional)&lt;/span&gt;&lt;/label&gt;
&lt;input type="text" id="nl-lastname" name="last_name" autocomplete="family-name" maxlength="100"&gt;
&lt;/div&gt;
&lt;div class="nl-span2"&gt;
&lt;label for="nl-company"&gt;Firma &lt;span class="nl-opt"&gt;(optional)&lt;/span&gt;&lt;/label&gt;
&lt;input type="text" id="nl-company" name="company" autocomplete="organization" maxlength="100"&gt;
&lt;/div&gt;
&lt;div class="nl-span2"&gt;
&lt;label for="nl-email"&gt;E-Mail-Adresse *&lt;/label&gt;
&lt;input type="email" id="nl-email" name="email" placeholder="deine@firma.de"
autocomplete="email" required maxlength="254"&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="nl-hp" aria-hidden="true"&gt;
&lt;label for="nl-website"&gt;Website&lt;/label&gt;
&lt;input type="text" id="nl-website" name="website" tabindex="-1" autocomplete="off"&gt;
&lt;/div&gt;
&lt;div class="newsletter-form-submit"&gt;
&lt;button type="submit" class="btn btn-primary"&gt;Download anfordern&lt;/button&gt;
&lt;/div&gt;
&lt;p class="newsletter-privacy"&gt;
Nach der Anmeldung bekommst Du eine Bestätigungsmail (Double-Opt-In). Erst nach Deinem
Klick auf den Bestätigungslink ist die Anmeldung aktiv und Du erhältst Deinen
persönlichen Download-Link. Details in der
&lt;a href="https://appontes.de/impressum/#datenschutz" target="_blank"&gt;Datenschutzerklärung&lt;/a&gt;.
&lt;/p&gt;
&lt;div class="newsletter-msg newsletter-msg-success" style="display:none"&gt;&lt;/div&gt;
&lt;div class="newsletter-msg newsletter-msg-error" style="display:none"&gt;&lt;/div&gt;
&lt;/form&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;script&gt;
(function() {
var box = document.currentScript.previousElementSibling;
if (!box || !box.classList.contains('newsletter-box')) return;
var form = box.querySelector('.newsletter-form');
var okMsg = box.querySelector('.newsletter-msg-success');
var errMsg = box.querySelector('.newsletter-msg-error');
function show(el, msg) { el.textContent = msg; el.style.display = 'block'; }
function hideAll() { okMsg.style.display = 'none'; errMsg.style.display = 'none'; }
form.addEventListener('submit', function(e) {
e.preventDefault();
hideAll();
var email = form.querySelector('input[name="email"]').value.trim();
var honeypot = form.querySelector('input[name="website"]').value;
if (honeypot) { show(errMsg, 'Fehler bei der Anmeldung.'); return; }
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
show(errMsg, 'Bitte gib eine gültige E-Mail-Adresse ein.');
return;
}
var btn = form.querySelector('button[type="submit"]');
var original = btn.textContent;
btn.textContent = 'Wird gesendet...';
btn.disabled = true;
fetch('/api/csrf.php', { credentials: 'same-origin' })
.then(function(r) {
if (!r.ok) throw new Error('Anmeldung momentan nicht möglich.');
return r.json();
})
.then(function(data) {
return fetch('/api/newsletter/newsletter.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'same-origin',
body: JSON.stringify({
email: email,
first_name: form.querySelector('input[name="first_name"]').value.trim(),
last_name: form.querySelector('input[name="last_name"]').value.trim(),
company: form.querySelector('input[name="company"]').value.trim(),
file: box.getAttribute('data-file') || '',
source: box.getAttribute('data-source') || '',
website: honeypot,
_token: data.token
})
});
})
.then(function(r) {
return r.json().then(function(data) {
if (!r.ok || !data.success) throw new Error(data.error || 'Es ist ein Fehler aufgetreten.');
return data;
});
})
.then(function(data) {
form.reset();
show(okMsg, data.message);
})
.catch(function(err) {
show(errMsg, err.message || 'Es ist ein Fehler aufgetreten. Bitte versuche es später erneut.');
})
.finally(function() {
btn.textContent = original;
btn.disabled = false;
});
});
})();
&lt;/script&gt;
&lt;h2&gt;Deadlocks im Griff? Wir helfen.&lt;/h2&gt;
&lt;p&gt;
Wenn bei Dir regelmäßig Zugriffe mit Fehler 1205 abbrechen, egal ob beim Buchen, in der Belegerfassung, beim Drucken oder in einer Schnittstelle, muss das nicht so bleiben. Wir analysieren die Deadlock-Graphen Deines Servers, finden die beteiligten Abläufe und beheben die Ursache, ob sie im Server, in der Wartung oder in einer Schnittstelle steckt. Auch bei allen anderen SQL-Server-Themen rund um die Sage 100 sind wir gern Dein Ansprechpartner.
&lt;/p&gt;
&lt;div style="text-align: center; margin: 3rem 0;"&gt;
&lt;a href="https://appontes.de/kontakt/?betreff=anfrage-sage" class="btn btn-primary"&gt;Deadlock-Analyse anfragen&lt;/a&gt;
&lt;/div&gt;</content:encoded></item><item><title>Darlehen an ein fremdes Unternehmen buchen: SKR03 und SKR04 auf beiden Seiten bis zur letzten Tilgung</title><link>https://appontes.de/blog/darlehen-unternehmen-skr03-skr04-sage-100/</link><guid isPermaLink="true">https://appontes.de/blog/darlehen-unternehmen-skr03-skr04-sage-100/</guid><pubDate>Mon, 10 Aug 2026 00:00:00 +0000</pubDate><dc:creator>Thomas Falkner</dc:creator><category>Sage 100</category><category>Rechnungswesen</category><category>SKR03</category><category>SKR04</category><description>Ein Unternehmen gibt einem nicht verbundenen Unternehmen ein Darlehen: Welche Konten im SKR03 und SKR04 richtig sind, wie Kreditgeber und Kreditnehmer jede Buchung von der Auszahlung bis zur vollständigen Tilgung erfassen und wie Du das im Sage 100 Rechnungswesen sauber umsetzt.</description><content:encoded>&lt;p&gt;&lt;img src="https://appontes.de/img/blog/darlehen-unternehmen-skr03-skr04.svg" alt="Darlehen an ein fremdes Unternehmen buchen: SKR03 und SKR04 auf beiden Seiten bis zur letzten Tilgung"&gt;&lt;/p&gt;
&lt;p&gt;
Nicht jeder Kredit kommt von der Bank. In der Praxis leiht ein Unternehmen einem anderen durchaus direkt Geld, etwa einem langjährigen Lieferanten, der eine Investition stemmen muss, oder einem Geschäftspartner in einer Wachstumsphase. Buchhalterisch ist das gut beherrschbar, wenn man von Anfang an die richtigen Konten wählt. Genau da passieren aber die meisten Fehler, denn die Kontenrahmen SKR03 und SKR04 unterscheiden sehr genau danach, wer der Vertragspartner ist.
&lt;/p&gt;
&lt;p&gt;
Dieser Beitrag zeigt den kompletten Lebenszyklus eines Darlehens zwischen zwei Unternehmen, die weder verbunden sind noch in einem Beteiligungsverhältnis stehen. Und zwar konsequent aus beiden Blickwinkeln: Der Kreditgeber bucht eine Forderung und Zinserträge, der Kreditnehmer eine Verbindlichkeit und Zinsaufwand. Alle Buchungssätze führen wir von der Auszahlung bis zur vollständigen Tilgung durch, jeweils mit den passenden Konten im SKR03 und SKR04. Zum Schluss geht es um die Umsetzung im Sage 100 Rechnungswesen.
&lt;/p&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;
&lt;strong&gt;Wichtig vorweg:&lt;/strong&gt; Dieser Beitrag ist eine fachliche Orientierung aus der ERP- und Rechnungswesenpraxis, keine Steuer- oder Rechtsberatung. Darlehensverträge zwischen Unternehmen sollten schriftlich geschlossen und mit der Steuerberatung abgestimmt werden. Relevante Grundlagen sind unter anderem der Bilanzausweis nach § 266 HGB, die Gliederung der GuV nach § 275 HGB und die Steuerbefreiung der Kreditgewährung nach § 4 Nr. 8 Buchst. a UStG.
&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;1. Der Ausgangsfall&lt;/h2&gt;
&lt;p&gt;
Die Alpha Maschinenbau GmbH gewährt der Beta Logistik GmbH ein Darlehen. Die beiden Unternehmen sind wirtschaftlich nicht verbunden: Es besteht keine Beteiligung, kein Konzernverhältnis und keine gesellschaftsrechtliche Nähe. Es handelt sich schlicht um zwei fremde Dritte mit einem Darlehensvertrag.
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Darlehensbetrag: 100.000,00 EUR&lt;/li&gt;
&lt;li&gt;Auszahlung: 02.01.2026 per Banküberweisung&lt;/li&gt;
&lt;li&gt;Laufzeit: 4 Jahre&lt;/li&gt;
&lt;li&gt;Zinssatz: 4,0 % pro Jahr, nachschüssig zahlbar zum 31.12.&lt;/li&gt;
&lt;li&gt;Tilgung: 25.000,00 EUR jährlich zum 31.12. (Ratentilgung)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Die Zinsen werden jeweils auf die Restschuld des laufenden Jahres berechnet. Daraus ergibt sich dieser Zins- und Tilgungsplan:
&lt;/p&gt;
&lt;table class="tech-table"&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Jahr&lt;/th&gt;
&lt;th&gt;Restschuld 01.01.&lt;/th&gt;
&lt;th&gt;Zinsen 4,0 %&lt;/th&gt;
&lt;th&gt;Tilgung&lt;/th&gt;
&lt;th&gt;Restschuld 31.12.&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2026&lt;/td&gt;
&lt;td&gt;100.000,00 EUR&lt;/td&gt;
&lt;td&gt;4.000,00 EUR&lt;/td&gt;
&lt;td&gt;25.000,00 EUR&lt;/td&gt;
&lt;td&gt;75.000,00 EUR&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2027&lt;/td&gt;
&lt;td&gt;75.000,00 EUR&lt;/td&gt;
&lt;td&gt;3.000,00 EUR&lt;/td&gt;
&lt;td&gt;25.000,00 EUR&lt;/td&gt;
&lt;td&gt;50.000,00 EUR&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2028&lt;/td&gt;
&lt;td&gt;50.000,00 EUR&lt;/td&gt;
&lt;td&gt;2.000,00 EUR&lt;/td&gt;
&lt;td&gt;25.000,00 EUR&lt;/td&gt;
&lt;td&gt;25.000,00 EUR&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2029&lt;/td&gt;
&lt;td&gt;25.000,00 EUR&lt;/td&gt;
&lt;td&gt;1.000,00 EUR&lt;/td&gt;
&lt;td&gt;25.000,00 EUR&lt;/td&gt;
&lt;td&gt;0,00 EUR&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;
Über die Laufzeit fließen also 100.000,00 EUR Tilgung und 10.000,00 EUR Zinsen. Wir rechnen bewusst mit einer Ratentilgung, weil Zins und Tilgung dort sauber getrennt sichtbar sind. Bei einem Annuitätendarlehen wäre die Jahresrate konstant und die Aufteilung in Zins und Tilgung würde sich jedes Jahr verschieben. An den Konten und an der Buchungslogik ändert das nichts, nur an den Beträgen pro Jahr.
&lt;/p&gt;
&lt;p&gt;
Einen solchen Tilgungsplan musst Du übrigens nicht von Hand rechnen: Unser kostenloser &lt;a href="https://appontes.de/tools/zins-tilgungsrechner/"&gt;Zins- und Tilgungsrechner&lt;/a&gt; erstellt ihn für beliebige Beträge, Zinssätze und Laufzeiten, wahlweise als Ratentilgung oder Annuität. Er erzeugt auf Knopfdruck auch gleich die Buchungssätze aus diesem Beitrag mit Deinen eigenen Zahlen.
&lt;/p&gt;
&lt;h2&gt;2. Die Kontenwahl: Warum "nicht verbunden" entscheidend ist&lt;/h2&gt;
&lt;p&gt;
SKR03 und SKR04 halten für Ausleihungen und Darlehen ganze Kontengruppen bereit, die nach dem Verhältnis zum Vertragspartner unterscheiden. Es gibt eigene Konten für verbundene Unternehmen, für Unternehmen mit Beteiligungsverhältnis, für Gesellschafter und für nahestehende Personen. Diese Unterscheidung ist kein Selbstzweck: Sie steuert den Bilanzausweis und die Zuordnung in der GuV, die das HGB für diese Fälle getrennt verlangt.
&lt;/p&gt;
&lt;p&gt;
Für unseren Fall zweier fremder Dritter gilt deshalb: Finger weg von Konten wie 0505 (SKR03) oder 0810 (SKR04), die für Ausleihungen an verbundene Unternehmen reserviert sind. Richtig sind die neutralen Darlehenskonten:
&lt;/p&gt;
&lt;table class="tech-table"&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Sachverhalt&lt;/th&gt;
&lt;th&gt;SKR03&lt;/th&gt;
&lt;th&gt;SKR04&lt;/th&gt;
&lt;th&gt;Ausweis&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Kreditgeber: Darlehensforderung&lt;/td&gt;
&lt;td&gt;0550 Darlehen&lt;/td&gt;
&lt;td&gt;0940 Darlehen&lt;/td&gt;
&lt;td&gt;Finanzanlagen, sonstige Ausleihungen&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kreditgeber: Zinsertrag&lt;/td&gt;
&lt;td&gt;2621 Erträge aus Ausleihungen des Finanzanlagevermögens&lt;/td&gt;
&lt;td&gt;7011 Erträge aus Ausleihungen des Finanzanlagevermögens&lt;/td&gt;
&lt;td&gt;GuV, Finanzergebnis&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kreditnehmer: Darlehensverbindlichkeit&lt;/td&gt;
&lt;td&gt;1705 Darlehen&lt;/td&gt;
&lt;td&gt;3560 Darlehen&lt;/td&gt;
&lt;td&gt;Sonstige Verbindlichkeiten&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kreditnehmer: Zinsaufwand&lt;/td&gt;
&lt;td&gt;2120 Zinsaufwendungen für langfristige Verbindlichkeiten&lt;/td&gt;
&lt;td&gt;7320 Zinsaufwendungen für langfristige Verbindlichkeiten&lt;/td&gt;
&lt;td&gt;GuV, Finanzergebnis&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Beide Seiten: Bank&lt;/td&gt;
&lt;td&gt;1200 Bank&lt;/td&gt;
&lt;td&gt;1800 Bank&lt;/td&gt;
&lt;td&gt;Umlaufvermögen&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;
Zwei Hinweise zur Einordnung. Erstens: Bei einer von vornherein auf vier Jahre angelegten Ausleihung wird das Darlehen regelmäßig dem Finanzanlagevermögen zugeordnet, sofern es nach der Zweckbestimmung dazu bestimmt ist, dem Geschäftsbetrieb dauerhaft zu dienen. Maßgeblich ist also nicht die Laufzeit allein, sondern die Zweckbestimmung bei Hingabe des Darlehens (§ 247 Abs. 2 HGB), für die eine mehrjährige Laufzeit ein starkes Indiz ist. Alternativ zur 0550 (SKR03) beziehungsweise 0940 (SKR04) kommt auch das Sammelkonto 0540 beziehungsweise 0930 für übrige sonstige Ausleihungen infrage. Wird das Geld dagegen von vornherein nur kurzfristig zur Verfügung gestellt, etwa als Überbrückung für wenige Monate, gehört die Forderung regelmäßig ins Umlaufvermögen. § 266 HGB trennt beide Fälle ausdrücklich: Sonstige Ausleihungen stehen im Finanzanlagevermögen, sonstige Vermögensgegenstände im Umlaufvermögen. Als Konten kommen dann zum Beispiel 1550 (SKR03) beziehungsweise 1360 (SKR04) in Betracht, die konkrete Kontierung hängt aber von der Kontenzuordnung im eingesetzten Kontenrahmen ab. Die Zinsen gehören in diesem Fall auf das Konto für sonstige Zinsen und ähnliche Erträge (SKR03 2650, SKR04 7100).
&lt;/p&gt;
&lt;p&gt;
Zweitens: Beim Kreditnehmer ist der Kredit gerade keine Verbindlichkeit gegenüber Kreditinstituten, denn die Alpha Maschinenbau GmbH ist keine Bank. Er gehört zu den sonstigen Verbindlichkeiten. Wer ihn auf einem Bankdarlehenskonto erfasst, verfälscht den Bilanzausweis und die Kennzahlen zur Bankverschuldung.
&lt;/p&gt;
&lt;h2&gt;3. Die Auszahlung am 02.01.2026&lt;/h2&gt;
&lt;p&gt;
Beim &lt;strong&gt;Kreditgeber&lt;/strong&gt; ist die Auszahlung ein reiner Aktivtausch: Bankguthaben wird zu einer Darlehensforderung. Ertrag entsteht dabei noch keiner.
&lt;/p&gt;
&lt;p&gt;SKR03:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0550 Darlehen 100.000,00 EUR
an 1200 Bank 100.000,00 EUR&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;SKR04:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0940 Darlehen 100.000,00 EUR
an 1800 Bank 100.000,00 EUR&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Beim &lt;strong&gt;Kreditnehmer&lt;/strong&gt; spiegelt sich der Vorgang: Das Bankguthaben steigt, gleichzeitig entsteht eine Verbindlichkeit in gleicher Höhe. Auch hier entsteht weder Ertrag noch Aufwand, die Bilanz verlängert sich lediglich.
&lt;/p&gt;
&lt;p&gt;SKR03:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1200 Bank 100.000,00 EUR
an 1705 Darlehen 100.000,00 EUR&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;SKR04:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1800 Bank 100.000,00 EUR
an 3560 Darlehen 100.000,00 EUR&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;4. Zins und Tilgung im ersten Jahr&lt;/h2&gt;
&lt;p&gt;
Zum 31.12.2026 zahlt die Beta Logistik GmbH 29.000,00 EUR: 4.000,00 EUR Zinsen auf die Restschuld von 100.000,00 EUR und 25.000,00 EUR Tilgung. Auch wenn das Geld in einer Überweisung ankommt, gehören in die Buchhaltung zwei getrennte Vorgänge, denn nur die Zinsen sind Ertrag beziehungsweise Aufwand. Die Tilgung berührt die GuV auf beiden Seiten nicht.
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Kreditgeber&lt;/strong&gt;, SKR03:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Zinszahlung 31.12.2026
1200 Bank 4.000,00 EUR
an 2621 Erträge aus Ausleihungen
des Finanzanlagevermögens 4.000,00 EUR
Tilgung 31.12.2026
1200 Bank 25.000,00 EUR
an 0550 Darlehen 25.000,00 EUR&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Kreditgeber&lt;/strong&gt;, SKR04:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Zinszahlung 31.12.2026
1800 Bank 4.000,00 EUR
an 7011 Erträge aus Ausleihungen
des Finanzanlagevermögens 4.000,00 EUR
Tilgung 31.12.2026
1800 Bank 25.000,00 EUR
an 0940 Darlehen 25.000,00 EUR&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Kreditnehmer&lt;/strong&gt;, SKR03:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Zinszahlung 31.12.2026
2120 Zinsaufwendungen für
langfristige Verbindlichkeiten 4.000,00 EUR
an 1200 Bank 4.000,00 EUR
Tilgung 31.12.2026
1705 Darlehen 25.000,00 EUR
an 1200 Bank 25.000,00 EUR&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Kreditnehmer&lt;/strong&gt;, SKR04:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Zinszahlung 31.12.2026
7320 Zinsaufwendungen für
langfristige Verbindlichkeiten 4.000,00 EUR
an 1800 Bank 4.000,00 EUR
Tilgung 31.12.2026
3560 Darlehen 25.000,00 EUR
an 1800 Bank 25.000,00 EUR&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Nach diesen Buchungen weist das Darlehenskonto auf beiden Seiten noch 75.000,00 EUR aus. Der Saldo muss auf den Cent mit dem Tilgungsplan übereinstimmen. Diese Abstimmung lohnt sich jedes Jahr, denn sie deckt sofort auf, wenn versehentlich eine Rate komplett als Aufwand oder komplett als Tilgung gebucht wurde.
&lt;/p&gt;
&lt;h2&gt;5. Alle weiteren Buchungen bis zur vollständigen Tilgung&lt;/h2&gt;
&lt;p&gt;
Die Folgejahre laufen nach demselben Muster, nur die Zinsbeträge sinken mit der Restschuld. Damit nichts fehlt, hier jede einzelne Buchung der Jahre 2027 bis 2029. Die Kontenpaare sind jeweils als SKR03 / SKR04 angegeben:
&lt;/p&gt;
&lt;table class="tech-table"&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Datum&lt;/th&gt;
&lt;th&gt;Vorgang&lt;/th&gt;
&lt;th&gt;Kreditgeber (Soll an Haben)&lt;/th&gt;
&lt;th&gt;Kreditnehmer (Soll an Haben)&lt;/th&gt;
&lt;th&gt;Betrag&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;31.12.2027&lt;/td&gt;
&lt;td&gt;Zinsen auf 75.000,00 EUR&lt;/td&gt;
&lt;td&gt;1200 / 1800 an 2621 / 7011&lt;/td&gt;
&lt;td&gt;2120 / 7320 an 1200 / 1800&lt;/td&gt;
&lt;td&gt;3.000,00 EUR&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;31.12.2027&lt;/td&gt;
&lt;td&gt;Tilgung&lt;/td&gt;
&lt;td&gt;1200 / 1800 an 0550 / 0940&lt;/td&gt;
&lt;td&gt;1705 / 3560 an 1200 / 1800&lt;/td&gt;
&lt;td&gt;25.000,00 EUR&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;31.12.2028&lt;/td&gt;
&lt;td&gt;Zinsen auf 50.000,00 EUR&lt;/td&gt;
&lt;td&gt;1200 / 1800 an 2621 / 7011&lt;/td&gt;
&lt;td&gt;2120 / 7320 an 1200 / 1800&lt;/td&gt;
&lt;td&gt;2.000,00 EUR&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;31.12.2028&lt;/td&gt;
&lt;td&gt;Tilgung&lt;/td&gt;
&lt;td&gt;1200 / 1800 an 0550 / 0940&lt;/td&gt;
&lt;td&gt;1705 / 3560 an 1200 / 1800&lt;/td&gt;
&lt;td&gt;25.000,00 EUR&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;31.12.2029&lt;/td&gt;
&lt;td&gt;Zinsen auf 25.000,00 EUR&lt;/td&gt;
&lt;td&gt;1200 / 1800 an 2621 / 7011&lt;/td&gt;
&lt;td&gt;2120 / 7320 an 1200 / 1800&lt;/td&gt;
&lt;td&gt;1.000,00 EUR&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;31.12.2029&lt;/td&gt;
&lt;td&gt;Schlusstilgung&lt;/td&gt;
&lt;td&gt;1200 / 1800 an 0550 / 0940&lt;/td&gt;
&lt;td&gt;1705 / 3560 an 1200 / 1800&lt;/td&gt;
&lt;td&gt;25.000,00 EUR&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;
Mit der Schlusstilgung am 31.12.2029 ist das Darlehen vollständig getilgt. Das Darlehenskonto steht auf beiden Seiten auf null: Beim Kreditgeber ist aus der Ausleihung wieder Bankguthaben geworden, beim Kreditnehmer ist die Verbindlichkeit erloschen. In der GuV bleiben über die Gesamtlaufzeit 10.000,00 EUR Zinsertrag beim Geber und 10.000,00 EUR Zinsaufwand beim Nehmer.
&lt;/p&gt;
&lt;h2&gt;6. Sonderfall Zinsabgrenzung: Wenn der Zinstermin nicht aufs Jahresende fällt&lt;/h2&gt;
&lt;p&gt;
In unserem Beispiel fallen Zinstermin und Bilanzstichtag zusammen, deshalb ist keine Abgrenzung nötig. Läge der Zinstermin zum Beispiel am 30.06., müssten beide Seiten zum 31.12. die wirtschaftlich verursachten, aber noch nicht gezahlten Zinsen des zweiten Halbjahres abgrenzen. Der Kreditgeber aktiviert die anteilige Zinsforderung als sonstigen Vermögensgegenstand:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SKR03: 1500 Sonstige Vermögensgegenstände an 2621
SKR04: 1300 Sonstige Vermögensgegenstände an 7011&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Der Kreditnehmer passiviert spiegelbildlich eine sonstige Verbindlichkeit:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SKR03: 2120 an 1700 Sonstige Verbindlichkeiten
SKR04: 7320 an 3500 Sonstige Verbindlichkeiten&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
In der Praxis wird eine solche Abschlussbuchung häufig zum 01.01. des Folgejahres automatisch storniert und die tatsächliche Zinszahlung anschließend vollständig gebucht. In Sage 100 bietet sich dafür eine Stornobuchung zum Jahresanfang oder eine feste Buchungsvorlage an, damit die Auflösung nicht vergessen wird.
&lt;/p&gt;
&lt;h2&gt;7. Umsatzsteuer: Zinsen ohne Steuer buchen&lt;/h2&gt;
&lt;p&gt;
Die Gewährung von Krediten ist nach § 4 Nr. 8 Buchst. a UStG steuerfrei. Auf die Zinsen fällt also keine Umsatzsteuer an und der Kreditnehmer hat keinen Vorsteuerabzug aus den Zinszahlungen. In der Praxis heißt das: Alle gezeigten Buchungen laufen ohne Steuerschlüssel beziehungsweise mit dem Schlüssel für steuerfreie Umsätze. Wer die Zinserträge versehentlich auf ein Erlöskonto mit Automatikfunktion bucht, produziert falsche Umsatzsteuer, deshalb gehören sie konsequent auf die Zinsertragskonten aus der Tabelle oben.
&lt;/p&gt;
&lt;p&gt;
Ein Randthema, das leicht unterschätzt wird: Auch einzelne oder gelegentliche Darlehensgewährungen können Auswirkungen auf den Vorsteuerabzug haben. Ob ein Finanzumsatz als Hilfsumsatz behandelt werden kann und deshalb bei einer Vorsteueraufteilung außer Betracht bleibt, hängt von den konkreten Umständen ab und sollte bei wesentlichen Beträgen steuerlich geprüft werden.
&lt;/p&gt;
&lt;h2&gt;8. Umsetzung im Sage 100 Rechnungswesen&lt;/h2&gt;
&lt;p&gt;
Fachlich ist damit alles geklärt, jetzt zur Technik. Im Sage 100 Rechnungswesen bildest Du den kompletten Ablauf über Sachkontenbuchungen ab. Ein paar Punkte machen die Umsetzung angenehm:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Kontenrahmen:&lt;/strong&gt; Sage 100 liefert SKR03 und SKR04 als Standardkontenrahmen mit. Die hier verwendeten Konten sind vorhanden oder lassen sich mit wenigen Klicks anlegen. Prüfe bei eigenen Konten die Zuordnung zur Bilanzposition, damit Auswertung und Jahresabschluss stimmen.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Buchungserfassung:&lt;/strong&gt; Auszahlung, Zins und Tilgung buchst Du in der Dialogbuchhaltung als Sachkontenbuchungen. Ein Personenkonto brauchst Du nicht, denn es handelt sich weder um eine Lieferung noch um eine Leistung mit offenem Posten.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Wiederkehrende Buchungen:&lt;/strong&gt; Zins- und Tilgungsbuchungen kehren jährlich mit bekannten Beträgen wieder. Dafür eignen sich Buchungsvorlagen oder wiederkehrende Buchungen, wie wir sie im Beitrag über &lt;a href="https://appontes.de/blog/wiederkehrende-buchungen-sage-100/"&gt;wiederkehrende Buchungen in Sage 100&lt;/a&gt; ausführlich beschrieben haben. Den kompletten Tilgungsplan kannst Du so einmal hinterlegen und jedes Jahr nur noch prüfen und freigeben.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Abstimmung:&lt;/strong&gt; Der Saldo des Darlehenskontos in der Summen- und Saldenliste muss jederzeit der Restschuld laut Tilgungsplan entsprechen. Diese Kontrolle gehört bei uns fest in die Jahresabschluss-Checkliste, zusammen mit einer Saldenbestätigung des Vertragspartners.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Belegablage:&lt;/strong&gt; Darlehensvertrag, Zahlungsnachweise und Tilgungsplan gehören als Belege zu den Buchungen. Bei einer Betriebsprüfung ist der Vertrag das erste Dokument, nach dem gefragt wird, gerade bei Krediten außerhalb des Bankensektors.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Wenn Du beim Kontieren schnell nachschlagen willst, welche Konten es rund um Darlehen und Ausleihungen gibt: Unser kostenloses &lt;a href="https://appontes.de/tools/kontenrahmen/"&gt;SKR04-Kontenrahmen-Tool&lt;/a&gt; und das &lt;a href="https://appontes.de/tools/kontenrahmen-skr03/"&gt;SKR03-Tool&lt;/a&gt; durchsuchen beide Kontenrahmen im Browser, mit dem &lt;a href="https://appontes.de/tools/kontenvergleich/"&gt;Kontenvergleich&lt;/a&gt; findest Du zu jedem SKR03-Konto die SKR04-Entsprechung.
&lt;/p&gt;
&lt;h2&gt;9. Häufige Fehler aus der Praxis&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Falsche Kontengruppe:&lt;/strong&gt; Das Darlehen landet auf einem Konto für verbundene Unternehmen oder Gesellschafter, obwohl keinerlei Verbindung besteht. Der Bilanzausweis ist damit falsch.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rate nicht aufgeteilt:&lt;/strong&gt; Die Jahresrate wird in einer Summe als Tilgung oder komplett als Zinsaufwand gebucht. Ergebnis und Restschuld stimmen dann beide nicht mehr.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Kredit als Bankverbindlichkeit:&lt;/strong&gt; Der Kreditnehmer bucht auf Verbindlichkeiten gegenüber Kreditinstituten. Das verzerrt Kennzahlen und Bankauswertungen.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Umsatzsteuer auf Zinsen:&lt;/strong&gt; Zinserträge laufen über ein Automatikkonto mit Steuerfunktion und lösen ungewollt Umsatzsteuer aus.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fehlender Vertrag:&lt;/strong&gt; Ohne schriftlichen Vertrag mit Laufzeit, Zinssatz und Tilgungsplan wird es in der Betriebsprüfung unangenehm, auch zwischen fremden Dritten.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;10. Fazit&lt;/h2&gt;
&lt;p&gt;
Ein Darlehen zwischen zwei nicht verbundenen Unternehmen ist buchhalterisch überschaubar, wenn drei Dinge stimmen. Die Kontenwahl muss zum Verhältnis der Vertragspartner passen, beim Geber als sonstige Ausleihung im Finanzanlagevermögen, beim Nehmer als sonstige Verbindlichkeit. Zins und Tilgung müssen bei jeder Rate getrennt gebucht werden, weil nur die Zinsen die GuV berühren. Und der Saldo des Darlehenskontos muss über die gesamte Laufzeit mit dem Tilgungsplan abstimmbar sein. Mit Buchungsvorlagen und wiederkehrenden Buchungen erledigt das Sage 100 Rechnungswesen den wiederkehrenden Teil fast von allein.
&lt;/p&gt;
&lt;p&gt;
Du willst Darlehen, Abgrenzungen oder andere Sonderfälle in Deiner Sage 100 Finanzbuchhaltung sauber aufsetzen? Dann sprich uns an, wir schauen gemeinsam auf Deine Prozesse.
&lt;/p&gt;
&lt;div style="text-align: center; margin: 3rem 0;"&gt;
&lt;a href="https://appontes.de/kontakt/?betreff=anfrage-sage" class="btn btn-primary"&gt;Buchhaltungsprozess in Sage 100 besprechen&lt;/a&gt;
&lt;/div&gt;</content:encoded></item><item><title>Mahngebühren richtig buchen: Ohne Umsatzsteuer, ohne Skonto-Trick, mit sauberem Offenen Posten</title><link>https://appontes.de/blog/mahngebuehren-buchen-skr03-skr04-sage-100/</link><guid isPermaLink="true">https://appontes.de/blog/mahngebuehren-buchen-skr03-skr04-sage-100/</guid><pubDate>Sat, 08 Aug 2026 00:00:00 +0000</pubDate><dc:creator>Thomas Falkner</dc:creator><category>Sage 100</category><category>Rechnungswesen</category><category>Mahnwesen</category><category>Umsatzsteuer</category><description>Der Kunde zahlt tatsächlich die Mahngebühr, und jetzt? Warum Mahngebühren als echter Schadensersatz ohne Umsatzsteuer bleiben, weshalb der Umweg über negativen Skonto oder das Ausziffern Geld kostet und wie Du Mahngebühren und Verzugszinsen in SKR03, SKR04 und Sage 100 sauber über Offene Posten buchst.</description><content:encoded>&lt;p&gt;&lt;img src="https://appontes.de/img/blog/mahngebuehren-buchen.svg" alt="Mahngebühren richtig buchen: Ohne Umsatzsteuer, ohne Skonto-Trick, mit sauberem Offenen Posten"&gt;&lt;/p&gt;
&lt;p&gt;
Das Mahnwesen nimmt in vielen Buchhaltungen einen immer größeren Raum ein. Zahlungsziele werden ausgereizt, die Zahl der Mahnläufe steigt und mit ihnen stehen Mahngebühren und Verzugszinsen auf dem Papier. In der Praxis werden diese Beträge vom Kunden allerdings selten bezahlt, und Hand aufs Herz: Konsequent eingebucht werden sie bei den meisten auch nicht.
&lt;/p&gt;
&lt;p&gt;
Spannend wird es in dem Moment, in dem ein Kunde die Mahngebühr tatsächlich überweist. Dann liegt plötzlich eine Überzahlung auf dem Offenen Posten und die Frage lautet: Wohin damit? Dieser Beitrag zeigt, warum Mahngebühren ohne Umsatzsteuer bleiben, welche verbreiteten Abkürzungen Dich bares Geld kosten und wie die saubere Variante über ein eigenes Konto und einen Offenen Posten aussieht, mit den passenden Konten in SKR03 und SKR04 und der Umsetzung im Sage 100 Rechnungswesen.
&lt;/p&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;
&lt;strong&gt;Wichtig vorweg:&lt;/strong&gt; Dieser Beitrag ist eine fachliche Orientierung aus der ERP- und Rechnungswesenpraxis, keine Steuer- oder Rechtsberatung. Relevante Grundlagen sind unter anderem der Verzug nach § 286 BGB, die Verzugszinsen nach § 288 BGB und die umsatzsteuerliche Einordnung von Schadensersatz in Abschnitt 1.3 des Umsatzsteuer-Anwendungserlasses (UStAE). Sonderfälle gehören in die Abstimmung mit der Steuerberatung.
&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;1. Die Einordnung: Mahngebühren sind echter Schadensersatz&lt;/h2&gt;
&lt;p&gt;
Eine Mahngebühr ist kein Entgelt für eine Lieferung oder Leistung. Der Kunde bekommt für die Gebühr nichts, sie gleicht lediglich den Schaden aus, der Dir durch den Zahlungsverzug entsteht. Umsatzsteuerlich wird sie deshalb regelmäßig als echter Schadensersatz eingeordnet und ist damit nicht steuerbar. Das Gleiche gilt für Verzugszinsen.
&lt;/p&gt;
&lt;p&gt;
Für die Praxis heißt das: Auf Mahngebühren wird keine Umsatzsteuer erhoben, keine ausgewiesen und keine abgeführt. Eine Mahnung mit ausgewiesener Umsatzsteuer auf die Gebühr wäre sogar riskant, denn unrichtig ausgewiesene Steuer wird nach § 14c UStG geschuldet. Vorsicht bei der Abgrenzung: Pauschalen, hinter denen tatsächlich eine eigene Leistung steht, etwa vertraglich vereinbarte Bearbeitungs- oder Serviceleistungen, können anders zu beurteilen sein. Ob im Einzelfall echter Schadensersatz oder ein Leistungsentgelt vorliegt, hängt von den konkreten Umständen ab und sollte bei wesentlichen Beträgen steuerlich geprüft werden.
&lt;/p&gt;
&lt;h2&gt;2. Die verbreitete Abkürzung: Mahngebühr als negativer Skonto&lt;/h2&gt;
&lt;p&gt;
Eine häufig zu beobachtende Verfahrensweise geht so: Der Kunde überweist Rechnungsbetrag plus Mahngebühr, der Buchhalter gleicht den Offenen Posten aus und erfasst die Überzahlung kurzerhand als negativen Skonto. Der Zahlungsausgleich ist damit erledigt und der OP ist zu. Bequem, aber gleich doppelt teuer.
&lt;/p&gt;
&lt;p&gt;
Erstens rechnet die Skontofunktion steuerlich: Skonto ist eine Entgeltminderung, die Erlöse und Umsatzsteuer korrigiert. Ein negativer Skonto wirkt entsprechend als Entgelterhöhung, erzeugt also zusätzliche Erlöse und zusätzliche Umsatzsteuer. Aus der nicht steuerbaren Mahngebühr von 10,00 EUR werden so 8,40 EUR Erlös und 1,60 EUR Umsatzsteuer, die Du ohne Not ans Finanzamt zahlst.
&lt;/p&gt;
&lt;p&gt;
Zweitens ruinierst Du Dir die Auswertung: Wer Skontoerträge und Skontoaufwendungen analysieren will, findet in den Konten plötzlich Mahngebühren mit umgekehrtem Vorzeichen. Die Aussage, wie viel Skonto tatsächlich gewährt wurde, ist damit dahin.
&lt;/p&gt;
&lt;h2&gt;3. Genauso problematisch: Ausziffern auf ein Erlöskonto&lt;/h2&gt;
&lt;p&gt;
Die zweite Abkürzung sieht ähnlich aus. Beim Zahlungsausgleich wird die Überzahlung über die Auszifferung direkt auf ein Erlöskonto gebucht, oft auf das Konto der ursprünglichen Rechnung. Auch hier entsteht eine Erlösbuchung inklusive Umsatzsteuer, denn das Erlöskonto bringt seinen Steuerschlüssel mit. Das Ergebnis ist dasselbe wie beim negativen Skonto: Steuer auf einen Betrag, der nicht steuerbar ist, und verfälschte Erlöskonten obendrein.
&lt;/p&gt;
&lt;h2&gt;4. Der saubere Weg: Eigenes Konto und Offener Posten für die Mahngebühr&lt;/h2&gt;
&lt;p&gt;
Richtig läuft es über ein eigenes Ertragskonto ohne Steuerschlüssel. Dem Grunde nach ist die vereinnahmte Mahngebühr ein sonstiger betrieblicher Ertrag, kein Umsatzerlös. In den DATEV-Kontenrahmen bieten sich dafür zum Beispiel diese Konten an, alternativ legst Du ein eigenes Konto "Mahngebühren" im Bereich der sonstigen betrieblichen Erträge an:
&lt;/p&gt;
&lt;table class="tech-table"&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Sachverhalt&lt;/th&gt;
&lt;th&gt;SKR03&lt;/th&gt;
&lt;th&gt;SKR04&lt;/th&gt;
&lt;th&gt;Hinweis&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Vereinnahmte Mahngebühren&lt;/td&gt;
&lt;td&gt;8605 Sonstige Erträge betrieblich und regelmäßig&lt;/td&gt;
&lt;td&gt;4835 Sonstige Erträge betrieblich und regelmäßig&lt;/td&gt;
&lt;td&gt;Ohne Steuerschlüssel buchen&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vereinnahmte Verzugszinsen&lt;/td&gt;
&lt;td&gt;2650 Sonstige Zinsen und ähnliche Erträge&lt;/td&gt;
&lt;td&gt;7100 Sonstige Zinsen und ähnliche Erträge&lt;/td&gt;
&lt;td&gt;Ohne Steuerschlüssel buchen&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Selbst gezahlte Mahngebühren&lt;/td&gt;
&lt;td&gt;4970 Nebenkosten des Geldverkehrs&lt;/td&gt;
&lt;td&gt;6855 Nebenkosten des Geldverkehrs&lt;/td&gt;
&lt;td&gt;Kein Vorsteuerabzug, es liegt keine Leistung vor&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;
Die konkrete Kontenwahl hängt von der Kontenzuordnung in Deinem Kontenrahmen ab. Entscheidend ist das Prinzip: Ein Konto ohne Umsatzsteuerfunktion, getrennt von Umsatzerlösen und getrennt vom Skonto.
&lt;/p&gt;
&lt;h3&gt;Schritt 1: Mahngebühr vor der Zahlung einbuchen&lt;/h3&gt;
&lt;p&gt;
Sobald die Mahnung mit Gebühr raus ist und Du die Gebühr tatsächlich fordern willst, buchst Du sie manuell auf den Debitor, ohne Umsatzsteuer. Unser Beispiel: Rechnung über 1.190,00 EUR brutto, dazu 10,00 EUR Mahngebühr.
&lt;/p&gt;
&lt;p&gt;SKR03:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Debitor 10,00 EUR
an 8605 Sonstige Erträge
betrieblich und regelmäßig 10,00 EUR&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;SKR04:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Debitor 10,00 EUR
an 4835 Sonstige Erträge
betrieblich und regelmäßig 10,00 EUR&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Dabei hast Du zwei Varianten. Entweder erweiterst Du den vorhandenen Offenen Posten der Rechnung um die Gebühr, dann steht der OP anschließend auf 1.200,00 EUR. Oder Du baust mit der Buchung einen eigenen Offenen Posten nur für die Mahngebühr auf. Die zweite Variante hat in der Praxis Vorteile: Die Gebühr bleibt einzeln sichtbar, kann separat weitergemahnt oder gezielt ausgebucht werden und verfälscht nicht den Blick auf die eigentliche Forderung.
&lt;/p&gt;
&lt;h3&gt;Schritt 2: Zahlung ausgleichen&lt;/h3&gt;
&lt;p&gt;
Zahlt der Kunde 1.200,00 EUR, gleichst Du beim Zahlungseingang beide Offenen Posten aus, den Rechnungs-OP über 1.190,00 EUR und den Mahngebühren-OP über 10,00 EUR. Skontofelder bleiben leer.
&lt;/p&gt;
&lt;p&gt;SKR03:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1200 Bank 1.200,00 EUR
an Debitor 1.200,00 EUR
(Ausgleich Rechnung 1.190,00 und Mahngebühr 10,00)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;SKR04:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1800 Bank 1.200,00 EUR
an Debitor 1.200,00 EUR
(Ausgleich Rechnung 1.190,00 und Mahngebühr 10,00)&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Schritt 3: Wenn die Gebühr doch nicht kommt&lt;/h3&gt;
&lt;p&gt;
Zahlt der Kunde nur die 1.190,00 EUR, gleichst Du den Rechnungs-OP aus und der Mahngebühren-OP bleibt stehen. Willst Du die Gebühr nicht weiterverfolgen, buchst Du den OP einfach wieder gegen dasselbe Ertragskonto aus. Eine Umsatzsteuerkorrektur ist nicht nötig, denn es war nie Umsatzsteuer enthalten. Genau das ist ein weiterer Vorteil der sauberen Variante.
&lt;/p&gt;
&lt;h2&gt;5. Umsetzung im Sage 100 Rechnungswesen&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Mahnwesen nutzen:&lt;/strong&gt; Sage 100 berechnet Mahngebühren und Verzugszinsen je Mahnstufe automatisch im Mahnlauf. Die Beträge auf der Mahnung sind aber zunächst nur Ausdruck, gebucht wird davon nichts. Ob Du sie einbuchst, entscheidest Du wie in Schritt 1 gezeigt.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OP-Buchung ohne Steuercode:&lt;/strong&gt; Die Buchung Debitor an Mahngebührenkonto erfasst Du in der Dialogbuchhaltung ohne Steuercode. Achte darauf, dass das Ertragskonto keine Steuerautomatik trägt, sonst rechnet Sage die Steuer wieder hinein.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Zahlungseingang mit Mehrfachausgleich:&lt;/strong&gt; Beim Zahlungseingang wählst Du beide Offenen Posten des Debitors aus und gleichst sie in einem Zug aus. Die Versuchung, die Differenz über das Skontofeld zu lösen, ist genau der Fehler aus Abschnitt 2.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Auswertung:&lt;/strong&gt; Ein eigenes Konto für Mahngebühren macht auf einen Blick sichtbar, was das Mahnwesen tatsächlich einbringt. Zusammen mit der OP-Liste siehst Du außerdem, welche Gebühren noch offen sind.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Wenn Du beim Kontieren nachschlagen willst, welche Konten es rund um sonstige Erträge und Zinsen gibt: Unsere kostenlosen Kontenrahmen-Tools für &lt;a href="https://appontes.de/tools/kontenrahmen/"&gt;SKR04&lt;/a&gt; und &lt;a href="https://appontes.de/tools/kontenrahmen-skr03/"&gt;SKR03&lt;/a&gt; durchsuchen beide Kontenrahmen direkt im Browser.
&lt;/p&gt;
&lt;h2&gt;6. Häufige Fehler aus der Praxis&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Negativer Skonto:&lt;/strong&gt; Die Überzahlung wandert ins Skontofeld und erzeugt ungewollt Erlöse und Umsatzsteuer.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ausziffern aufs Erlöskonto:&lt;/strong&gt; Gleiches Ergebnis über einen anderen Weg, die Steuerautomatik des Erlöskontos schlägt zu.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Umsatzsteuer auf der Mahnung ausgewiesen:&lt;/strong&gt; Unrichtig ausgewiesene Steuer wird nach § 14c UStG geschuldet, auch wenn der Vorgang nicht steuerbar ist.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gebühr nie eingebucht, aber bezahlt:&lt;/strong&gt; Ohne OP für die Mahngebühr steht die Zahlung als unklarer Überhang auf dem Debitor und wird irgendwann falsch ausgeziffert.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Alles auf einem Sammelkonto:&lt;/strong&gt; Mahngebühren, Verzugszinsen und echte Erlöse auf einem Konto machen jede Auswertung und jede Betriebsprüfung mühsamer als nötig.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;7. Fazit&lt;/h2&gt;
&lt;p&gt;
Mahngebühren sind schnell erklärt und trotzdem eine beliebte Fehlerquelle: Sie sind regelmäßig echter Schadensersatz, bleiben also ohne Umsatzsteuer, und gehören deshalb weder ins Skontofeld noch auf ein Erlöskonto mit Steuerautomatik. Mit einem eigenen Ertragskonto und einem eigenen Offenen Posten ist der Fall in zwei Buchungen sauber erledigt, inklusive einfacher Ausbuchung, falls der Kunde die Gebühr doch nicht zahlt. Das Sage 100 Rechnungswesen unterstützt jeden dieser Schritte, vom Mahnlauf über die OP-Verwaltung bis zum Mehrfachausgleich beim Zahlungseingang.
&lt;/p&gt;
&lt;p&gt;
Du willst Dein Mahnwesen in Sage 100 vom Mahnvorschlag bis zur Verbuchung durchgängig aufsetzen? Dann sprich uns an, wir schauen gemeinsam auf Deinen Prozess.
&lt;/p&gt;
&lt;div style="text-align: center; margin: 3rem 0;"&gt;
&lt;a href="https://appontes.de/kontakt/?betreff=anfrage-sage" class="btn btn-primary"&gt;Mahnwesen in Sage 100 besprechen&lt;/a&gt;
&lt;/div&gt;</content:encoded></item><item><title>Sage 100: Wenn der BlobStorage nach einem Update nicht mehr startet</title><link>https://appontes.de/blog/blobstorage-startet-nicht-sage-100/</link><guid isPermaLink="true">https://appontes.de/blog/blobstorage-startet-nicht-sage-100/</guid><pubDate>Wed, 05 Aug 2026 00:00:00 +0000</pubDate><dc:creator>Thomas Falkner</dc:creator><category>Sage 100</category><category>BlobStorage</category><category>Applikationsserver</category><category>IT-Infrastruktur</category><description>Ein Setup-Lauf verwirft die STS-Knoten aus den Dienst-Konfigurationen der Sage 100. Warum die ArgumentNullException in configuration.Host kein Bug ist, wie Du die Ursache findest und die Konfiguration sauber wiederherstellst.</description><content:encoded>&lt;p&gt;&lt;img src="https://appontes.de/img/blog/blobstorage-sts.svg" alt="Sage 100: Wenn der BlobStorage nach einem Update nicht mehr startet"&gt;&lt;/p&gt;
&lt;p&gt;
Nach einem Update der Sage 100 Serverkomponenten lässt sich der BlobStorage-Dienst nicht mehr starten. Im Ereignisprotokoll steht eine Meldung, die auf den ersten Blick nach einem Fehler in der Sage-Bibliothek aussieht:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Der Dienst kann nicht gestartet werden. System.ArgumentNullException:
Der Wert darf nicht NULL sein.
Parametername: configuration.Host
bei Sagede.Shared.Identity.Sts.Client.StsAuthenticationClient..ctor(
IStsClientConfiguration configuration, Boolean validateToken)
bei Sagede.BlobStorageServer.Configuration.HostConfigHelper
.LoadBasicHttpConfiguration(...)
bei Sagede.BlobStorageServer.SageBlobStorageService.OnStart(String[] args)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Dazu kommt ein &lt;code&gt;Application Error&lt;/code&gt; mit Ausnahmecode &lt;code&gt;0xe0434352&lt;/code&gt;. Das ist der Standardcode für eine unbehandelte .NET-Ausnahme. Der Dienst versucht den Start typischerweise mehrfach und stirbt jedes Mal in derselben Zeile.
&lt;/p&gt;
&lt;p&gt;
Die Meldung sieht nach einem Defekt aus. Tatsächlich ist sie eine völlig korrekte Aussage über eine unvollständige Konfiguration. Wir hatten genau diesen Fall bei einem Kunden auf dem Tisch und zeigen Dir hier, wie Du ihn sauber diagnostizierst und behebst.
&lt;/p&gt;
&lt;h2&gt;Was der STS ist und warum ihn der BlobStorage braucht&lt;/h2&gt;
&lt;p&gt;
STS steht für Security Token Service. Das ist der interne Identity-Dienst der Sage 100. Er stellt Tokens aus, mit denen sich die Sage-Dienste untereinander und gegenüber den Clients authentifizieren.
&lt;/p&gt;
&lt;p&gt;Die Rollenverteilung ist für die Fehlersuche entscheidend:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Der &lt;strong&gt;Applikationsserver hostet&lt;/strong&gt; den STS, standardmäßig auf Port 5466. In seiner Kernkonfiguration &lt;code&gt;Sagede.ApplicationServer.Core.config&lt;/code&gt; steht dafür ein &lt;code&gt;&amp;lt;stsServer&amp;gt;&lt;/code&gt;-Knoten mit Host-Adresse und Zertifikats-Thumbprint.&lt;/li&gt;
&lt;li&gt;Alle anderen Dienste wie BlobStorage oder Application Gateway &lt;strong&gt;melden sich als Client an&lt;/strong&gt;. Dafür steht in ihrer jeweiligen Konfiguration ein &lt;code&gt;&amp;lt;stsClient&amp;gt;&lt;/code&gt;-Knoten mit Host, &lt;code&gt;clientId&lt;/code&gt; und &lt;code&gt;clientSecret&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Der BlobStorage baut beim Start für jeden seiner Endpunkte einen &lt;code&gt;StsAuthenticationClient&lt;/code&gt; auf. Dessen Konstruktor prüft als Erstes, ob eine Host-Adresse vorliegt. Fehlt der &lt;code&gt;&amp;lt;stsClient&amp;gt;&lt;/code&gt;-Knoten komplett, ist &lt;code&gt;configuration.Host&lt;/code&gt; schlicht &lt;code&gt;null&lt;/code&gt;. Der Dienst kommt dann gar nicht erst bis zum Öffnen seiner Ports.
&lt;/p&gt;
&lt;h2&gt;Die Ursache: Das Setup schreibt Konfigurationen neu&lt;/h2&gt;
&lt;p&gt;
Sage-Setups erzeugen die Dienst-Konfigurationsdateien aus mitgelieferten &lt;code&gt;.default&lt;/code&gt;-Vorlagen neu. Diese Vorlagen enthalten die STS-Knoten nur als auskommentiertes Beispiel. Die echten, umgebungsspezifischen Werte werden bei der Ersteinrichtung eingetragen und sind der Vorlage naturgemäß unbekannt.
&lt;/p&gt;
&lt;p&gt;
Läuft ein Update oder eine Reparaturinstallation, kann dabei die gepflegte Konfiguration durch die Vorlage ersetzt werden. Andere Änderungen des Setups bleiben sichtbar erhalten. In unserem Fall wurde etwa ein zusätzlicher SageId-Endpunkt eingetragen. Das zeigt, dass die Datei tatsächlich neu erzeugt und nicht nur zurückgesetzt wurde. Die STS-Konfiguration hingegen fehlt danach.
&lt;/p&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;
&lt;strong&gt;Der wichtigste Punkt bei der Fehlersuche:&lt;/strong&gt; Es ist praktisch nie nur eine Datei betroffen. Wer nur den BlobStorage repariert, hat anschließend zwar einen Dienst, der startet. Aber keinen STS, mit dem er reden könnte, weil auch dem Applikationsserver sein &lt;code&gt;&amp;lt;stsServer&amp;gt;&lt;/code&gt;-Knoten fehlt. Zur Diagnose gehört deshalb immer der Blick auf alle Dienst-Konfigurationen, nicht nur auf die des abstürzenden Dienstes.
&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;
Ein guter Indikator: Stehen der Applikationsserver und der Administrationsdienst ebenfalls auf „Beendet" und wurden sie laut Ereignisprotokoll zum Zeitpunkt des Setups gestoppt, ohne je wieder gestartet worden zu sein, ist das Bild komplett.
&lt;/p&gt;
&lt;h2&gt;Diagnose&lt;/h2&gt;
&lt;p&gt;Zwei Handgriffe genügen, um die Vermutung zu bestätigen.&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Erstens:&lt;/strong&gt; In den Installationsverzeichnissen der Dienste liegen neben der aktiven Konfiguration Sicherungskopien mit Zeitstempel im Namen, nach dem Muster &lt;code&gt;JJJJMMTT_hhmmss_&amp;lt;Dateiname&amp;gt;.config&lt;/code&gt;. Sage legt sie bei jeder Änderung durch ein Setup selbst an. Ein Durchsuchen dieser Kopien nach &lt;code&gt;stsClient&lt;/code&gt; zeigt sofort, welche Stände die Knoten hatten und ab welchem Zeitpunkt sie fehlen:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Get-ChildItem "&amp;lt;Installationspfad&amp;gt;" -Filter "*.config" | ForEach-Object {
[PSCustomObject]@{
Name = $_.Name
Geaendert = $_.LastWriteTime
STS = (Select-String -Path $_.FullName -Pattern "stsServer|stsClient" -Quiet)
}
} | Sort-Object Geaendert -Descending | Format-Table -AutoSize&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Achte darauf, nur Treffer außerhalb der Kommentarblöcke zu werten. Die Beispielkonfiguration in den Kommentaren enthält die Knoten ebenfalls.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Zweitens:&lt;/strong&gt; Das Ereignisprotokoll rund um den Zeitstempel der Konfigurationsänderung zeigt, welche Dienste das Setup gestoppt hat. Zusammen ergibt das eine klare Chronologie.
&lt;/p&gt;
&lt;h2&gt;Die Lösung&lt;/h2&gt;
&lt;p&gt;
Übernimm die STS-Knoten aus der jüngsten Sicherungskopie, die sie noch enthält, in die aktuelle Konfiguration. Lege vorher eine eigene Kopie der aktuellen Dateien an. Die vom Setup erzeugten Sicherungen sind hilfreich, aber Du willst auch Deinen eigenen Zwischenstand zurückholen können.
&lt;/p&gt;
&lt;p&gt;
In der Konfiguration des &lt;strong&gt;BlobStorage-Servers&lt;/strong&gt; gehört der Client-Knoten in den &lt;code&gt;&amp;lt;BlobStorage&amp;gt;&lt;/code&gt;-Abschnitt, hinter die Endpunktliste:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;BlobStorage StorageRoot="..."&amp;gt;
&amp;lt;EndPoints&amp;gt;
&amp;lt;!-- ... --&amp;gt;
&amp;lt;/EndPoints&amp;gt;
&amp;lt;stsClient enabled="true"
host="https://&amp;lt;servername&amp;gt;:&amp;lt;port&amp;gt;"
clientId="&amp;lt;GUID&amp;gt;"
clientSecret="&amp;lt;GUID&amp;gt;" /&amp;gt;
&amp;lt;MultiUserServer Name="\\." RegistryKey="Software\Sage\Office Line\9.0" /&amp;gt;
&amp;lt;/BlobStorage&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
In der Kernkonfiguration des &lt;strong&gt;Applikationsservers&lt;/strong&gt; gehören beide Knoten in den &lt;code&gt;&amp;lt;security&amp;gt;&lt;/code&gt;-Abschnitt:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;security&amp;gt;
&amp;lt;!-- ... --&amp;gt;
&amp;lt;stsClient enabled="true"
host="https://&amp;lt;servername&amp;gt;:&amp;lt;port&amp;gt;"
clientId="&amp;lt;GUID&amp;gt;"
clientSecret="&amp;lt;GUID&amp;gt;" /&amp;gt;
&amp;lt;stsServer enabled="true"
host="https://&amp;lt;servername&amp;gt;:&amp;lt;port&amp;gt;"
certificateThumbprint="&amp;lt;Thumbprint&amp;gt;" /&amp;gt;
&amp;lt;/security&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Beachte, dass Applikationsserver und BlobStorage &lt;strong&gt;unterschiedliche&lt;/strong&gt; &lt;code&gt;clientId&lt;/code&gt;/&lt;code&gt;clientSecret&lt;/code&gt;-Paare verwenden. Jeder Dienst ist am STS als eigener Client registriert. Die Werte lassen sich nicht gegeneinander austauschen.
&lt;/p&gt;
&lt;p&gt;Anschließend startest Du die Dienste in dieser Reihenfolge:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Applikationsserver, denn er bringt den STS hoch&lt;/li&gt;
&lt;li&gt;Administrationsdienst&lt;/li&gt;
&lt;li&gt;BlobStorage-Server&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Die Stolperfalle: Der Zertifikats-Thumbprint&lt;/h2&gt;
&lt;p&gt;
Hier lohnt sich Sorgfalt. Der &lt;code&gt;certificateThumbprint&lt;/code&gt; im &lt;code&gt;&amp;lt;stsServer&amp;gt;&lt;/code&gt;-Knoten bestimmt, mit welchem Zertifikat der Applikationsserver den STS-Port an HTTP.SYS bindet. Ein Setup stellt die Bindungen aber unter Umständen um, etwa von einem dedizierten STS-Zertifikat auf das allgemeine Maschinenzertifikat.
&lt;/p&gt;
&lt;p&gt;Was aktuell tatsächlich gebunden ist, zeigt Dir:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;netsh http show sslcert&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Übernimm den Thumbprint, der dort für den STS-Port hinterlegt ist, und nicht blind den Wert aus der alten Sicherungskopie. Andernfalls setzt der Applikationsserver beim Start die Bindung wieder um. Im ungünstigen Fall passt der Zertifikatsname anschließend nicht mehr zum Hostnamen, unter dem die Clients den STS ansprechen. Du hättest dann statt eines Startfehlers ein Zertifikatsproblem, und das ist deutlich schwerer zu diagnostizieren.
&lt;/p&gt;
&lt;p&gt;
Prüfe bei der Gelegenheit auch, ob der Common Name des gebundenen Zertifikats zu der Host-Adresse passt, die in den &lt;code&gt;stsClient&lt;/code&gt;-Knoten steht.
&lt;/p&gt;
&lt;h2&gt;Was kein brauchbarer Funktionstest ist&lt;/h2&gt;
&lt;p&gt;
Nach der Reparatur willst Du natürlich verifizieren, dass die Client-Zugangsdaten am STS noch gültig sind. Der naheliegende Versuch, ein Token per &lt;code&gt;client_credentials&lt;/code&gt; über die Discovery-URL anzufordern, führt in die Irre: Der Sage-STS beantwortet auch das sonst anonyme &lt;code&gt;/.well-known/openid-configuration&lt;/code&gt; mit &lt;strong&gt;401 Unauthorized&lt;/strong&gt;, und zwar unabhängig davon, ob Du anonym oder mit Windows-Anmeldeinformationen anfragst.
&lt;/p&gt;
&lt;p&gt;
Ein 401 an dieser Stelle ist also kein Beleg dafür, dass &lt;code&gt;clientId&lt;/code&gt; oder &lt;code&gt;clientSecret&lt;/code&gt; ungültig wären. Er sagt schlicht gar nichts aus.
&lt;/p&gt;
&lt;p&gt;
Ähnlich begrenzt aussagekräftig ist ein Aufruf der BlobStorage-Endpunkte: Ein 404 auf dem Wurzelpfad zeigt lediglich, dass der HTTP-Listener steht. Das ist eine sinnvolle Bestätigung, dass der Dienst seine Ports geöffnet hat, aber kein Nachweis funktionierender Authentifizierung.
&lt;/p&gt;
&lt;p&gt;
Der belastbare Test ist ein echter Vorgang aus der Sage 100 heraus, der den BlobStorage nutzt. Etwa das Hinterlegen eines Briefpapiers oder ein Dokumenten-Upload. Erst wenn der durchläuft, ist die Kette vollständig geprüft. Schlägt er mit Authentifizierungsfehlern fehl, sind die Client-Registrierungen im STS tatsächlich verloren gegangen und müssen neu angelegt werden.
&lt;/p&gt;
&lt;h2&gt;Vorbeugen&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Vor jedem Update&lt;/strong&gt; die Konfigurationsdateien aller Sage-Dienste an einen Ort außerhalb der Installationsverzeichnisse sichern. Die vom Setup erzeugten Zeitstempel-Kopien sind eine gute Rückfallebene, aber sie liegen im selben Verzeichnis und können bei einer Deinstallation mit verschwinden.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Nach jedem Update&lt;/strong&gt; gezielt prüfen, ob die STS-Knoten noch vorhanden sind, bevor Anwender auf Fehler stoßen. Ein kurzes Skript über alle Dienstverzeichnisse genügt.&lt;/li&gt;
&lt;li&gt;Die &lt;code&gt;clientId&lt;/code&gt;/&lt;code&gt;clientSecret&lt;/code&gt;-Paare der einzelnen Dienste zusammen mit dem Zertifikats-Thumbprint in der Systemdokumentation festhalten. Wenn die Sicherungskopien einmal nicht ausreichen, ist das der schnellste Weg zurück.&lt;/li&gt;
&lt;li&gt;Nach einem Setup daran denken, dass gestoppte Dienste auch gestoppt bleiben. Ein Blick auf den Status aller Sage-Dienste gehört zum Abschluss jedes Updates.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Fazit&lt;/h2&gt;
&lt;p&gt;
Die &lt;code&gt;ArgumentNullException&lt;/code&gt; in &lt;code&gt;configuration.Host&lt;/code&gt; liest sich wie ein Bug, ist aber eine präzise Aussage: Dem Dienst fehlt seine STS-Client-Konfiguration. Ursache ist in aller Regel ein Setup, das die gepflegte Konfiguration durch die Standardvorlage ersetzt hat. Der Fix ist unspektakulär: Die Knoten aus der letzten guten Sicherungskopie zurückschreiben und die Dienste in der richtigen Reihenfolge starten. Wichtig sind die beiden Details drumherum: Alle betroffenen Konfigurationen prüfen, nicht nur die des abstürzenden Dienstes, und beim Zertifikats-Thumbprint den Ist-Zustand der HTTP.SYS-Bindungen übernehmen statt den Wert von früher.
&lt;/p&gt;
&lt;p&gt;
Wenn Deine Sage 100 nach einem Update streikt und Du nicht weiterkommst, schau Dir auch unseren Beitrag zur &lt;a href="https://appontes.de/blog/sage-100-applikationsserver-performance/"&gt;Performance-Optimierung des Applikationsservers&lt;/a&gt; an. Oder melde Dich direkt bei uns.
&lt;/p&gt;
&lt;div style="text-align: center; margin: 3rem 0;"&gt;
&lt;a href="https://appontes.de/kontakt/?betreff=anfrage-sage" class="btn btn-primary"&gt;Unterstützung bei Sage 100 Updates anfragen&lt;/a&gt;
&lt;/div&gt;</content:encoded></item><item><title>OCI 5.0 Punchout: Wie Dein Katalog ins Einkaufssystem Deiner Kunden kommt</title><link>https://appontes.de/blog/oci-punchout-sage-100/</link><guid isPermaLink="true">https://appontes.de/blog/oci-punchout-sage-100/</guid><pubDate>Fri, 24 Jul 2026 00:00:00 +0000</pubDate><dc:creator>Thomas Falkner</dc:creator><category>Sage 100</category><category>OCI</category><category>Punchout</category><category>E-Procurement</category><category>Schnittstellen</category><description>Ein Großkunde verlangt einen OCI-Katalog und niemand im Haus weiß, was genau damit gemeint ist. Wie Punchout technisch funktioniert, was Version 5.0 kann und woran die Anbindung an Sage 100 in Projekten wirklich hängt.</description><content:encoded>&lt;p&gt;&lt;img src="https://appontes.de/img/blog/oci-punchout.svg" alt="OCI 5.0 Punchout: Wie Dein Katalog ins Einkaufssystem Deiner Kunden kommt"&gt;&lt;/p&gt;
&lt;p&gt;
"Wir stellen unsere Beschaffung auf ein E-Procurement-System um. Bitte stellen Sie uns Ihren Katalog als OCI-Punchout bereit." Mit so einer Mail vom Einkauf eines Großkunden fängt das Thema meistens an. Man liest den Satz zweimal, sucht danach und landet vor allem in SAP-Dokumentation, die für eine ganz andere Systemwelt geschrieben ist. Dabei steckt hinter der Anforderung ein überschaubarer Mechanismus, und sie lässt sich auch dann erfüllen, wenn im Haus keine SAP-Landschaft läuft, sondern eine Sage 100. Wir haben solche Anbindungen umgesetzt und beschreiben hier, wie das Verfahren funktioniert und wo in den Projekten die Zeit tatsächlich draufgeht.
&lt;/p&gt;
&lt;h2&gt;Was hinter OCI steckt&lt;/h2&gt;
&lt;p&gt;
OCI steht für &lt;strong&gt;Open Catalog Interface&lt;/strong&gt;. Entwickelt hat den Standard SAP für die eigenen Beschaffungssysteme, inzwischen sprechen ihn praktisch alle verbreiteten E-Procurement-Plattformen, etwa Onventis, Jaggaer oder Unite. Die aktuelle Version 5.0 stammt aus dem Jahr 2013. Das klingt erst mal alt, heißt in der Praxis aber vor allem: Der Standard ist stabil, da ändert sich nichts mehr unter der Hand.
&lt;/p&gt;
&lt;p&gt;
Die Grundidee: Statt dass der Lieferant seinen Katalog als Datei ins Einkaufssystem des Kunden hochlädt und bei jeder Preisänderung eine neue Datei schickt, bleibt der Katalog beim Lieferanten. Der Einkäufer springt aus seinem System in den Webshop des Lieferanten, sucht dort aus und nimmt den Warenkorb mit zurück. Dieses Rausspringen und Zurückkommen hat dem Verfahren seinen Namen gegeben: &lt;strong&gt;Punchout&lt;/strong&gt;.
&lt;/p&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;
Der eigentliche Gewinn gegenüber statischen Katalogdateien: Preise, Sortiment und Verfügbarkeit kommen live aus dem System des Lieferanten. Niemand pflegt Exportdateien, niemand spielt veraltete Datenstände ein.
&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;So läuft ein Punchout ab&lt;/h2&gt;
&lt;p&gt;Der Ablauf besteht aus vier Schritten, und wenn man ihn einmal gesehen hat, ist die Magie raus.&lt;/p&gt;
&lt;h3&gt;1. Der Absprung ins Katalogsystem&lt;/h3&gt;
&lt;p&gt;
Der Einkäufer klickt in seinem Einkaufssystem auf den hinterlegten Katalog. Das System ruft die vereinbarte URL des Lieferanten-Shops auf und übergibt per HTTP-POST eine Handvoll Parameter: Zugangsdaten, die erwartete OCI-Version und vor allem die &lt;code&gt;HOOK_URL&lt;/code&gt;, also die Rücksprungadresse, an die der Warenkorb später zurückgeschickt wird. Der Shop prüft die Zugangsdaten und startet eine Session. Der Einkäufer bekommt davon nichts mit, er landet ohne separates Login direkt im Katalog.
&lt;/p&gt;
&lt;h3&gt;2. Einkaufen wie im Webshop&lt;/h3&gt;
&lt;p&gt;
Jetzt passiert das, was jeder aus dem Onlinehandel kennt: Suchen, vergleichen, in den Warenkorb legen. Der Unterschied liegt unter der Haube. Weil der Shop weiß, welcher Kunde da eingesprungen ist, zeigt er dessen Konditionen, also verhandelte Preise, freigegebenes Sortiment und kundenspezifische Artikelnummern.
&lt;/p&gt;
&lt;h3&gt;3. Der Rücksprung mit dem Warenkorb&lt;/h3&gt;
&lt;p&gt;
Statt auf "Kaufen" klickt der Einkäufer auf "Warenkorb übertragen". Der Shop baut daraus ein HTML-Formular mit standardisierten Feldern und schickt es per POST an die &lt;code&gt;HOOK_URL&lt;/code&gt;. Jede Position wird in nummerierte Felder zerlegt, unter anderem:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;NEW_ITEM-DESCRIPTION[n]&lt;/code&gt;: Die Artikelbezeichnung&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NEW_ITEM-VENDORMAT[n]&lt;/code&gt;: Die Artikelnummer des Lieferanten&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NEW_ITEM-QUANTITY[n]&lt;/code&gt; und &lt;code&gt;NEW_ITEM-UNIT[n]&lt;/code&gt;: Menge und Mengeneinheit&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NEW_ITEM-PRICE[n]&lt;/code&gt;, &lt;code&gt;NEW_ITEM-PRICEUNIT[n]&lt;/code&gt; und &lt;code&gt;NEW_ITEM-CURRENCY[n]&lt;/code&gt;: Preis, Preiseinheit und Währung&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NEW_ITEM-LEADTIME[n]&lt;/code&gt;: Die Lieferzeit in Tagen&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NEW_ITEM-CUST_FIELD1&lt;/code&gt; bis &lt;code&gt;CUST_FIELD5&lt;/code&gt;: Freie Felder für alles, was der Standard nicht abdeckt&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;4. Weiterverarbeitung im Einkaufssystem&lt;/h3&gt;
&lt;p&gt;
Aus dem übernommenen Warenkorb macht das Einkaufssystem eine Bedarfsanforderung oder Bestellung, die den normalen internen Weg geht: Freigabe, Budgetprüfung, Genehmigungsworkflow. An dieser Stelle sitzt ein Missverständnis, das uns immer wieder begegnet: &lt;strong&gt;OCI überträgt keine Bestellung.&lt;/strong&gt; Es überträgt einen Warenkorb ins Einkaufssystem des Kunden, mehr nicht. Die Bestellung selbst kommt erst nach der internen Freigabe beim Lieferanten an, per E-Mail, als PDF oder über EDI. Diesen zweiten Kanal muss man von Anfang an mitplanen, sonst wartet die eigene Auftragserfassung auf Aufträge, die auf dem OCI-Weg nie kommen werden.
&lt;/p&gt;
&lt;h2&gt;Was in Version 5.0 dazugekommen ist&lt;/h2&gt;
&lt;p&gt;
Am Kernablauf hat sich seit den frühen Versionen wenig geändert. Version 5.0 ergänzt Funktionen, mit denen das Einkaufssystem den Katalog auch maschinell abfragen kann, ohne dass ein Mensch durch den Shop klickt. Gesteuert wird das über den Parameter &lt;code&gt;FUNCTION&lt;/code&gt; im Aufruf:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;DETAIL:&lt;/strong&gt; Ruft zu einem bekannten Artikel die aktuelle Detailseite im Katalog auf, etwa aus einer alten Bestellung heraus.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;VALIDATE:&lt;/strong&gt; Prüft im Hintergrund, ob ein Artikel noch bestellbar ist und was er aktuell kostet.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SOURCING:&lt;/strong&gt; Sucht zu einem Bedarf passende Bezugsquellen im Katalog.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;BACKGROUND_SEARCH:&lt;/strong&gt; Erlaubt dem Einkaufssystem eine katalogübergreifende Suche, ohne dass der Anwender jeden Katalog einzeln öffnet.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Massendaten als JSON:&lt;/strong&gt; Katalogdaten lassen sich strukturiert herunterladen, damit das Einkaufssystem sie für die eigene Suche indizieren kann.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
In der Praxis relativiert sich das. Viele Einkaufssysteme und Kataloge nutzen bis heute nur den Punchout selbst plus &lt;code&gt;DETAIL&lt;/code&gt;, und etliche Anbindungen laufen weiter nach OCI 4.0. Wer eine Schnittstelle neu baut, sollte die 5.0-Funktionen anbieten können, darf aber nicht überrascht sein, wenn die Gegenseite davon nichts konfiguriert. Im Ariba-Umfeld gibt es mit cXML-Punchout übrigens einen zweiten Standard nach demselben Prinzip, XML-Nachrichten statt Formularfelder. Eine sauber gebaute OCI-Anbindung ist dafür die halbe Miete.
&lt;/p&gt;
&lt;h2&gt;Was hat das mit Sage 100 zu tun?&lt;/h2&gt;
&lt;p&gt;
Sage 100 bringt von Haus aus keinen OCI-Punchout mit. Trotzdem ist die Warenwirtschaft die richtige Grundlage dafür, denn alles, was der Katalog braucht, liegt dort schon gepflegt vor: Artikel, Varianten, kundenindividuelle Preise, Rabatte, Bestände. Genau da setzen wir an. Wichtig ist nur, die beiden Richtungen auseinanderzuhalten, denn "OCI mit Sage 100" kann zwei sehr verschiedene Projekte bedeuten.
&lt;/p&gt;
&lt;h3&gt;Als Lieferant: Dein Sortiment im Einkaufssystem Deiner Kunden&lt;/h3&gt;
&lt;p&gt;
Das ist der Fall aus der Mail vom Anfang. Dein Kunde, oft ein Konzern oder ein öffentlicher Auftraggeber, beschafft über ein E-Procurement-System und erwartet Deinen Katalog als Punchout. Wir stellen dafür einen Webkatalog bereit, der seine Daten direkt aus Deiner Sage 100 bezieht. Artikelstamm, kundenindividuelle Preislisten und Verfügbarkeiten kommen live aus der Warenwirtschaft, ohne doppelte Datenpflege. Der Warenkorb geht OCI-konform zurück, und die später eintreffende Bestellung landet als Auftrag wieder in Deiner Sage 100. Unterm Strich ist das ein zusätzlicher Vertriebskanal, und zwar der, den Großkunden zunehmend zur Bedingung machen. Gerade im technischen B2B-Handel ist so eine Anbindung ein typischer Baustein der Gesamtlösung, mehr dazu auf unserer Seite &lt;a href="https://appontes.de/sage-100/technischer-grosshandel/"&gt;Sage 100 für technischen Großhandel&lt;/a&gt;.
&lt;/p&gt;
&lt;h3&gt;Als Einkäufer: Lieferantenkataloge in Deinem Einkauf&lt;/h3&gt;
&lt;p&gt;
Die Gegenrichtung gibt es auch. Wenn Dein Team regelmäßig C-Teile, Bürobedarf oder Werkzeug bei Lieferanten mit OCI-fähigen Shops beschafft, kann es aus dem Einkaufsprozess heraus in deren Kataloge springen. Der zurückgegebene Warenkorb wird zur Bestellung in der Sage 100, mit sauber zugeordneten Artikeln, Mengeneinheiten und Preisen statt Copy-and-paste aus dem Browser.
&lt;/p&gt;
&lt;h2&gt;Woran Punchout-Projekte in der Praxis hängen&lt;/h2&gt;
&lt;p&gt;
Die OCI-Felder zu befüllen ist der einfache Teil. Die Erfahrung aus unseren Projekten: Die Zeit steckt in den Details dazwischen.
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Mengeneinheiten.&lt;/strong&gt; Einkaufssysteme erwarten in &lt;code&gt;NEW_ITEM-UNIT&lt;/code&gt; meist ISO-Codes, also etwa PCE für Stück. In der Sage 100 heißt die Einheit aber "Stk" oder "Stück". Ohne sauberes Mapping in beide Richtungen scheitert die Übernahme, oder schlimmer, es entstehen stillschweigend falsche Bestellmengen. Die gängigen Codes haben wir in einem kleinen &lt;a href="https://appontes.de/tools/iso-mengeneinheiten/"&gt;Nachschlagetool für ISO-Mengeneinheiten&lt;/a&gt; gesammelt.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Preise und Preiseinheiten.&lt;/strong&gt; Übertragen werden Nettopreise. Wer Preise je 100 Stück führt, muss die Preiseinheit korrekt mitgeben, ein übersehenes &lt;code&gt;PRICEUNIT&lt;/code&gt; verschiebt den Preis mal eben um den Faktor 100.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Feldlängen und Encoding.&lt;/strong&gt; &lt;code&gt;DESCRIPTION&lt;/code&gt; fasst 40 Zeichen, längere Texte gehören in den Langtext. Und kaputte Umlaute fallen grundsätzlich erst beim Test mit dem echten Einkaufssystem auf, nie vorher.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Testen ohne Gegenseite.&lt;/strong&gt; Das Einkaufssystem des Kunden steht meist erst spät zur Verfügung, und jeder Testlauf braucht dort einen Ansprechpartner. Für die ersten Runden haben wir deshalb einen kostenlosen &lt;a href="https://appontes.de/tools/oci-punchout-tester/"&gt;OCI-Punchout-Tester&lt;/a&gt; gebaut: Er simuliert das Einkaufssystem, nimmt den Warenkorb an einer Test-HOOK_URL entgegen und prüft die Felder auf genau die Punkte aus dieser Liste.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Jeder Kunde konfiguriert anders.&lt;/strong&gt; Der Standard lässt Spielraum, und jedes Einkaufssystem nutzt ihn. Welche Felder Pflicht sind, wie die &lt;code&gt;CUST_FIELD&lt;/code&gt;-Felder belegt werden sollen, welche OCI-Version erwartet wird: Verbindlich klärt sich das erst im gemeinsamen Test mit dem Einkauf des Kunden. Diesen Termin sollte man früh einplanen, er entscheidet über den Zeitplan.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Fazit&lt;/h2&gt;
&lt;p&gt;
OCI-Punchout ist ein alter, unaufgeregter Standard, und genau das macht ihn angenehm: Absprung in den Katalog, Einkaufen zu den eigenen Konditionen, Warenkorb zurück. Der Aufwand in Projekten steckt selten in der Schnittstelle selbst, sondern in Mengeneinheiten, Preislogik und der Abstimmung mit dem Einkaufssystem der Gegenseite.
&lt;/p&gt;
&lt;p&gt;
Wenn bei Dir gerade so eine Anfrage auf dem Tisch liegt oder Du Lieferantenkataloge in Deinen Einkauf holen willst: Wir haben diese Projekte mit der Sage 100 umgesetzt und wissen, wo die Zeit draufgeht. Meld Dich einfach.
&lt;/p&gt;
&lt;div style="text-align: center; margin: 3rem 0;"&gt;
&lt;a href="https://appontes.de/kontakt/?betreff=anfrage-sage" class="btn btn-primary"&gt;OCI-Anbindung an Sage 100 besprechen&lt;/a&gt;
&lt;/div&gt;</content:encoded></item><item><title>Artikeletiketten mit Barcode drucken, direkt im Browser</title><link>https://appontes.de/blog/etiketten-drucken-browser/</link><guid isPermaLink="true">https://appontes.de/blog/etiketten-drucken-browser/</guid><pubDate>Fri, 24 Jul 2026 00:00:00 +0000</pubDate><dc:creator>Thomas Falkner</dc:creator><category>Sage 100</category><category>Lager</category><category>Etiketten</category><category>Barcode</category><category>Tools</category><description>Die Etiketten-App macht aus einer CSV-Datei oder dem Sage-100-Artikelstamm fertige Etiketten mit EAN-, QR-, Code-128- und Code-39-Codes. Mit Designer, gängigen Bogenformaten und offline nutzbar als installierte App.</description><content:encoded>&lt;p&gt;&lt;img src="https://appontes.de/img/blog/etiketten-app.svg" alt="Artikeletiketten mit Barcode drucken, direkt im Browser"&gt;&lt;/p&gt;
&lt;p&gt;
Etiketten braucht jedes Lager: Wareneingang, Lagerplätze, Musterteile, Preisschilder. In der Praxis entsteht so etwas oft mit einer Word-Vorlage und einer Excel-Liste, die irgendwer vor Jahren angelegt hat. Bei jedem Sortimentswechsel geht die Bastelei von vorn los. Wir haben dafür die &lt;a href="https://appontes.de/etiketten-app/"&gt;Etiketten-App&lt;/a&gt; gebaut. Sie läuft komplett im Browser, ohne Installation und ohne Serverkontakt für Deine Daten.
&lt;/p&gt;
&lt;h2&gt;Artikel laden: CSV oder direkt aus Sage 100&lt;/h2&gt;
&lt;p&gt;
Du ziehst eine CSV-Datei in die App, der Spaltenaufbau ist egal. Anhand der Überschriften schlägt die App vor, welche Spalte Artikelnummer, Bezeichnung oder EAN ist, den Rest ordnest Du per Klick zu. Eine Anzahl-Spalte steuert, wie viele Etiketten je Artikel gedruckt werden.
&lt;/p&gt;
&lt;p&gt;
Für Sage-Anwender geht es noch direkter: Die App holt die Artikel &lt;strong&gt;live aus der Sage 100&lt;/strong&gt;, über unseren Connector. Token eintragen, Abfrage wählen, laden. Kein Export, kein Umweg über Excel, keine veralteten Stände. Und wer nur einen Teil des Sortiments braucht, filtert die geladenen Artikel direkt in der App, auch mit mehreren verknüpften Bedingungen. Die Filter lassen sich benennen und wiederverwenden.
&lt;/p&gt;
&lt;h2&gt;Echte Barcodes&lt;/h2&gt;
&lt;p&gt;
Aus der EAN wird ein scannbarer EAN-13- oder EAN-8-Barcode als Vektorgrafik. Die Prüfziffer wird vorher kontrolliert. Eine kaputte Nummer landet als deutlicher Hinweis auf dem Etikett und nicht als Barcode, den kein Scanner liest. Im Designer stehen zusätzlich QR-Code, Code 128 und Code 39 zur Auswahl, etwa für Artikelnummern, Lagerplätze oder einen Link ins Lagerverwaltungssystem.
&lt;/p&gt;
&lt;h2&gt;Bogen und Rolle&lt;/h2&gt;
&lt;p&gt;
Bei den Formaten sind die üblichen Verdächtigen dabei: randlose A4-Raster von 70 × 16,9 bis 105 × 148 mm, die L-Serie mit Rand und Steg, Rollenformate für Brother- und Dymo-Drucker und ein freies Maß. Gedruckt wird millimetergenau über den Druckdialog des Browsers, auf Wunsch als PDF. Angebrochene Bögen sind kein Problem, die Startposition lässt sich versetzen. Für den Testdruck auf Normalpapier gibt es Schnittlinien.
&lt;/p&gt;
&lt;h2&gt;Der Designer&lt;/h2&gt;
&lt;p&gt;
Das Standard-Layout reicht für viele Fälle. Wenn nicht, öffnest Du den Designer: Texte, Datenfelder, Codes, Logo und Linien frei auf dem Etikett platzieren, mit der Maus schieben und in der Größe ziehen. Position und Maße lassen sich auch in Millimetern eintippen, und mit den Pfeiltasten geht es in halben Millimetern voran. Wer sich vertut, drückt Strg+Z. Entwürfe werden im Browser gespeichert, lassen sich benennen, wieder laden und als Datei an Kollegen weitergeben. Beim Gestalten blätterst Du durch Deine echten Artikel und siehst sofort, ob auch lange Bezeichnungen ins Layout passen.
&lt;/p&gt;
&lt;h2&gt;Als App installieren, offline drucken&lt;/h2&gt;
&lt;p&gt;
Die Etiketten-App ist eine installierbare Web-App (PWA). Über den Installieren-Button bekommt sie ein eigenes Icon auf Desktop oder Startbildschirm und ein eigenes Fenster ohne Browserleisten. Weil alles lokal im Browser rechnet, funktioniert sie auch &lt;strong&gt;offline&lt;/strong&gt;, etwa auf dem Tablet im Lager ohne WLAN-Abdeckung. Nur der Direktabruf aus der Sage 100 braucht naturgemäß eine Verbindung. Updates holt sich die App beim nächsten Start von selbst.
&lt;/p&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;
Alle Daten bleiben auf Deinem Gerät: CSV-Verarbeitung, Barcode-Erzeugung und Druck laufen komplett lokal im Browser. Beim Laden aus Sage 100 gehen die Artikeldaten über den Appontes-Connector und werden nicht gespeichert.
&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;Ausprobieren&lt;/h2&gt;
&lt;p&gt;
Am schnellsten geht es mit der &lt;a href="https://appontes.de/downloads/etiketten-beispiel.csv" download&gt;Beispiel-CSV&lt;/a&gt;: herunterladen, in die &lt;a href="https://appontes.de/etiketten-app/"&gt;Etiketten-App&lt;/a&gt; ziehen, Format wählen, drucken. Ob Deine eigenen EANs stimmen, verrät Dir der &lt;a href="https://appontes.de/tools/gtin-pruefer/"&gt;GTIN- / EAN-Prüfer&lt;/a&gt;, und die &lt;a href="https://appontes.de/tools/ean-suche/"&gt;EAN-Suche&lt;/a&gt; zeigt, welches Produkt hinter einer Nummer steckt.
&lt;/p&gt;
&lt;p&gt;
Und wenn Du den Etikettendruck fest in Deine Sage-100-Prozesse einbauen willst, vom Wareneingang bis zum automatischen Druck auf dem Zebra-Drucker: Solche Anbindungen bauen wir.
&lt;/p&gt;
&lt;div style="text-align: center; margin: 3rem 0;"&gt;
&lt;a href="https://appontes.de/kontakt/?betreff=anfrage-sage" class="btn btn-primary"&gt;Etikettendruck mit Sage 100 besprechen&lt;/a&gt;
&lt;/div&gt;</content:encoded></item><item><title>Formatierung von Datumsangaben und Geldbeträgen</title><link>https://appontes.de/blog/formatierung-datumsangaben-geldbetraege/</link><guid isPermaLink="true">https://appontes.de/blog/formatierung-datumsangaben-geldbetraege/</guid><pubDate>Thu, 23 Jul 2026 00:00:00 +0000</pubDate><dc:creator>Sebastian Wandtke</dc:creator><category>SQL-Basics</category><description>Mit CONVERT() und FORMAT() machst Du Datumsangaben und Geldbeträge in SQL-Abfragen gut lesbar: Deutsches Datumsformat, 1000er-Trennzeichen, €-Zeichen und Prozentwerte mit je einem kurzen SQL-Ausdruck.</description><content:encoded>&lt;p&gt;&lt;img src="https://appontes.de/img/blog/formatierung-datumsangaben-geldbetraege.svg" alt="Formatierung von Datumsangaben und Geldbeträgen"&gt;&lt;/p&gt;
&lt;p&gt;
In vielen SQL-Abfragen gehört das Formatieren von Datumsangaben oder Geldbeträgen einfach dazu.
&lt;/p&gt;
&lt;p&gt;
Steht ein Datum im DATETIME-Datentyp in der Datenbank, soll dem Anwender nicht "2026-07-17 10:31:27.253" angezeigt werden, sondern ein leicht lesbares Format. Das Gleiche gilt für Geldbeträge. Handelt es sich um große Zahlen, so ist die Ausgabe von "100000.00" wenig hilfreich, schnell kann eine Null zu viel oder zu wenig wahrgenommen werden.
&lt;/p&gt;
&lt;p&gt;
Für beide Anwendungsfälle lässt sich mit kurzen SQL-Ausdrücken ein besser lesbares Format erzeugen.
&lt;/p&gt;
&lt;h2&gt;Datumsangaben formatieren&lt;/h2&gt;
&lt;p&gt;
Hier gibt es zwei Herangehensweisen, &lt;code&gt;CONVERT()&lt;/code&gt; und &lt;code&gt;FORMAT()&lt;/code&gt;. Beides sind SQL-Funktionen, die die Lesbarkeit von Datumsangaben verbessern. Während die &lt;code&gt;CONVERT()&lt;/code&gt;-Funktion auch mit großen Datenmengen zügig arbeitet, erlaubt die &lt;code&gt;FORMAT()&lt;/code&gt;-Funktion mehr Flexibilität.
&lt;/p&gt;
&lt;p&gt;
Nehmen wir das Beispiel von oben. In Deiner Datenbank steht im DATETIME-Datentyp "2026-07-17 10:31:27.253" und die Tabellenspalte bzw. das Feld ist mit &lt;code&gt;MeinDatum&lt;/code&gt; benannt. Jetzt lässt sich mit folgender kurzer &lt;code&gt;CONVERT()&lt;/code&gt;-Anweisung daraus ein gut lesbares Ergebnis erzeugen:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CONVERT(VARCHAR(10), MeinDatum, 104)
-- Ergebnis: 17.07.2026&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Damit bist Du im deutschsprachigen Raum in den meisten Fällen bereits am Ziel. Kurze Erklärung: Die &lt;code&gt;CONVERT()&lt;/code&gt;-Funktion wandelt einen Datentyp in einen anderen um. Hier lag &lt;code&gt;MeinDatum&lt;/code&gt; im DATETIME-Typ vor und wurde in den VARCHAR-Datentyp umgewandelt. VARCHAR ist flexibel, da es einfacher Text ist und sich so fürs Darstellen gut eignet. Die 10 in Klammern gibt an, dass der Ausgabewert maximal 10 Zeichen lang sein darf, was genau zum deutschen Datumsformat passt. Dass das Datum das typische Format des deutschsprachigen Raums zeigt, wird durch die letzte Zahl im Code, 104, erreicht. 104 ist einfach der Style-Parameter für das deutsche Datumsformat. Verwendest Du hier 101, wird im Datum die Monatsangabe zuerst genannt, also typisch für den englischen Sprachraum.
&lt;/p&gt;
&lt;p&gt;
Das gleiche Ergebnis kannst Du mit der &lt;code&gt;FORMAT()&lt;/code&gt;-Funktion erreichen:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;FORMAT(MeinDatum, 'dd.MM.yyyy', 'de-DE')
-- Ergebnis: 17.07.2026&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Auch hier kurz erklärt: In der &lt;code&gt;FORMAT()&lt;/code&gt;-Funktion gibst Du zuerst das Datum an, das Du umwandeln möchtest. Als Zweites kannst Du angeben, wie das Zielformat aussieht, hier &lt;code&gt;'dd.MM.yyyy'&lt;/code&gt; für Tag, Monat und Jahr, und zuletzt gibst Du die sogenannte Kulturangabe an, also hier &lt;code&gt;'de-DE'&lt;/code&gt;, da wir das typische Format für den deutschsprachigen Raum erhalten möchten.
&lt;/p&gt;
&lt;p&gt;
Wie flexibel die Darstellung mit der &lt;code&gt;FORMAT()&lt;/code&gt;-Funktion ist, zeigt sich hier:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;FORMAT(MeinDatum, 'dd.MM.yyyy HH:mm', 'de-DE')
-- Ergebnis: 17.07.2026 10:31&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Hier kann durch die Angabe von &lt;code&gt;'dd.MM.yyyy&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;HH:mm'&lt;/code&gt; genau der Abstand zwischen dem Datums- und dem Uhrzeit-Teil in der Ausgabe festgelegt werden, indem Du eine beliebige Anzahl an Leerzeichen verwendest. Datum und Uhrzeit werden in der gleichen Zelle ausgegeben, aber bleiben durch größeren Abstand gut lesbar.
&lt;/p&gt;
&lt;h2&gt;Geldbeträge formatieren&lt;/h2&gt;
&lt;p&gt;
Geldbeträge formatierst Du am besten mit der &lt;code&gt;FORMAT()&lt;/code&gt;-Funktion. Steht in Deiner Datenbank ein Betrag mit der Bezeichnung &lt;code&gt;MeinBetrag&lt;/code&gt; von 100000 im MONEY-Datentyp, lässt sich mit der folgenden kurzen SQL-Anweisung ein gut lesbares Ergebnis erzielen:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;FORMAT(MeinBetrag, 'N2', 'de-DE')
-- Ergebnis: 100.000,00&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Das ist in den meisten Fällen schon genau das, was Du brauchst. Du gibst zuerst den Betrag an, dessen Darstellung Du optimieren möchtest. Dann den Formatstring &lt;code&gt;'N2'&lt;/code&gt;, um 2 Nachkommastellen anzeigen zu lassen, und als Drittes, wie beim Datum, die Kulturangabe (&lt;code&gt;'de-DE'&lt;/code&gt;). Leicht lässt sich durch Veränderung der Kulturangabe auf &lt;code&gt;'en-US'&lt;/code&gt; auch die typisch amerikanische Darstellung mit Komma als 1000er-Trennzeichen und Punkt als Dezimaltrennzeichen erhalten.
&lt;/p&gt;
&lt;p&gt;
Praktisch auch, dass sich mit &lt;code&gt;'C2'&lt;/code&gt; statt &lt;code&gt;'N2'&lt;/code&gt; als Formatstring direkt ein €-Zeichen einfügen lässt:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;FORMAT(MeinBetrag, 'C2', 'de-DE')
-- Ergebnis: 100.000,00 €&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Dabei ist die Kombination aus &lt;code&gt;'C2'&lt;/code&gt; als Formatstring und der Kulturangabe vielseitig, weil sich mit &lt;code&gt;'C2'&lt;/code&gt; und &lt;code&gt;'en-US'&lt;/code&gt; ganz leicht eine Darstellung des Betrages in $ erhalten lässt.
&lt;/p&gt;
&lt;p&gt;
Auch für die Darstellung von Prozentzahlen ist die &lt;code&gt;FORMAT()&lt;/code&gt;-Funktion bestens geeignet:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;FORMAT(0.1234, 'P', 'de-DE')
-- Ergebnis: 12,34 %&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Fazit&lt;/h2&gt;
&lt;p&gt;
Meist reicht in der Praxis je ein SQL-Ausdruck, um Datumsangaben und Geldbeträge sehr gut lesbar darzustellen. Nutze für Datumsangaben &lt;code&gt;CONVERT(VARCHAR(10), MeinDatum, 104)&lt;/code&gt; und für Geldbeträge &lt;code&gt;FORMAT(MeinBetrag, 'N2', 'de-DE')&lt;/code&gt; und sehr schnell wirst Du diese ohne großes Nachdenken fast automatisch einsetzen. Wenn Du dann noch im Hinterkopf hast, dass beide Funktionen etwas angepasst noch deutlich flexibler sind, kannst Du bei Bedarf sehr leicht nachschlagen, welche Eingaben genau zu Deinem Zielformat führen.
&lt;/p&gt;</content:encoded></item><item><title>Plan Guides im SQL Server: Abfragen optimieren, die Du gar nicht ändern kannst</title><link>https://appontes.de/blog/plan-guides-sql-server-abfragen-optimieren/</link><guid isPermaLink="true">https://appontes.de/blog/plan-guides-sql-server-abfragen-optimieren/</guid><pubDate>Thu, 09 Jul 2026 00:00:00 +0000</pubDate><dc:creator>Thomas Falkner</dc:creator><category>SQL Server</category><category>Performance</category><category>Plan Guide</category><category>Sage 100</category><description>Eine Abfrage aus der Anwendung läuft plötzlich minutenlang, obwohl niemand etwas geändert hat? Mit einem Plan Guide steuerst Du den Ausführungsplan, ohne eine Zeile Anwendungscode anzufassen. Ein echter Fall aus einer Sage 100 Datenbank, ehrlich nachgemessen.</description><content:encoded>&lt;p&gt;&lt;img src="https://appontes.de/img/blog/plan-guides-sql-server.svg" alt="Plan Guides im SQL Server: Abfragen optimieren, die Du gar nicht ändern kannst"&gt;&lt;/p&gt;
&lt;p&gt;
Plan Guides haben einen mäßigen Ruf. Zu fummelig, zu leicht falsch gesetzt, und wenn sie stillschweigend nicht mehr greifen, sucht man den Grund halbe Nachmittage. An dem Ruf ist etwas dran. Trotzdem sind sie in bestimmten Situationen das einzige Werkzeug, das übrig bleibt, und eine dieser Situationen begegnet uns bei Sage-100-Kunden immer wieder. Deshalb dieser Beitrag.
&lt;/p&gt;
&lt;p&gt;Das Muster ist fast immer gleich. Gestern lief die Rechnungsauskunft normal, heute steht sie. Kein Update, kein neuer Code, niemand hat etwas angefasst. Trotzdem braucht dieselbe Abfrage plötzlich das Zehnfache. Oft genug liegt es am Ausführungsplan, den sich der SQL Server neu zusammengebaut hat, diesmal falsch. Es gibt andere Ursachen, Blocking, einen I/O-Engpass, eine gekippte Statistik, aber ein entgleister Plan gehört zu den häufigsten. Läge die Abfrage in einer eigenen Prozedur, würdest Du einen Hint dranschreiben und fertig. Bei einer Standardsoftware wie Sage 100 gehört der SQL-Text aber der Anwendung. Du kommst an die Quelle nicht ran. Genau dafür wurden Plan Guides gebaut.&lt;/p&gt;
&lt;h2&gt;Kurz gesagt: Was ein Plan Guide macht&lt;/h2&gt;
&lt;p&gt;Ein Plan Guide hängt einen Query Hint von außen an eine Abfrage. Die Anwendung schickt weiter exakt dasselbe SQL, aber der Server behandelt es beim Kompilieren so, als stünde Dein &lt;code&gt;OPTION (...)&lt;/code&gt; mit im Text. Der Hersteller merkt nichts davon, das nächste Update überschreibt nichts, und Du hast trotzdem die Kontrolle über die Strategie. Microsoft nennt in der &lt;a href="https://learn.microsoft.com/de-de/sql/relational-databases/performance/plan-guides" target="_blank" rel="noopener"&gt;Dokumentation zu Planhinweislisten&lt;/a&gt; genau diesen Fall als Einsatzzweck: Wenn Du den Text der Abfrage nicht ändern möchtest oder kannst, etwa bei einer Drittanbieteranwendung.&lt;/p&gt;
&lt;p&gt;Es gibt drei Typen. &lt;strong&gt;SQL&lt;/strong&gt; für einzelne Anweisungen, die als Ad-hoc-Statement oder über &lt;code&gt;sp_executesql&lt;/code&gt; hereinkommen, und das ist bei ERP-Systemen mit Abstand der häufigste Fall. &lt;strong&gt;OBJECT&lt;/strong&gt; für Statements innerhalb einer Prozedur, Funktion oder eines Triggers. Und &lt;strong&gt;TEMPLATE&lt;/strong&gt;, das steuert die Parametrisierung selbst und wird so selten gebraucht, dass Du es vermutlich nie anfassen wirst. Für den Rest dieses Beitrags geht es um den SQL-Typ.&lt;/p&gt;
&lt;h2&gt;Warum der Optimizer überhaupt danebengreift&lt;/h2&gt;
&lt;p&gt;Wichtig zum Verständnis: Der Server baut den Plan einmal und verwendet ihn danach wieder. Beim Kompilieren schaut er sich den konkreten Parameterwert an, der gerade anliegt, und optimiert den Plan anhand der Statistiken genau für diesen einen Wert. Dieses Erschnüffeln nennt sich Parameter Sniffing. Solange die folgenden Aufrufe ähnlich viele Zeilen treffen, geht das gut. Weichen sie stark ab, passt der einmal gewählte Plan nicht mehr. Die üblichen Auslöser:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ungleich verteilte Daten. Der beim ersten Aufruf gesniffte Wert traf eine Handvoll Zeilen, der nächste trifft Hunderttausende. Der Plan bleibt aber der alte. Genau das sehen wir gleich im Beispiel.&lt;/li&gt;
&lt;li&gt;Schiefe oder veraltete Statistiken, typischerweise nach einem großen Import oder einer Migration. Die hinterlegte Verteilung stimmt nicht mehr, der Optimizer verschätzt sich um Größenordnungen.&lt;/li&gt;
&lt;li&gt;Plan-Regression nach einem Wechsel des Compatibility Levels oder des Cardinality Estimators. Eine Abfrage, die seit Jahren brav lief, bekommt auf einmal einen anderen Plan.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In all diesen Fällen weißt Du oft genau, welchen Plan der Server nehmen sollte. Sagen kannst Du es ihm nur nicht, weil die Quelle nicht Dir gehört. Der Plan Guide schließt diese Lücke.&lt;/p&gt;
&lt;h2&gt;Ein echter Fall aus einer Sage-100-Datenbank&lt;/h2&gt;
&lt;p&gt;Am konkreten Beispiel wird es greifbarer. Die Belegtabelle &lt;code&gt;KHKVKBelege&lt;/code&gt; einer Produktivdatenbank, rund 1,7 Millionen Verkaufsbelege, auf der Spalte &lt;code&gt;Belegkennzeichen&lt;/code&gt; ein schmaler nicht gruppierter Index. Diese Spalte ist grotesk ungleich gefüllt:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Belegkennzeichen Anzahl Belege
---------------- -------------
VFR 632.848
VLL 497.705
VVA 214.380
...
VSR 193
VFT 174&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Das häufigste Kennzeichen macht allein gut ein Drittel der Tabelle aus, das seltenste kommt nicht mal 200 Mal vor. Für Parameter Sniffing gibt es kaum eine schönere Ausgangslage. Die Anwendung schickt eine parametrisierte Abfrage, im Kern diese hier:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;exec sp_executesql
N'SELECT BelID, Belegnummer, Belegdatum, A0Name1, Nettobetrag
FROM KHKVKBelege
WHERE Belegkennzeichen = @kz AND Mandant = @m',
N'@kz varchar(3), @m smallint',
@kz = 'VFT', @m = 1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Kompiliert der Server das zum ersten Mal für ein seltenes Kennzeichen wie &lt;code&gt;VFT&lt;/code&gt;, schätzt er eine Handvoll Treffer und nimmt einen Index Seek mit Key Lookup. Für 174 Zeilen ist das goldrichtig, da gibt es nichts zu meckern. Nachgemessen an den logischen Lesevorgängen, also den 8-KB-Seiten, die der Server anfassen muss:&lt;/p&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;Ein und dasselbe Statement, drei Situationen:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;VFT&lt;/code&gt; (174 Treffer), Index Seek: &lt;strong&gt;719&lt;/strong&gt; Lesevorgänge.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;VFR&lt;/code&gt; (632.848 Treffer), Table Scan: &lt;strong&gt;464.056&lt;/strong&gt; Lesevorgänge.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;VFR&lt;/code&gt;, aber mit dem Seek-Plan, der eigentlich für &lt;code&gt;VFT&lt;/code&gt; gedacht war: &lt;strong&gt;6.962.174&lt;/strong&gt; Lesevorgänge.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;Die dritte Zeile ist der Schaden. Der zwischengespeicherte Seek-Plan trifft auf das häufige Kennzeichen und macht brav für jeden der 630.000 Treffer einen einzelnen Key Lookup in die Haupttabelle. Aus einem sauberen Scan mit 464.000 Lesevorgängen werden knapp sieben Millionen, Faktor fünfzehn. Im Arbeitsalltag ist das der Unterschied zwischen einer Auskunft, die aufgeht, und einem Fenster, das einfach steht.&lt;/p&gt;
&lt;p&gt;Das Perfide daran: Aus Anwendersicht wirkt es wie Zufall, ob Du in den GAU läufst. In Wahrheit hängt es daran, welcher Parameterwert bei der nächsten Kompilierung anliegt, also nach einem Neustart, einem Statistik-Update oder wenn der Plan aus dem Cache geflogen ist. Findest Du den Übeltäter über den Plan Cache oder den Query Store, siehst Du es sofort am verräterischen Missverhältnis im Plan: Geschätzte 174 Zeilen, tatsächlich 632.848. Wenn Estimated und Actual so weit auseinanderliegen, ist Sniffing fast immer die Antwort.&lt;/p&gt;
&lt;h2&gt;Der Plan Guide gegen das Sniffing&lt;/h2&gt;
&lt;p&gt;Die naheliegende Reaktion ist, dem Server das Sniffing abzugewöhnen und ihn mit der Durchschnittsverteilung rechnen zu lassen. Der Hint dafür heißt &lt;code&gt;OPTIMIZE FOR UNKNOWN&lt;/code&gt;. Klingt nach der sauberen Lösung. Ist sie in diesem Fall aber nicht, und das sieht man erst, wenn man nachmisst. Die Durchschnittsschätzung landet hier bei rund 122.000 Zeilen, und mit dieser Schätzung bleibt der Optimizer trotzdem beim Index Seek mit Key Lookup, statt auf den Scan zu wechseln:&lt;/p&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;&lt;code&gt;VFR&lt;/code&gt; mit &lt;code&gt;OPTIMIZE FOR UNKNOWN&lt;/code&gt;: &lt;strong&gt;2.572.590&lt;/strong&gt; Lesevorgänge. Besser als die knapp sieben Millionen aus dem Sniffing-GAU, aber immer noch das rund Fünffache des optimalen Scans mit 464.056. Für diese Abfrage ist der Durchschnitts-Hint also nicht die Lösung, sondern nur ein etwas weniger schlimmer Fehler.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Was hier wirklich zieht, ist &lt;code&gt;OPTION (RECOMPILE)&lt;/code&gt;. Damit baut der Server bei jedem Aufruf einen frischen Plan, sniffed den tatsächlich übergebenen Wert und liefert pro Wert das Optimum: Den Seek für &lt;code&gt;VFT&lt;/code&gt; mit 719 Lesevorgängen, den Scan für &lt;code&gt;VFR&lt;/code&gt; mit 464.056. Kein einziger Ausreißer mehr. In den Anwendungscode können wir den Hint nicht schreiben, also hängen wir ihn per Plan Guide an. Genau dieses Muster zeigt übrigens auch die Microsoft-Dokumentation als Beispiel:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;EXEC sp_create_plan_guide
@name = N'PG_Belege_Belegkennzeichen',
@stmt = N'SELECT BelID, Belegnummer, Belegdatum, A0Name1, Nettobetrag
FROM KHKVKBelege
WHERE Belegkennzeichen = @kz AND Mandant = @m',
@type = N'SQL',
@module_or_batch = NULL,
@params = N'@kz varchar(3), @m smallint',
@hints = N'OPTION (RECOMPILE)';&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Der Preis ist eine Kompilierung pro Ausführung. Bei dieser Auskunft, die ein Sachbearbeiter ein paar Mal am Tag aufruft, fällt das nicht ins Gewicht. Läuft eine Abfrage dagegen zehntausendfach pro Stunde mit demselben Wert, willst Du nicht jedes Mal neu kompilieren. Dann ist der bessere Weg, gezielt den guten Plan festzunageln, also den Scan, der für den häufigen Fall ideal und für die seltenen Werte gerade noch in Ordnung ist. Aber als robuster Startpunkt ist &lt;code&gt;RECOMPILE&lt;/code&gt; hier goldrichtig.&lt;/p&gt;
&lt;p&gt;Und jetzt der nervige Teil, der die meisten Plan Guides scheitern lässt. Der Text in &lt;code&gt;@stmt&lt;/code&gt; muss zeichengenau dem entsprechen, was die Anwendung schickt. Die Doku ist da unmissverständlich: SQL Server vergleicht Zeichen für Zeichen, ohne jede Normalisierung. Jedes Leerzeichen, jeder Zeilenumbruch, jede Klammer. Ein Tippfehler, und der Guide liegt nutzlos herum, ohne dass Dich irgendwer warnt. Also nicht abtippen, sondern den exakten Text aus dem Plan Cache holen, über &lt;code&gt;sys.dm_exec_query_stats&lt;/code&gt; zusammen mit &lt;code&gt;sys.dm_exec_sql_text&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Nicht verwechseln solltest Du das mit &lt;code&gt;sp_create_plan_guide_from_handle&lt;/code&gt;. Diese Prozedur macht etwas anderes: Sie friert einen bereits im Cache liegenden Plan ein, im Kern wie ein &lt;code&gt;USE PLAN&lt;/code&gt;. Praktisch, wenn Du einen konkreten guten Plan dauerhaft festhalten willst. Für unseren Sniffing-Fall aber mit Vorsicht zu genießen, denn wenn gerade der katastrophale Seek-Plan im Cache liegt und Du ihn erwischst, nagelst Du genau den fest. Zum reinen Ermitteln des Statement-Texts taugt sie nicht, dafür sind die beiden DMVs oben da.&lt;/p&gt;
&lt;p&gt;Ob der Guide gültig ist, sagt Dir diese Abfrage. Kommt kein Ergebnis zurück, passt es:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT * FROM sys.fn_validate_plan_guide(
(SELECT plan_guide_id FROM sys.plan_guides
WHERE name = N'PG_Belege_Belegkennzeichen'));&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Gültig heißt aber noch nicht angewendet. Ob er wirklich greift, verrät der Ausführungsplan: Im Eigenschaftenfenster (F4 auf dem Wurzeloperator) muss das Attribut &lt;code&gt;PlanGuideName&lt;/code&gt; mit Deinem Namen auftauchen. Erst dann glaube ich es.&lt;/p&gt;
&lt;h2&gt;Neuere Versionen machen es einfacher&lt;/h2&gt;
&lt;p&gt;Der klassische Plan Guide ist alt und ein bisschen sperrig, und Microsoft hat das Drumherum inzwischen deutlich komfortabler gemacht. Auf welcher SQL-Server-Version was geht, ändert sich von Release zu Release, deshalb hier nur die groben Linien und für die Details der Verweis auf die offizielle Doku.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Willst Du bloß einen bekannten guten Plan festhalten, geht das über den Query Store per Plan-Forcing bequemer als über einen Plan Guide, ganz ohne die heikle Textzuordnung.&lt;/li&gt;
&lt;li&gt;Willst Du einen Hint setzen, ohne den Code zu ändern, gibt es seit SQL Server 2022 die &lt;a href="https://learn.microsoft.com/de-de/sql/relational-databases/performance/query-store-hints" target="_blank" rel="noopener"&gt;Query Store Hints&lt;/a&gt;. Microsoft empfiehlt sie in der Doku inzwischen ausdrücklich als den einfacheren Weg gegenüber Plan Guides.&lt;/li&gt;
&lt;li&gt;Und die Parameter Sensitive Plan Optimization kann genau die Art von Schieflage, die wir oben hatten, auf neueren Versionen teils von selbst entschärfen, indem sie je nach Parameterwert unterschiedliche Pläne vorhält.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Für welche Version welches dieser Werkzeuge verfügbar und sinnvoll ist, schaust Du am besten tagesaktuell in der Microsoft-Dokumentation nach. Der klassische Plan Guide bleibt trotzdem relevant: Auf älteren Versionen, für OBJECT- und TEMPLATE-Fälle, und immer dann, wenn die bequemeren Wege für Deine Situation nicht greifen.&lt;/p&gt;
&lt;p&gt;Bei alldem ein Wort der Warnung, das mir wichtig ist. Ein erzwungener Plan oder Hint ist eine Krücke, keine Heilung. Er ist goldrichtig, wenn Du an die Quelle nicht rankommst. Aber er versteinert eine Entscheidung, die der Optimizer sonst laufend an neue Datenmengen anpasst. Also: Jeden Guide dokumentieren, nach jedem Anwendungsupdate erneut prüfen, und ihn wieder rausschmeißen, sobald die eigentliche Ursache behoben ist. Der vergessene Plan Guide, der seit drei Jahren einen längst überholten Plan festhält, ist einer der undankbarsten Fehler überhaupt, weil ihn niemand mehr auf dem Schirm hat.&lt;/p&gt;
&lt;h2&gt;Fazit&lt;/h2&gt;
&lt;p&gt;Plan Guides sehen nach Nischenwissen aus, aber sie geben Dir die Kontrolle über Abfragen zurück, die Du eigentlich nicht anfassen darfst, und bei einer Standardsoftware wie Sage 100 ist das der Normalfall, nicht die Ausnahme. Unser Belegbeispiel zeigt zweierlei: Den Hebel, aus fast sieben Millionen Lesevorgängen werden mit dem richtigen Hint wieder ein paar Hunderttausend. Und die Mahnung, erst zu messen. Der auf den ersten Blick naheliegende &lt;code&gt;OPTIMIZE FOR UNKNOWN&lt;/code&gt; hätte hier nur die Hälfte gebracht, gemessen wurde es besser mit &lt;code&gt;RECOMPILE&lt;/code&gt;. Welchen Plan der Server warum nimmt, versteht man nicht durch Raten, sondern durch Nachschauen.&lt;/p&gt;
&lt;p&gt;Falls bei Euch so eine Abfrage regelmäßig entgleist und keiner den Grund findet: Das ist genau die Sorte Problem, die wir gern übernehmen. Meldet Euch.&lt;/p&gt;
&lt;div style="text-align: center; margin: 3rem 0;"&gt;
&lt;a href="https://appontes.de/kontakt/?betreff=anfrage-sage" class="btn btn-primary"&gt;SQL-Performance prüfen lassen&lt;/a&gt;
&lt;/div&gt;</content:encoded></item><item><title>Sanktionslisten prüfen: Kunden und Lieferanten in Minuten gegen die EU-Liste abgleichen</title><link>https://appontes.de/blog/sanktionslisten-check-stammdaten/</link><guid isPermaLink="true">https://appontes.de/blog/sanktionslisten-check-stammdaten/</guid><pubDate>Thu, 02 Jul 2026 00:00:00 +0000</pubDate><dc:creator>Thomas Falkner</dc:creator><category>Sage 100</category><category>Compliance</category><category>Stammdaten</category><category>Rechnungswesen</category><description>Sanktionslisten gelten nicht nur für Banken, sondern für jedes Unternehmen. Wie Du einzelne Namen oder ganze Kunden- und Lieferantenlisten aus Sage 100 gegen die EU-Konsolidierte-Liste abgleichst, was ein guter Treffer-Score bedeutet und warum der Abgleich komplett lokal im Browser läuft.</description><content:encoded>&lt;p&gt;&lt;img src="https://appontes.de/img/blog/sanktionslisten-check.svg" alt="Sanktionslisten prüfen: Kunden und Lieferanten in Minuten gegen die EU-Liste abgleichen"&gt;&lt;/p&gt;
&lt;p&gt;
Es gibt Pflichten, die viele mittelständische Unternehmen mit Banken verbinden und nicht mit sich selbst. Der Abgleich von Geschäftspartnern gegen Sanktionslisten gehört dazu. Tatsächlich richtet sich das EU-Sanktionsrecht an jeden. Wer einer sanktionierten Person oder Organisation Gelder oder wirtschaftliche Ressourcen zur Verfügung stellt, verstößt dagegen, unabhängig davon, ob er eine Bank ist oder ein Handwerksbetrieb mit dreißig Mitarbeitern.
&lt;/p&gt;
&lt;p&gt;
Die gute Nachricht: Ein erster Abgleich ist keine Raketentechnik. Die EU stellt eine konsolidierte Liste der sanktionierten Personen, Gruppen und Organisationen bereit. Genau dagegen kannst Du Deine Kunden und Lieferanten prüfen. Damit das schnell geht und Du nicht erst eine Software einführen musst, haben wir einen &lt;a href="https://appontes.de/tools/sanktionslisten-check/"&gt;Sanktionslisten-Schnellcheck&lt;/a&gt; gebaut, der direkt im Browser läuft.
&lt;/p&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;&lt;strong&gt;Kurz vorab:&lt;/strong&gt; Dieser Beitrag ist eine praktische Einordnung, keine Rechtsberatung. Der Schnellcheck ist eine erste Plausibilitätsprüfung, kein rechtssicherer Nachweis. Ein Treffer ist ein Hinweis, den Du fachlich prüfen musst, und ein fehlender Treffer schließt eine Betroffenheit nicht sicher aus. Für die verbindliche Beurteilung im Einzelfall ist die amtliche Liste maßgeblich. In Deutschland ist die Deutsche Bundesbank das Servicezentrum für Finanzsanktionen.&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;1. Warum das jeden betrifft, nicht nur Banken&lt;/h2&gt;
&lt;p&gt;
Sanktionen sind in den vergangenen Jahren spürbar in den Alltag normaler Unternehmen gerückt. Wer im Ausland einkauft, mit neuen Lieferanten startet oder Zahlungen ins Ausland auslöst, sollte wissen, mit wem er es zu tun hat. Ein Treffer muss dabei nicht offensichtlich sein. Firmen tauchen unter Tochtergesellschaften auf, Personen unter verschiedenen Schreibweisen, und eine sanktionierte Partei steht selten mit dem Namen in der Liste, den Du gerade in Deinem Beleg vor Dir hast.
&lt;/p&gt;
&lt;p&gt;
Der Sinn eines Abgleichs ist deshalb nicht, jeden Geschäftspartner unter Generalverdacht zu stellen. Es geht darum, die wenigen auffälligen Fälle früh zu erkennen, bevor eine Zahlung rausgeht. Genau dafür ist ein Schnellcheck da: Er ersetzt keine Compliance-Abteilung, aber er verschafft Dir in Minuten einen ersten belastbaren Eindruck.
&lt;/p&gt;
&lt;h2&gt;2. Was der Schnellcheck macht&lt;/h2&gt;
&lt;p&gt;
Das Tool gleicht Namen und Firmen gegen die EU-Konsolidierte-Liste der Finanzsanktionen ab. Diese Liste wird von der Europäischen Kommission bereitgestellt und im Hintergrund automatisch aktuell gehalten. Welcher Listenstand gerade geprüft wird, siehst Du direkt im Tool angezeigt, damit Du weißt, worauf Deine Prüfung beruht.
&lt;/p&gt;
&lt;p&gt;
Zu jedem möglichen Treffer bekommst Du nicht nur ein Ja oder Nein, sondern die Details, die Du für die weitere Prüfung brauchst: Den Namen aus der Liste, bekannte Aliasnamen, soweit vorhanden das Land und das Geburtsdatum, das zugrunde liegende EU-Programm und die Referenznummer des Eintrags. So kannst Du selbst beurteilen, ob der Treffer zu Deinem Geschäftspartner passt oder nur eine zufällige Namensähnlichkeit ist.
&lt;/p&gt;
&lt;h2&gt;3. Einzelner Name oder ganze Liste aus Sage 100&lt;/h2&gt;
&lt;p&gt;
Für die schnelle Frage zwischendurch gibst Du einfach einen Namen oder eine Firma ein, optional dazu das Land und bei Personen das Geburtsjahr. Das reicht, um einen neuen Geschäftspartner vor dem ersten Auftrag kurz gegenzuprüfen.
&lt;/p&gt;
&lt;p&gt;
Interessanter für die Buchhaltung ist die Listenprüfung. Du exportierst Deine Kunden, Lieferanten und Ansprechpartner aus Sage 100 als CSV und lädst die Datei hoch. Das Tool erkennt die typischen Spalten eines Sage-Exports automatisch, also Kto, Matchcode, Name1, Name2, Strasse, PLZ, Ort und Land, und prüft jede Zeile. Am Ende steht eine Übersicht in der Art: So viele Datensätze geprüft, so viele sind manuell zu prüfen. Die auffälligen Zeilen kannst Du als CSV exportieren oder als PDF ausdrucken und an die Kollegen weitergeben, die den Fall final beurteilen.
&lt;/p&gt;
&lt;h2&gt;4. Warum ein Score und kein einfaches Ja oder Nein&lt;/h2&gt;
&lt;p&gt;
Ein reiner Textvergleich reicht bei Namen nicht aus. Menschen und Firmen tauchen in verschiedenen Schreibweisen auf, mit Umlauten oder ohne, mit oder ohne Rechtsform, transkribiert aus anderen Alphabeten. Deshalb arbeitet der Check mit einem unscharfen Abgleich. Namen werden normalisiert, Rechtsformen wie GmbH, AG oder Ltd werden herausgerechnet, und es wird tokenweise verglichen.
&lt;/p&gt;
&lt;p&gt;
Der entscheidende Kniff dabei: Seltene, kennzeichnende Namensbestandteile zählen stärker als Allerweltswörter. Dass zwei Firmen beide das Wort Trading oder Bank im Namen tragen, ist kein Treffer. Dass ein ungewöhnlicher Eigenname übereinstimmt, dagegen schon. So bekommst Du eine überschaubare Zahl echter Prüffälle statt einer Flut von Fehlalarmen. Das Ergebnis ist ein Score mit klarer Einordnung, von unauffällig über möglicher Treffer bis Treffer prüfen. Behandle einen Treffer immer als Hinweis, nicht als gesichertes Urteil.
&lt;/p&gt;
&lt;h2&gt;5. Alles bleibt lokal im Browser&lt;/h2&gt;
&lt;p&gt;
Kunden- und Lieferantenlisten sind sensible Daten. Deshalb war uns von Anfang an wichtig, dass diese Daten Dein Gerät nicht verlassen. Der Ablauf ist bewusst umgedreht: Nicht Deine Liste wandert zu einem Server, sondern die Sanktionsliste wird einmal in Deinen Browser geladen. Der komplette Abgleich passiert danach lokal auf Deinem Rechner. Es wird nichts hochgeladen, nichts gespeichert und nichts zum Training verwendet. Du kannst den Check also bedenkenlos mit echten Stammdaten nutzen.
&lt;/p&gt;
&lt;h2&gt;6. Wo die Grenzen liegen&lt;/h2&gt;
&lt;p&gt;
Eine ehrliche Einordnung gehört dazu. Der Schnellcheck prüft derzeit gegen die EU-Konsolidierte-Liste. UN-, UK- und US-Listen wie die OFAC-Liste sind nicht enthalten. Er ist eine Plausibilitätsprüfung und kein rechtssicherer Nachweis. Bei stark abweichenden Schreibweisen kann ein tatsächlicher Treffer durchrutschen, und umgekehrt bleibt jeder angezeigte Treffer ein Prüffall, kein bestätigtes Ergebnis. Für die verbindliche Beurteilung zählt die amtliche Liste im Einzelfall, im Zweifel gemeinsam mit fachkundiger Beratung.
&lt;/p&gt;
&lt;p&gt;
Für den ersten Eindruck und die regelmäßige Selbstkontrolle ist das Werkzeug aber genau richtig. Probier es einfach aus: &lt;a href="https://appontes.de/tools/sanktionslisten-check/"&gt;Sanktionslisten-Schnellcheck öffnen&lt;/a&gt;. Und wenn aus der gelegentlichen manuellen Prüfung eine feste Routine werden soll, lässt sich das automatisieren. Wir können Deine Kunden und Lieferanten aus Sage 100 regelmäßig gegen die aktuellen Listen prüfen und auffällige Treffer sauber protokollieren, damit Du im Ernstfall nachweisen kannst, dass Du hingeschaut hast. Melde Dich, wenn Du das aufsetzen möchtest.
&lt;/p&gt;</content:encoded></item><item><title>Wie Sage 100 den Steuercode in der Warenwirtschaft ermittelt</title><link>https://appontes.de/blog/steuercodeermittlung-sage-100/</link><guid isPermaLink="true">https://appontes.de/blog/steuercodeermittlung-sage-100/</guid><pubDate>Tue, 30 Jun 2026 00:00:00 +0000</pubDate><dc:creator>Thomas Falkner</dc:creator><category>Sage 100</category><category>Umsatzsteuer</category><category>Warenwirtschaft</category><description>Warum schlägt Sage 100 bei einer Belegposition automatisch 19 Prozent, 7 Prozent oder steuerfrei vor? Wir erklären das Zusammenspiel aus Besteuerungsart, Steuerklasse und dem entscheidenden Register Gebiet, mit dem betriebswirtschaftlichen Hintergrund dazu.</description><content:encoded>&lt;p&gt;&lt;img src="https://appontes.de/img/blog/steuercodeermittlung-sage-100.svg" alt="Wie Sage 100 den Steuercode in der Warenwirtschaft ermittelt"&gt;&lt;/p&gt;
&lt;p&gt;
Du erfasst in der Sage 100 einen Auftrag, wählst einen Artikel aus, und schon steht in der Position ein Steuercode mit 19 Prozent. Beim nächsten Artikel sind es plötzlich 7 Prozent, beim Kunden aus dem EU-Ausland mit Umsatzsteuer-Identifikationsnummer steht da auf einmal eine ganz andere Schlüsselung. Woher weiß das System das eigentlich? Und vor allem: Worauf kannst Du Dich verlassen, wenn am Monatsende die Umsatzsteuervoranmeldung daraus entsteht?
&lt;/p&gt;
&lt;p&gt;
Die kurze Antwort: Sage 100 rät nicht, sondern rechnet. Der vorgeschlagene Steuercode ist das Ergebnis einer klaren Logik aus zwei Stammdaten und einer Zuordnungstabelle. Wer diese Logik kennt, versteht nicht nur, warum ein Vorschlag so aussieht, wie er aussieht, sondern kann Fehler auch dort beheben, wo sie entstehen.
&lt;/p&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;
&lt;strong&gt;Wichtig vorweg:&lt;/strong&gt; Dieser Beitrag erklärt, auf welche Weise Sage 100 den Steuercode technisch ermittelt. Er ist keine steuerliche Beratung und keine Vorgabe, welcher Steuersatz auf welchen Geschäftsvorfall gehört. Welche Steuercodes für Deine Vorgänge richtig sind, klärst Du mit Deiner Steuerberatung. Geplante Änderungen an den Einstellungen probierst Du am besten vorher im Demo- oder einem eigenen Testmandanten aus.
&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;Warum die richtige Schlüsselung mehr als eine Formsache ist&lt;/h2&gt;
&lt;p&gt;
Bevor wir in die Technik gehen, ein Wort dazu, warum das Thema im Tagesgeschäft so viel Gewicht hat. Der Steuercode an einer Belegposition entscheidet, wie der Umsatz umsatzsteuerlich behandelt wird. Daraus speisen sich die Buchungen, die Umsatzsteuervoranmeldung und am Ende die Zusammenfassende Meldung. Ein falscher Code bleibt deshalb selten ein Einzelfehler. Er wandert durch die ganze Kette bis zum Finanzamt.
&lt;/p&gt;
&lt;p&gt;
Die Fälle, in denen es darauf ankommt, sind im Mittelstand Alltag. Eine innergemeinschaftliche Lieferung an einen Geschäftskunden in der EU ist nur dann steuerfrei, wenn die Voraussetzungen stimmen und eine gültige Umsatzsteuer-Identifikationsnummer vorliegt. Bei bestimmten Leistungen greift die Steuerschuldumkehr nach Paragraf 13b UStG, dann weist Du als Lieferant gar keine Steuer aus, sondern der Empfänger schuldet sie. Und bei Artikeln mit ermäßigtem Satz, etwa Büchern oder bestimmten Lebensmitteln, sind es eben 7 statt 19 Prozent. Sage 100 bildet diese Unterschiede über den Steuercode ab, und genau deshalb lohnt es sich zu verstehen, wie er entsteht.
&lt;/p&gt;
&lt;h2&gt;Die zwei Zutaten: Besteuerungsart und Steuerklasse&lt;/h2&gt;
&lt;p&gt;
Die ganze Ermittlung beruht auf dem Zusammenspiel von zwei Informationen. Die eine hängt am Geschäftspartner, die andere am Artikel.
&lt;/p&gt;
&lt;p&gt;
Die &lt;strong&gt;Besteuerungsart&lt;/strong&gt; hinterlegst Du beim Kunden oder Lieferanten. Sie beantwortet die Frage, in welchem steuerlichen Kontext der Geschäftspartner steht: Inland, EU mit gültiger Umsatzsteuer-Identifikationsnummer, Drittland, ein Fall der Steuerschuldumkehr und so weiter. Betriebswirtschaftlich ist das die Sicht auf das Gegenüber, also wer kauft oder liefert und unter welchen Regeln.
&lt;/p&gt;
&lt;p&gt;
Die &lt;strong&gt;Steuerklasse&lt;/strong&gt; hinterlegst Du beim Artikel. Sie sagt, ob für diesen Artikel der normale Satz, der ermäßigte Satz oder gar kein Steuersatz gilt. Auch Sonderregelungen für einzelne Artikel lassen sich hier abbilden. Das ist die Sicht auf das, was verkauft wird.
&lt;/p&gt;
&lt;p&gt;
Aus der Kombination dieser beiden Angaben leitet Sage 100 den Steuercode der Position ab. Man kann sich das wie eine Tabelle vorstellen: In der einen Achse steht, mit wem Du es zu tun hast, in der anderen, was über den Tresen geht. Im Schnittpunkt liegt der passende Steuercode. Genau diese Tabelle pflegst Du an einer zentralen Stelle, dazu gleich mehr.
&lt;/p&gt;
&lt;h2&gt;Wo die Grundlagen liegen&lt;/h2&gt;
&lt;p&gt;
Die Bausteine dafür findest Du im Hauptmenü unter &lt;em&gt;Grundlagen – Umsatzsteuer&lt;/em&gt;. Drei Punkte sind dort wichtig:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Besteuerungsarten.&lt;/strong&gt; Hier legst Du fest, welchem Besteuerungsgebiet oder welcher Besteuerungsform ein Kunde oder Lieferant unterliegt.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Steuerklassen.&lt;/strong&gt; Hier bestimmst Du, ob für einen Artikel kein, der ermäßigte oder der normale Mehrwertsteuersatz gilt, inklusive eventueller Sonderfälle.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Steuersätze.&lt;/strong&gt; Hier liegen die eigentlichen Prozentsätze, also die 19 oder 7 Prozent, die hinter den Codes stehen.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Diese Grundlagen sind die Voraussetzung. Damit daraus an der Position ein konkreter Code wird, müssen die Informationen aber auch in den Stammdaten ankommen.
&lt;/p&gt;
&lt;h2&gt;Wo Du die Einstellungen pro Datensatz pflegst&lt;/h2&gt;
&lt;p&gt;
Beim Geschäftspartner findest Du die Besteuerungsart im Kontokorrentstamm. Du öffnest unter &lt;em&gt;Stammdaten – Kunden/Lieferanten&lt;/em&gt; (oder über &lt;em&gt;Stammdaten – Adressen&lt;/em&gt; beim Bearbeiten des Kontokorrents) den gewünschten Datensatz und legst im Register &lt;em&gt;Grundlagen&lt;/em&gt; die standardmäßig geltende Besteuerungsart fest.
&lt;/p&gt;
&lt;p&gt;
Beim Artikel sitzt die Steuerklasse im Register &lt;em&gt;Faktura&lt;/em&gt; unter &lt;em&gt;Stammdaten – Artikel&lt;/em&gt;. Ein praktischer Hinweis am Rande: Weil sich die Oberfläche der Sage 100 anpassen lässt, kann es sein, dass diese Felder bei Dir in einem anderen Register oder an einer anderen Stelle liegen. Die Logik dahinter bleibt aber dieselbe.
&lt;/p&gt;
&lt;p&gt;
Hier zeigt sich auch der betriebswirtschaftliche Kern: Die Steuerermittlung ist nur so gut wie Deine Stammdaten. Wird ein Neukunde mit der falschen Besteuerungsart angelegt oder ein Artikel der falschen Steuerklasse zugeordnet, schlägt Sage 100 zuverlässig den falschen Code vor, und zwar auf jedem künftigen Beleg. Saubere Stammdaten sind deshalb kein Selbstzweck, sondern die Stelle, an der sich Steuerfehler am günstigsten vermeiden lassen.
&lt;/p&gt;
&lt;h2&gt;Das Herzstück: Das Register Gebiet&lt;/h2&gt;
&lt;p&gt;
Jetzt zur eigentlichen Schaltzentrale. Die Verknüpfung von Steuerklasse und Besteuerungsart zu einem konkreten Steuercode passiert im Register &lt;em&gt;Gebiet&lt;/em&gt;, das Du unter &lt;em&gt;Grundlagen – Umsatzsteuer – Steuerklassen&lt;/em&gt; findest. Das ist die erwähnte Tabelle, in der die beiden Achsen zusammenkommen.
&lt;/p&gt;
&lt;p&gt;
So liest Du sie: Oben markierst Du eine Steuerklasse, zum Beispiel den Normalsatz. Im unteren Bereich siehst Du dann die einzelnen Gebiete, also die verschiedenen Besteuerungsarten wie Inland, EU mit Umsatzsteuer-Identifikationsnummer oder die Fälle nach Paragraf 13b. Zu jedem Gebiet ist hinterlegt, welcher Steuercode für eine Lieferung und welcher für einen Erwerb gezogen wird. Genau dieser Eintrag landet später in der Belegposition.
&lt;/p&gt;
&lt;p&gt;
Zwei Beispiele aus dem Standard-Demomandanten machen das greifbar:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Du erfasst einen Verkaufsbeleg für einen Kunden mit der Besteuerungsart &lt;em&gt;EU mit Umsatzsteuer-Identifikationsnummer&lt;/em&gt; und einem Artikel im Normalsatz. In den Positionsdetails siehst Du, dass Steuercode 10 gezogen wird. Der Grund: Für die Kombination aus Steuerklasse Normalsatz und Gebiet EU mit UStID ist im Register Gebiet genau dieser Code als Steuercode Lieferung eingestellt.&lt;/li&gt;
&lt;li&gt;Du legst für einen Inländer einen Auftrag über einen Artikel mit der Steuerklasse &lt;em&gt;Ermäßigter Satz&lt;/em&gt; an. Hier wird Steuercode 2 herangezogen, weil dieser für das Gebiet Inland und die Steuerklasse Ermäßigter Satz gepflegt ist.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Wenn Du also wissen willst, warum eine Position einen bestimmten Code bekommt, musst Du nicht raten. Du schaust Dir an, welche Besteuerungsart am Partner und welche Steuerklasse am Artikel steht, und liest im Register Gebiet den Schnittpunkt ab. Das ist die ganze Mechanik.
&lt;/p&gt;
&lt;h2&gt;Worauf Du im Alltag achten solltest&lt;/h2&gt;
&lt;h3&gt;EU-Länder und die Lieferschwelle&lt;/h3&gt;
&lt;p&gt;
Neben den allgemeinen Gebieten bietet Dir das Register Gebiet auch die einzelnen EU-Länder an. Die dort eingetragenen Steuercodes kommen zum Einsatz, sobald die Lieferschwelle überschritten ist. Das ist vor allem für den Versandhandel an Privatkunden in der EU relevant. Seit 2021 gilt hier eine gemeinsame, EU-weite Schwelle, ab der Du die Umsatzsteuer des Bestimmungslandes abführen musst, in der Praxis meist gebündelt über das One-Stop-Shop-Verfahren. Wer regelmäßig an Endkunden ins EU-Ausland verkauft, sollte diese Einstellungen also bewusst pflegen und nicht dem Zufall überlassen.
&lt;/p&gt;
&lt;h3&gt;Änderungen wirken nicht rückwirkend&lt;/h3&gt;
&lt;p&gt;
Ein Punkt, der schnell für Verwirrung sorgt: Wenn Du unter &lt;em&gt;Grundlagen – Umsatzsteuer&lt;/em&gt; etwas änderst, musst Du die Anwendung einmal neu starten, damit die Änderung greift. Und sie gilt ausdrücklich nicht rückwirkend. Bereits erfasste Belege werden nicht automatisch aktualisiert. Das ist betriebswirtschaftlich sogar gewollt, denn ein einmal gestellter Beleg soll seinen steuerlichen Inhalt behalten. Es bedeutet aber, dass Du nach einer Umstellung gezielt prüfen musst, welche offenen Vorgänge noch die alte Schlüsselung tragen.
&lt;/p&gt;
&lt;h3&gt;Wenn die Besteuerungsart versehentlich falsch war&lt;/h3&gt;
&lt;p&gt;
Der Klassiker: Beim Erfassen fällt auf, dass ein Kunde die falsche Besteuerungsart hatte. Solange im Vorgang noch keine Folgebelege existieren, kannst Du das direkt in den Positionsdetails im Belegkopf korrigieren. Liegt zum Beispiel nur eine Auftragsbestätigung vor, lässt sich die Besteuerungsart dort noch ändern. Sobald aber zu dieser Auftragsbestätigung bereits ein Lieferschein erfasst und gespeichert wurde, geht das nicht mehr so einfach.
&lt;/p&gt;
&lt;p&gt;
Für diesen Fall gibt es zwei praktikable Wege. Entweder eröffnest Du einen neuen Vorgang und erfasst die weiteren Belege dort, oder Du änderst den Steuercode gezielt für die einzelnen Positionen über das Menü im Positionsregister unter &lt;em&gt;Schnelländerung – Steuercodes ändern&lt;/em&gt;. Beachte dabei, dass sich zu Zuschlagsartikeln im Belegfuß keine Positionsdetails aufrufen lassen.
&lt;/p&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;
&lt;strong&gt;Ein nützlicher Kniff:&lt;/strong&gt; Hast Du die Besteuerungsart zuerst im Stammdatensatz korrigiert, kannst Du im Belegkopf einmal kurz auf einen alternativen Rechnungsempfänger wechseln und danach wieder auf den ursprünglichen Auftraggeber zurückstellen. Dadurch stößt Sage 100 eine neue Ermittlung der Steuer an. Solche Korrekturen solltest Du protokollieren und im Zweifel mit Deiner Steuerberatung abstimmen, am besten für alle Belege des Vorgangs einheitlich.
&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;
Für den Einkauf gibt es zusätzlich eine Einstellung unter &lt;em&gt;Grundlagen – Mandant – Einstellungen&lt;/em&gt; im Register &lt;em&gt;Einkaufsbelege&lt;/em&gt;, mit der Du die Besteuerungsart auch noch für Folgebelege anpassen kannst.
&lt;/p&gt;
&lt;h2&gt;Fazit&lt;/h2&gt;
&lt;p&gt;
Der Steuercode in der Sage 100 Warenwirtschaft fällt nicht vom Himmel. Er entsteht aus der Besteuerungsart am Geschäftspartner, der Steuerklasse am Artikel und der Zuordnung im Register Gebiet, das beides zusammenführt. Wer dieses Dreieck versteht, kann jeden Vorschlag nachvollziehen und Fehler an der Wurzel beheben, statt sie Position für Position auszubessern.
&lt;/p&gt;
&lt;p&gt;
Der wirtschaftliche Hebel liegt dabei in den Stammdaten. Eine sauber gepflegte Besteuerungsart und die richtige Steuerklasse sorgen dafür, dass die Umsatzsteuer von der Erfassung bis zur Voranmeldung stimmt, ohne ständiges Nachbessern. Genau hier setzen wir an, wenn wir Sage 100 einführen oder bestehende Installationen aufräumen.
&lt;/p&gt;
&lt;p&gt;
Du bist Dir bei Deiner Steuerschlüsselung unsicher oder willst Deine Stammdaten einmal sauber aufsetzen, bevor sich Fehler durch die Voranmeldung ziehen? Dann lass uns darüber sprechen.
&lt;/p&gt;
&lt;div style="text-align: center; margin: 3rem 0;"&gt;
&lt;a href="https://appontes.de/kontakt/?betreff=anfrage-sage" class="btn btn-primary"&gt;Kostenlose Erstberatung vereinbaren&lt;/a&gt;
&lt;/div&gt;</content:encoded></item><item><title>Rechnungsersetzende Gutschrift im Einkauf: Self-Billing in Sage 100</title><link>https://appontes.de/blog/rechnungsersetzende-gutschrift-sage-100/</link><guid isPermaLink="true">https://appontes.de/blog/rechnungsersetzende-gutschrift-sage-100/</guid><pubDate>Sat, 27 Jun 2026 00:00:00 +0000</pubDate><dc:creator>Thomas Falkner</dc:creator><category>Sage 100</category><category>Einkauf</category><category>Rechnungswesen</category><description>Beim Gutschriftverfahren rechnest Du als Einkäufer selbst gegenüber Deinem Lieferanten ab, statt auf dessen Rechnung zu warten. Wir erklären den betriebswirtschaftlichen Hintergrund, die steuerlichen Spielregeln und wie Du die rechnungsersetzende Gutschrift in Sage 100 einrichtest und buchst.</description><content:encoded>&lt;p&gt;&lt;img src="https://appontes.de/img/blog/rechnungsersetzende-gutschrift.svg" alt="Rechnungsersetzende Gutschrift im Einkauf: Self-Billing in Sage 100"&gt;&lt;/p&gt;
&lt;p&gt;
Normalerweise ist die Rollenverteilung im Einkauf klar: Dein Lieferant erbringt die Leistung und schickt Dir dafür eine Rechnung, die Du prüfst und bezahlst. Beim Gutschriftverfahren drehst Du genau diesen Ablauf um. Du bekommst weiterhin die Ware oder Leistung, aber die Abrechnung erstellst Du selbst und schickst sie an Deinen Lieferanten. Diese rechnungsersetzende Gutschrift tritt steuerlich an die Stelle der Eingangsrechnung. In Sage 100 steht Dir dafür eine eigene Belegart zur Verfügung.
&lt;/p&gt;
&lt;p&gt;
In diesem Beitrag schauen wir uns zuerst an, was eine rechnungsersetzende Gutschrift überhaupt ist und warum sie sich betriebswirtschaftlich lohnen kann. Danach gehen wir die steuerlichen Spielregeln durch und zeigen Dir, welche Einstellungen Du in Sage 100 vornimmst und wie der Beleg am Ende im Rechnungswesen ankommt.
&lt;/p&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;
&lt;strong&gt;Wichtig vorweg:&lt;/strong&gt; Dieser Beitrag erklärt das Gutschriftverfahren und seine Abbildung in Sage 100. Er ist keine Steuer- oder Rechtsberatung. Ob das Verfahren für Dich passt und welche Pflichtangaben Dein konkreter Fall braucht, klärst Du mit Deiner Steuerberatung. Geplante Änderungen an Belegarten, Workflows und Steuereinstellungen probierst Du am besten vorher im Demo- oder einem eigenen Testmandanten aus.
&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;Was eine rechnungsersetzende Gutschrift ist, und was sie nicht ist&lt;/h2&gt;
&lt;p&gt;
Das Wort Gutschrift ist im Alltag doppelt belegt, und genau hier entsteht die häufigste Verwechslung. Gemeint ist hier nicht die kaufmännische Gutschrift, mit der ein Lieferant eine zu hohe Rechnung korrigiert oder eine Rücksendung erstattet. Diese Korrektur ist eigentlich eine Rechnungsberichtigung und mindert ein bestehendes Entgelt.
&lt;/p&gt;
&lt;p&gt;
Die rechnungsersetzende Gutschrift ist etwas völlig anderes. Sie ist eine vollwertige Abrechnung über eine Leistung, nur dass nicht der leistende Unternehmer abrechnet, sondern Du als Leistungsempfänger. Im Umsatzsteuerrecht ist das die Gutschrift im Sinne des § 14 Abs. 2 UStG, international als Self-Billing bekannt. Weil sie an die Stelle der Rechnung tritt, muss sie auch alle Pflichtangaben einer Rechnung erfüllen. Die Steuer, die Du darin ausweist, schuldet weiterhin Dein Lieferant, und für Dich ist sie die Grundlage des Vorsteuerabzugs.
&lt;/p&gt;
&lt;h2&gt;Der betriebswirtschaftliche Hintergrund: Wer die Daten hat, rechnet ab&lt;/h2&gt;
&lt;p&gt;
Auf den ersten Blick klingt es nach Mehrarbeit, die Rechnung des Lieferanten selbst zu schreiben. Der Sinn erschließt sich, wenn man fragt, wer eigentlich die besseren Daten für die Abrechnung hat. In vielen Konstellationen ist das der Einkäufer, nicht der Verkäufer.
&lt;/p&gt;
&lt;p&gt;
Denk an einen Lohnfertiger, der nach gefertigten Stückzahlen abgerechnet wird, die in Deinem System erfasst sind. Oder an Provisionen, deren Höhe sich aus Deinen Umsätzen ergibt. Oder an Mengen und Qualitäten, die erst bei der Wareneingangsprüfung feststehen. In all diesen Fällen kennst Du die abrechnungsrelevanten Zahlen früher und genauer als Dein Lieferant. Lässt Du ihn die Rechnung schreiben, beginnt ein Abgleich mit Rückfragen und Korrekturen. Rechnest Du selbst ab, entfällt diese Schleife.&lt;/p&gt;
&lt;p&gt;Daraus ergeben sich die typischen Vorteile des Verfahrens:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Du bestimmst den Zeitpunkt der Abrechnung und kannst sie an Deine Wareneingänge oder Abrechnungsläufe koppeln.&lt;/li&gt;
&lt;li&gt;Format, Aufbau und Kontierung folgen Deinen Vorgaben, alle Belege sehen gleich aus und lassen sich einheitlich verarbeiten.&lt;/li&gt;
&lt;li&gt;Die Durchlaufzeiten sinken, weil der Umweg über Rechnungsstellung, Prüfung und Klärung beim Lieferanten entfällt.&lt;/li&gt;
&lt;li&gt;Dein Lieferant wird spürbar entlastet, gerade wenn er viele kleinteilige Positionen sonst manuell fakturieren müsste.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Verbreitet ist das Gutschriftverfahren deshalb dort, wo der Abnehmer den Takt vorgibt: Bei Provisions- und Lizenzabrechnungen, in der Lohnfertigung, in Einkaufsgenossenschaften und in eingespielten Lieferbeziehungen mit festen Konditionen, etwa im Handel oder in der Zulieferindustrie. Der gemeinsame Nenner ist immer derselbe: Die Information für die Abrechnung liegt auf der Einkaufsseite.
&lt;/p&gt;
&lt;h2&gt;Die Spielregeln: Eine Gutschrift ist eine Rechnung mit Umkehrung&lt;/h2&gt;
&lt;p&gt;
Weil die rechnungsersetzende Gutschrift steuerlich die Rechnung ersetzt, gelten für sie strenge Anforderungen. Ein paar Punkte solltest Du kennen, bevor Du das Verfahren aufsetzt:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Vorherige Vereinbarung.&lt;/strong&gt; Du und Dein Lieferant müsst vor der Abrechnung vereinbaren, dass per Gutschrift abgerechnet wird. Ohne diese Abrede ist das Verfahren nicht zulässig.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pflichtangabe Gutschrift.&lt;/strong&gt; Seit 2013 muss der Beleg ausdrücklich das Wort Gutschrift tragen (§ 14 Abs. 4 Nr. 10 UStG). Fehlt die Angabe, kann der Vorsteuerabzug gefährdet sein.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Alle Rechnungspflichtangaben.&lt;/strong&gt; Die Gutschrift braucht dieselben Angaben wie eine Rechnung, darunter die Steuernummer oder USt-IdNr Deines Lieferanten als leistendem Unternehmer, nicht Deine eigene.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Widerspruchsrecht.&lt;/strong&gt; Dein Lieferant kann der Gutschrift widersprechen. Tut er das, verliert das Dokument die Wirkung einer Rechnung (§ 14 Abs. 2 UStG). Damit fällt auch die Grundlage für den Vorsteuerabzug weg.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;E-Rechnungspflicht.&lt;/strong&gt; Da die Gutschrift eine Rechnung ersetzt, gelten auch die Vorgaben zur E-Rechnung im B2B-Bereich entsprechend. Wie eine E-Rechnung aufgebaut ist, zeigen wir im Beitrag &lt;a href="https://appontes.de/blog/e-rechnung-sage-100/"&gt;zur E-Rechnung in Sage 100&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;
Ein falscher oder zu hoher Steuerausweis in der Gutschrift bleibt nicht folgenlos. Hier kann eine nach § 14c UStG zusätzlich geschuldete Steuer im Raum stehen. Die Steuersätze und die Behandlung Deiner Vorgänge stimmst Du deshalb sauber mit Deiner Steuerberatung ab, bevor das Verfahren in den Echtbetrieb geht.
&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;Schritt 1: Die Belegart im Einkauf einrichten&lt;/h2&gt;
&lt;p&gt;
In Sage 100 erstellst Du eine rechnungsersetzende Gutschrift über die Belegart Gutschriftverfahren im Einkauf. Das ist ein Initialbeleg, den Du auch ganz ohne Vorbeleg erfassen kannst. Du musst also nicht zwingend einen Wareneingang oder eine Bestellung vorliegen haben, um abzurechnen.
&lt;/p&gt;
&lt;p&gt;
Die Nummernkreise dieser Belegart sind an den Rechnungseingang gekoppelt. Einen eigenen Nummernkreis musst Du dafür nicht anlegen. Willst Du das Gutschriftverfahren dagegen als Folgebeleg aus einem Wareneingang oder einer Bestellung heraus aufrufen, passt Du den Belegworkflow im Bereich Einkauf entsprechend an.
&lt;/p&gt;
&lt;h2&gt;Schritt 2: Druckprozesse und Sage DMS&lt;/h2&gt;
&lt;p&gt;
Damit die Gutschrift auch sauber gedruckt und versendet wird, legst Du die Druckprozesse für die neue Belegart unter Administration und Druckprozesse fest. In der Praxis hat es sich bewährt, sich dabei am vorhandenen Druckprozess des Rechnungseingangs zu orientieren. So bleibt der Aufbau vertraut und Du musst das Rad nicht neu erfinden.
&lt;/p&gt;
&lt;p&gt;
Setzt Du Sage DMS ein, lohnt ein zusätzlicher Blick in den Administrator der Sage 100. Prüfe dort die Einstellungen zur Belegart und triff bei Bedarf eine passende Zuordnung, damit die Gutschriften auch im Dokumentenmanagement an der richtigen Stelle landen.
&lt;/p&gt;
&lt;h2&gt;Schritt 3: Auswirkungen im Einkaufsvorgang&lt;/h2&gt;
&lt;p&gt;
Im laufenden Vorgang verhält sich die rechnungsersetzende Gutschrift wie eine Eingangsrechnung. Über die Mandantengrundlagen legst Du fest, wodurch ein Einkaufsvorgang als erfüllt gilt, wahlweise mit dem Wareneingang oder mit der Eingangsrechnung. Hast Du die Vorgangserfüllung auf Rechnungseingang gestellt, erfüllt auch das Gutschriftverfahren den Vorgang.
&lt;/p&gt;
&lt;p&gt;
In der Schnellauskunft zu einem Vorgang taucht das Gutschriftverfahren folgerichtig im Bereich Berechnet auf. Du siehst also auf einen Blick, dass der Vorgang abgerechnet ist, genau wie bei einer klassischen Eingangsrechnung.
&lt;/p&gt;
&lt;h2&gt;Schritt 4: Buchungsübergabe ins Rechnungswesen&lt;/h2&gt;
&lt;p&gt;
Bei der Übergabe ins Rechnungswesen wird die rechnungsersetzende Gutschrift einer Eingangsrechnung gleichgesetzt. Es entsteht der gewohnte Buchungssatz Wareneingang an Kreditor, abhängig von Deinen Einstellungen im Rechnungswesen. Die Steuer wird wie bei einer Eingangsrechnung behandelt.
&lt;/p&gt;
&lt;p&gt;
Auch bei den Details gibt es keine Sonderlogik: Wareneingangscode, Buchungstext und Steuereinstellungen sind deckungsgleich mit denen einer Eingangsrechnung im Einkauf. Wenn Du also mit Wareneingangscodes arbeitest, um Aufwände differenziert zu verbuchen, greift dieselbe Mechanik, die wir im Beitrag &lt;a href="https://appontes.de/blog/buchungsuebergabe-erloescodes-sage-100/"&gt;zur Buchungsübergabe mit Erlöscodes&lt;/a&gt; beschrieben haben. Für die Buchhaltung ändert sich im Tagesgeschäft also nichts, der Beleg fügt sich nahtlos ein.
&lt;/p&gt;
&lt;h2&gt;Typische Stolpersteine&lt;/h2&gt;
&lt;p&gt;Aus der Projektpraxis kennen wir ein paar Punkte, an denen es beim Gutschriftverfahren hakt:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Die Vereinbarung mit dem Lieferanten fehlt oder ist nicht dokumentiert. Ohne sie steht das ganze Verfahren auf wackeligem Grund.&lt;/li&gt;
&lt;li&gt;Auf dem Beleg fehlt das Wort Gutschrift oder es steht die eigene statt der Lieferanten-USt-IdNr darauf. Beides gefährdet den Vorsteuerabzug.&lt;/li&gt;
&lt;li&gt;Die Vorgangserfüllung in den Mandantengrundlagen steht auf Wareneingang. Dann erfüllt die Gutschrift den Vorgang nicht so, wie erwartet.&lt;/li&gt;
&lt;li&gt;Der Druckprozess für die neue Belegart wurde vergessen, sodass die Gutschrift zwar erfasst, aber nicht sauber ausgegeben werden kann.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Fazit&lt;/h2&gt;
&lt;p&gt;
Die rechnungsersetzende Gutschrift ist mehr als eine technische Spielerei. Sie verlagert die Abrechnung dorthin, wo die besseren Daten liegen, und spart auf beiden Seiten Zeit und Rückfragen. Sage 100 bildet das Verfahren als eigene Belegart sauber ab, von der Erfassung im Einkauf über die Vorgangserfüllung bis zur Buchungsübergabe, die der Eingangsrechnung gleicht. Der eigentliche Aufwand liegt weniger in der Technik als in den Rahmenbedingungen: Die Vereinbarung mit dem Lieferanten, die korrekten Pflichtangaben und eine mit der Steuerberatung abgestimmte steuerliche Behandlung.
&lt;/p&gt;
&lt;p&gt;
Du überlegst, das Gutschriftverfahren in Deinem Einkauf einzuführen, oder willst die Belegart in Sage 100 sauber aufsetzen? Dann lass uns gemeinsam einen Blick auf Deine Prozesse werfen.
&lt;/p&gt;
&lt;div style="text-align: center; margin: 3rem 0;"&gt;
&lt;a href="https://appontes.de/kontakt/?betreff=anfrage-sage" class="btn btn-primary"&gt;Gutschriftverfahren in Sage 100 einrichten lassen&lt;/a&gt;
&lt;/div&gt;</content:encoded></item><item><title>Die Zusammenfassende Meldung (ZM): Was sie ist und wie Sage 100 sie abbildet</title><link>https://appontes.de/blog/zusammenfassende-meldung-zm-sage-100/</link><guid isPermaLink="true">https://appontes.de/blog/zusammenfassende-meldung-zm-sage-100/</guid><pubDate>Thu, 25 Jun 2026 00:00:00 +0000</pubDate><dc:creator>Thomas Falkner</dc:creator><category>Sage 100</category><category>Umsatzsteuer</category><category>Rechnungswesen</category><description>Wer steuerfrei ins EU-Ausland liefert oder grenzüberschreitend Leistungen erbringt, muss eine Zusammenfassende Meldung abgeben. Wir erklären, was die ZM ist, wofür das Finanzamt sie braucht und wie Du sie in Sage 100 sauber abbildest.</description><content:encoded>&lt;p&gt;&lt;img src="https://appontes.de/img/blog/zusammenfassende-meldung-zm.svg" alt="Die Zusammenfassende Meldung (ZM): Was sie ist und wie Sage 100 sie abbildet"&gt;&lt;/p&gt;
&lt;p&gt;
Du lieferst Ware an einen Kunden in Österreich, schreibst die Rechnung ohne Umsatzsteuer und buchst alles sauber als innergemeinschaftliche Lieferung. So weit, so vertraut. Dann kommt am Monatsende neben der Umsatzsteuervoranmeldung noch eine zweite Meldung dazu, von der viele zum ersten Mal stutzen: Die Zusammenfassende Meldung, kurz ZM. Sie ist kein Beiwerk und auch keine freiwillige Statistik, sondern eine echte Pflicht. Und seit ein paar Jahren hängt sogar die Steuerfreiheit Deiner EU-Lieferungen daran.
&lt;/p&gt;
&lt;p&gt;
In diesem Beitrag erklären wir Dir, was die ZM ist, warum das Finanzamt sie braucht und welche Umsätze überhaupt hineingehören. Danach zeigen wir Dir, wie Du das Ganze in Sage 100 abbildest, von den Stammdaten bis zur fertigen Meldung.
&lt;/p&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;
&lt;strong&gt;Wichtig vorweg:&lt;/strong&gt; Dieser Beitrag erklärt das Prinzip der Zusammenfassenden Meldung und ihre Abbildung in Sage 100. Er ist keine Steuerberatung und keine Vorgabe, welcher Umsatz in Deinem Einzelfall meldepflichtig ist oder wie er einzuordnen ist. Ob und in welcher Form Du ZM-pflichtig bist, klärst Du mit Deiner Steuerberatung. Geplante Änderungen an Steuercodes und Einstellungen probierst Du am besten vorher im Demo- oder einem eigenen Testmandanten aus.
&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;Was die Zusammenfassende Meldung überhaupt ist&lt;/h2&gt;
&lt;p&gt;
Die Zusammenfassende Meldung ist eine elektronische Meldung an das Bundeszentralamt für Steuern (BZSt). Darin listest Du, getrennt nach Geschäftspartner, auf, welche grenzüberschreitenden Umsätze Du innerhalb der EU getätigt hast. Pro Partner nennst Du dessen Umsatzsteuer-Identifikationsnummer und die Summe der Bemessungsgrundlagen für den Meldezeitraum. Rechtsgrundlage ist § 18a UStG.
&lt;/p&gt;
&lt;p&gt;
Wichtig ist der Unterschied zur Umsatzsteuervoranmeldung. In der Voranmeldung meldest Du Summen, also wie viel steuerfreie innergemeinschaftliche Lieferungen Du insgesamt hattest. Die ZM geht eine Ebene tiefer: Sie sagt dem Finanzamt, an welchen konkreten Kunden mit welcher USt-IdNr wie viel geliefert oder geleistet wurde. Beides muss am Ende zusammenpassen.
&lt;/p&gt;
&lt;h2&gt;Welche Umsätze in die ZM gehören&lt;/h2&gt;
&lt;p&gt;Gemeldet werden im Wesentlichen diese Vorgänge:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Innergemeinschaftliche Warenlieferungen&lt;/strong&gt; an Unternehmer in anderen EU-Mitgliedstaaten, die bei Dir steuerfrei sind.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Im übrigen Gemeinschaftsgebiet steuerpflichtige sonstige Leistungen&lt;/strong&gt; nach § 3a Abs. 2 UStG, bei denen die Steuerschuld auf den Leistungsempfänger übergeht. Das ist das EU-Pendant zum Reverse-Charge-Verfahren.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Innergemeinschaftliche Dreiecksgeschäfte&lt;/strong&gt;, bei denen Du als mittlerer Unternehmer auftrittst.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lieferungen im Rahmen von Konsignationslagern&lt;/strong&gt; (Call-off-Stock nach § 6b UStG). § 18a UStG erfasst hier auch das Verbringen der Ware ins Lager und einen späteren Erwerberwechsel, also nicht nur den klassischen Umsatz.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Die Meldung unterscheidet diese Fälle. Warenlieferungen werden als normale innergemeinschaftliche Lieferungen gemeldet, gesonderte Kennzeichnungen sind vor allem für sonstige Leistungen und Dreiecksgeschäfte relevant. In den ELSTER- und Importstrukturen steckt diese Unterscheidung in der Angabe zur Art der Leistung. Sie ist nicht nur Formsache, sondern entscheidet darüber, wie die andere Finanzverwaltung den Vorgang verarbeitet.
&lt;/p&gt;
&lt;p&gt;
Reine Inlandsumsätze, Lieferungen an Privatpersonen oder Exporte in Drittländer außerhalb der EU gehören dagegen nicht in die ZM. Bei der Abgrenzung kommt es wie so oft auf den Einzelfall an, und genau hier lohnt der Blick mit der Steuerberatung.
&lt;/p&gt;
&lt;h2&gt;Wofür das Finanzamt die ZM braucht&lt;/h2&gt;
&lt;p&gt;
Der eigentliche Sinn der ZM erschließt sich, wenn man sich anschaut, wie eine innergemeinschaftliche Lieferung steuerlich funktioniert. Bei Dir als Lieferant ist sie steuerfrei. Versteuert wird sie nicht bei Dir, sondern beim Erwerber im anderen Mitgliedstaat, und zwar als innergemeinschaftlicher Erwerb. Die Steuer wandert also über die Grenze mit.
&lt;/p&gt;
&lt;p&gt;
Damit dabei nichts verloren geht, gleichen die EU-Staaten ihre Daten ab. Deine ZM landet über das BZSt im europäischen Mehrwertsteuer-Informationsaustauschsystem, bekannt als MIAS oder unter dem Kürzel VIES. Die Finanzverwaltung im Land Deines Kunden kann dort sehen, dass Du an diese USt-IdNr geliefert hast, und prüfen, ob der Kunde den Erwerb auch ordentlich versteuert hat. Die ZM ist damit das Kontrollnetz, das die Steuerfreiheit auf Deiner Seite mit der Steuerpflicht auf der anderen Seite verbindet.
&lt;/p&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;
Seit den sogenannten Quick Fixes ist die ordnungsgemäße ZM eine wichtige Voraussetzung für die Steuerfreiheit der innergemeinschaftlichen Lieferung. Gibst Du für eine Lieferung keine, eine unrichtige oder eine unvollständige ZM ab, kann die Steuerfreiheit gefährdet sein. Eine verspätete Abgabe ist ebenfalls nicht harmlos und kann Sanktionen auslösen, führt nach der seit 2022 entschärften Verwaltungsauffassung aber nicht schon allein automatisch zum Verlust der Steuerfreiheit. Die Meldung ist also kein lästiges Anhängsel, sondern gehört zu den Voraussetzungen dafür, dass Du überhaupt ohne Umsatzsteuer fakturieren darfst.
&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;Fristen und Abgabe&lt;/h2&gt;
&lt;p&gt;
Die ZM gibst Du elektronisch ab, entweder über das BZSt-Online-Portal oder über die ELSTER-Schnittstelle. Die Fristen sind eigen und unterscheiden sich von der Voranmeldung:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Warenlieferungen und Dreiecksgeschäfte&lt;/strong&gt; meldest Du grundsätzlich monatlich, bis zum 25. Tag nach Ablauf des Meldezeitraums. Quartalsweise darfst Du abgeben, wenn die Summe der Bemessungsgrundlagen weder im laufenden noch in einem der vier vorangegangenen Quartale jeweils mehr als 50.000 Euro beträgt.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sonstige Leistungen&lt;/strong&gt; meldest Du grundsätzlich quartalsweise.&lt;/li&gt;
&lt;li&gt;Eine &lt;strong&gt;Dauerfristverlängerung&lt;/strong&gt;, wie Du sie vielleicht für die Umsatzsteuervoranmeldung nutzt, gilt für die ZM nicht. Der 25. ist hier wirklich der 25.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Welcher Rhythmus für Dich gilt, stimmst Du am besten einmal grundsätzlich mit Deiner Steuerberatung ab und hinterlegst ihn dann fest in Deinem Ablauf.
&lt;/p&gt;
&lt;h2&gt;Die Grundlage in Sage 100: saubere Stammdaten&lt;/h2&gt;
&lt;p&gt;
Eine korrekte ZM entsteht nicht erst bei der Meldung, sondern schon bei der Erfassung. Damit Sage 100 einen Umsatz überhaupt als meldepflichtig erkennt, müssen zwei Dinge stimmen: Die USt-IdNr des Kunden und der Steuercode am Beleg.
&lt;/p&gt;
&lt;h3&gt;Die Umsatzsteuer-Identifikationsnummer im Kundenstamm&lt;/h3&gt;
&lt;p&gt;
Ohne gültige USt-IdNr des Erwerbers gibt es keine steuerfreie innergemeinschaftliche Lieferung und damit auch keine korrekte Zeile in der ZM. Die Nummer hinterlegst Du im Kundenstamm im Bereich der Gebietsangaben. Sie ist das Sortierkriterium der ganzen Meldung, denn die ZM fasst die Umsätze je USt-IdNr zusammen.
&lt;/p&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;
Prüfe die USt-IdNr Deiner EU-Kunden, am besten qualifiziert über das BZSt. So stellst Du sicher, dass Nummer, Name und Anschrift zusammenpassen. Eine ungültige oder veraltete Nummer fällt sonst erst auf, wenn das BZSt die ZM zurückweist, und dann sitzt Du an der Korrektur statt am Tagesgeschäft.
&lt;/p&gt;
&lt;/div&gt;
&lt;h3&gt;Der richtige Steuercode am Beleg&lt;/h3&gt;
&lt;p&gt;
Über den Steuercode entscheidet Sage 100, wie ein Umsatz behandelt wird. Für die ZM brauchst Du Steuercodes, die einen Umsatz eindeutig als innergemeinschaftliche Lieferung oder als im EU-Ausland steuerpflichtige sonstige Leistung kennzeichnen. Diese Codes steuern nicht nur die steuerfreie Buchung, sondern liefern auch das Merkmal, an dem die Auswertung später erkennt, dass und mit welchem Kennzeichen der Umsatz in die Meldung gehört. Wie Sage 100 den passenden Code an der Position überhaupt ermittelt, haben wir im Beitrag &lt;a href="https://appontes.de/blog/steuercodeermittlung-sage-100/"&gt;zur Steuercodeermittlung&lt;/a&gt; ausführlich beschrieben.
&lt;/p&gt;
&lt;h2&gt;Die ZM in Sage 100 erstellen&lt;/h2&gt;
&lt;p&gt;
Sind die Stammdaten und die Steuercodes sauber, ist der Rest fast Routine. Im Rechnungswesen findest Du die Auswertung zur Zusammenfassenden Meldung. Du wählst den Meldezeitraum, und Sage 100 sammelt alle Buchungen mit den passenden Steuercodes ein und verdichtet sie je USt-IdNr und Meldekennzeichen. Du bekommst also genau die Struktur, die die Meldung verlangt: Pro Geschäftspartner eine Zeile mit Nummer, Summe und gegebenenfalls dem Kennzeichen für sonstige Leistungen oder Dreiecksgeschäfte.
&lt;/p&gt;
&lt;p&gt;
Aus dieser Auswertung heraus erzeugst Du die elektronische Übermittlung. Über die ELSTER-Schnittstelle geht die Meldung an das BZSt, ohne dass Du die Zahlen noch einmal in ein Portal abtippen musst. Wie reibungslos das läuft, hängt allerdings von ein paar Rahmenbedingungen ab: Von der eingesetzten Sage-Version, der eingerichteten ELSTER- und Zertifikatsanbindung, sauber gepflegten Steuercodes und den passenden Mandanteneinstellungen. Sind diese Voraussetzungen erfüllt, ist die eigentliche Abgabe der angenehme Teil der Arbeit.
&lt;/p&gt;
&lt;h2&gt;Abstimmen lohnt sich: ZM gegen Voranmeldung&lt;/h2&gt;
&lt;p&gt;
Bevor Du die Meldung abschickst, lohnt ein kurzer Abgleich. Die Summe Deiner innergemeinschaftlichen Lieferungen in der ZM sollte grundsätzlich zu dem passen, was in der Umsatzsteuervoranmeldung als steuerfreie innergemeinschaftliche Lieferung steht. Beide Meldungen speisen sich aus denselben Buchungen, also sollten sie zusammenpassen. Stimmen sie nicht überein, steckt oft ein falscher Steuercode, eine fehlende USt-IdNr oder ein Umsatz im falschen Zeitraum dahinter.
&lt;/p&gt;
&lt;p&gt;
Nicht jede Abweichung ist allerdings ein Fehler. Der Meldezeitraum der ZM kann bei innergemeinschaftlichen Lieferungen nach § 18a Abs. 8 UStG an der Rechnungsstellung hängen, spätestens am Folgemonat der Lieferung. Dadurch landet ein Umsatz in ZM und Voranmeldung gelegentlich in unterschiedlichen Zeiträumen, ohne dass etwas falsch wäre. Geh Differenzen also nach, nimm sie aber nicht reflexhaft als Buchungsfehler. Echte Fehler findest Du auf diese Weise lieber selbst, bevor das Finanzamt sie findet.
&lt;/p&gt;
&lt;h2&gt;Typische Stolpersteine&lt;/h2&gt;
&lt;p&gt;Aus unseren Sage 100 Projekten kennen wir ein paar Fehlerbilder, die rund um die ZM immer wieder auftauchen:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Beim Kunden fehlt die USt-IdNr oder sie ist veraltet. Der Umsatz wird dann falsch geschlüsselt oder fällt aus der Meldung.&lt;/li&gt;
&lt;li&gt;Sonstige Leistungen werden wie Warenlieferungen behandelt, weil das Meldekennzeichen über den Steuercode nicht richtig gesetzt ist.&lt;/li&gt;
&lt;li&gt;Die ZM wird nur quartalsweise gedacht, obwohl für Warenlieferungen der monatliche Rhythmus gilt. Die Dauerfristverlängerung der Voranmeldung hilft hier nicht.&lt;/li&gt;
&lt;li&gt;ZM und Voranmeldung werden nie gegeneinander abgestimmt, sodass Differenzen erst bei einer Rückfrage des Finanzamts auffallen.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Fazit&lt;/h2&gt;
&lt;p&gt;
Die Zusammenfassende Meldung ist das Kontrollnetz, das steuerfreie EU-Lieferungen mit der Besteuerung beim Empfänger verbindet. Seit sie Voraussetzung für die Steuerfreiheit ist, gehört sie zu den Pflichten, bei denen Sorgfalt sich wirklich auszahlt. Die gute Nachricht: In Sage 100 ist die Meldung kein Kraftakt, wenn die Grundlagen stimmen. Eine gepflegte USt-IdNr im Kundenstamm, die richtigen Steuercodes am Beleg und ein kurzer Abgleich mit der Voranmeldung, dann ist die Meldung am Ende reine Routine.
&lt;/p&gt;
&lt;p&gt;
Du bist Dir bei der Schlüsselung Deiner EU-Umsätze unsicher oder willst Deinen ZM-Ablauf in Sage 100 einmal sauber aufsetzen? Dann lass uns gemeinsam einen Blick auf Deinen Mandanten werfen.
&lt;/p&gt;
&lt;div style="text-align: center; margin: 3rem 0;"&gt;
&lt;a href="https://appontes.de/kontakt/?betreff=anfrage-sage" class="btn btn-primary"&gt;ZM in Sage 100 einrichten lassen&lt;/a&gt;
&lt;/div&gt;</content:encoded></item><item><title>Warum unsere Website keinen Cookie-Banner hat</title><link>https://appontes.de/blog/warum-kein-cookie-banner/</link><guid isPermaLink="true">https://appontes.de/blog/warum-kein-cookie-banner/</guid><pubDate>Mon, 22 Jun 2026 00:00:00 +0000</pubDate><dc:creator>Thomas Falkner</dc:creator><category>Datenschutz</category><category>DSGVO</category><category>Webentwicklung</category><description>Kaum eine Website kommt heute ohne nervigen Cookie-Banner aus. Unsere schon. Wir erklären, warum wir keinen brauchen, was rechtlich dahintersteckt und wie wir die Seite technisch dafür gebaut haben.</description><content:encoded>&lt;p&gt;&lt;img src="https://appontes.de/img/blog/kein-cookie-banner.svg" alt="Warum unsere Website keinen Cookie-Banner hat"&gt;&lt;/p&gt;
&lt;p&gt;
Du kennst das: Kaum öffnest Du eine Website, schiebt sich ein Banner ins Bild. "Wir nutzen Cookies, akzeptiere alles oder klick Dich durch drei Untermenüs." Lästig, allgegenwärtig und für viele längst zum Reflex geworden, einfach auf "Alle akzeptieren" zu tippen. Auf unserer Seite suchst Du so ein Banner vergeblich. Das ist kein Versehen, sondern eine bewusste Entscheidung. Und sie ist auch rechtlich sauber. Warum, das erklären wir hier.
&lt;/p&gt;
&lt;h2&gt;Wofür ein Cookie-Banner überhaupt da ist&lt;/h2&gt;
&lt;p&gt;
Ein Cookie-Banner ist kein Selbstzweck und auch keine reine Höflichkeit. Er ist eine rechtliche Pflicht, aber nur unter einer bestimmten Bedingung. Nach dem Telekommunikation-Digitale-Dienste-Datenschutz-Gesetz (TDDDG, früher TTDSG) brauchst Du die Einwilligung der Besucher immer dann, wenn Du Informationen auf deren Gerät speicherst oder ausliest, die für den Betrieb der Seite nicht zwingend nötig sind.
&lt;/p&gt;
&lt;p&gt;
Das betrifft vor allem zwei Dinge: Tracking und externe Dienste. Also Google Analytics, das Dein Verhalten auswertet. Den Facebook-Pixel, der Dich für Werbung markiert. Eingebettete YouTube-Videos oder Google Maps, die im Hintergrund Daten an US-Server senden. Genau für solche Fälle ist der Banner gedacht. Er holt vorab Deine Erlaubnis ein, bevor Dritte mitlesen.
&lt;/p&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;
Der entscheidende Punkt: Ein Banner ist nur dann Pflicht, wenn die Website auch wirklich etwas tut, das eine Einwilligung erfordert. Wer nicht trackt und keine fremden Dienste einbindet, braucht auch keine Einwilligung. Es gibt nämlich nichts, dem man zustimmen müsste.
&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;Was unsere Website nicht tut&lt;/h2&gt;
&lt;p&gt;
Wir haben unsere Seite von Anfang an so gebaut, dass genau diese einwilligungspflichtigen Dinge gar nicht erst vorkommen. Konkret heißt das:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Kein Tracking.&lt;/strong&gt; Wir setzen kein Google Analytics ein, kein Matomo, kein Plausible, keinen Facebook-Pixel und kein sonstiges Analyse-Tool. Wir wissen schlicht nicht, wer Du bist oder wie Du Dich durch die Seite klickst.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Keine Fonts von Google.&lt;/strong&gt; Die Schriftarten liegen direkt auf unserem Server. Es geht keine Anfrage an Google, bei der Deine IP-Adresse übertragen würde. Genau das war jahrelang eine der häufigsten Abmahnfallen.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Keine eingebetteten Drittinhalte.&lt;/strong&gt; Keine YouTube-Videos, kein Google Maps, keine Social-Media-Widgets, die im Hintergrund nach Hause funken.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Keine Werbe- oder Marketing-Cookies.&lt;/strong&gt; Wir verkaufen keine Werbeflächen und bauen keine Profile auf.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Alles, was Du auf der Seite siehst, kommt von unserem eigenen Server in Deutschland. Es gibt keinen Umweg über einen US-Konzern und keine versteckten Datenströme zu Dritten. Diesen Grundsatz halten wir konsequent durch, weil er für uns zum Selbstverständnis als IT-Dienstleister gehört. Wie wir das beim Dateiaustausch lösen, haben wir in einem &lt;a href="https://appontes.de/blog/datenschutzkonformer-dateiaustausch/"&gt;eigenen Beitrag&lt;/a&gt; beschrieben.
&lt;/p&gt;
&lt;h2&gt;Aber ein bisschen Cookie ist doch dabei, oder?&lt;/h2&gt;
&lt;p&gt;
Ehrlich gesagt: Ja, ein einziger. Aber er ist genau von der Sorte, für die Du keine Einwilligung brauchst. Wenn Du unser Kontaktformular benutzt, setzt der Server einen technischen Sitzungs-Cookie. Der hat eine klar umrissene Aufgabe: Er schützt das Formular vor Missbrauch durch sogenannte Cross-Site-Request-Forgery, also davor, dass jemand das Absenden in Deinem Namen fälscht.
&lt;/p&gt;
&lt;p&gt;
Dieser Cookie speichert keine Informationen über Dich, verfolgt Dich nicht über Seiten hinweg und wird auch nicht an Dritte weitergegeben. Er entsteht erst in dem Moment, in dem Du aktiv mit dem Formular arbeitest, und nicht schon beim bloßen Aufruf der Startseite. Genau solche technisch notwendigen Cookies nimmt das Gesetz ausdrücklich von der Einwilligungspflicht aus. Ohne sie würde die Funktion schlicht nicht sicher arbeiten.
&lt;/p&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;
Die Faustregel lautet: Cookies, die nötig sind, damit eine vom Nutzer gewünschte Funktion überhaupt läuft, sind erlaubt. Cookies, die Dich beobachten oder vermarkten sollen, brauchen Deine Zustimmung. Bei uns gibt es nur die erste Sorte.
&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;Warum uns das wichtig ist&lt;/h2&gt;
&lt;p&gt;
Man könnte sagen, ein Banner ist schnell eingebaut und niemanden stört es ernsthaft. Wir sehen das anders. Ein Cookie-Banner ist immer ein Eingeständnis: Hier passiert etwas mit Deinen Daten, dem Du erst zustimmen musst. Wenn wir diesen Banner weglassen können, ist das die ehrlichere Variante. Es gibt nichts zu verbergen und nichts abzunicken.
&lt;/p&gt;
&lt;p&gt;
Dazu kommt der praktische Nutzen für Dich. Keine Klickstrecke, kein Verdeckter Inhalt, keine Frage, was Du eigentlich gerade erlaubst. Die Seite lädt, und Du kannst sie sofort nutzen. Datenschutz heißt für uns nicht, möglichst aufwendig um Einwilligung zu bitten, sondern erst gar keine Daten zu sammeln, die diese Einwilligung nötig machen.
&lt;/p&gt;
&lt;p&gt;
Als Unternehmen, das seine Kunden zu Datenschutz, sicherer Infrastruktur und digitaler Souveränität berät, finden wir: Dieser Anspruch sollte auch für die eigene Website gelten. Nicht nur auf dem Papier in der Datenschutzerklärung, sondern überprüfbar im Code.
&lt;/p&gt;
&lt;h2&gt;Fazit&lt;/h2&gt;
&lt;p&gt;
Ein Cookie-Banner ist kein Qualitätsmerkmal, sondern die Folge davon, dass eine Website trackt oder fremde Dienste einbindet. Wer darauf verzichtet, braucht keinen Banner. Wir haben unsere Seite genau so aufgebaut: Ohne Analyse-Tools, ohne externe Schriften, ohne eingebettete Drittinhalte. Der einzige Cookie ist technisch notwendig und schützt Dein Kontaktformular. Mehr nicht.
&lt;/p&gt;
&lt;p&gt;
Du willst Deine eigene Website oder IT datenschutzfreundlich aufstellen, ohne Dich durch Banner und Grauzonen zu kämpfen? Dann lass uns darüber sprechen.
&lt;/p&gt;
&lt;div style="text-align: center; margin: 3rem 0;"&gt;
&lt;a href="https://appontes.de/kontakt/?betreff=sonstiges" class="btn btn-primary"&gt;Kostenlose Erstberatung vereinbaren&lt;/a&gt;
&lt;/div&gt;</content:encoded></item><item><title>Backups, die im Ernstfall halten: Warum erfolgreiche Sicherungen trügen können</title><link>https://appontes.de/blog/backups-pruefen-sage-100/</link><guid isPermaLink="true">https://appontes.de/blog/backups-pruefen-sage-100/</guid><pubDate>Mon, 15 Jun 2026 00:00:00 +0000</pubDate><dc:creator>Thomas Falkner</dc:creator><category>Sage 100</category><category>SQL Server</category><category>Datensicherung</category><category>IT-Sicherheit</category><description>Ein grünes Backup-Protokoll ist keine Garantie für eine funktionierende Wiederherstellung. Wie eine SQL-Server-Sicherungskette für Sage 100 still kaputtgeht, woran Du es erkennst und wie Du Deine Backups in wenigen Minuten selbst prüfst.</description><content:encoded>&lt;p&gt;&lt;img src="https://appontes.de/img/blog/backups-pruefen-sage-100.svg" alt="Backups, die im Ernstfall halten: Warum erfolgreiche Sicherungen trügen können"&gt;&lt;/p&gt;
&lt;p&gt;
Es gibt einen Satz, der in der IT teuer werden kann: „Unsere Backups laufen jede Nacht durch." Das stimmt meistens sogar. Trotzdem stehen Unternehmen im Ernstfall vor einer Sicherung, aus der sich nicht das wiederherstellen lässt, was sie brauchen. Der Grund ist fast nie ein lautes Scheitern. Es ist ein stiller Fehler, der monatelang unbemerkt bleibt, weil jede einzelne Sicherung brav „erfolgreich" meldet.
&lt;/p&gt;
&lt;p&gt;
Sage 100 speichert seine Daten in einer Microsoft-SQL-Server-Datenbank. Damit hängt die Sicherheit Eurer Buchhaltung, Aufträge und Stammdaten direkt an einer sauberen Sicherungsstrategie auf dem SQL Server. Dieser Beitrag zeigt, wo solche Strategien still kaputtgehen und wie Du das selbst prüfst.
&lt;/p&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;
&lt;strong&gt;Kurz vorab:&lt;/strong&gt; Eine erfolgreich abgeschlossene Sicherung sagt nur, dass das Schreiben geklappt hat. Ob sich daraus im Notfall ein funktionierender Stand wiederherstellen lässt, ist eine andere Frage. Die Antwort darauf liefert nur ein getesteter Restore.
&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;Die Sicherungskette, die niemand sieht&lt;/h2&gt;
&lt;p&gt;
Eine typische SQL-Server-Strategie besteht aus drei Bausteinen. Die Vollsicherung enthält den kompletten Stand. Die Differenzsicherung enthält nur die Änderungen seit der letzten Vollsicherung. Die Log-Sicherung enthält die einzelnen Transaktionen dazwischen. Zusammen ergeben sie eine Kette, mit der Du nicht nur den Stand von gestern Nacht, sondern auch einen Zeitpunkt mittags um 11:43 Uhr wiederherstellen kannst.
&lt;/p&gt;
&lt;p&gt;
Entscheidend ist das Wort Kette. Eine Differenzsicherung ist für sich allein wertlos. Sie funktioniert nur zusammen mit genau der Vollsicherung, auf der sie aufbaut. Diese Vollsicherung nennt sich Differenzbasis. Und genau hier passiert der häufigste stille Fehler.
&lt;/p&gt;
&lt;h2&gt;Der Klassiker: Das ungeplante Vollbackup&lt;/h2&gt;
&lt;p&gt;
Stell Dir vor, Eure geplante Sicherung macht sonntags eine Vollsicherung und an den übrigen Tagen Differenzsicherungen. Alles läuft. Dann installiert jemand ein zusätzliches Tool, ein Monitoring oder eine Backup-Software, die einmalig „zur Sicherheit" eine eigene Vollsicherung zieht. Diese Vollsicherung wird ohne das Kennzeichen COPY_ONLY ausgeführt.
&lt;/p&gt;
&lt;p&gt;
Was technisch korrekt klingt, hat eine unangenehme Folge: Eine normale Vollsicherung setzt die Differenzbasis neu. Ab diesem Moment beziehen sich alle Differenzsicherungen nicht mehr auf Eure geplante Sonntags-Vollsicherung, sondern auf das fremde Vollbackup. Liegt dieses Vollbackup an einem anderen Ort oder wird es nicht aufbewahrt, fehlt im Ernstfall die passende Basis. Die Differenzsicherungen laufen ins Leere, obwohl jede für sich erfolgreich war.
&lt;/p&gt;
&lt;p&gt;
Genau dafür gibt es das Kennzeichen COPY_ONLY. Eine COPY_ONLY-Vollsicherung verändert die Differenzbasis nicht. Sie ist gedacht für Sonder- und Ad-hoc-Sicherungen, die den geplanten Rhythmus nicht stören sollen. Fehlt COPY_ONLY bei einem ungeplanten Vollbackup, bricht die Kette.
&lt;/p&gt;
&lt;h2&gt;Weitere stille Risiken&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Fehlende Log-Sicherungen:&lt;/strong&gt; Steht eine Datenbank im Wiederherstellungsmodell FULL, aber es werden nie Log-Sicherungen gemacht, wächst das Transaktionsprotokoll unbegrenzt. Gleichzeitig ist keine Wiederherstellung auf einen Zeitpunkt möglich.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lücken in der Log-Kette:&lt;/strong&gt; Auch die Log-Sicherungen bilden eine Kette. Fehlt ein Glied, lässt sich über diese Lücke hinweg kein durchgängiger Zeitpunkt mehr herstellen.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sicherung auf dem falschen Laufwerk:&lt;/strong&gt; Backups, die auf demselben Laufwerk oder gar auf der Systemplatte C: liegen, sind bei einem Hardware- oder Verschlüsselungsvorfall genauso weg wie die Originaldaten.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Zu alte Sicherungen:&lt;/strong&gt; Eine Vollsicherung, die Wochen zurückliegt, bedeutet im Ernstfall einen entsprechend großen Datenverlust.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Ein Backup ohne getesteten Restore ist kein Backup&lt;/h2&gt;
&lt;p&gt;
Der wichtigste Satz zum Schluss zuerst: Erst ein erfolgreich getesteter Wiederherstellungslauf beweist, dass Eure Sicherung etwas wert ist. Alles davor ist eine begründete Hoffnung. Ein Restore-Test deckt nicht nur kaputte Ketten auf, sondern auch praktische Fragen: Wie lange dauert die Wiederherstellung wirklich? Wer darf sie durchführen? Sind die Sicherungen überhaupt erreichbar?
&lt;/p&gt;
&lt;p&gt;
Als Orientierung hat sich die 3-2-1-Regel bewährt: Drei Kopien der Daten, auf zwei verschiedenen Medien, davon eine außer Haus. Für Sage 100 heißt das konkret: Regelmäßige Voll-, Differenz- und Log-Sicherungen, auf ein separates Ziel, plus eine Kopie an einem anderen Ort, und regelmäßige Restore-Tests.
&lt;/p&gt;
&lt;h2&gt;So prüfst Du Deine Sicherungskette selbst&lt;/h2&gt;
&lt;p&gt;
Der SQL Server protokolliert jede Sicherung in seiner eigenen Historie. Diese Historie lässt sich auslesen und auswerten, ganz ohne in die Produktivdatenbank einzugreifen. Genau dafür haben wir ein Werkzeug gebaut: Der &lt;a href="https://appontes.de/tools/sql-backup-chain-analyzer/"&gt;SQL-Backup-Chain-Analyzer&lt;/a&gt; liest die exportierte Backup-Historie und prüft die Kette auf genau die Punkte aus diesem Beitrag. Er erkennt unter anderem eine verschobene Differenzbasis, fehlende Log-Sicherungen, Sicherungen auf dem falschen Laufwerk und auffällige Lücken.
&lt;/p&gt;
&lt;p&gt;
Eine fertige SQL-Abfrage und eine Schritt-für-Schritt-Anleitung, wie Du die Historie aus dem SQL Server Management Studio als CSV exportierst, findest Du direkt im Tool. Die Datei wird ausschließlich lokal in Deinem Browser ausgewertet, es werden keine Daten übertragen. Datenbank- und Pfadnamen kannst Du vorher anonymisieren.
&lt;/p&gt;
&lt;h2&gt;Backup ist auch ein GoBD-Thema&lt;/h2&gt;
&lt;p&gt;
Eine funktionierende Datensicherung ist nicht nur Betriebssicherheit, sondern auch Teil der GoBD-Anforderungen an die Nachvollziehbarkeit und Verfügbarkeit Deiner steuerrelevanten Daten. Wie es um Sicherung, Berechtigungen, Protokollierung und Dokumentation in Deiner Sage-100-Umgebung steht, kannst Du mit unserem &lt;a href="https://appontes.de/tools/gobd-check/"&gt;GoBD-Selbstcheck&lt;/a&gt; in wenigen Minuten einschätzen.
&lt;/p&gt;
&lt;p&gt;
Wenn Du wissen willst, ob Eure Sicherungsstrategie im Ernstfall wirklich trägt, schauen wir uns das gemeinsam an. Wir betreuen Sage 100 inklusive der darunterliegenden SQL-Server-Umgebung und prüfen Sicherungskette, Wiederherstellung und Berechtigungen technisch und fachlich. &lt;a href="https://appontes.de/kontakt/?betreff=anfrage-sage"&gt;Melde Dich&lt;/a&gt;, dann klären wir Deinen Fall.
&lt;/p&gt;</content:encoded></item><item><title>Buchungsübergabe mit Erlöscodes in Sage 100: Umsätze sauber aufsplitten</title><link>https://appontes.de/blog/buchungsuebergabe-erloescodes-sage-100/</link><guid isPermaLink="true">https://appontes.de/blog/buchungsuebergabe-erloescodes-sage-100/</guid><pubDate>Wed, 27 May 2026 00:00:00 +0000</pubDate><dc:creator>Thomas Falkner</dc:creator><category>Sage 100</category><category>Rechnungswesen</category><category>Warenwirtschaft</category><category>Controlling</category><description>Alle Umsätze landen auf einem Erlöskonto? Mit Erlöscodes splittet Sage 100 die Buchungsübergabe aus der Warenwirtschaft automatisch auf differenzierte Sachkonten. So richtest Du es ein und gewinnst eine aussagekräftige BWA.</description><content:encoded>&lt;p&gt;&lt;img src="https://appontes.de/img/blog/buchungsuebergabe-erloescodes.svg" alt="Buchungsübergabe mit Erlöscodes in Sage 100: Umsätze sauber aufsplitten"&gt;&lt;/p&gt;
&lt;p&gt;
Deine Warenwirtschaft schreibt Rechnungen, das Rechnungswesen verbucht sie. Klingt einfach, und in Sage 100 läuft diese Übergabe auch zuverlässig. Die spannende Frage ist nur: Auf welchen Konten landen die Erlöse am Ende? In vielen Mandanten fließt alles auf ein oder zwei Sammelkonten. Der Umsatz stimmt, aber sobald jemand wissen will, wie viel davon aus Eigenprodukten, Handelsware oder Dienstleistung stammt, fängt die Sucherei an. Genau dafür gibt es in Sage 100 die Erlöscodes. Sie steuern, auf welches Sachkonto eine Position bei der Übergabe gebucht wird, vollautomatisch und ohne dass jemand in der Buchhaltung etwas nachsortieren muss.
&lt;/p&gt;
&lt;p&gt;
In diesem Beitrag zeigen wir Dir, warum sich differenzierte Erlöskonten betriebswirtschaftlich lohnen und wie Du die Buchungsübergabe mit Erlöscodes Schritt für Schritt einrichtest. Die Logik gilt im Verkauf wie im Einkauf gleichermaßen, wir bleiben in den Beispielen beim Verkauf.
&lt;/p&gt;
&lt;h2&gt;Warum überhaupt differenzieren?&lt;/h2&gt;
&lt;p&gt;
Ein einziges Erlöskonto ist schnell eingerichtet und trotzdem teuer erkauft. Die meisten Unternehmen verdienen ihr Geld in unterschiedlichen Bereichen: Ein Teil aus dem Verkauf eigener Produkte, ein Teil aus Handelsware, vielleicht noch ein Stück aus Wartung oder Service. Solange all das auf demselben Konto liegt, siehst Du in der BWA nur eine einzige Umsatzzeile. Ob ein Rückgang aus dem Kerngeschäft kommt oder nur eine Sparte schwächelt, lässt sich daraus nicht ablesen.
&lt;/p&gt;
&lt;p&gt;
Trennst Du die Erlöse dagegen auf eigene Konten, bekommst Du diese Information geschenkt. Deine BWA zeigt dann pro Bereich, wie viel zum Umsatz beigetragen wird. Buchst Du zusätzlich die zugehörigen Wareneinsätze auf getrennte Aufwandskonten, entsteht eine Art Deckungsbeitragsrechnung im Kleinen, ganz ohne separates Controllingwerkzeug. Standardkontenrahmen wie der SKR04 sind genau dafür gemacht und halten reichlich Platz für differenzierte Erlöskonten bereit.
&lt;/p&gt;
&lt;p&gt;Typische Schnitte, nach denen Unternehmen ihre Erlöse aufteilen:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;nach Produktgruppen oder Sparten, etwa Eigenprodukte, Handelsware, Dienstleistung&lt;/li&gt;
&lt;li&gt;nach Vertriebskanälen, zum Beispiel Ladengeschäft, Onlineshop, Außendienst&lt;/li&gt;
&lt;li&gt;nach Kundengruppen oder Regionen, etwa Inland, EU, Drittland&lt;/li&gt;
&lt;li&gt;nach steuerlicher Behandlung, also unterschiedliche Steuersätze oder steuerfreie Umsätze sauber getrennt&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Gerade der letzte Punkt ist mehr als Komfort. Wenn unterschiedliche Steuersachverhalte von vornherein auf eigenen Konten landen, wird die Umsatzsteuer-Voranmeldung nachvollziehbarer und in der Betriebsprüfung leichter zu erklären.
&lt;/p&gt;
&lt;h2&gt;Wie der Erlöscode in die Kontonummer wandert&lt;/h2&gt;
&lt;p&gt;
Das Prinzip ist clever: Der Erlöscode ist kein zusätzliches Feld, das irgendwo separat mitläuft. Er wird bei der Übergabe direkt zum Bestandteil der Kontonummer im Rechnungswesen. Du definierst ein Basiskonto und legst fest, an welcher Stelle dieser Kontonummer der Code eingesetzt wird. Aus einem Basiskonto und einem Code entsteht so das konkrete Erlöskonto, auf das die Position gebucht wird.
&lt;/p&gt;
&lt;p&gt;
Ein einfaches Beispiel: Du nutzt im SKR04 die 4400 als Erlöse zu 19 Prozent und reservierst eine zweistellige Position für den Code. Erlöscode 10 für Eigenprodukte und 20 für Handelsware führen dann auf getrennte Konten im 44er-Bereich. Jede Position trägt ihren Code mit, und bei der Übergabe sortiert Sage 100 die Buchung automatisch auf das richtige Konto.
&lt;/p&gt;
&lt;h2&gt;Schritt 1: Erlöscodes anlegen&lt;/h2&gt;
&lt;p&gt;
Die Codes legst Du in den &lt;strong&gt;Grundlagen der Warenwirtschaft&lt;/strong&gt; im Bereich Faktura an. Du vergibst je Code einen numerischen Schlüssel und eine Bezeichnung. Der Schlüssel muss eine Zahl sein und darf 9999 nicht überschreiten.
&lt;/p&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;Denk an dieser Stelle schon an die Buchhaltung. Der Schlüssel wird später Teil der Kontonummer. Plane die Stellenanzahl deshalb so, dass sie zu Deinem Sachkontenrahmen passt, und lieber etwas großzügiger, damit später angelegte Sparten noch hineinpassen.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;
Im selben Bereich der Grundlagen findest Du übrigens auch die übrigen Codes für die Übergabe, etwa Wareneingangscodes für den Einkauf. Die Mechanik dahinter ist dieselbe, nur dass es dort um Aufwands-, Wareneinsatz- oder Warenbestandskonten geht.
&lt;/p&gt;
&lt;h2&gt;Schritt 2: Codes den Stammdaten zuordnen&lt;/h2&gt;
&lt;p&gt;
Einen angelegten Erlöscode kannst Du an zwei Stellen hinterlegen, beim Kunden und beim Artikel. Beide Einträge werden im Verkaufsbeleg vorgeschlagen und lassen sich dort bei Bedarf noch anpassen.
&lt;/p&gt;
&lt;h3&gt;Im Kundenstamm&lt;/h3&gt;
&lt;p&gt;Die Zuordnung beim Kunden nimmst Du im Bereich Verkauf und Lieferung vor. Sie eignet sich, wenn Du Umsätze pro Kundengruppe oder Region trennen willst.&lt;/p&gt;
&lt;h3&gt;Im Artikelstamm&lt;/h3&gt;
&lt;p&gt;Beim Artikel sitzt der Erlöscode im Bereich Faktura. Das ist der richtige Hebel, wenn Du nach Produktgruppen oder Sortimenten differenzierst.&lt;/p&gt;
&lt;h3&gt;Im Verkaufsbeleg&lt;/h3&gt;
&lt;p&gt;
Im Belegkopf schlägt Sage 100 den Erlöscode des Kunden vor. Dieser Wert gilt für den aktuellen Beleg und alle daraus aufgebauten Folgebelege, wird aber nicht in die Stammdaten zurückgeschrieben. Aus dem Belegkopf wandert der Code automatisch in die Artikelpositionen, und zwar unabhängig davon, was beim Artikel selbst hinterlegt ist. Änderst Du den Code im Kopf nachträglich, fragt das Programm, ob die Änderung auch für die bereits erfassten Positionen gelten soll.
&lt;/p&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;Für die Übergabe zählen am Ende immer die Erlöscodes der Positionen. Willst Du innerhalb eines Belegs nach einzelnen Artikeln aufteilen, änderst Du den Code direkt in der jeweiligen Position. Und falls beim Kunden kein Code hinterlegt ist, greift automatisch der Code aus dem Artikelstamm.&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;Schritt 3: Mandantengrundlagen im Rechnungswesen prüfen&lt;/h2&gt;
&lt;p&gt;
Wechsel jetzt ins Rechnungswesen, in den Bereich Schnittstelle Warenwirtschaft der Mandanten-Grundlagen. Hier entscheidest Du, ob fehlende Sachkonten bei der Übergabe automatisch angelegt werden sollen.
&lt;/p&gt;
&lt;p&gt;
Steht die Einstellung auf Ja und es gibt zu einem genutzten Erlöscode noch kein passendes Konto, legt Sage 100 dieses bei der Übergabe selbst an. Als Vorlage dient das beim Steuercode hinterlegte Vorlagenkonto. Das ist bequem, hat aber eine Kehrseite: Ein einmal bebuchtes Konto lässt sich nicht mehr löschen.
&lt;/p&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;In sauber geführten Mandanten legen wir die Erlöskonten lieber bewusst vorab an, statt sie automatisch entstehen zu lassen. So behältst Du die Kontrolle über Deinen Kontenrahmen und sammelst keine Konten an, die durch einen Tippfehler im Code aus Versehen bebucht wurden.&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;Schritt 4: Position des Codes in den Festkonten festlegen&lt;/h2&gt;
&lt;p&gt;
Jetzt kommt das Herzstück. Damit der Code tatsächlich in die Kontonummer eingesetzt wird, passt Du im Rechnungswesen die &lt;strong&gt;Festkonten für die Umsatzsteuer&lt;/strong&gt; an. Für jeden Steuercode kannst Du getrennt hinterlegen, an welcher Stelle der Kontonummer der Erlöscode steht. Du wählst die entsprechende Zeile und legst die Position über den Button Code fest.
&lt;/p&gt;
&lt;p&gt;
Sage 100 zeigt Dir dabei anhand der hinterlegten Ausgangskontonummer die möglichen Stellen an. Frei wählbare Positionen werden mit einem &lt;code&gt;x&lt;/code&gt; markiert. Du bestimmst also genau, wo der Code sitzt:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Basiskonto: 44xx0
Erlöscode 10 → 44100 (Eigenprodukte)
Erlöscode 20 → 44200 (Handelsware)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Aus unserer Projektpraxis haben sich ein paar Faustregeln bewährt:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Kläre vorab die Anzahl der Stellen und plane künftige Anforderungen gleich mit ein. Ein zu eng gewählter Rahmen rächt sich später.&lt;/li&gt;
&lt;li&gt;Wähle als Basiskonto eines, das die Erlöscodes auch wirklich aufnehmen kann, ohne dass Du dabei in einen fremden Kontenbereich rutschst.&lt;/li&gt;
&lt;li&gt;Erweitere bei Bedarf Deinen Sachkontenrahmen, damit eine saubere Trennung möglich ist und die Konten sprechend bleiben.&lt;/li&gt;
&lt;li&gt;Hast Du einen zweistelligen Bereich reserviert, aber nur einen einstelligen Code vergeben, füllt Sage 100 linksbündig mit einer Null auf. Aus der 1 wird dann 01.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Schritt 5: Buchungen übergeben&lt;/h2&gt;
&lt;p&gt;
Die eigentliche Übergabe läuft wie gewohnt, entweder über den &lt;strong&gt;Übergabelauf&lt;/strong&gt; oder &lt;strong&gt;sofort&lt;/strong&gt; beim Speichern eines Rechnungsbelegs. Beide Wege beherrschen die Übergabe mit Erlöscodes ohne Einschränkung. Wenn Du die Grundlagen sauber eingerichtet hast, musst Du im laufenden Betrieb gar nichts mehr tun. Die Codes hängen an den Belegen, und die Aufteilung auf die Konten passiert im Hintergrund.
&lt;/p&gt;
&lt;h2&gt;Typische Stolpersteine&lt;/h2&gt;
&lt;p&gt;Aus unseren Sage 100 Projekten kennen wir ein paar Fehlerbilder, die immer wieder auftauchen:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Der Stellenrahmen für den Code wird zu knapp geplant. Kommt später eine Sparte hinzu, passt sie nicht mehr in das Schema, und es entsteht Flickwerk.&lt;/li&gt;
&lt;li&gt;Die automatische Kontenanlage steht auf Ja, ohne dass es jemand weiß. Über die Zeit füllt sich der Kontenrahmen mit Konten, die niemand bewusst angelegt hat.&lt;/li&gt;
&lt;li&gt;Codes werden nur beim Artikel gepflegt, der Belegkopf überschreibt sie aber. Wer das Zusammenspiel von Kopf und Position nicht kennt, wundert sich über die Buchungen.&lt;/li&gt;
&lt;li&gt;Erlöskonten und Steuercodes passen nicht zusammen. Achte darauf, dass das Basiskonto je Steuercode zum tatsächlichen Steuersatz der Position passt.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Fazit&lt;/h2&gt;
&lt;p&gt;
Erlöscodes sind in Sage 100 ein kleiner Eingriff mit großer Wirkung. Einmal durchdacht eingerichtet, sortieren sie Deine Umsätze bei jeder Buchungsübergabe automatisch auf die richtigen Konten. Das Ergebnis ist eine BWA, die Dir wirklich etwas sagt, eine nachvollziehbare Umsatzsteuer und eine Buchhaltung, die nichts mehr von Hand nachsortieren muss. Der Aufwand liegt fast vollständig in der Planung: Welche Sparten willst Du sehen, wie viele Stellen brauchst Du, welcher Kontenrahmen trägt das Schema?
&lt;/p&gt;
&lt;p&gt;
Du willst Deine Erlöse endlich differenziert auswerten oder bist Dir bei der Stellenlogik im Kontenrahmen unsicher? Dann lass uns gemeinsam einen Blick auf Deinen Mandanten werfen.
&lt;/p&gt;
&lt;div style="text-align: center; margin: 3rem 0;"&gt;
&lt;a href="https://appontes.de/kontakt/?betreff=anfrage-sage" class="btn btn-primary"&gt;Erlöscodes in Sage 100 einrichten lassen&lt;/a&gt;
&lt;/div&gt;</content:encoded></item><item><title>E-Rechnung schnell prüfen: XRechnung und ZUGFeRD direkt im Browser kontrollieren</title><link>https://appontes.de/blog/erechnung-pruefen-tool/</link><guid isPermaLink="true">https://appontes.de/blog/erechnung-pruefen-tool/</guid><pubDate>Wed, 13 May 2026 00:00:00 +0000</pubDate><dc:creator>Thomas Falkner</dc:creator><category>Sage 100</category><category>E-Rechnung</category><category>Rechnungswesen</category><description>Eine eingegangene XRechnung oder ZUGFeRD-Datei auf Format, Pflichtfelder und Rechensummen prüfen, ohne den XML-Code lesen zu müssen. Unser kostenloses Tool zeigt die Rechnung lesbar an und läuft komplett lokal im Browser.</description><content:encoded>&lt;p&gt;&lt;img src="https://appontes.de/img/blog/erechnung-pruefer.svg" alt="E-Rechnung schnell prüfen: XRechnung und ZUGFeRD direkt im Browser kontrollieren"&gt;&lt;/p&gt;
&lt;p&gt;
Seit die E-Rechnung im Geschäftsverkehr zur Pflicht geworden ist, landen strukturierte Rechnungen im Posteingang, die man nicht mehr einfach mit dem Auge prüfen kann. Eine XRechnung ist reines XML, und auch bei ZUGFeRD steckt die eigentliche Rechnung als XML im PDF. Die Frage, ob alle Pflichtangaben vorhanden sind und ob die Summen stimmen, lässt sich am Beleg selbst kaum beantworten.
&lt;/p&gt;
&lt;p&gt;
Genau dafür haben wir ein kleines Werkzeug gebaut. Du lädst die XML hoch oder fügst sie ein, und der &lt;a href="https://appontes.de/tools/erechnung-pruefer/"&gt;E-Rechnungs-Prüfer&lt;/a&gt; zeigt Dir die Rechnung lesbar an, prüft die wichtigsten Punkte und sagt Dir, wo etwas fehlt. Die Hintergründe zur E-Rechnung selbst haben wir in einem &lt;a href="https://appontes.de/blog/e-rechnung-sage-100/"&gt;eigenen Beitrag&lt;/a&gt; beschrieben, hier geht es um die schnelle Kontrolle im Alltag.
&lt;/p&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;
&lt;strong&gt;Wichtig vorweg:&lt;/strong&gt; Das Tool macht eine Plausibilitäts- und Vollständigkeitsprüfung, keine zertifizierte Validierung. Für die rechtsverbindliche Prüfung gegen alle Geschäftsregeln gibt es den offiziellen Validator der KoSIT. Im Zweifel nutzt Du diesen oder stimmst den Fall mit Deiner Steuerberatung ab.
&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;1. Warum eine schnelle Prüfung im Alltag hilft&lt;/h2&gt;
&lt;p&gt;
Die typischen Stolpersteine sind selten exotisch. Mal fehlt die Leitweg-ID, die bei Rechnungen an öffentliche Auftraggeber Pflicht ist. Mal passt das Rechnungsdatum vom Format nicht, mal fehlt die Umsatzsteuer-Identifikationsnummer des Verkäufers, und manchmal gehen schlicht die Summen nicht auf. Solche Punkte fallen im XML kaum auf, sorgen aber später für Rückfragen oder eine abgelehnte Rechnung.
&lt;/p&gt;
&lt;p&gt;
Wenn Du einen Beleg vor der Weitergabe oder vor dem Import in Sage 100 kurz gegenprüfst, fängst Du diese Fehler früh ab. Das spart Nachfragen und vermeidet, dass eine unvollständige Rechnung erst im Workflow auffällt.
&lt;/p&gt;
&lt;h2&gt;2. Was das Tool prüft&lt;/h2&gt;
&lt;p&gt;
Der Prüfer erkennt zunächst das Format. Unterstützt werden XRechnung im UBL- und im CII-Format sowie die CII-XML von ZUGFeRD und Factur-X. Danach schaut er sich die wesentlichen Inhalte an:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Rechnungsnummer, Rechnungsdatum und Währung,&lt;/li&gt;
&lt;li&gt;Verkäufer und Käufer samt Umsatzsteuer-Identifikationsnummer,&lt;/li&gt;
&lt;li&gt;Leitweg-ID beziehungsweise Käuferreferenz,&lt;/li&gt;
&lt;li&gt;Anzahl der Positionen und den ausgewiesenen Steuerbetrag,&lt;/li&gt;
&lt;li&gt;und die Rechensumme, also ob Brutto gleich Netto plus Steuer ist.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Das Ergebnis ist eine Prüfliste mit klaren Symbolen für in Ordnung, Hinweis und Fehler, dazu ein kurzes Gesamturteil. So siehst Du auf einen Blick, ob der Beleg sauber ist oder wo Du genauer hinschauen solltest.
&lt;/p&gt;
&lt;h2&gt;3. Lesbare Übersicht statt XML&lt;/h2&gt;
&lt;p&gt;
Neben der Prüfliste stellt das Tool die Rechnung lesbar dar: Nummer, Datum, Beteiligte, Beträge in Netto, Steuer und Brutto. Du musst Dich also nicht durch verschachtelte Tags arbeiten, sondern siehst die wichtigen Werte aufbereitet. Das hilft auch dann, wenn Du einfach nur schnell wissen willst, was in einer eingegangenen Datei eigentlich drinsteht.
&lt;/p&gt;
&lt;h2&gt;4. Kopfdaten korrigieren&lt;/h2&gt;
&lt;p&gt;
Manchmal stimmt fast alles, nur eine Kleinigkeit im Kopf passt nicht. Für solche Fälle kannst Du Rechnungsnummer, Datum und Leitweg-ID direkt anpassen und die korrigierte XML wieder herunterladen. Bewusst beschränkt sich das auf einzelne vorhandene Kopffelder, damit die Struktur der Datei gültig bleibt. Beträge und Positionen rührt das Tool nicht an.
&lt;/p&gt;
&lt;h2&gt;5. Läuft lokal, nichts wird hochgeladen&lt;/h2&gt;
&lt;p&gt;
Rechnungen sind sensible Daten. Deshalb läuft die gesamte Prüfung ausschließlich in Deinem Browser. Die XML wird lokal eingelesen und ausgewertet, es werden keine Daten an einen Server übertragen oder gespeichert. Du kannst das Tool also bedenkenlos mit echten Belegen nutzen.
&lt;/p&gt;
&lt;h2&gt;6. Wo die Grenzen liegen&lt;/h2&gt;
&lt;p&gt;
Eine ehrliche Einordnung gehört dazu. Das Werkzeug ersetzt keine zertifizierte Validierung gegen den vollständigen Regelsatz der EN 16931 und der XRechnung. Es deckt Format, Pflichtfelder und die wichtigsten Summen ab, nicht jede einzelne Geschäftsregel. Bei ZUGFeRD oder Factur-X liegt die Rechnungs-XML eingebettet im PDF. Du kannst die PDF deshalb direkt hochladen, das Tool liest die enthaltene XML automatisch aus und prüft sie wie eine reine XRechnung. Auch das passiert vollständig lokal im Browser.
&lt;/p&gt;
&lt;p&gt;
Probier es einfach aus: &lt;a href="https://appontes.de/tools/erechnung-pruefer/"&gt;E-Rechnung prüfen&lt;/a&gt;. Wenn Dir eine Prüfung fehlt oder Du die Anbindung an Deinen Rechnungseingang in Sage 100 sauber aufsetzen willst, melde Dich. Genau aus solchen Anforderungen entstehen unsere Werkzeuge.
&lt;/p&gt;</content:encoded></item><item><title>Welches Konto war das nochmal? Interaktiver SKR03/SKR04-Kontenrahmen mit Buchungshilfe</title><link>https://appontes.de/blog/skr03-skr04-kontenrahmen-tools/</link><guid isPermaLink="true">https://appontes.de/blog/skr03-skr04-kontenrahmen-tools/</guid><pubDate>Wed, 29 Apr 2026 00:00:00 +0000</pubDate><dc:creator>Thomas Falkner</dc:creator><category>Sage 100</category><category>Rechnungswesen</category><category>SKR04</category><category>SKR03</category><description>Kontonummern nachschlagen, einen Buchungssatz aus einem Satz erzeugen, Soll an Haben prüfen und zwischen SKR03 und SKR04 umschlüsseln: Kleine, kostenlose Werkzeuge für die tägliche Kontierungsarbeit in Sage 100.</description><content:encoded>&lt;p&gt;&lt;img src="https://appontes.de/img/blog/kontenrahmen-tools.svg" alt="Welches Konto war das nochmal? Interaktiver SKR03/SKR04-Kontenrahmen mit Buchungshilfe"&gt;&lt;/p&gt;
&lt;p&gt;
Im Buchhaltungsalltag verliert man schnell Zeit mit denselben Handgriffen. Auf welches Konto kommt die Telefonrechnung? Wie hieß die Vorsteuer im SKR03 nochmal, und wie lautet die im SKR04? Wie sieht der vollständige Buchungssatz mit Steueranteil aus? Wer mit Sage 100 arbeitet, kennt das. Meistens landet man in einer PDF-Liste oder im Kontenplan und sucht sich die Nummer zusammen.
&lt;/p&gt;
&lt;p&gt;
Wir haben uns aus genau diesen Situationen ein paar Werkzeuge gebaut und stellen sie frei zur Verfügung. Sie laufen direkt im Browser, ohne Anmeldung, und decken die Dinge ab, die im Tagesgeschäft am häufigsten auftauchen. Dieser Beitrag zeigt, was drinsteckt und wofür Du es nutzen kannst.
&lt;/p&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;
&lt;strong&gt;Kurz vorab:&lt;/strong&gt; Die Erklärungen und Beispielbuchungen sind eine fachliche Orientierung aus der Praxis, keine Steuerberatung. Buchungssätze können je nach Sachverhalt abweichen, und maßgeblich ist immer der offizielle DATEV-Kontenrahmen. Im Zweifel stimmst Du den Fall mit Deiner Steuerberatung ab.
&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;1. Der komplette Kontenrahmen, durchsuchbar nach Gliederung&lt;/h2&gt;
&lt;p&gt;
Den Anfang macht der Kontenrahmen selbst, einmal als &lt;a href="https://appontes.de/tools/kontenrahmen/"&gt;SKR04&lt;/a&gt; und einmal als &lt;a href="https://appontes.de/tools/kontenrahmen-skr03/"&gt;SKR03&lt;/a&gt;. Statt einer endlosen Liste klappst Du die Struktur auf: Beim SKR04 nach Bilanz und Gewinn- und Verlustrechnung, beim SKR03 nach den Kontenklassen. Ein farbiger Punkt zeigt Dir auf einen Blick, ob ein Konto aktiv, passiv, Aufwand oder Ertrag ist.
&lt;/p&gt;
&lt;p&gt;
Das Suchfeld findet Konten nach Nummer und nach Bezeichnung. Tippst Du 1200 oder Kasse, springt das passende Konto heraus. Zu den gebräuchlichsten Konten haben wir eine kurze Erklärung und eine Beispielbuchung hinterlegt, damit Du nicht nur die Nummer, sondern auch den Zusammenhang siehst.
&lt;/p&gt;
&lt;h2&gt;2. Buchungssatz aus einem Satz&lt;/h2&gt;
&lt;p&gt;
Der Buchungs-Assistent nimmt Dir die erste Einordnung ab. Du beschreibst den Vorgang in eigenen Worten, zum Beispiel „Ich kaufe Büromaterial für 60 EUR 19%", und bekommst einen fertigen Vorschlag: Bürobedarf im Soll, die abziehbare Vorsteuer dazu, der Bruttobetrag im Haben gegen Bank oder Kasse.
&lt;/p&gt;
&lt;p&gt;
Er erkennt das Konto über Stichwörter, dazu Betrag, Steuersatz und Zahlweise. Schreibst Du bar, bucht er gegen die Kasse, schreibst Du auf Rechnung, gegen den Lieferanten. Netto oder Brutto kannst Du umstellen. Auch Sonderfälle sind dabei, etwa der 70/30-Split bei Bewirtungskosten oder die Sofortabschreibung bei geringwertigen Wirtschaftsgütern.
&lt;/p&gt;
&lt;p&gt;
Ehrlich gesagt steckt dahinter keine große künstliche Intelligenz, sondern eine saubere Stichworterkennung, die lokal im Browser läuft. Das hat einen praktischen Vorteil: Es ist schnell und Deine Eingaben verlassen den Rechner nicht. Damit der Assistent auch Deine Formulierungen versteht, kannst Du eigene Synonyme pflegen. Wer statt Telefon lieber Handyvertrag oder Mobilfunkvertrag tippt, hinterlegt das einmal und der Vorschlag passt.
&lt;/p&gt;
&lt;h2&gt;3. Soll an Haben prüfen, auch bei Splitbuchungen&lt;/h2&gt;
&lt;p&gt;
Manchmal hast Du den Buchungssatz schon im Kopf und willst nur kurz gegenprüfen. Dafür gibt es den Buchungssatz-Prüfer. Du wählst die Konten über die Suche aus, trägst die Beträge ein und siehst sofort, ob Soll gleich Haben ist. Dazu nennt er den Buchungstyp, also Aktivtausch, Bilanzverlängerung, eine erfolgswirksame Aufwands- oder Ertragsbuchung, und gibt eine Einschätzung zur Plausibilität.
&lt;/p&gt;
&lt;p&gt;
Zusammengesetzte Buchungen mit mehreren Konten auf beiden Seiten sind ausdrücklich vorgesehen. Gerade bei einer Eingangsrechnung mit Vorsteuer oder bei einer Aufteilung auf mehrere Kostenkonten ist das hilfreich, weil der Saldo direkt mitläuft.
&lt;/p&gt;
&lt;h2&gt;4. Zwischen SKR03 und SKR04 umschlüsseln&lt;/h2&gt;
&lt;p&gt;
Wer Mandanten mit unterschiedlichen Kontenrahmen betreut oder Belege aus einer anderen Buchhaltung übernimmt, kennt die Sucherei nach dem passenden Gegenstück. Der Konten-Umschlüssler nimmt Dir das ab. Du wählst die Richtung, von SKR04 nach SKR03 oder umgekehrt, und gibst eine Kontonummer oder eine Bezeichnung ein.
&lt;/p&gt;
&lt;p&gt;
Tippst Du 6815, bekommst Du im SKR03 das 4930 für Bürobedarf. Gibst Du stattdessen einen Begriff ein, listet das Tool alle Treffer auf. Die Zuordnung beruht auf den übereinstimmenden Bezeichnungen beider Kontenrahmen und deckt die gängigen Konten ab. Nicht jedes Spezialkonto hat ein eindeutiges Gegenstück, das sagen wir auch offen dazu.
&lt;/p&gt;
&lt;h2&gt;5. Warum wir das gemacht haben&lt;/h2&gt;
&lt;p&gt;
Wir bauen unsere Werkzeuge aus dem, was uns und unseren Kunden im Alltag begegnet. Die Kontierung gehört dazu. Statt jedes Mal eine Liste zu durchsuchen, wollten wir die Antwort in ein paar Sekunden haben, und zwar für beide Kontenrahmen. Das Ergebnis ist bewusst schlicht: Keine Installation, keine Anmeldung, klare Vorschläge mit einem ehrlichen Hinweis, dass die endgültige Verantwortung bei der fachlichen Prüfung bleibt.
&lt;/p&gt;
&lt;p&gt;
Probier es aus: &lt;a href="https://appontes.de/tools/kontenrahmen/"&gt;SKR04-Kontenrahmen&lt;/a&gt;, &lt;a href="https://appontes.de/tools/kontenrahmen-skr03/"&gt;SKR03-Kontenrahmen&lt;/a&gt; und der &lt;a href="https://appontes.de/tools/kontenvergleich/"&gt;Konten-Umschlüssler&lt;/a&gt;. Wenn Dir ein Konto, eine Formulierung oder eine Funktion fehlt, sag uns Bescheid. Genau so sind diese Tools entstanden.
&lt;/p&gt;</content:encoded></item><item><title>Sachkontonummern in Sage 100 verlängern: Wann es sinnvoll ist und wie es funktioniert</title><link>https://appontes.de/blog/sachkonten-nummern-erweitern-sage-100/</link><guid isPermaLink="true">https://appontes.de/blog/sachkonten-nummern-erweitern-sage-100/</guid><pubDate>Wed, 15 Apr 2026 00:00:00 +0000</pubDate><dc:creator>Thomas Falkner</dc:creator><category>Sage 100</category><category>Rechnungswesen</category><category>Administration</category><description>Wenn der Kontenplan zu eng wird: Warum es sinnvoll sein kann, die Stellenzahl der Sachkonten zu erweitern, und wie Du die Kontennummernerweiterung in Sage 100 sauber durchführst, inklusive aller bestehenden Buchungen.</description><content:encoded>&lt;p&gt;&lt;img src="https://appontes.de/img/blog/sachkonten-nummern-erweitern.svg" alt="Sachkontonummern in Sage 100 verlängern: Wann es sinnvoll ist und wie es funktioniert"&gt;&lt;/p&gt;
&lt;p&gt;
Manchmal stößt man im Rechnungswesen an eine unscheinbare Grenze: Die Sachkonten haben zu wenige Stellen. Du willst die Buchungen aus der Warenwirtschaft feiner trennen, mit Einkaufs- und Erlöscodes arbeiten oder schlicht mehr Konten je Bereich anlegen, und der bestehende Kontenplan gibt das nicht mehr her. Gerade zur Vorbereitung auf ein neues Geschäftsjahr taucht diese Frage gern auf.
&lt;/p&gt;
&lt;p&gt;
Die gute Nachricht: Sage 100 kann die Anzahl der Sachkontenstellen nachträglich erweitern, und zwar inklusive aller bereits erfassten Konten und Buchungen. Diese Kontennummernerweiterung gibt es schon lange, eingeführt rund um die Mehrwertsteuer-Umstellung 2006, damals noch in der Office Line. Sie arbeitet je Mandant und ist sehr mächtig. Sie ist aber auch endgültig.
&lt;/p&gt;
&lt;div class="blog-callout"&gt;
&lt;p&gt;
&lt;strong&gt;Wichtig vorweg:&lt;/strong&gt; Diese Umstellung lässt sich nicht rückgängig machen. Mache vorher eine vollständige Datensicherung und stimme das Vorhaben mit Deiner Steuerberatung ab. Ein Zurück gibt es nur über das Backup.
&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;1. Warum die Kontonummern überhaupt verlängern?&lt;/h2&gt;
&lt;p&gt;
Eine zusätzliche Stelle klingt nach einer Kleinigkeit, eröffnet aber im Kontenplan viel Platz. Typische Gründe aus der Praxis:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Feinere Gliederung:&lt;/strong&gt; Du willst Erlöse und Aufwendungen nach Sparten, Marken, Standorten oder Geschäftsbereichen trennen und brauchst dafür mehr Konten je Gruppe, als die bisherige Stellenzahl hergibt.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Einkaufs- und Erlöscodes aus der Warenwirtschaft:&lt;/strong&gt; Wer die Buchungsübergabe sauber nach Code strukturiert, landet schnell bei vielen Erlös- und Wareneingangskonten. Eine zusätzliche Stelle schafft die nötige Systematik.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bessere Auswertungen:&lt;/strong&gt; Mehr Detailtiefe direkt im Konto erleichtert Auswertungen und Controlling, ohne jede Differenzierung über Kostenstellen abbilden zu müssen.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Einheitliche Struktur über mehrere Mandanten:&lt;/strong&gt; Wenn Tochtergesellschaften oder weitere Mandanten dazukommen, hilft ein einheitliches, längeres Nummernschema bei Vergleich und Konsolidierung.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vorgaben von außen:&lt;/strong&gt; Manchmal geben Steuerberatung, DATEV-Anbindung oder ein übernommenes Altsystem ein längeres Format vor.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Kurz gesagt: Wenn die Struktur wächst und Du Buchungen künftig granularer abbilden willst, ist die Verlängerung der Sachkontonummern oft der sauberere Weg, statt Konten zu überladen oder Sachverhalte in Textfelder auszulagern.
&lt;/p&gt;
&lt;h2&gt;2. Wie Sage die Stellenzahl festlegt&lt;/h2&gt;
&lt;p&gt;
Bei der Anlage eines Mandanten wählst Du den Kontenrahmen und die Formatierung nach Sage- oder DATEV-Vorgaben. Damit wird die Anzahl der Stellen für die Sachkonten fest vorbelegt. Einsehen kannst Du das im Sage Administrator im Bereich der Feldformatierung.
&lt;/p&gt;
&lt;p&gt;
Im &lt;strong&gt;Eingabeformat&lt;/strong&gt; sind die Stellenzahl und die Ausrichtung über Sonderzeichen hinterlegt. Wichtig zu verstehen: Wenn Du dort nur das Eingabeformat änderst, wirkt das ausschließlich auf zukünftige Eingaben. Deine bereits angelegten Sachkonten und alle Buchungen bleiben unverändert. Für eine echte Umstellung des gesamten Bestands brauchst Du deshalb die Kontennummernerweiterung.
&lt;/p&gt;
&lt;h2&gt;3. Die Kontennummernerweiterung Schritt für Schritt&lt;/h2&gt;
&lt;p&gt;
Im Sage Administrator öffnest Du in der &lt;strong&gt;Feldformatierung Sachkonten&lt;/strong&gt; die Erweiterung. Im folgenden Dialog legst Du fest, wie umgestellt wird:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Einfügen nach Stelle:&lt;/strong&gt; Hier bestimmst Du die Position der neuen Stelle. Soll sie am Ende der Nummer stehen, gibst Du bei einer vierstelligen Nummer die 4 an. Du kannst die zusätzliche Stelle aber auch an einer anderen Position einfügen.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Einzufügendes Format:&lt;/strong&gt; Das Sonderzeichen für die neue Stelle. Orientiere Dich dabei an Deinen bisherigen Sachkonteneinstellungen, damit das Format stimmig bleibt.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Einzufügendes Zeichen:&lt;/strong&gt; Womit die vorhandenen Nummern aufgefüllt werden. In der Praxis ist das fast immer die 0.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Neues Format:&lt;/strong&gt; Wird zur Kontrolle angezeigt und lässt sich nicht direkt ändern. Eine Testeingabe zeigt Dir, welche Kontonummer beim Anlegen künftig gebildet wird.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gültigkeitsbereich:&lt;/strong&gt; Optional grenzt Du die Erweiterung auf einen Bereich ein, etwa wenn Du nur einen Teil der Konten anders erweitern willst. Achtung: Das kann zu unterschiedlich langen Kontonummern in einer Buchhaltung führen.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;4. Transaktionssicherheit: Tempo gegen Sicherheit&lt;/h2&gt;
&lt;p&gt;
Über die Option &lt;strong&gt;Transaktionssicherheit während der Aktualisierung ausschalten&lt;/strong&gt; steuerst Du, ob die Umstellung intern protokolliert wird. Schaltest Du sie aus, läuft die Aktualisierung schneller, im Fehlerfall hilft Dir dann aber nur die Datensicherung. Lässt Du die Transaktionssicherheit aktiv, dauert die Umstellung länger, ist dafür besser abgesichert. Vor dem Start weist Dich das Programm ausdrücklich darauf hin, dass die Änderung unwiderruflich ist.
&lt;/p&gt;
&lt;h2&gt;5. Was sich danach ändert&lt;/h2&gt;
&lt;p&gt;
Die Erweiterung betrifft nicht nur die Stammdaten. Neben allen vorhandenen Sachkonten werden auch sämtliche Buchungen aller Geschäftsjahre auf das neue Format umgestellt. Neue Sachkonten legst Du anschließend automatisch in der neuen, längeren Formatierung an. Der gesamte Bestand ist damit konsistent.
&lt;/p&gt;
&lt;h2&gt;6. Vorbereitung: Die kurze Checkliste&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Vollständige Datensicherung erstellen und prüfen, ob sie sich zurückspielen lässt.&lt;/li&gt;
&lt;li&gt;Das Vorhaben mit der Steuerberatung abstimmen.&lt;/li&gt;
&lt;li&gt;Wenn möglich, die Umstellung vorab in einem Kopiemandanten testen.&lt;/li&gt;
&lt;li&gt;Schnittstellen und Auswertungen prüfen, die auf einer festen Kontonummernlänge aufbauen: DATEV-Export, Bankanbindung, eigene Reports, OP-Listen, Drittsysteme.&lt;/li&gt;
&lt;li&gt;Ein ausreichendes Zeitfenster einplanen und die Anwender informieren.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Die Kontennummernerweiterung ist ein starkes Werkzeug, wenn der Kontenplan mit dem Unternehmen mitwachsen soll. Weil sie tief in den Datenbestand eingreift, lohnt sich die saubere Vorbereitung. Wenn Du die Umstellung planst, begleiten wir Dich als zertifizierter Sage-Partner gern, von der Struktur über den Test bis zur Durchführung. Sprich uns einfach an: &lt;a href="https://appontes.de/kontakt/?betreff=anfrage-sage"&gt;Kontakt&lt;/a&gt; oder direkt einen &lt;a href="https://appontes.de/termin/"&gt;Beratungstermin&lt;/a&gt;.
&lt;/p&gt;</content:encoded></item></channel></rss>