BI Generatoren

Erstellt: 22.04.2020, Änderung:
Hinweis auf Verbleib von bestehenden Werten bei Neuberechnung eingefügt.
Mehr ansehen

Für die Bereitstellung der Daten für das Business Intelligence Modul setzen wir einen Datenspeicher gemäss dem Datawarehouse Konzept ein, z.T. auch "OLAP Cube" genannt. Je nach Selektion der Dimensionen wird dann sinngemäss ein Schnitt aus einem Würfel geschnitten.

Im Wesentlichen besteht das Datawarehouse aus einer grossen Datentabelle (Cube) mit vorberechneten Datenwerten. Dadurch wird ein effizienter, Businesslogik unabhängiger Zugriff auf die BI Daten und somit eine performante Anzeige auch mit grossen Datenmengen ermöglicht.

Die Berechnung erfolgt zeitlich unabhängig und mit voller Businesslogik Unterstützung via regelmässiger geplanter Aufgaben. So kann die Berechnung bei Bedarf in einzelnen Paketen (z.B. einzelne Monate) in eigenen Prozessen geschehen oder sogar parallelisiert werden..

Die Berechnungslogik wird in "Generatoren" genannten Python-Scripts definiert. Diese sind auf den Kennzahlen hinterlegt. Um den Code eines Generators einzusehen, klicken Sie auf den Button mit den drei Punkten beim Feld Generator auf der Kennzahl:

Der Generator muss für die Kennzahlen, auf denen er hinterlegt ist, eine Berechnung enthalten. Der interne Name der Kennzahl muss also mit den vom Generator zurückgelieferten Werten übereinstimmen.

Generatoren erweitern / erstellen

Generatoren können auch erweitert bzw. neue Generatoren geschrieben werden. Dafür erzeugen Sie im Ordner Einstellungen > Scripts einen neuen Scripteintrag und verfassen den Generator-Code als Python Script.

Die Bezeichnung des Scripteintrags ist der Modulname. Zusammen mit dem Klassen-Namen des Generators bildet er die Generator-ID. Diese können Sie bei den BI Kennzahlen, die durch den Generator berechnet werden, als Generator angeben.

 

Modulnamen müssen eindeutig sein. Sie "überschreiben" also nicht einen bestehenden Generator, indem Sie ein Modul gleichen Namens verfassen, sondern indem Sie einen neuen Generator erstellen und auf den entsprechenden Kennzahlen hinterlegen.

Die Deklaration des Generators ist wie folgt:

class <Generatorname>(object):

Auf das Generator-Objekt kann im Script jederzeit über self zugegriffen werden. Innerhalb des Generators stehen folgende Methoden zur Verfügung:

Methode Beschreibung
get_dimensions(self) Mit dieser Methode wird angegeben, für welche Dimensionen der Generator Werte berechnet:

def get_dimensions(self):
    return ['Projekt', 'Projektbearbeiter']

In den Kennzahlen müssen genauso viele Dimensionen angegeben werden, wie hier geliefert werden, und zwar in der angegebenen Reihenfolge:

Möchte man also zum Beispiel Werte sowohl für Bearbeiter als Projektleiter als auch für Bearbeiter als Hauptbearbeiter anzeigen, muss die Dimension Projektbearbeiter zweimal angegeben werden:

def get_dimensions(self):
    return ['Projekt', 'Projektbearbeiter', 'Projektbearbeiter']

Und auf der Kennzahl:

get_measures(self) Mit dieser Methode wird angegeben, welche Kennzahlen damit berechnet werden. Die Rückgabewerte müssen den internen Namen auf den Kennzahlen entsprechen.

def get_measures(self):
    return ['OffersQuantity']

Auf allen Kennzahlen, die hier zurückgeliefert werden, kann der Generator dann hinterlegt werden.

initialize(self, startdate, enddate) Als erstes wird diese Methode durchlaufen. Die Variablen startdate und enddate enthalten das Datumsintervall der gesamten berechneten Periode.

Hier kann man die Listen der verwendeten Objekte performanceoptimiert preloaden. So hat man alle relevanten Daten der gesamten Periode. In der Methode generate() werden die Daten dann pro Monat berechnet.

generate(self, startdate, enddate) Die generate-Methode wird so viel Mal durchlaufen, wie es Monate in der berechneten Periode hat.

Die Variablen startdate und enddate enthalten immer den ersten und den letzten Tag des Monats.

