Beispiel Gewinnverteilung ◦ Zusammenfassung ◦ ?

Im Mittelpunkt dieses Beispiels steht die Gewinnverteilung einer Aktiengesellschaft (AG) nach Artikel 671 des schweizerischen Obligationenrechts (OR). Es soll nicht nur die Themen Objekte und Benutzerschnittstelle vertiefen, sondern auch die phasenweise Entwicklung eines komplexeren Programms veranschaulichen. Das Thema ist wie folgt gegliedert:

1. Buchhalterische Voraussetzungen

2. Spezifikation

3. Entwurf
4. Implementation

###
Erfolgsverteilung in der doppelten Buchhaltung

Der Ablauf einer doppelten Buchhaltung besteht aus drei Phasen:

1. Zu Beginn der Buchungsperiode wird die Bilanz (Vermögensrechnung) eröffnet.

2. Während der Buchungsperiode wird der Geschäftsverkehr doppelt verbucht. Jeder Geschäftsfall wir durch einen oder mehrere Buchungssätze festgehalten. Doppelt verbuchen heisst den Sollspalten eines Buchungssatzes gleich viel belasten wie seinen Habenspalten gutgeschrieben wird.

3. Am Ende der Buchungsperiode werden die Vermögens- und Schuldkonten in der Bilanz zusammengefasst. Die Aufwand- und Erfolgskonten werden in der Erfolgsrechnung (Gewinn- und Verlustrechnung) abgeschlossen.

Zu den Abschlussarbeiten der Erfolgsrechnung gehört auch die Verbuchung der Gewinnverteilung. Wir veranschaulichen an ihrer Implementation ausgewählte Begriffe der Programmentwicklung unter VBA und Excel. Die Buchhaltung einer Aktiengesellschaft (AG) enthält die folgenden Erfolgsverteilungskonten:

- Das Konto Aktienkapital (AK) enthält die Eigentümeranteile

- Die Erfolgsrechnung (ER) ermittelt den Gewinn oder Verlust. Dieser wird am Ende der Buchhaltungsperiode auf das Konto ”Gewinn“verteilung übertragen

- Der Reservefonds (Res) bewahrt den nicht ausgeschütteten Gewinn auf

- Dividende (Div) enthält den Gewinnanteil der Aktionäre

- Tantième (Tant) enthält den Gewinnanteil der Verwaltungsräte

- Das Konto ”Gewinn“verteilung (GV) verteilt den Erfolg (Gewinn oder Verlust). Der Buchungssatz für die Verteilung der Dividende heisst zum Beispiel “Gewinnverteilung an Dividende”: Das heisst, die Dividende wird von der Sollspalte des Kontos Gewinnverteilung abgezogen und in der Habenspalte des Passivkontos Dividende als Schuld verbucht. Jede Erfolgsverbuchung ändert so den Saldo des Kontos Gewinnverteilung.

Bei der Präsentation des Beispiels folgen wir den Entwicklungsphasen Spezifikation, Entwurf und Implementation.

###
Spezifikation

#### a) Grobspezifikation

Der folgende Bildschirmausschnitt beschreibt den Zweck der Arbeitsmappe Gewinnverteilung.xls. Der Entwickler trägt sie zu Beginn des Projekts unter dem Excel-Menüpunkt »Datei/Eigenschaften ein:

#### b) Feinspezifikation

Die folgende Feinspezifikation geht nach dem EVA-Prinzip des Themas Modularisierung vor und wendet die gesetzlichen Vorschriften von OR 671 und die kaufmännische Praxis auf eine konkrete Gewinnverteilungsaufgabe an:

#### Eingabe

Weil das Programm - anders als ein reales Buchhaltungspaket - den Verkehr der vergangenen Buchungsperiode noch nicht aufgezeichnet hat, muss es den zusammengefassten Verkehr vom Benutzer einlesen, zum Beispiel ...

Beteiligte Konten | Beispielsaldi
Aufwand (Unternehmungsaufwand) | 150’000.-
Ertrag (Unternehmungsertrag) | 180’000.-
Aktienkapital (Grundkapital) | 100’000.-
Reserve (Reservefonds) | 5’000.-
Tantième in % | 10%

