Artikelverwaltung, Teil 2

André Minhorst, Duisburg

Im ersten Teil dieser Beitragsreihe haben Sie das Datenmodell und die wesentlichen Formulare der Artikelverwaltung kennen gelernt. Nun beschäftigen Sie sich mit den Inventuren: Welche Faktoren sind dafür wichtig Wie werden bereits in einer Inventur berücksichtigte Daten bei folgenden Inventuren ausgeschlossen Außerdem erfahren Sie in dieser Folge, wie Sie Berichte für die Ausgabe von Artikel- und Inventurdaten erstellen.

Hinweis

Die Musterlösung zu diesem Beitrag heißt Artikelverwaltung00.mdb und funktioniert mit Access 2000 und höher. Sie finden die Datenbank auf der Heft-CD oder im Internet unter http://www.access-im-unternehmen.de (Shortlink 280). Der erste Teil dieses Beitrags steht an gleicher Stelle unter dem Shortlink 273 bereit.

Eine Inventur ist die Aufnahme des Bestands aller Vermögenswerte eines Unternehmens, also auch der vorhandenen Artikel. Die in die Artikelverwaltung integrierte Inventurfunktion ermöglicht dies ausschließlich für die Artikel; die Aufnahme aller für eine Inventur notwendigen Informationen würde den Umfang des Beitrags leider sprengen. Diese Inventurfunktion berücksichtigt lediglich die in der Datenbank gespeicherten Artikel. Die Menge der vorhandenen Artikel sowie deren Maßeinheiten sollten regelmäßig zum Bilanzstichtag bekannt sein, um eine ordnungsgemäße Buchhaltung zu ermöglichen. Der Artikelbestand muss allerdings nicht genau an diesem Tag gezählt werden.

Inventurarten

Bild 1: Aufruf der Inventur