Die im initialize() vorgeladenen Daten können hier nun pro Monat gefiltert und berechnet werden.

Rückgabewert

Als Rückgabewert wird ein Tuple aus Dimensionen und ein Tuple aus Measures (Kennzahlen) zurückgeliefert, in genau der oben deklarierten Reihenfolge.

Der Rückgabewert wird nicht wie sonst in Python mit return() zurückgegeben, sondern mit yield():

yield((project, project.projektleiter), (OffersQuantity,))

Die Verwendung von yield() hat zur Folge, dass es nicht nur einen Rückgabewert gibt (und alle Daten mühsam in einem Array zusammengefasst und dann zurückgegeben werden müssen), sondern jede Zeile zurückgegeben werden kann, bis der gesamte Code abgelaufen ist. So können zum Beispiel innerhalb einer Projekt-Schleife die berechneten Daten pro Projekt etc. laufend einfach "abgeliefert" werden (siehe Beispielcode weiter unten).

Währungen

Falls man in Vertec mit mehr als einer Währung arbeitet, muss man dies bei der Berechnung beachten. Dafür kann pro Rückgabezeile optional eine Währung mitgegeben werden (Beispiel aus dem mitgelieferten InvoiceGenerator):

yield ((project), turnover_tuple, project.waehrung)

Vertec kümmert sich dann selbst um die korrekte Umrechnung in die Leitwährung. Angezeigt werden die Werte immer in Leitwährung.

finalize(self) Am Schluss wird noch die finalize-Methode durchlaufen. Darin können zum Beispiel nicht mehr benötigte Objekte aus dem Memory wieder entfernt werden.

 

Beispielcode

# Generator for data related to project offers.
#
# 12.03.2020, Vertec AG, sth: Version 100: created

VERSION = 100

class OffersGenerator(object):
    """
    Calculate all offers 
    """        
    def get_dimensions(self):
        return ['Projekt', 'Projektbearbeiter']
        
    def get_measures(self):
        return ['OffersQuantity']
        
    def initialize(self, startdate, enddate):   
        """ 
        Preload all projects that could have offers in given date range
        """         
        # collect all corresponding offers
        offers = vtcapp.getwithsql("Offerte", "datum<=%s AND datum>=%s" % (vtcapp.sqldateliteral(enddate), vtcapp.sqldateliteral(startdate)), "") 
        if offers:
            # collect all corresponding projects        
            self.projects = vtcapp.getwithsql("Projekt", "bold_id IN (SELECT projekt from offerte where bold_id in (%s))" % offers.idstring(), "")
        else:
            self.projects = []
      
    def generate(self, startdate, enddate):
        """
        Calculate measures for given period. Uses the stored projects from the initialization step.
        """
        for project in self.projects:
            # calculate quantity for current month
            OffersQuantity = project.evalocl("offerten->select((datum<=%s) and (datum>=%s))->size" % (vtcapp.ocldate(enddate), vtcapp.ocldate(startdate)))
            
            yield((project, project.projektleiter), (OffersQuantity,))

    def finalize(self):
        pass

 

Standard BI Generatoren

Vertec liefert standardmässig folgende Generatoren mit:

Generator-Name Verwendete Daten Berechnete Kennzahlen
ServicesGenerator.ServicesGenerator Leistungssummen (globaler groupLeistungen Operator) gruppiert nach Projekt, Phase, Bearbeiter und Tätigkeit.
  • Honorar extern
  • Honorar intern
  • Aufwand extern
  • Aufwand intern
  • Kosten
  • Honorar extern verrechnet
  • Honorar extern offen
  • Honorar extern abgeschrieben
  • Deckungsbeitrag (DB)
ProjectGenerator.ProjectGenerator Leistungssummen (globaler groupLeistungen Operator) gruppiert nach Projekt und Rechnung. Verwendet nur die produktiven Projekte.
  • Bestand Vorschüsse
  • Angefangene Arbeiten
UsersGenerator.UsersGenerator Projektbearbeiter, die vor dem Enddatum eingetreten und noch nicht ausgetreten sind bzw. deren Austrittsdatum nach dem Startdatum liegt.
  • Vollzeitstellen
  • Sollzeit
  • Präsenzzeit
  • Überzeitsaldo
  • Feriensaldo
  • Feriensaldo abgegrenzt
InvoicesGenerator.InvoicesGenerator Rechnungen, welche verrechnet sind und deren Valutadatum innerhalb des berechneten Datumsbereichs liegt.
  • Umsatz Leistungen
  • Umsatz Spesen
  • Umsatz Auslagen