#### Ausgabe

Alle Buchungssätze der Gewinnverteilung sollen im Format “<Sollkonto> an <Habenkonto>, <Betrag>” auf dem Tabellenblatt ausgegeben werden:

#### Verarbeitung

##### a. Wortlaut und Interpretation des Gesetzes

OR 671 regelt die Erfolgsverteilung einer Aktiengesellschaft. Die geklammerten Ziffern des folgenden Gesetzestexts verweisen auf den entwurfssprachlichen Algorithmus. Reservezuweisungen sind unterstrichen:

> "Aus dem Reingewinn ist jährlich ein Betrag von einem Zwanzigstel einem allgemeinen Reservefonds zuzuweisen (1), bis dieser Fonds die Höhe von einem Fünftel des einbezahlten Grundkapitals erreicht hat (2).

> Diesem Reservefonds sind, auch nachdem er die gesetzliche Höhe erreicht hat, zuzuweisen: ...
> ein Zehntel derjenigen Beträge (3), die aus dem Reingewinn nach der ordentlichen Speisung des Reservefonds (1) und nach Bezahlung einer Dividende von fünf vom Hundert an Aktionäre (4) und sonstige Gewinnbeteiligte (5) verteilt werden."

Die folgende Regelung ergänzt OR 671. Sie ist nicht bindend, in der Praxis aber weit verbreitet:

> Nach der ordentlichen Reservezuweisung (s. 1) erhält der Verwaltungsrat eine Tantième in % des Gewinns (5). Nach der zweiten Speisung der Reserve (s. 3) sind vom Gewinnrest soviele ganze Prozent vom einbezahlten Grundkapital wie möglich als Zusatzdividende auszuschütten (6).

Eine verbale Spezifikation ist selten eindeutig. Die Interpretation der oben beschriebenen Erfolgsverteilung ist vor allem aus den folgenden Gründen schwierig:

- OR 671 setzt die folgenden Buchhaltungskenntnisse voraus:

> - Der Reingewinn (Nettogewinn oder kurz Gewinn) ist die Differenz von Ertrag und Aufwand

> - Der Reservefonds enthält jene Gewinnanteile, die nicht als Dividende an Aktionäre oder als Tantième an die Verwaltungsräte verteilt worden sind

> - Berechnungsbasis der Dividende ist das Grundkapital (Aktienkapital)

> - Eine erste Zuweisung an die Aktionäre heisst Grunddividende, solange sie einen Fünftel des Aktienkapitals nicht überschreitet. Was darüber hinaus geht, heisst Zusatzdividende (Superdividende). Im Gegensatz zur Grunddividende zieht die Zusatzdividende eine Reservezuweisung nach sich.

- Die Zusammenhänge zwischen den Absätzen von OR 671 sind nicht offensichtlich. Gemäss Auslegungspraxis beziehen sich die blauen Textstellen des zweiten Absatzes auf den blauen Teil des ersten Absatzes.

  "Aus dem Reingewinn ist jährlich ein Betrag von einem Zwanzigstel einem allgemeinen Reservefonds zuzuweisen, bis dieser Fonds die Höhe von einem Fünftel des einbezahlten Grundkapitals erreicht hat.

  Diesem Reservefonds sind, auch nachdem er die gesetzliche Höhe erreicht hat, zuzuweisen: ...
  ein Zehntel derjenigen Beträge, die aus dem Reingewinn nach der ordentlichen Speisung des Reservefonds und nach Bezahlung einer Dividende von fünf vom Hundert an Aktionäre und sonstige Gewinnbeteiligte verteilt werden."

- OR 671 verwendet Begriffe, die nicht auf Anhieb klar sind. Unter sonstige Gewinnbeteiligte versteht der dritte Absatz zum Beispiel die Verwaltungsräte. Auch ein Zehntel derjenigen Beträge, die ... nach Bezahlung einer Dividende von fünf vom Hundert an Aktionäre und sonstige Gewinnbeteiligte verteilt werden ist mehrdeutig. Der Gesetzgeber will damit Folgendes sagen: Nach Verteilung einer Grunddividende von mindestens 5% müssen 10% einer allfälligen Zusatzdividende und 10% einer allfälligen Tantième den Reserven zugewiesen werden.