Es gibt mehrere Varianten von Inventuren, unter anderem die folgenden:

  • Stichtagsinventur: Findet innerhalb von zehn Tagen vor und zehn Tagen nach dem Abschluss-Stichtag statt. Das Ergebnis wird auf den Abschluss-Stichtag hochgerechnet.
  • Verlegte Inventur: Erfolgt zwischen drei Monaten vor und zwei Monaten nach dem Abschluss-Stichtag. Die Zählung der unterschiedlichen Artikel muss nicht an einem Tag erfolgen. Die Werte für jeden einzelnen Artikel werden auf den Abschluss-Stichtag hochgerechnet.
  • Permanente Inventur: Die Inventur erfolgt fast ausschließlich über die Bewertung der Ein- und Ausgänge eines Artikels. Der Soll- und der Ist-Zustand müssen einmal im Jahr abgeglichen werden.
  • Die Anwendung unterstützt alle genannten Inventurarten. Der einzige Unterschied zwischen den Arten ist der Zeitpunkt, an dem Soll- und Istwert des Bestands eines Artikels ermittelt werden müssen. Mit der Artikelverwaltung können Sie den Zeitpunkt der Zählung für jeden einzelnen Artikel festlegen.

    Wie arbeitet die Inventurfunktion

    Die Inventurfunktion kann für jeden Artikel einzeln aufgerufen werden. Der Aufruf erfolgt über die Schaltfläche Inventur starten der Detailansicht eines Artikels im Formular frmArtikel (siehe Bild 1).

    Die dadurch ausgelöste Ereignisprozedur öffnet das Formular frmInventur für den aktuell im Artikelformular angezeigten Artikel (siehe Bild 2).

    Bild 2: Eingabe des gezählten Bestands

    Dieses Formular zeigt folgende Informationen an:

  • Datum der letzten Inventur
  • Bestand bei der letzten Inventur
  • Datum der aktuellen Inventur
  • Berechneter Bestand (aktuelle Inventur)
  • Tatsächlicher Bestand (aktuelle Inventur)
  • Differenz zwischen tatsächlichem und berechnetem Bestand
  • Die mit einem roten Rahmen versehenen Informationen kann der Benutzer selbst ändern. Das Datum wird automatisch mit dem aktuellen Datum vorgelegt, es kann aber nachträglich geändert werden.

    Bei der Programmierung des Formulars frmInventur und der enthaltenen Funktionen sind einige Punkte zu beachten, die im nachfolgenden Abschnitt geklärt werden. Anschließend finden Sie eine Beschreibung der Funktion selbst.

    Wichtige Voraussetzungen

    Die Inventurfunktion startet mit dem Mausklick auf die Schaltfläche Inventur starten des Artikelformulars. Das Formular frmInventur zur Eingabe der Inventurdaten bezieht seine Daten über diverse Zugriffe auf die in der Datenbank enthaltenen Tabellen.

    So durchsucht das Formular die Tabelle tblInventuren, ob es bereits eine Inventur zu dem zu untersuchenden Artikel gibt, und liest gegebenenfalls das Datum der Inventur und den Bestand in die entsprechenden Felder des Formulars ein.

    Ist noch kein Inventurdatensatz vorhanden und dementsprechend noch keine Zählung des Artikels erfolgt, verwendet das Formular Standardwerte: als Datum den 1.1.1900 und als Bestand den Wert 0.

    Der im Feld Berechneter Bestand angezeigte Wert ist die Anzahl des Artikels, die sich aus dem Stand bei der letzten Inventur und den seitdem erfolgten Zu- und Abgängen berechnet.

    Dabei spielt natürlich das Datum der aktuellen Inventur eine wichtige Rolle: Beim öffnen des Formulars zeigt dieses das aktuelle Datum und den Bestand zu diesem Datum an. Wenn der Benutzer das Datum verändert, wird auch der berechnete Bestand angepasst. Neben dem Inventurdatum muss der Benutzer auch die tatsächliche Anzahl des Artikels angeben. Erst dann wird die Differenz berechnet und die Inventurdaten können gespeichert werden.

    Private Sub Form_Current()
        Dim datLetzteInventur As Date
        Dim lngBestandLetzteInventur As Long
        Me!txtArtikel = Artikelbezeichnung(lngArtikelID)
        Call LetzteInventur(lngArtikelID, datLetzteInventur, lngBestandLetzteInventur)
        Me!txtDatumLetzteInventur = datLetzteInventur
        Me!txtBestandLetzteInventur = lngBestandLetzteInventur
        Me!txtDatumAktuelleInventur = Date
        Me!txtBestandAktuelleInventurBerechnet = lngBestandLetzteInventur + _        BestandsaenderungSumme(lngArtikelID, Date)
    End Sub

    Quellcode 1

    Private Function Artikelbezeichnung(lngArtikelID As Long) As String
        Dim db As DAO.Database
        Dim rstArtikel As DAO.Recordset
        Set db = CurrentDb
        Set rstArtikel = db.OpenRecordset("SELECT Bezeichnung FROM tblArtikel " _        & "WHERE ArtikelID = " & lngArtikelID, dbOpenDynaset)
        Artikelbezeichnung = rstArtikel!Bezeichnung
        Set db = Nothing
    End Function

    Quellcode 2

    Technische Umsetzung

    Die erste Prozedur, die bei der Verwendung des Formulars frmInventuren zum Zuge kommt, ist die Ereignisprozedur, die beim öffnen des Formulars ausgelöst wird. Sie weist der modulweit deklarierten Variablen lngArtikel die per öffnungsargument von der aufrufenden Instanz übergebene Artikelnummer zu.

    Private Sub Form_Open(Cancel As Integer)
        lngArtikelID = Me.OpenArgs
    End Sub

    Die Ermittlung der im Formular angezeigten Werte erfolgt in der Ereignisprozedur, die durch das Ereignis Beim Anzeigen ausgelöst wird (s. Quellcode 1). Die Prozedur ermittelt zunächst anhand des Werts des Feldes ArtikelID die Artikelbezeichnung und trägt diese in das Textfeld txtArtikel ein. Dazu verwendet sie die Prozedur aus Quellcode 2. Diese Prozedur liefert die Artikelbezeichnung für die als Parameter übergebene Artikel-ID. Dabei instanziert sie ein Database-Objekt und ein Recordset-Objekt und ermittelt über eine entsprechende Abfrage eine Datensatzgruppe mit dem gesuchten Artikeldatensatz.

    Performance statt Dlookup

    Statt dieser Funktion hätte man auch einen entsprechenden Aufruf der Dlookup-Funktion verwenden können (in einer Zeile):

    Me!txtArtikel = DLookup("Bezeichnung", "tblArtikel", "ArtikelID = " & lngArtikelID)

    Das wäre zwar wesentlich platzsparender und damit auch übersichtlicher gewesen, allerdings ist die Performance der Domänenfunktionen relativ schlecht. Ein konkreter Test mit je 1000 Aufrufen jeder Funktion in einer Schleife brachte ein eindeutiges Ergebnis: über mehrere Läufe hinweg war die DAO-Variante circa 50-100% schneller als die Dlookup-Funktion.

    Private Sub LetzteInventur(lngArtikelID As Long, datLetzteInventur As Date, _    lngBestandLetzteInventur As Long)
        Dim db As DAO.Database
        Dim rstInventuren As DAO.Recordset
        Dim rstBestandsaenderungen As DAO.Recordset
        Set db = CurrentDb
        Set rstInventuren = db.OpenRecordset("SELECT TOP 1 Inventurdatum, " _        & "Lagerbestand FROM tblInventuren WHERE ArtikelID = " & lngArtikelID _        & " ORDER BY Inventurdatum DESC", dbOpenDynaset)
        If Not rstInventuren.EOF Then
            datLetzteInventur = rstInventuren!Inventurdatum
            lngBestandLetzteInventur = rstInventuren!Lagerbestand
        Else
            Set rstBestandsaenderungen = db.OpenRecordset("SELECT Datum " _            & "FROM tblBestandsaenderungen WHERE ArtikelID = " & lngArtikelID _            & " ORDER BY Datum DESC", dbOpenDynaset)
            If Not rstBestandsaenderungen.EOF Then
                datLetzteInventur = rstBestandsaenderungen!Datum
            Else
                datLetzteInventur = "1.1.1900"
            End If
            lngBestandLetzteInventur = 0
            rstBestandsaenderungen.Close
        End If
        rstInventuren.Close
        Set rstInventuren = Nothing
        Set rstBestandsaenderungen = Nothing
    End Sub

    Quellcode 3

    Daten der letzten Inventur ermitteln

    In einer weiteren externen Routine ermittelt die Prozedur Form_Current das Datum der letzten Inventur und den Bestand bei der letzten Inventur.

    Da die beiden zu ermittelnden Werte aus der gleichen Tabelle stammen und gleichzeitig mit einer Routine ermittelt werden sollen, können nicht beide per Rückgabewert an die aufrufende Prozedur übermittelt werden.

    Die betroffene Routine heißt LetzteInventur und hat drei Parameter, von denen einer als Eingangs- und zwei als Ausgangsparameter verwendet werden. Die Ausgangsparameter werden bereits in der aufrufenden Prozedur Form_Current deklariert und als Variable übergeben (in einer Zeile):

    Call LetzteInventur(lngArtikelID, datLetzteInventur, lngBestandLetzteInventur)

    Die beiden letzten Parameter dieses Aufrufs werden in der Prozedur LetzteInventur mit den gewünschten Daten gefüllt (s. Quellcode 3).

    Um diese Daten zu ermitteln, greift die Prozedur auf zwei Tabellen zu. Zunächst sucht sie in der Tabelle tblInventuren nach der aktuellsten Inventur für diesen Artikel. Die dazu verwendete Abfrage ist nach dem Inventurdatum sortiert und gibt durch die Option TOP 1 nur den ersten Eintrag der Datensatzgruppe zurück. Ist dieser Datensatz vorhanden, liest die Prozedur das Inventurdatum und den Lagerbestand aus der Tabelle aus und schreibt sie in die entsprechenden Rückgabeparameter.

    Private Function BestandsaenderungSumme(lngArtikelID As Long, _    datAktuelleInventur As Date) As Long
        Dim db As DAO.Database
        Dim rstBestandsaenderungSumme As DAO.Recordset
        Set db = CurrentDb
        Set rstBestandsaenderungSumme = _        db.OpenRecordset("SELECT Sum(Anzahl * Vorzeichen) AS LagerbestandGesamt " _        & "FROM tblBestandsaenderungen WHERE ArtikelID = " & lngArtikelID _        & " AND Inventur = False AND Datum <= " _        & ISODatum(Me.txtDatumAktuelleInventur), dbOpenDynaset)
        BestandsaenderungSumme = Nz(rstBestandsaenderungSumme!LagerbestandGesamt, 0)
        rstBestandsaenderungSumme.Close
        Set rstBestandsaenderungSumme = Nothing
        Set db = Nothing
    End Function

    Quellcode 4

    Wenn die Datensatzgruppe leer ist, wurde noch keine Inventur für diesen Artikel durchgeführt. In dem Fall sind weitere Untersuchungen erforderlich, um halbwegs sinnvolle Werte zurückzugeben. Wenn noch keine Inventur stattgefunden hat, wäre der Stand vor der ersten Bestandsänderung der letzte bestätigte Stand – und der ist immer 0. Als Datum stellt die Prozedur in dem Fall das Datum der ersten Bestandsänderung ein. Wenn weder eine Bestandsänderung noch eine Inventur für einen Artikel stattgefunden hat, ist Fantasie gefragt: Als Datum wird dann der 1.1.1900 und als Bestand der Wert 0 zurückgegeben.

    Einstellen des Datums der aktuellen Inventur

    Als Datum für die aktuelle Inventur trägt die Prozedur Form_Current das aktuelle Datum ein.

    Bestandsänderung berechnen

    Fehlt noch die berechnete Bestandsänderung seit der letzten Inventur. Für deren Ermittlung ist wiederum eine Funktion zuständig. Diese heißt BestandsaenderungSumme und erwartet die Artikel-ID und das Datum der aktuellen Inventur, das auch in diesem Fall mit der Date-Funktion ermittelt wird (s. Quellcode 4).

    Diese Funktion berechnet mit der Sum-Funktion in einer Abfrage über die Datensätze der Tabelle tblBestandsaenderungen die Größe der änderung am Bestand des betroffenen Artikels.

    Dabei offenbart sich die Technik, mit der eine Bestandsveränderung als inventarisiert gekennzeichnet wird: Die Tabelle tblBestandsaenderungen enthält ein Feld namens Inventur, das nach der Berücksichtigung in einer Inventur den Wert True erhält.

    Sie haben das Ende des frei verfügbaren Textes erreicht. Möchten Sie ...

    TestzugangOder bist Du bereits Abonnent? Dann logge Dich gleich hier ein. Die Zugangsdaten findest Du entweder in der aktuellen Print-Ausgabe auf Seite U2 oder beim Online-Abo in der E-Mail, die Du als Abonnent regelmäßig erhältst:

    Schreibe einen Kommentar