diff --git a/dopt.DeltaBarth/DataObjects.cs b/dopt.DeltaBarth/DataObjects.cs
index ec8dc0c..a0f368e 100644
--- a/dopt.DeltaBarth/DataObjects.cs
+++ b/dopt.DeltaBarth/DataObjects.cs
@@ -7,44 +7,130 @@ using System.Collections.Immutable;
namespace dopt.DeltaBarth.DataObjects
{
+ ///
+ /// Eine verpackte Fehlermeldung, die vom API-Server zur Verfügung gestellt wurde.
+ ///
public record class ApiServerError
{
+ ///
+ /// Statuscode der HTTP-Anfrage
+ ///
public required int status_code { get; init; }
+ ///
+ /// Fehlerbezeichnung
+ ///
public required string message { get; init; }
+ ///
+ /// optional: spezifischer Code als Text, der vom Server ausgegeben wurde
+ ///
public string? code { get; init; }
+ ///
+ /// optional: spezifische Hinweise als Text, der vom Server ausgegeben wurde
+ ///
public string? hints { get; init; }
+ ///
+ /// optional: spezifischer Typus als Text, der vom Server ausgegeben wurde
+ ///
public string? type { get; init; }
+ ///
+ /// optional: spezifischer Titel als Text, der vom Server ausgegeben wurde
+ ///
public string? title { get; init; }
+ ///
+ /// optional: spezifischer ID (vermutlich zur Nachverfolgung) als Text, der vom Server ausgegeben wurde
+ ///
public string? traceId { get; init; }
}
+ ///
+ /// Status-Objekt: Gibt Aufschluss über Erfolg/Misserfolg einer Routine und beschreibt aufgetretene Fehler
+ /// mit zusätzlichen Informationen
+ ///
public record class Status
{
+ ///
+ /// bibliotheksinterner Fehlercode
+ ///
public required int code { get; init; }
+ ///
+ /// Fehlerbeschreibung oder Python-Exception-Name
+ ///
public required string description { get; init; }
+ ///
+ /// genauere Beschreibung oder Fehler-Inhalt
+ ///
public required string message { get; init; }
+ ///
+ /// optional: eventuell aufgetretener API-Server-Fehler
+ ///
public ApiServerError? apiServerError { get; init; }
}
+ ///
+ /// Nutzerdaten zur API-Interaktion
+ ///
public record class Credentials
{
+ ///
+ /// Nutzername
+ ///
public required string username { get; init; }
+ ///
+ /// Passwort
+ ///
public required string password { get; init; }
+ ///
+ /// Datenbank
+ ///
public required string database { get; init; }
+ ///
+ /// Mandant
+ ///
public required string mandant { get; init; }
}
+ ///
+ /// Einzelergebnis der Umsatzprognose, 1 Eintrag von potenziell mehreren
+ ///
public record class UmsatzPrognoseEinzelergebnis
{
+ ///
+ /// Jahr des Eintrags
+ ///
public required int jahr { get; init; }
+ ///
+ /// Monat des Eintrags
+ ///
public required int monat { get; init; }
+ ///
+ /// Prognosewert für den Umsatz
+ ///
public required decimal vorhersage { get; init; }
}
+ ///
+ /// Sammlung von unterschiedlichen Einzelergebnissen
+ ///
+ ///
public record class UmsatzPrognoseErgebnisse
{
+ ///
+ /// unveränderliche Sammlung von Einzelergebnissen in Form eines Array
+ ///
public required ImmutableArray daten { get; init; }
}
+ ///
+ /// Ausgabe der Prognose-Pipeline:
+ /// enthält das Ergebnis als auch einen dazugehörigen Status
+ ///
public record class UmsatzPrognoseAusgabe
{
+ ///
+ /// Sammlung von Prognosewerten
+ ///
+ ///
public required UmsatzPrognoseErgebnisse response { get; init; }
+ ///
+ /// Status über den Erfolg/Misserfolg der Routine
+ ///
+ ///
public required Status status { get; init; }
}
}
diff --git a/dopt.DeltaBarth/Plugin.cs b/dopt.DeltaBarth/Plugin.cs
index 13a87cb..2ff618a 100644
--- a/dopt.DeltaBarth/Plugin.cs
+++ b/dopt.DeltaBarth/Plugin.cs
@@ -4,32 +4,95 @@ using System.Text.Json;
namespace dopt.DeltaBarth
{
+ ///
+ /// Spiegelung der internen Fehlertypen innerhalb der Python-Bibliothek
+ ///
public enum StatusCodes
{
+ ///
+ /// erfolgreiche, fehlerfreie Durchführung der Routine
+ ///
[Description("Keine Fehler aufgetreten")]
Erfolg = 0,
+ ///
+ /// Bei der API-Abfrage wurde der Timeout getriggert.
+ ///
[Description("Bei der Verbindung zum API-Server kam es zum Timeout")]
VerbindungTimeout = 1,
+ ///
+ /// Bei der API-Abfrage ist ein unerwarteter Fehler aufgetreten, der unmittelbar die HTTP-Anfrage betrifft.
+ ///
[Description("Bei der Verbindung zum API-Server ist ein Fehler aufgetreten")]
VerbindungFehler = 2,
+ ///
+ /// Der ausgewählte Datensatz enthält nicht genügend Datenpunkte.
+ ///
[Description("Der bereitgestellte Datensatz enthält in Summe zu wenige Einzeleinträge")]
DatensatzZuWenigeDatenpunkte = 3,
+ ///
+ /// Der ausgewählte Datensatz enthält nach Aggregation pro Monat nicht genügend Datenpunkte.
+ ///
[Description("Der bereitgestellte Datensatz enthält nach Aggregation zu Monaten zu wenig Einträge")]
DatensatzZuWenigeMonatsdatenpunkte = 4,
- [Description("Die Prognosequalität des Modells erfüllt nicht ide Mindestanforderungen")]
+ ///
+ /// Die Prognosequalität des Modells ist nicht zufriedenstellend. Eine verlässliche Prognose ist nicht möglich.
+ ///
+ [Description("Die Prognosequalität des Modells erfüllt nicht die Mindestanforderungen")]
KeineVerlaesslichePrognose = 5,
+ ///
+ /// Es ist intern ein Fehler aufgetreten aufgetreten
+ ///
+ [Description("Interne Fehler, die während der Routine aufgetreten sind")]
+ InternerFehler = 100,
+ ///
+ /// Es ist ein Fehler beim Schreiben der programminternen Datenbank aufgetreten.
+ ///
+ [Description("Interne Fehler, die während der Datenbankinteraktion aufgetreten sind")]
+ InternerDbFehler = 150,
+ ///
+ /// Es ist ein Fehler auf dem API-Server aufgetreten.
+ /// Das dazugehörige Status-Objekt sollte diesen Fehler zur Verfügung stellen können.
+ ///
+ ///
+ ///
[Description("Vom API-Server wurde eine Fehlermeldung zurückgegeben")]
ApiServerFehler = 400,
}
+ ///
+ /// Eine Exception, die genutzt wird, um anzuzeigen, dass beim Parsen der Python-Objekte
+ /// ein Fehler aufgetreten ist.
+ ///
public class PythonParsingException : Exception
{
+ ///
+ /// Konstruktor ohne Inhalt
+ ///
public PythonParsingException() { }
+ ///
+ /// Konstruktor mit Nachricht
+ ///
+ ///
public PythonParsingException(string message) : base(message) { }
}
+ ///
+ /// Plugin-Klasse, mit der die Interaktion der zugrundeliegenden Python-Runtime erfolgt
+ ///
public class Plugin : SharpPython.BasePlugin
{
+ ///
+ /// Python-interne Zustandsverwaltung
+ ///
protected dynamic pyModManagement;
+ ///
+ /// Python-interne Routinen und Pipelines
+ ///
protected dynamic pyModPipeline;
+ ///
+ /// Konstruktor der Plugin-Klasse.
+ /// Kann mit beliebigem Pfad zu einer Python-Runtime initialisiert werden.
+ ///
+ /// Der Pfad zur Python-Runtime. Dieser muss zu dem Ordner zeigen,
+ /// in welchem die Runtime in Form eines Ordners mit dem Namen "python" abliegt.
public Plugin(string runtimePath) : base(runtimePath: runtimePath, verbose: false)
{
base.Initialise();
@@ -39,12 +102,30 @@ namespace dopt.DeltaBarth
pyModPipeline = Py.Import("delta_barth.pipelines");
}
}
+ ///
+ /// Initialisiert das Plugin mit allen relevanten Paramtern für die weitere Nutzung.
+ /// Diese Methode sollte nur einmal je Instanz genutzt werden.
+ ///
+ /// Pfad zu einem Ordner, in dem Programmdaten ohne Bedenken dauerhaft abgelegt werden können.
+ /// Basis-URL zum Zugriff auf die API. Dies muss eine vollständige URL sein inkl. der Route "/api".
+ /// Nutzername für die Datenbankanmeldung.
+ /// Passwort für die Datenbankanmeldung.
+ /// Name der Datenbank, bei der die Anmeldung erfolgen soll.
+ /// Mandant für die Datenbankanmeldung.
public void Startup(string datenPfad, string basisApiUrl, string nutzername, string passwort, string datenbank, string mandant)
{
AssertNotDisposed();
Setup(datenPfad, basisApiUrl);
SetzeNutzerdaten(nutzername, passwort, datenbank, mandant);
}
+ ///
+ /// Diese Methode erlaubt es, die relevanten Nutzerdaten zur Laufzeit des Plugins zu ändern.
+ /// Dies beinhaltet: Nutzername, Passwort, Datenbankname, Mandant
+ ///
+ /// Nutzername für die Datenbankanmeldung.
+ /// Passwort für die Datenbankanmeldung.
+ /// Name der Datenbank, bei der die Anmeldung erfolgen soll.
+ /// Mandant für die Datenbankanmeldung.
public void SetzeNutzerdaten(string nutzername, string passwort, string datenbank, string mandant)
{
AssertNotDisposed();
@@ -52,6 +133,17 @@ namespace dopt.DeltaBarth
pyModManagement.set_credentials(nutzername, passwort, datenbank, mandant);
}
}
+ ///
+ /// Ausführung der Umsatzprognose-Pipeline mit Dummy-Daten.
+ /// Es werden keine API-Abrufe durchgeführt und somit auch keine Live-Daten genutzt.
+ ///
+ /// optional: Firmen-ID, für die die Pipeline ausgeführt werden soll.
+ /// Wird der Parameter nicht zur Verfügung gestellt, werden alle Firmen bzw. Kunden abgerufen
+ /// optional: Start-Datum, ab dem die Daten für die Erstellung des Prognosemodells genutzt werden.
+ /// Daten, die weiter in der Vergangenheit liegen, werden nicht berücksichtigt.
+ /// Wird der Parameter nicht zur Verfügung gestellt, wird die gesamte Historie genutzt.
+ /// Umsatzprognose inkl. Status-Objekt zur Nachvollziehbarkeit etwaig aufgetretener Fehler.
+ ///
public DataObjects.UmsatzPrognoseAusgabe UmsatzprognoseDummy(int? firmaId, DateTime? analyseBeginn)
{
AssertNotDisposed();
@@ -63,6 +155,18 @@ namespace dopt.DeltaBarth
var parsed = JsonSerializer.Deserialize(pyJson) ?? throw new PythonParsingException("Could not correctly parse object from Python");
return parsed;
}
+ ///
+ /// Ausführung der Umsatzprognose-Pipeline mit Live-Daten.
+ /// Es werden API-Abrufe durchgeführt und somit auch Live-Daten genutzt.
+ /// Hierfür muss sichergestellt sein, dass der API-Server erreichbar und abrufbereit ist.
+ ///
+ /// optional: Firmen-ID, für die die Pipeline ausgeführt werden soll.
+ /// Wird der Parameter nicht zur Verfügung gestellt, werden alle Firmen bzw. Kunden abgerufen
+ /// optional: Start-Datum, ab dem die Daten für die Erstellung des Prognosemodells genutzt werden.
+ /// Daten, die weiter in der Vergangenheit liegen, werden nicht berücksichtigt.
+ /// Wird der Parameter nicht zur Verfügung gestellt, wird die gesamte Historie genutzt.
+ /// Umsatzprognose inkl. Status-Objekt zur Nachvollziehbarkeit etwaig aufgetretener Fehler.
+ ///
public DataObjects.UmsatzPrognoseAusgabe Umsatzprognose(int? firmaId, DateTime? analyseBeginn)
{
AssertNotDisposed();
@@ -74,6 +178,11 @@ namespace dopt.DeltaBarth
var parsed = JsonSerializer.Deserialize(pyJson) ?? throw new PythonParsingException("Could not correctly parse object from Python");
return parsed;
}
+ ///
+ /// Setup der Python-internen Umgebung
+ ///
+ /// Pfad zu einem Ordner, in dem Programmdaten ohne Bedenken dauerhaft abgelegt werden können.
+ /// Basis-URL zum Zugriff auf die API. Dies muss eine vollständige URL sein inkl. der Route "/api".
protected void Setup(string datenPfad, string basisApiUrl)
{
AssertNotDisposed();
@@ -82,6 +191,10 @@ namespace dopt.DeltaBarth
pyModManagement.setup(datenPfad, basisApiUrl);
}
}
+ ///
+ /// Hole die konfigurierte API-Basis-URL aus der Python-Umgebung
+ ///
+ /// konfigurierte Basis-URL
protected string GetBaseApiUrl()
{
AssertNotDisposed();
@@ -92,6 +205,10 @@ namespace dopt.DeltaBarth
}
return pyJson;
}
+ ///
+ /// Hole den konfigurierten Datenpfad zur Dateiverwaltung aus der Python-Umgebung
+ ///
+ /// konfigurierten Datenpfad
protected string GetDataPath()
{
AssertNotDisposed();
@@ -102,6 +219,11 @@ namespace dopt.DeltaBarth
}
return pyJson;
}
+ ///
+ /// Hole die konfigurierten Nutzerdaten zur API-Interaktion aus der Python-Umgebung
+ ///
+ /// konfigurierte Nutzerdaten
+ ///
protected DataObjects.Credentials GetCredentials()
{
AssertNotDisposed();
diff --git a/dopt.DeltaBarth/dopt.DeltaBarth.csproj b/dopt.DeltaBarth/dopt.DeltaBarth.csproj
index a520fe0..90063bd 100644
--- a/dopt.DeltaBarth/dopt.DeltaBarth.csproj
+++ b/dopt.DeltaBarth/dopt.DeltaBarth.csproj
@@ -7,6 +7,7 @@
x64
x64
0.3.3-dev1
+ True