##### b. Übung der Praxis

Die Praxis schüttet vom Gewinnrest meist soviele ganze Prozent Zusatzdividende vom Aktienkapital wie möglich aus. Eine Zusatzdividende erfordert eine zusätzliche Reservezuweisung von 10% (Reservezuweisung = 0.1*Zusatzdividende). Wir berechnen die ganzzahlige prozentuale Zusatzdividende schrittweise:

1. Zunächst berechnen wir den Betrag, den wir als Zusatzdividende aus dem Saldo von 'Gewinnverteilung' (Gewinnrest) ausschütten könnten

2. Dann drücken wir diesen Betrag als genauen Prozentsatz vom Aktienkapital aus.

3. Diesen genauen Prozentsatz runden wir auf den ganzzahligen ab

4. Schliesslich berechnen wir mit dem ganzzahligen Prozentsatz die endgültige Zusatzdividende.

Der genaue Zusatzdividendensatz ZusatzdivSatz ergibt sich aus den Gleichungen (1) bis (3) und den algebraischen Vereinfachungen (4) bis (7):

>     Zusatzdividende = ZusatzdivSatz * 0.01AK 					(1)
>     ZusatzdivSatz = (GV - ResAufZusatzdiv) / 0.01AK 				(2)
>     ResAufZusatzdiv = 0.1 * ZusatzdivSatz * 0.01AK 				(3)

(3) ist die Reservevorschrift von OR 671. (2) berechnet den ZusatzdivSatz, der sich nach Abzug der Reservezuweisung ResAufZusatzdiv noch aus dem Gewinnrest ausschütten lässt. Gleichung (4) vereinfacht (2), indem sie ResAufZusatzdiv durch (3) ersetzt. Nach den Schritten (5) und (6) ergibt (7) schliesslich den ZusatzdivSatz als Quotienten zwischen dem Gewinnrest GV und dem Produkts 0.011AK:

>     ZusatzdivSatz = (GV - 0.1 * ZusatzdivSatz * 0.01AK) / 0.01 AK		(4)
>     ZusatzdivSatz = GV / 0.01 AK - 0.1 * ZusatzdivSatz			(5)
>     1.1 ZusatzdivSatz = GV / 0.01AK						(6)
>     ZusatzdivSatz = GV / 0.01AK / 1.1 = GV / 0.011AK				(7)

Die VBA-Funktion Int ergibt den ganzzahligen Anteil ihres Arguments. Int(99.8) ergibt zum Beispiel die Integer-Zahl 99. Den ganzzahligen Zusatzdividendensatz berechnen wir deshalb als Int(GV / 0.011AK). Nach (1) lautet die VBA-Formel für die Zusatzdividende deshalb:

>     Zusatzdividende = Int(GV / 0.011AK) * 0.01AK

###
Entwurf

Die Arbeitsmappe Gewinnverteilung.xls setzt sich aus den folgenden Objekten zusammen:

Tabellenblatt Dialogblatt

- Ausgabebereich für die Ergebnisse der Gewinnverteilung
- Schaltfläche ‘Start’

Formular Eingabeformular

- Bezeichnungs- und Textfelder für die Eingabedaten
- Schaltflächen ‘Verbuchen’ und ‘Abbrechen’

Modul Verarbeitung.

#### a) Kernalgorithmus

Bevor wir die Gewinnverteilung in VBA implementieren, formulieren wir eine erste entwurfssprachliche Annäherung an den Kernalgorithmus. Dabei verwenden wir die folgenden Abkürzungen:

> ER Erfolgsrechnung
> GV Gewinnverteilung
> AK Aktienkapital
> T% Tantième in %
> kursiv Buchungssätze