PhasesGenerator.PhasesGenerator Projektphasen der obersten Ebene, welche ein Erteiltdatum haben und deren Erteiltdatum vor dem Enddatum liegt, und die nicht oder erst nach dem Startdatum abgeschlossen wurden:

  • Auftragsbestand Honorar
  • Auftragseingang Honorar
  • Aufwand Ist
  • Aufwand Budget Rest
  • Aufwand Budget Total

 

Daten berechnen

Die Daten werden regelmässig über eine (oder mehrere) geplante Aufgabe in der Nacht berechnet. Die geplanten Aufgaben finden Sie im Ordner Einstellungen > Geplante Aufgaben.

Bei diesem Vorgang werden alle bei den aktiven Kennzahlen hinterlegten Generatoren angestossen und die Werte für das Datumsintervall von Januar des vorletzten Jahres bis Ende des aktuellen Monats vorberechnet.

Auf der Aufgabe ist im Status sichtbar, ob die Berechnung erfolgreich war oder fehlgeschlagen ist. Im Ausgabefenster wird die Rückmeldung der Berechnung angezeigt.

Eine Vertec App muss dafür nicht laufen, nur ein laufender CloudServer ist Voraussetzung. Für die Batch-Berechnung wird auf der geplanten Aufgabe ein Benutzer hinterlegt, welcher für die Berechnung verwendet wird. Dieser Benutzer muss über Administratoren-Rechte verfügen, um die Berechnungen durchführen zu können.

Variante Cloud Abo

Im Cloud Abo kann die Zeit auf der Oberfläche nicht verändert werden. Die Berechnung erfolgt immer über Nacht. Welches der genaue Zeitpunkt ist, wird unter Nächste Ausführung angezeigt:

Berechnung manuell anstossen

Eine BI-Berechnung kann auch manuell angestossen werden. Hier gibt es zwei Varianten:

  • Geplante Aufgabe jetzt ausführen: Dafür wird im Kontextmenü der geplanten Aufgabe der Menüpunkt Jetzt ausführen geklickt:

Dadurch wird die Berechnung aller Generatoren auf allen aktiven Kennzahlen angestossen.

Achtung: Die Berechnung wird direkt in der laufenden Vertec App gestartet und nicht wie bei der zeitgesteuerten Ausführung in einem separaten Task Runner Prozess. Das sollte nicht im laufenden Betrieb gemacht werden, da die Berechnung sehr lange dauern und Vertec dadurch blockiert sein kann.

  • Anstossen der Berechnung eines Generators: Auf den einzelnen Kennzahlen kann die Berechnung manuell angestossen werden, indem im Kontextmenü Kennzahlen neu berechnen gewählt wird:

Dabei wird der auf der Kennzahl hinterlege Generator angestossen und die entsprechenden Kennzahlen neu berechnet. Es kann jeweils das Datumsintervall noch gesetzt werden:

Am Ende kommt eine Meldung, welche Kennzahlen berechnet wurden.

Einmal berechnete Werte für einen Zeitraum und die betroffenen Kennzahlen bleiben im System vorhanden.

Bei einer Neuberechnung der Daten werden bereits vorhandene Werte nur für diesen Zeitraum und die betroffenen Kennzahlen gelöscht und dann die neuen Werte eingefügt. Alle anderen Werte bleiben bestehen.

Python Methoden zur Berechnung der BI Daten

Es gibt zwei Python Methoden für die Berechnung der BI Daten.

vtcapp.standardprocessbi() Löst die Berechnung aller Generatoren auf allen aktiven Kennzahlen aus.

Benötigt Administrator-Rechte.

Entspricht der Durchführung der standardmässig mitgelieferten geplanten Aufgabe, siehe oben.

vtcapp.processbi(von: String, bis: String, generator: String) Löst die Berechnung des als Parameter mitgelieferten Generators aus.

Benötigt Administrator-Rechte.

Von- und Bis-Datum werden als String im Format "Jahr-Monat" angegeben.

Der Generator muss gleich angegeben werden wie bei den Kennzahlen, also "<Modulname>.<Generatorname>".

vtcapp.processbi("2018-01", "2020-02", "OffersGenerator.OffersGenerator")

Entspricht der Berechnung der BI Daten auf einer Kennzahl, siehe oben.

Diese Methode kann z.B auch über eine geplante Aufgabe automatisiert werden.