Compare commits
11 Commits
v0.3.2
...
numpy_impo
| Author | SHA1 | Date | |
|---|---|---|---|
| 3af9c4fc6d | |||
| fd86abd872 | |||
| 725e323f98 | |||
| 6558d0818c | |||
| c1d4062391 | |||
| 80eea91542 | |||
| be4ab681a4 | |||
| c536db0ef6 | |||
| 01b5695d8d | |||
| 821d9d1ed5 | |||
| 95f958c29e |
13
build_runtime.ps1
Normal file
13
build_runtime.ps1
Normal file
@@ -0,0 +1,13 @@
|
||||
param(
|
||||
[switch]$Get = $false
|
||||
)
|
||||
|
||||
if ($Get) {
|
||||
pycage get -rt 20250409 3.11.12
|
||||
pycage venv upgrade-pip
|
||||
}
|
||||
|
||||
pycage venv add -i http://localhost:8001/simple/ delta-barth
|
||||
pycage compile -f -d
|
||||
pycage compile -o 1 -f
|
||||
pycage clean dist-info
|
||||
@@ -46,7 +46,7 @@ namespace dopt.DeltaBarth.Tests
|
||||
Assert.AreEqual(102, parsed.code);
|
||||
Assert.IsTrue(parsed.description.Contains("internal error occurred"));
|
||||
Assert.AreEqual("caused by test", parsed.message);
|
||||
Assert.IsNull(parsed.apiServerError);
|
||||
Assert.IsNull(parsed.api_server_error);
|
||||
PrettyPrint(parsed);
|
||||
plugin.Dispose();
|
||||
}
|
||||
@@ -151,7 +151,7 @@ namespace dopt.DeltaBarth.Tests
|
||||
Assert.AreEqual(0, parsed.status.code);
|
||||
Assert.AreEqual("Erfolg", parsed.status.description);
|
||||
Assert.AreEqual("", parsed.status.message);
|
||||
Assert.IsNull(parsed.status.apiServerError);
|
||||
Assert.IsNull(parsed.status.api_server_error);
|
||||
// check result
|
||||
for (int i = 0; i < parsed.response.daten.Length; i++)
|
||||
{
|
||||
|
||||
@@ -40,22 +40,22 @@ namespace dopt.DeltaBarth.Tests
|
||||
{
|
||||
private const string absPath = @"A:\Arbeitsaufgaben\Delta-Barth\cs-wrapper\dopt.DeltaBarth";
|
||||
public TPlugin() : base(absPath) { }
|
||||
public new DataObjects.Credentials GetCredentials()
|
||||
{
|
||||
return base.GetCredentials();
|
||||
}
|
||||
public new string GetBaseApiUrl()
|
||||
{
|
||||
return base.GetBaseApiUrl();
|
||||
}
|
||||
public new string GetDataPath()
|
||||
{
|
||||
return base.GetDataPath();
|
||||
}
|
||||
public new void Setup(string datenPfad, string basisApiUrl)
|
||||
{
|
||||
base.Setup(datenPfad, basisApiUrl);
|
||||
}
|
||||
//public new DataObjects.Credentials GetCredentials()
|
||||
//{
|
||||
// return base.GetCredentials();
|
||||
//}
|
||||
//public new string GetBaseApiUrl()
|
||||
//{
|
||||
// return base.GetBaseApiUrl();
|
||||
//}
|
||||
//public new string GetDataPath()
|
||||
//{
|
||||
// return base.GetDataPath();
|
||||
//}
|
||||
//public new void Setup(string datenPfad, string basisApiUrl)
|
||||
//{
|
||||
// base.Setup(datenPfad, basisApiUrl);
|
||||
//}
|
||||
}
|
||||
[TestClass]
|
||||
public sealed class PluginTest
|
||||
@@ -78,134 +78,201 @@ namespace dopt.DeltaBarth.Tests
|
||||
test.Dispose();
|
||||
}
|
||||
[TestMethod]
|
||||
public void Set_and_Obtain_Credentials_Test()
|
||||
public void DebugCall_Test()
|
||||
{
|
||||
var test = new TPlugin();
|
||||
string user = "user", password = "password", database = "DB1", mandant = "mandant1";
|
||||
test.SetzeNutzerdaten(user, password, database, mandant);
|
||||
var creds = test.GetCredentials();
|
||||
PrettyPrint(creds);
|
||||
Assert.AreEqual(user, creds.username);
|
||||
Assert.AreEqual(password, creds.password);
|
||||
Assert.AreEqual(database, creds.database);
|
||||
Assert.AreEqual(mandant, creds.mandant);
|
||||
test.Dispose();
|
||||
}
|
||||
[TestMethod]
|
||||
public void SetupSession_Test()
|
||||
{
|
||||
var test = new TPlugin();
|
||||
string apiUrlSet = "http://10.2.22.21:8080/api/";
|
||||
test.Setup(baseDataPath, apiUrlSet);
|
||||
// data path
|
||||
var dataPathGet = test.GetDataPath();
|
||||
Console.WriteLine($"Result for data path from Python session was: {dataPathGet}");
|
||||
bool pathElementsContained = dataPathGet.Contains("test_data_path");
|
||||
Assert.IsTrue(pathElementsContained);
|
||||
// API URL
|
||||
var apiUrlGet = test.GetBaseApiUrl();
|
||||
Console.WriteLine($"Result for API URL from Python session was: {apiUrlGet}");
|
||||
Assert.AreEqual(apiUrlSet, apiUrlGet);
|
||||
test.Dispose();
|
||||
}
|
||||
[TestMethod]
|
||||
public void Startup_Test()
|
||||
{
|
||||
var test = new TPlugin();
|
||||
string apiUrlSet = "http://10.2.22.21:8080/api/", user = "user", password = "password", database = "DB1", mandant = "mandant1";
|
||||
test.Startup(baseDataPath, apiUrlSet, user, password, database, mandant);
|
||||
var apiUrlGet = test.GetBaseApiUrl();
|
||||
var creds = test.GetCredentials();
|
||||
Console.WriteLine($"Result from Python session was: API-URL={apiUrlGet}, creds={creds}");
|
||||
PrettyPrint(creds);
|
||||
Assert.AreEqual(apiUrlSet, apiUrlGet);
|
||||
Assert.AreEqual(user, creds.username);
|
||||
Assert.AreEqual(password, creds.password);
|
||||
Assert.AreEqual(database, creds.database);
|
||||
Assert.AreEqual(mandant, creds.mandant);
|
||||
test.Dispose();
|
||||
}
|
||||
[TestMethod]
|
||||
public void UmsatzprognoseDummy_WithoutParams_Test()
|
||||
{
|
||||
var test = new TPlugin();
|
||||
string apiUrlSet = "http://10.2.22.21:8080/api/", user = "user", password = "password", database = "DB1", mandant = "mandant1";
|
||||
test.Startup(baseDataPath, apiUrlSet, user, password, database, mandant);
|
||||
var res = test.UmsatzprognoseDummy(null, null);
|
||||
PrettyPrint(res);
|
||||
test.Dispose();
|
||||
}
|
||||
[TestMethod]
|
||||
public void UmsatzprognoseDummy_WithCompanyIdWithoutDate_Test()
|
||||
{
|
||||
var test = new TPlugin();
|
||||
string apiUrlSet = "http://10.2.22.21:8080/api/", user = "user", password = "password", database = "DB1", mandant = "mandant1";
|
||||
test.Startup(baseDataPath, apiUrlSet, user, password, database, mandant);
|
||||
var comp_id = 1000;
|
||||
var res = test.UmsatzprognoseDummy(comp_id, null);
|
||||
PrettyPrint(res);
|
||||
test.Dispose();
|
||||
}
|
||||
[TestMethod]
|
||||
public void UmsatzprognoseDummy_WithoutCompanyIdWithDate_Test()
|
||||
{
|
||||
var test = new TPlugin();
|
||||
string apiUrlSet = "http://10.2.22.21:8080/api/", user = "user", password = "password", database = "DB1", mandant = "mandant1";
|
||||
test.Startup(baseDataPath, apiUrlSet, user, password, database, mandant);
|
||||
var date = new DateTime(2023, 1, 1, 12, 45, 30);
|
||||
var res = test.UmsatzprognoseDummy(null, date);
|
||||
PrettyPrint(res);
|
||||
test.Dispose();
|
||||
}
|
||||
[TestMethod]
|
||||
public void Umsatzprognose_NoConnectionNeeded_Test()
|
||||
{
|
||||
var test = new TPlugin();
|
||||
string apiUrlSet = config.apiUrl, user = config.username, password = config.password, database = config.database, mandant = config.mandant;
|
||||
test.Startup(baseDataPath, apiUrlSet, user, password, database, mandant);
|
||||
var date = new DateTime(2030, 1, 1, 12, 45, 30);
|
||||
var res = test.Umsatzprognose(null, date);
|
||||
PrettyPrint(res);
|
||||
test.Dispose();
|
||||
}
|
||||
[TestMethod]
|
||||
[TestCategory("ActiveAPI")]
|
||||
public void Umsatzprognose_WithCompanyIdWithoutDate_Test()
|
||||
{
|
||||
var test = new TPlugin();
|
||||
string apiUrlSet = config.apiUrl, user = config.username, password = config.password, database = config.database, mandant = config.mandant;
|
||||
test.Startup(baseDataPath, apiUrlSet, user, password, database, mandant);
|
||||
var comp_id = 1024;
|
||||
var res = test.Umsatzprognose(comp_id, null);
|
||||
Assert.AreEqual(4, res.status.code);
|
||||
PrettyPrint(res);
|
||||
test.Dispose();
|
||||
}
|
||||
[TestMethod]
|
||||
[TestCategory("ActiveAPI")]
|
||||
public void Umsatzprognose_WithoutCompanyIdWithInvalidDate_Test()
|
||||
{
|
||||
var test = new TPlugin();
|
||||
string apiUrlSet = config.apiUrl, user = config.username, password = config.password, database = config.database, mandant = config.mandant;
|
||||
test.Startup(baseDataPath, apiUrlSet, user, password, database, mandant);
|
||||
var date = new DateTime(2030, 1, 1, 12, 45, 30);
|
||||
var res = test.Umsatzprognose(null, date);
|
||||
Assert.AreEqual(3, res.status.code);
|
||||
PrettyPrint(res);
|
||||
test.Dispose();
|
||||
}
|
||||
[TestMethod]
|
||||
[TestCategory("ActiveAPI")]
|
||||
public void Umsatzprognose_WithoutCompanyIdWithValidDate_Test()
|
||||
{
|
||||
var test = new TPlugin();
|
||||
string apiUrlSet = config.apiUrl, user = config.username, password = config.password, database = config.database, mandant = config.mandant;
|
||||
test.Startup(baseDataPath, apiUrlSet, user, password, database, mandant);
|
||||
var date = new DateTime(2015, 1, 1, 12, 45, 30);
|
||||
var res = test.Umsatzprognose(null, date);
|
||||
Assert.AreEqual(4, res.status.code);
|
||||
PrettyPrint(res);
|
||||
test.DebugCall();
|
||||
test.Dispose();
|
||||
}
|
||||
//[TestMethod]
|
||||
//public void Set_and_Obtain_Credentials_Test()
|
||||
//{
|
||||
// var test = new TPlugin();
|
||||
// string user = "user", password = "password", database = "DB1", mandant = "mandant1";
|
||||
// test.SetzeNutzerdaten(user, password, database, mandant);
|
||||
// var creds = test.GetCredentials();
|
||||
// PrettyPrint(creds);
|
||||
// Assert.AreEqual(user, creds.username);
|
||||
// Assert.AreEqual(password, creds.password);
|
||||
// Assert.AreEqual(database, creds.database);
|
||||
// Assert.AreEqual(mandant, creds.mandant);
|
||||
// test.Dispose();
|
||||
//}
|
||||
//[TestMethod]
|
||||
//public void SetupSession_Test()
|
||||
//{
|
||||
// var test = new TPlugin();
|
||||
// string apiUrlSet = "http://10.2.22.21:8080/api/";
|
||||
// test.Setup(baseDataPath, apiUrlSet);
|
||||
// // data path
|
||||
// var dataPathGet = test.GetDataPath();
|
||||
// Console.WriteLine($"Result for data path from Python session was: {dataPathGet}");
|
||||
// bool pathElementsContained = dataPathGet.Contains("test_data_path");
|
||||
// Assert.IsTrue(pathElementsContained);
|
||||
// // API URL
|
||||
// var apiUrlGet = test.GetBaseApiUrl();
|
||||
// Console.WriteLine($"Result for API URL from Python session was: {apiUrlGet}");
|
||||
// Assert.AreEqual(apiUrlSet, apiUrlGet);
|
||||
// test.Dispose();
|
||||
//}
|
||||
//[TestMethod]
|
||||
//public void Startup_Test()
|
||||
//{
|
||||
// var test = new TPlugin();
|
||||
// string apiUrlSet = "http://10.2.22.21:8080/api/", user = "user", password = "password", database = "DB1", mandant = "mandant1";
|
||||
// test.Startup(baseDataPath, apiUrlSet, user, password, database, mandant);
|
||||
// var apiUrlGet = test.GetBaseApiUrl();
|
||||
// var creds = test.GetCredentials();
|
||||
// Console.WriteLine($"Result from Python session was: API-URL={apiUrlGet}, creds={creds}");
|
||||
// PrettyPrint(creds);
|
||||
// Assert.AreEqual(apiUrlSet, apiUrlGet);
|
||||
// Assert.AreEqual(user, creds.username);
|
||||
// Assert.AreEqual(password, creds.password);
|
||||
// Assert.AreEqual(database, creds.database);
|
||||
// Assert.AreEqual(mandant, creds.mandant);
|
||||
// test.Dispose();
|
||||
//}
|
||||
//[TestMethod]
|
||||
//public void UmsatzprognoseDummy_WithoutParams_Test()
|
||||
//{
|
||||
// var test = new TPlugin();
|
||||
// string apiUrlSet = "http://10.2.22.21:8080/api/", user = "user", password = "password", database = "DB1", mandant = "mandant1";
|
||||
// test.Startup(baseDataPath, apiUrlSet, user, password, database, mandant);
|
||||
// var res = test.UmsatzprognoseDummy(null, null);
|
||||
// PrettyPrint(res);
|
||||
// Assert.AreEqual((int)StatusCodes.Erfolg, res.status.code);
|
||||
// test.Dispose();
|
||||
//}
|
||||
//[TestMethod]
|
||||
//public void UmsatzprognoseDummy_WithCompanyIdWithoutDate_Test()
|
||||
//{
|
||||
// var test = new TPlugin();
|
||||
// string apiUrlSet = "http://10.2.22.21:8080/api/", user = "user", password = "password", database = "DB1", mandant = "mandant1";
|
||||
// test.Startup(baseDataPath, apiUrlSet, user, password, database, mandant);
|
||||
// var comp_id = 1000;
|
||||
// var res = test.UmsatzprognoseDummy(comp_id, null);
|
||||
// PrettyPrint(res);
|
||||
// Assert.AreEqual((int)StatusCodes.Erfolg, res.status.code);
|
||||
// test.Dispose();
|
||||
//}
|
||||
//[TestMethod]
|
||||
//public void UmsatzprognoseDummy_WithoutCompanyIdWithDate_Test()
|
||||
//{
|
||||
// var test = new TPlugin();
|
||||
// string apiUrlSet = "http://10.2.22.21:8080/api/", user = "user", password = "password", database = "DB1", mandant = "mandant1";
|
||||
// test.Startup(baseDataPath, apiUrlSet, user, password, database, mandant);
|
||||
// var date = new DateTime(2023, 1, 1, 12, 45, 30);
|
||||
// var res = test.UmsatzprognoseDummy(null, date);
|
||||
// PrettyPrint(res);
|
||||
// Assert.AreEqual((int)StatusCodes.Erfolg, res.status.code);
|
||||
// test.Dispose();
|
||||
//}
|
||||
//[TestMethod]
|
||||
//public void Umsatzprognose_NoConnectionNeeded_Test()
|
||||
//{
|
||||
// var test = new TPlugin();
|
||||
// string apiUrlSet = config.apiUrl, user = config.username, password = config.password, database = config.database, mandant = config.mandant;
|
||||
// test.Startup(baseDataPath, apiUrlSet, user, password, database, mandant);
|
||||
// var date = new DateTime(2030, 1, 1, 12, 45, 30);
|
||||
// var res = test.Umsatzprognose(null, date);
|
||||
// PrettyPrint(res);
|
||||
// test.Dispose();
|
||||
//}
|
||||
//[TestMethod]
|
||||
//[TestCategory("ActiveAPI")]
|
||||
//public void Umsatzprognose_WithCompanyIdWithDate_Test()
|
||||
//{
|
||||
// var test = new TPlugin();
|
||||
// string apiUrlSet = config.apiUrl, user = config.username, password = config.password, database = config.database, mandant = config.mandant;
|
||||
// test.Startup(baseDataPath, apiUrlSet, user, password, database, mandant);
|
||||
// var date = new DateTime(2023, 8, 15, 12, 45, 30);
|
||||
// List<int> comp_id = new List<int> { 1027, 5661, 1024 };
|
||||
// var res = test.Umsatzprognose(comp_id, date);
|
||||
// PrettyPrint(res);
|
||||
// Assert.AreEqual(4, res.status.code);
|
||||
// Assert.AreEqual((int)StatusCodes.DatensatzZuWenigeMonatsdatenpunkte, res.status.code);
|
||||
// test.Dispose();
|
||||
//}
|
||||
//[TestMethod]
|
||||
//[TestCategory("ActiveAPI")]
|
||||
//public void Umsatzprognose_WithCompanyIdWithoutDate_Test()
|
||||
//{
|
||||
// var test = new TPlugin();
|
||||
// string apiUrlSet = config.apiUrl, user = config.username, password = config.password, database = config.database, mandant = config.mandant;
|
||||
// test.Startup(baseDataPath, apiUrlSet, user, password, database, mandant);
|
||||
// List<int> comp_id = new List<int> { 5661 };
|
||||
// var res = test.Umsatzprognose(comp_id, null);
|
||||
// PrettyPrint(res);
|
||||
// Assert.AreEqual(4, res.status.code);
|
||||
// Assert.AreEqual((int)StatusCodes.DatensatzZuWenigeMonatsdatenpunkte, res.status.code);
|
||||
// test.Dispose();
|
||||
//}
|
||||
//[TestMethod]
|
||||
//public void Umsatzprognose_WithCompanyIdWithoutDate_Test_FailConnection()
|
||||
//{
|
||||
// var test = new TPlugin();
|
||||
// string apiUrlSet = config.apiUrl, user = config.username, password = config.password, database = config.database, mandant = config.mandant;
|
||||
// test.Startup(baseDataPath, apiUrlSet, user, password, database, mandant);
|
||||
// List<int> comp_id = new List<int> { 5661 };
|
||||
// var res = test.Umsatzprognose(comp_id, null);
|
||||
// PrettyPrint(res);
|
||||
// Assert.AreEqual(1, res.status.code);
|
||||
// Assert.AreEqual((int)StatusCodes.VerbindungTimeout, res.status.code);
|
||||
// test.Dispose();
|
||||
//}
|
||||
//[TestMethod]
|
||||
//[TestCategory("ActiveAPI")]
|
||||
//public void Umsatzprognose_WithoutCompanyIdWithInvalidDate_Test()
|
||||
//{
|
||||
// var test = new TPlugin();
|
||||
// string apiUrlSet = config.apiUrl, user = config.username, password = config.password, database = config.database, mandant = config.mandant;
|
||||
// test.Startup(baseDataPath, apiUrlSet, user, password, database, mandant);
|
||||
// var date = new DateTime(2030, 1, 1, 12, 45, 30);
|
||||
// var res = test.Umsatzprognose(null, date);
|
||||
// PrettyPrint(res);
|
||||
// Assert.AreEqual(3, res.status.code);
|
||||
// Assert.AreEqual((int)StatusCodes.DatensatzZuWenigeDatenpunkte, res.status.code);
|
||||
// test.Dispose();
|
||||
//}
|
||||
//[TestMethod]
|
||||
//public void Umsatzprognose_WithoutCompanyIdWithInvalidDate_Test_FailConnection()
|
||||
//{
|
||||
// var test = new TPlugin();
|
||||
// string apiUrlSet = config.apiUrl, user = config.username, password = config.password, database = config.database, mandant = config.mandant;
|
||||
// test.Startup(baseDataPath, apiUrlSet, user, password, database, mandant);
|
||||
// var date = new DateTime(2030, 1, 1, 12, 45, 30);
|
||||
// var res = test.Umsatzprognose(null, date);
|
||||
// PrettyPrint(res);
|
||||
// Assert.AreEqual(1, res.status.code);
|
||||
// Assert.AreEqual((int)StatusCodes.VerbindungTimeout, res.status.code);
|
||||
// test.Dispose();
|
||||
//}
|
||||
//[TestMethod]
|
||||
//[TestCategory("ActiveAPI")]
|
||||
//public void Umsatzprognose_WithoutCompanyIdWithValidDate_Test()
|
||||
//{
|
||||
// var test = new TPlugin();
|
||||
// string apiUrlSet = config.apiUrl, user = config.username, password = config.password, database = config.database, mandant = config.mandant;
|
||||
// test.Startup(baseDataPath, apiUrlSet, user, password, database, mandant);
|
||||
// var date = new DateTime(2021, 1, 1, 12, 45, 30);
|
||||
// var res = test.Umsatzprognose(null, date);
|
||||
// PrettyPrint(res);
|
||||
// Assert.AreEqual(0, res.status.code);
|
||||
// Assert.AreEqual((int)StatusCodes.Erfolg, res.status.code);
|
||||
// test.Dispose();
|
||||
//}
|
||||
//[TestMethod]
|
||||
//public void Umsatzprognose_WithoutCompanyIdWithValidDate_Test_FailConnection()
|
||||
//{
|
||||
// var test = new TPlugin();
|
||||
// string apiUrlSet = config.apiUrl, user = config.username, password = config.password, database = config.database, mandant = config.mandant;
|
||||
// test.Startup(baseDataPath, apiUrlSet, user, password, database, mandant);
|
||||
// var date = new DateTime(2015, 1, 1, 12, 45, 30);
|
||||
// var res = test.Umsatzprognose(null, date);
|
||||
// PrettyPrint(res);
|
||||
// Assert.AreEqual(1, res.status.code);
|
||||
// Assert.AreEqual((int)StatusCodes.VerbindungTimeout, res.status.code);
|
||||
// test.Dispose();
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,44 +7,134 @@ using System.Collections.Immutable;
|
||||
|
||||
namespace dopt.DeltaBarth.DataObjects
|
||||
{
|
||||
/// <summary>
|
||||
/// Eine verpackte Fehlermeldung, die vom API-Server zur Verfügung gestellt wurde.
|
||||
/// </summary>
|
||||
public record class ApiServerError
|
||||
{
|
||||
/// <summary>
|
||||
/// Statuscode der HTTP-Anfrage
|
||||
/// </summary>
|
||||
public required int status_code { get; init; }
|
||||
/// <summary>
|
||||
/// Fehlerbezeichnung
|
||||
/// </summary>
|
||||
public required string message { get; init; }
|
||||
/// <summary>
|
||||
/// optional: spezifischer Code als Text, der vom Server ausgegeben wurde
|
||||
/// </summary>
|
||||
public string? code { get; init; }
|
||||
/// <summary>
|
||||
/// optional: spezifische Hinweise als Text, der vom Server ausgegeben wurde
|
||||
/// </summary>
|
||||
public string? hints { get; init; }
|
||||
/// <summary>
|
||||
/// optional: spezifischer Typus als Text, der vom Server ausgegeben wurde
|
||||
/// </summary>
|
||||
public string? type { get; init; }
|
||||
/// <summary>
|
||||
/// optional: spezifischer Titel als Text, der vom Server ausgegeben wurde
|
||||
/// </summary>
|
||||
public string? title { get; init; }
|
||||
/// <summary>
|
||||
/// optional: zusätzliche Fehlerdetails, die vom Server ausgegeben wurden
|
||||
/// </summary>
|
||||
public Dictionary<string, List<string>>? errors { get; init; }
|
||||
/// <summary>
|
||||
/// optional: spezifischer ID (vermutlich zur Nachverfolgung) als Text, der vom Server ausgegeben wurde
|
||||
/// </summary>
|
||||
public string? traceId { get; init; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Status-Objekt: Gibt Aufschluss über Erfolg/Misserfolg einer Routine und beschreibt aufgetretene Fehler
|
||||
/// mit zusätzlichen Informationen
|
||||
/// </summary>
|
||||
public record class Status
|
||||
{
|
||||
/// <summary>
|
||||
/// bibliotheksinterner Fehlercode
|
||||
/// </summary>
|
||||
public required int code { get; init; }
|
||||
/// <summary>
|
||||
/// Fehlerbeschreibung oder Python-Exception-Name
|
||||
/// </summary>
|
||||
public required string description { get; init; }
|
||||
/// <summary>
|
||||
/// genauere Beschreibung oder Fehler-Inhalt
|
||||
/// </summary>
|
||||
public required string message { get; init; }
|
||||
public ApiServerError? apiServerError { get; init; }
|
||||
/// <summary cref="ApiServerError">
|
||||
/// optional: eventuell aufgetretener API-Server-Fehler
|
||||
/// </summary>
|
||||
public ApiServerError? api_server_error { get; init; }
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// Nutzerdaten zur API-Interaktion
|
||||
/// </summary>
|
||||
public record class Credentials
|
||||
{
|
||||
/// <summary>
|
||||
/// Nutzername
|
||||
/// </summary>
|
||||
public required string username { get; init; }
|
||||
/// <summary>
|
||||
/// Passwort
|
||||
/// </summary>
|
||||
public required string password { get; init; }
|
||||
/// <summary>
|
||||
/// Datenbank
|
||||
/// </summary>
|
||||
public required string database { get; init; }
|
||||
/// <summary>
|
||||
/// Mandant
|
||||
/// </summary>
|
||||
public required string mandant { get; init; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Einzelergebnis der Umsatzprognose, 1 Eintrag von potenziell mehreren
|
||||
/// </summary>
|
||||
public record class UmsatzPrognoseEinzelergebnis
|
||||
{
|
||||
/// <summary>
|
||||
/// Jahr des Eintrags
|
||||
/// </summary>
|
||||
public required int jahr { get; init; }
|
||||
/// <summary>
|
||||
/// Monat des Eintrags
|
||||
/// </summary>
|
||||
public required int monat { get; init; }
|
||||
/// <summary>
|
||||
/// Prognosewert für den Umsatz
|
||||
/// </summary>
|
||||
public required decimal vorhersage { get; init; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Sammlung von unterschiedlichen Einzelergebnissen
|
||||
/// <see cref="UmsatzPrognoseEinzelergebnis"/>
|
||||
/// </summary>
|
||||
public record class UmsatzPrognoseErgebnisse
|
||||
{
|
||||
/// <summary>
|
||||
/// unveränderliche Sammlung von Einzelergebnissen in Form eines Array
|
||||
/// </summary>
|
||||
public required ImmutableArray<UmsatzPrognoseEinzelergebnis> daten { get; init; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Ausgabe der Prognose-Pipeline:
|
||||
/// enthält das Ergebnis als auch einen dazugehörigen Status
|
||||
/// </summary>
|
||||
public record class UmsatzPrognoseAusgabe
|
||||
{
|
||||
/// <summary>
|
||||
/// Sammlung von Prognosewerten
|
||||
/// <see cref="UmsatzPrognoseErgebnisse"/>
|
||||
/// </summary>
|
||||
public required UmsatzPrognoseErgebnisse response { get; init; }
|
||||
/// <summary>
|
||||
/// Status über den Erfolg/Misserfolg der Routine
|
||||
/// <see cref="Status"/>
|
||||
/// </summary>
|
||||
public required Status status { get; init; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,106 +1,262 @@
|
||||
using Python.Runtime;
|
||||
using System.ComponentModel;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace dopt.DeltaBarth
|
||||
{
|
||||
/// <summary>
|
||||
/// Spiegelung der internen Fehlertypen innerhalb der Python-Bibliothek
|
||||
/// </summary>
|
||||
public enum StatusCodes
|
||||
{
|
||||
/// <summary>
|
||||
/// erfolgreiche, fehlerfreie Durchführung der Routine
|
||||
/// </summary>
|
||||
[Description("Keine Fehler aufgetreten")]
|
||||
Erfolg = 0,
|
||||
/// <summary>
|
||||
/// Bei der API-Abfrage wurde der Timeout getriggert.
|
||||
/// </summary>
|
||||
[Description("Bei der Verbindung zum API-Server kam es zum Timeout")]
|
||||
VerbindungTimeout = 1,
|
||||
/// <summary>
|
||||
/// Bei der API-Abfrage ist ein unerwarteter Fehler aufgetreten, der unmittelbar die HTTP-Anfrage betrifft.
|
||||
/// </summary>
|
||||
[Description("Bei der Verbindung zum API-Server ist ein Fehler aufgetreten")]
|
||||
VerbindungFehler = 2,
|
||||
/// <summary>
|
||||
/// Der ausgewählte Datensatz enthält nicht genügend Datenpunkte.
|
||||
/// </summary>
|
||||
[Description("Der bereitgestellte Datensatz enthält in Summe zu wenige Einzeleinträge")]
|
||||
DatensatzZuWenigeDatenpunkte = 3,
|
||||
/// <summary>
|
||||
/// Der ausgewählte Datensatz enthält nach Aggregation pro Monat nicht genügend Datenpunkte.
|
||||
/// </summary>
|
||||
[Description("Der bereitgestellte Datensatz enthält nach Aggregation zu Monaten zu wenig Einträge")]
|
||||
DatensatzZuWenigeMonatsdatenpunkte = 4,
|
||||
/// <summary>
|
||||
/// Die Prognosequalität des Modells ist nicht zufriedenstellend. Eine verlässliche Prognose ist nicht möglich.
|
||||
/// </summary>
|
||||
[Description("Die Prognosequalität des Modells erfüllt nicht die Mindestanforderungen")]
|
||||
KeineVerlaesslichePrognose = 5,
|
||||
/// <summary>
|
||||
/// Es ist intern ein Fehler aufgetreten aufgetreten
|
||||
/// </summary>
|
||||
[Description("Interne Fehler, die während der Routine aufgetreten sind")]
|
||||
InternerFehler = 100,
|
||||
/// <summary>
|
||||
/// Es ist ein Fehler beim Schreiben der programminternen Datenbank aufgetreten.
|
||||
/// </summary>
|
||||
[Description("Interne Fehler, die während der Datenbankinteraktion aufgetreten sind")]
|
||||
InternerDbFehler = 150,
|
||||
/// <summary>
|
||||
/// Es ist ein Fehler auf dem API-Server aufgetreten.
|
||||
/// Das dazugehörige Status-Objekt sollte diesen Fehler zur Verfügung stellen können.
|
||||
/// <see cref="DataObjects.Status"/>
|
||||
/// <see cref="DataObjects.ApiServerError"/>
|
||||
/// </summary>
|
||||
[Description("Vom API-Server wurde eine Fehlermeldung zurückgegeben")]
|
||||
ApiServerFehler = 400,
|
||||
}
|
||||
/// <summary>
|
||||
/// Eine Exception, die genutzt wird, um anzuzeigen, dass beim Parsen der Python-Objekte
|
||||
/// ein Fehler aufgetreten ist.
|
||||
/// </summary>
|
||||
public class PythonParsingException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Konstruktor ohne Inhalt
|
||||
/// </summary>
|
||||
public PythonParsingException() { }
|
||||
/// <summary>
|
||||
/// Konstruktor mit Nachricht
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
public PythonParsingException(string message) : base(message) { }
|
||||
}
|
||||
/// <summary>
|
||||
/// Plugin-Klasse, mit der die Interaktion der zugrundeliegenden Python-Runtime erfolgt
|
||||
/// </summary>
|
||||
public class Plugin : SharpPython.BasePlugin
|
||||
{
|
||||
/// <summary>
|
||||
/// Python-interne Zustandsverwaltung
|
||||
/// </summary>
|
||||
protected dynamic pyModManagement;
|
||||
/// <summary>
|
||||
/// Python-interne Routinen und Pipelines
|
||||
/// </summary>
|
||||
protected dynamic pyModPipeline;
|
||||
public Plugin(string runtimePath) : base(runtimePath: runtimePath, verbose: false)
|
||||
/// <summary>
|
||||
/// Debug-Modul für Python-Umgebung
|
||||
/// </summary>
|
||||
protected dynamic pyDebug;
|
||||
/// <summary>
|
||||
/// Konstruktor der Plugin-Klasse.
|
||||
/// Kann mit beliebigem Pfad zu einer Python-Runtime initialisiert werden.
|
||||
/// </summary>
|
||||
/// <param name="runtimePath">Der Pfad zur Python-Runtime. Dieser muss zu dem Ordner zeigen,
|
||||
/// in welchem die Runtime in Form eines Ordners mit dem Namen "python" abliegt.</param>
|
||||
public Plugin(string runtimePath) : base(SharpPython.PyOptimLevels.O, threaded: true, runtimePath: runtimePath, verbose: false)
|
||||
{
|
||||
base.Initialise();
|
||||
using (Py.GIL())
|
||||
{
|
||||
pyModManagement = Py.Import("delta_barth.management");
|
||||
pyModPipeline = Py.Import("delta_barth.pipelines");
|
||||
pyDebug = Py.Import("delta_barth._debug");
|
||||
}
|
||||
}
|
||||
public void Startup(string datenPfad, string basisApiUrl, string nutzername, string passwort, string datenbank, string mandant)
|
||||
/// <summary>
|
||||
/// Gibt Runtime-relevante Pfade in der Konsole aus
|
||||
/// </summary>
|
||||
public string DebugCall()
|
||||
{
|
||||
AssertNotDisposed();
|
||||
Setup(datenPfad, basisApiUrl);
|
||||
SetzeNutzerdaten(nutzername, passwort, datenbank, mandant);
|
||||
}
|
||||
public void SetzeNutzerdaten(string nutzername, string passwort, string datenbank, string mandant)
|
||||
{
|
||||
AssertNotDisposed();
|
||||
using (Py.GIL()) {
|
||||
pyModManagement.set_credentials(nutzername, passwort, datenbank, mandant);
|
||||
}
|
||||
}
|
||||
public DataObjects.UmsatzPrognoseAusgabe UmsatzprognoseDummy(int? firmaId, DateTime? buchungsDatum)
|
||||
{
|
||||
AssertNotDisposed();
|
||||
string pyJson;
|
||||
string infos;
|
||||
using (Py.GIL())
|
||||
{
|
||||
pyJson = pyModPipeline.pipeline_sales_forecast_dummy(firmaId, buchungsDatum);
|
||||
|
||||
infos = pyDebug.print_infos();
|
||||
}
|
||||
var parsed = JsonSerializer.Deserialize<DataObjects.UmsatzPrognoseAusgabe>(pyJson);
|
||||
if (parsed == null) { throw new PythonParsingException("Could not correctly parse object from Python"); }
|
||||
Console.WriteLine(infos);
|
||||
Console.WriteLine($"PyEngine - PYHOME: {PythonEngine.PythonHome}");
|
||||
Console.WriteLine($"PyEngine - PYPATH: {PythonEngine.PythonPath}");
|
||||
|
||||
return parsed;
|
||||
return infos;
|
||||
}
|
||||
public DataObjects.UmsatzPrognoseAusgabe Umsatzprognose(int? firmaId, DateTime? buchungsDatum)
|
||||
{
|
||||
AssertNotDisposed();
|
||||
string pyJson;
|
||||
using (Py.GIL())
|
||||
{
|
||||
pyJson = pyModPipeline.pipeline_sales_forecast(firmaId, buchungsDatum);
|
||||
}
|
||||
var parsed = JsonSerializer.Deserialize<DataObjects.UmsatzPrognoseAusgabe>(pyJson);
|
||||
if (parsed == null) { throw new PythonParsingException("Could not correctly parse object from Python"); }
|
||||
///// <summary>
|
||||
///// Initialisiert das Plugin mit allen relevanten Paramtern für die weitere Nutzung.
|
||||
///// Diese Methode sollte nur einmal je Instanz genutzt werden.
|
||||
///// </summary>
|
||||
///// <param name="datenPfad">Pfad zu einem Ordner, in dem Programmdaten ohne Bedenken dauerhaft abgelegt werden können.</param>
|
||||
///// <param name="basisApiUrl">Basis-URL zum Zugriff auf die API. Dies muss eine vollständige URL sein inkl. der Route "/api".</param>
|
||||
///// <param name="nutzername">Nutzername für die Datenbankanmeldung.</param>
|
||||
///// <param name="passwort">Passwort für die Datenbankanmeldung.</param>
|
||||
///// <param name="datenbank">Name der Datenbank, bei der die Anmeldung erfolgen soll.</param>
|
||||
///// <param name="mandant">Mandant für die Datenbankanmeldung.</param>
|
||||
//public void Startup(string datenPfad, string basisApiUrl, string nutzername, string passwort, string datenbank, string mandant)
|
||||
//{
|
||||
// AssertNotDisposed();
|
||||
// Setup(datenPfad, basisApiUrl);
|
||||
// SetzeNutzerdaten(nutzername, passwort, datenbank, mandant);
|
||||
//}
|
||||
///// <summary>
|
||||
///// Diese Methode erlaubt es, die relevanten Nutzerdaten zur Laufzeit des Plugins zu ändern.
|
||||
///// Dies beinhaltet: Nutzername, Passwort, Datenbankname, Mandant
|
||||
///// </summary>
|
||||
///// <param name="nutzername">Nutzername für die Datenbankanmeldung.</param>
|
||||
///// <param name="passwort">Passwort für die Datenbankanmeldung.</param>
|
||||
///// <param name="datenbank">Name der Datenbank, bei der die Anmeldung erfolgen soll.</param>
|
||||
///// <param name="mandant">Mandant für die Datenbankanmeldung.</param>
|
||||
//public void SetzeNutzerdaten(string nutzername, string passwort, string datenbank, string mandant)
|
||||
//{
|
||||
// AssertNotDisposed();
|
||||
// using (Py.GIL()) {
|
||||
// pyModManagement.set_credentials(nutzername, passwort, datenbank, mandant);
|
||||
// }
|
||||
//}
|
||||
///// <summary>
|
||||
///// Ausführung der Umsatzprognose-Pipeline mit Dummy-Daten.
|
||||
///// Es werden keine API-Abrufe durchgeführt und somit auch keine Live-Daten genutzt.
|
||||
///// </summary>
|
||||
///// <param name="firmaId">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</param>
|
||||
///// <param name="analyseBeginn">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.</param>
|
||||
///// <returns cref="DataObjects.UmsatzPrognoseAusgabe">Umsatzprognose inkl. Status-Objekt zur Nachvollziehbarkeit etwaig aufgetretener Fehler.</returns>
|
||||
///// <exception cref="PythonParsingException"></exception>
|
||||
//public DataObjects.UmsatzPrognoseAusgabe UmsatzprognoseDummy(int? firmaId, DateTime? analyseBeginn)
|
||||
//{
|
||||
// AssertNotDisposed();
|
||||
// string pyJson;
|
||||
// using (Py.GIL())
|
||||
// {
|
||||
// pyJson = pyModPipeline.pipeline_sales_forecast_dummy(firmaId, analyseBeginn);
|
||||
// }
|
||||
// var parsed = JsonSerializer.Deserialize<DataObjects.UmsatzPrognoseAusgabe>(pyJson) ?? throw new PythonParsingException("Could not correctly parse object from Python");
|
||||
// return parsed;
|
||||
//}
|
||||
///// <summary>
|
||||
///// 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.
|
||||
///// </summary>
|
||||
///// <param name="firmaIds">optional: Liste von Firmen-IDs, für die die Pipeline ausgeführt werden soll.
|
||||
///// Wird der Parameter nicht zur Verfügung gestellt, werden alle Firmen bzw. Kunden abgerufen</param>
|
||||
///// <param name="analyseBeginn">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.</param>
|
||||
///// <returns cref="DataObjects.UmsatzPrognoseAusgabe">Umsatzprognose inkl. Status-Objekt zur Nachvollziehbarkeit etwaig aufgetretener Fehler.</returns>
|
||||
///// <exception cref="PythonParsingException"></exception>
|
||||
//public DataObjects.UmsatzPrognoseAusgabe Umsatzprognose(List<int>? firmaIds, DateTime? analyseBeginn)
|
||||
//{
|
||||
// AssertNotDisposed();
|
||||
// string pyJson;
|
||||
// using (Py.GIL())
|
||||
// {
|
||||
// pyJson = pyModPipeline.pipeline_sales_forecast(firmaIds, analyseBeginn);
|
||||
// }
|
||||
// var parsed = JsonSerializer.Deserialize<DataObjects.UmsatzPrognoseAusgabe>(pyJson) ?? throw new PythonParsingException("Could not correctly parse object from Python");
|
||||
// return parsed;
|
||||
//}
|
||||
///// <summary>
|
||||
///// Setup der Python-internen Umgebung
|
||||
///// </summary>
|
||||
///// <param name="datenPfad">Pfad zu einem Ordner, in dem Programmdaten ohne Bedenken dauerhaft abgelegt werden können.</param>
|
||||
///// <param name="basisApiUrl">Basis-URL zum Zugriff auf die API. Dies muss eine vollständige URL sein inkl. der Route "/api".</param>
|
||||
//protected void Setup(string datenPfad, string basisApiUrl)
|
||||
//{
|
||||
// AssertNotDisposed();
|
||||
// using (Py.GIL())
|
||||
// {
|
||||
// pyModManagement.setup(datenPfad, basisApiUrl);
|
||||
// }
|
||||
//}
|
||||
///// <summary>
|
||||
///// Hole die konfigurierte API-Basis-URL aus der Python-Umgebung
|
||||
///// </summary>
|
||||
///// <returns>konfigurierte Basis-URL</returns>
|
||||
//protected string GetBaseApiUrl()
|
||||
//{
|
||||
// AssertNotDisposed();
|
||||
// string pyJson;
|
||||
// using (Py.GIL())
|
||||
// {
|
||||
// pyJson = (string)pyModManagement.get_base_url();
|
||||
// }
|
||||
// return pyJson;
|
||||
//}
|
||||
///// <summary>
|
||||
///// Hole den konfigurierten Datenpfad zur Dateiverwaltung aus der Python-Umgebung
|
||||
///// </summary>
|
||||
///// <returns>konfigurierten Datenpfad</returns>
|
||||
//protected string GetDataPath()
|
||||
//{
|
||||
// AssertNotDisposed();
|
||||
// string pyJson;
|
||||
// using (Py.GIL())
|
||||
// {
|
||||
// pyJson = (string)pyModManagement.get_data_path();
|
||||
// }
|
||||
// return pyJson;
|
||||
//}
|
||||
///// <summary>
|
||||
///// Hole die konfigurierten Nutzerdaten zur API-Interaktion aus der Python-Umgebung
|
||||
///// </summary>
|
||||
///// <returns cref="DataObjects.Credentials">konfigurierte Nutzerdaten</returns>
|
||||
///// <exception cref="PythonParsingException"></exception>
|
||||
//protected DataObjects.Credentials GetCredentials()
|
||||
//{
|
||||
// AssertNotDisposed();
|
||||
// string pyJson;
|
||||
// using (Py.GIL())
|
||||
// {
|
||||
// pyJson = (string)pyModManagement.get_credentials();
|
||||
// }
|
||||
|
||||
return parsed;
|
||||
}
|
||||
protected void Setup(string datenPfad, string basisApiUrl)
|
||||
{
|
||||
AssertNotDisposed();
|
||||
using (Py.GIL())
|
||||
{
|
||||
pyModManagement.setup(datenPfad, basisApiUrl);
|
||||
}
|
||||
}
|
||||
protected string GetBaseApiUrl()
|
||||
{
|
||||
AssertNotDisposed();
|
||||
string pyJson;
|
||||
using (Py.GIL())
|
||||
{
|
||||
pyJson = (string)pyModManagement.get_base_url();
|
||||
}
|
||||
return pyJson;
|
||||
}
|
||||
protected string GetDataPath()
|
||||
{
|
||||
AssertNotDisposed();
|
||||
string pyJson;
|
||||
using (Py.GIL())
|
||||
{
|
||||
pyJson = (string)pyModManagement.get_data_path();
|
||||
}
|
||||
return pyJson;
|
||||
}
|
||||
protected DataObjects.Credentials GetCredentials()
|
||||
{
|
||||
AssertNotDisposed();
|
||||
string pyJson;
|
||||
using (Py.GIL())
|
||||
{
|
||||
pyJson = (string)pyModManagement.get_credentials();
|
||||
}
|
||||
|
||||
DataObjects.Credentials? parsed = JsonSerializer.Deserialize<DataObjects.Credentials>(pyJson);
|
||||
if (parsed == null) { throw new PythonParsingException("Could not correctly parse object from Python"); }
|
||||
|
||||
return parsed;
|
||||
}
|
||||
// DataObjects.Credentials? parsed = JsonSerializer.Deserialize<DataObjects.Credentials>(pyJson);
|
||||
// return parsed ?? throw new PythonParsingException("Could not correctly parse object from Python");
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,11 +6,12 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<Platforms>x64</Platforms>
|
||||
<Version>0.3.2</Version>
|
||||
<Version>0.4.1-alpha1</Version>
|
||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="dopt.SharpPython" Version="0.4.0" />
|
||||
<PackageReference Include="dopt.SharpPython" Version="0.4.2" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
Reference in New Issue
Block a user