>     Falls Aufwand < Ertrag dann                          '---- Gewinn
>       Gewinn = Ertrag - Aufwand
>       ER an GV, Gewinn
>       Falls Reserve < AK / 5 dann                             '(2)
>         GV an Reserve, Gewinn / 20                            '(1)
>         GV an Dividende, Aktienkapital / 20                   '(4)
>         GV an Tantième, Gewinn * T% / 100                     '(5)
>         GV an Reserve, Gewinn * T% / 100 / 10                 '(3)
>         ZusatzDivSatz =  GV / 0.011AK                         'siehe oben (3 c)
>         Zusatzdividende = AK * Int (ZusatzDivSatz) / 100
>         GV an Dividende,  Zusatzdividende                     '(5,6)
>         GV an Reserve, Zusatzdividende / 10                   '(3)
>       Falls GV > 0 dann
>         GV an Reserve, GV
>     sonst                                                '---- Verlust
>       Verlust = Aufwand - Ertrag
>       Falls Verlust < Reserve dann
>         Reserve an ER, Verlust
>       sonst
>         Reserve an ER, Reserve
>         GV an ER, Verlust - Reserve

>     Gewinnverteilung gemäss OR 671 und Praxis

Wer diesen Algorithmus mit der Subroutine Buchungssätze()der Arbeitsmappe Gewinnverteilung.xls vergleicht, stösst auf den folgenden Unterschied: Die programmiersprachliche Version prüft für jeden Buchungssatz, ob der laufende Saldo des Gewinnverteilungskontos für die Buchung ausreicht. Um das Verständnis zu erleichtern haben wir diese Prüfung weggelassen und nur nur den algorithmischen Kern skizziert.

#### b) Dialogblatt

Der grösste Teil von Gewinnverteilung.xls widmet sich der Benutzeroberfläche. Das folgende Bild zeigt im Hintergrund die vier Spalten des Tabellenblatts Dialogblatt. Die Ausgabeanweisung Range(Zelle).Value = Wert schreibt jeden vom Programm ermittelten Wert in die passende Zelle von Dialogblatt. Ein Klick auf die Schaltflläche ‘Start’ ruft die Ereignisprozedur Start_Click() auf, die ihrerseits das Eingabeformular 'Falldaten eingeben' anzeigt.

Auf dem farbigen Hintergrund des Tabellenblatts sehen Sie ...

- ein Eingabeformular mit fünf weissen Textfeldern und Defaultwerten

- ein Meldungsfeld mit der Reaktion auf den Eingabefehler "zehn" des letzten Textfelds.

>     Eingabe- und Ausgabebereich von Gewinnverteilung.xls

Wie ein Tabellenblatt stellt auch ein benutzerdefiniertes Formular Objekte, Eigenschaften und Methoden bereit. Das obige Eingabeformular 'Falldaten eingeben' enthält für jede Eingabe ein Bezeichnungsfeld und ein Textfeld (weisses Feld rechts vom Bezeichnungsfeld).

#### c) Eingabeformular

Das nächste Bild zeigt den Entwurf des oben gezeigten Eingabeformulars. Der Entwurf verläuft in vier Schritten:

> 1. Entwicklungsumgebung aufrufen (»Alt/F11)
> 2. Leeren Formularrahmen zeichnen
> 3. Steuerlemente in den Formularrahmen setzen (Bezeichnungs- und Textfelder; Schaltflächen)
> 4. Den Steuerelementen Ereignisprozeduren zuordnen (abbrechen_Click, verbuchen_Click).

>     Entwurf des Eingabeformulars "Falldaten eingeben"

> Das fertige Formular lässt sich mit mit dem VBA-Befehl Show anzeigen und mit Hide vorübergehend ausblenden.

### Implementation in VBA

#### a) Modul Verarbeitung

Nach dem Entwurf des algorithmischen Kerns und der Benutzeroberfläche skizzieren wir den VBA-Code. Elemente des Objektmodells von Excel sind blau, 'Schaltflächen' stehen zwischen Hochkommas und Ereignisprozeduren sind rot. Anders als der Programmcode kontrolliert die entwurfssprachliche Variante von Buchungssätze() nicht für jeden Buchungssatz, ob der Saldo des Kontos Gewinnverteilung noch ausreicht.

>     Ereignisprozedur Start_Click()
>       Ausgabebereich des Tabellenblatts Dialogblatt löschen
>       Eingabeformular mit ‘Abbrechen’ und ‘Verbuchen’ anzeigen
>       Falls abgebrochen <> True dann Buchungssätze()

>     Ereignisprozedur abbrechen_Click()
>       Eingabeformular nach Klick auf ‘Abbrechen’ schliessen
>       abgebrochen = True

>     Ereignisprozedur verbuchen_Click()
>       '--- Leere und nichtnummerische Eingaben verhindern
>       Für jedes Feld von Eingabeformular
>         Falls Feld leer oder nichtnummerisch dann
>           Formular nach Klick auf ‘Verbuchen’ nicht schliessen
>           Fehlermeldung zeigen
>       Kontrolle an den Benutzer zurückgeben

>     Subroutine Buchungssätze()
>       Eingabeformular lesen (Aufwand, Ertrag, Aktienkapital, Reserve, Tantième in %)
>       '-- Buchungssätze gemäss OR 671 und Praxis auf Dialogblatt schreiben
>       Falls Gewinn dann
>         BS "ER", "GV", Gewinn 'Reingewinn
>         Falls Reserve < AK dann
>           BS "GV", "Reserve", Gewinn / 20
>         BS "GV", "Dividende", Aktienkapital / 20
>         BS "GV", "Reserve", Gewinn / 20 / 10
>         BS "GV", "Tantieme", Gewinn * Tantiemensatz / 100
>         BS "GV", "Reserve", Gewinn * Tantiemensatz / 100 / 10
>         BS "GV", "Dividende", AK * Int(GV / 0.011AK) / 100
>         BS "GV", "Reserve", AK * Int(GV / 0.011AK) / 100 / 10
>         Falls GV < 0 dann
>           "GV", "Reserve", GV
>       sonst ‘Verlust
>         Falls Verlust < Reserve DANN
>           BS "Reserve", "ER", Verlust
>         sonst
>           BS "Reserve", "ER", Reserve
>           BS "GV", "ER", Verlust - Reserve

>     Subroutine BS(Sollkonto, Habenkonto, Buchungsbetrag)
>       Buchungssatz auf Dialogblatt schreiben
>       Konto Gewinnverteilung nachführen

>     Modul Verarbeitung (Objekt, Ereignisprozedur, ‘Schaltfläche’)

#### b) Codierung

Wir untersuchen den Programmcode nur ausschnittsweise:

1. In einem ersten Schritt unterscheiden wir zwischen Variablen, die für das ganze Projekt, für ein Modul oder nur eine Prozedur gelten.

2. Dann analysieren wir die Ereignisprozeduren der Start-Schaltfläche und des Eingabeformulars.

3. Schliesslich gewinnen wir einen Überblick über das ganze Programmierprojekt Gewinnverteilung und lernen den den Objektkatalog kennen.

##### a. Globale und lokale Variablen

Der folgende Code-Abschnitt deklariert zu Beginn die Variable abgebrochen als öffentlich (Public), damit sie im ganzen Projekt, das heisst sowohl im Modul Dialogblatt als auch im Modul Eingabeformular, verwendet werden kann. Ausgabezeile und GV sind hingegen Private-Variablen, weil sie je nur in einem einzigen Modul vorkommen.

>     ' --- Public für alle Module sichtbar
>     Public abgebrochen As Boolean   ' True, falls “Abbrechen”

>     ' --- Private nur für das Verarbeitungsmodul sichtbar
>     Private Ausgabezeile As Integer
>     Private GV As Currency          ' Konto Gewinnverteilung

Eine Variable, die nur in jenem Modul oder in jener Prozedur sichtbar ist, in der sie vereinbart worden ist, heisst lokal. Der Programmierer darf zum Beispiel eine private Variable nur in jenem Modul verwenden, in dem er sie eingeführt hat. Wenn er hingegen eine Variable als Public vereinbart, dann darf er sie auch ausserhalb des deklarierenden Moduls, das heisst im ganzen Projekt, ansprechen. Variablen, die auch ausserhalb des deklarierenden Unterprogramms oder Moduls gelten, heissen global.

Einfachprogramme enthalten allerdings die Schlüsselwörter Public und Private nur selten. Am häufigsten ist das Schlüsselwort Dim. Es dient der Vereinbarung einer Variablen innerhalb einer einzigen Prozedur. Man sagt auch, der Gültigkeitsbereich einer Dim-Variablen beschränke sich auf die Prozedur. Private deklariert hingegen Variablen, die für alle Prozeduren eines Moduls gelten; solche Variablen sind also global innerhalb eines Moduls. Public macht sogar eine Vereinbarung für alle Module eines Projekts - zum Beispiel aller Module des Projekts “Gewinnverteilung” - sichtbar. Solche Variablen sind innerhalb eines Projekts global.

##### b. Ereignisprozeduren

>     Sub Start_Click()
>       ' --- Dialogblatt und Eingabeformular initialisieren
>       GV = 0
>       abgebrochen = False
>       ' Ausgabebereich des Dialogblatts löschen
>       Dialogblatt.Range("A4:F11").ClearContents
>       ' Eingabeformular die Kontrolle übergeben
>       Eingabeformular.Show          ' laden und anzeigen
>       ' --- Gefülltes Eingabeformular verarbeiten
>       If abgebrochen = False Then
>         Buchungssätze
>         Unload Eingabeformular      ' aus Speicher entfernen
>       End If
>     End Sub

Die Ereignisprozedur Start_Click() lädt mit dem Befehl Eingabeformular.Show das Eingabeformular in den Internspeicher und zeigt es auf dem Bildschirm. Die Zeile Unload Eingabeformular entfernt das Formular erst, nachdem der Benutzer die Dateneingabe regulär abgeschlossen hat oder die Schaltfläche ‘Abbrechen’ geklickt hat. Das Programm erkennt am Wert True der Public-Variable abgebrochen, dass der Benutzer die Eingabe abgebrochen hat. Anders als Unload Eingabeformular löscht Eingabeformular.Hide das Eingabeformular nicht aus dem Internspeicher, sondern zeigt es nur bis zum Befehl Eingabeformular.Show nicht mehr an.

Der nächste Programmausschnitt enthält die Ereignisprozeduren der beiden Schaltflächen ‘Abbrechen’ und ‘Verbuchen’. Verbuchen_Click() prüft nur die Gültigkeit der Eingabedaten, die Kernprozedur Buchungssätze wird aus Start_Click() aufgerufen.

>     'Modul Eingabeformular
>     '---------------------
>     Private Sub Abbrechen_Click()
>       abgebrochen = True
>       Unload Eingabeformular
>     End Sub

>     Private Sub Verbuchen_Click()
>       'Eingabeformular nach Klick auf "Verbuchen" prüfen
>       'Aufwand, etc. sind Textfelder des Eingabeformulars
>       'Aufwand="" bedeutet dasselbe wie Aufwand.Value=""
>       If Aufwand = "" Or _
>         Ertrag = "" Or _
>         Aktienkapital = "" Or _
>         Reserve = "" Or _
>         TantièmeInProzent = ""
>       Then
>         MsgBox "Keine Leereingaben möglich"
>       ElseIf Not (IsNumeric(Aufwand) And _
>         IsNumeric(Ertrag) And _
>         IsNumeric(Aktienkapital) And _
>         IsNumeric(Reserve) And _
>         IsNumeric(TantièmeInProzent))
>       Then
>         MsgBox "Nur nummerische Eingaben möglich"
>       Else
>         Eingabeformular.Hide     'vorübergehend ausblenden
>       End If
>     End Sub

In einem grösseren Projekt wie Gewinnverteilung helfen der Projektexplorer und der Objektkatalog, die Übersicht zu bewahren.

Übung Gewinnverteilung