7 Commits

5 changed files with 84 additions and 14 deletions

View File

@@ -46,7 +46,7 @@ namespace dopt.DeltaBarth.Tests
Assert.AreEqual(102, parsed.code); Assert.AreEqual(102, parsed.code);
Assert.IsTrue(parsed.description.Contains("internal error occurred")); Assert.IsTrue(parsed.description.Contains("internal error occurred"));
Assert.AreEqual("caused by test", parsed.message); Assert.AreEqual("caused by test", parsed.message);
Assert.IsNull(parsed.apiServerError); Assert.IsNull(parsed.api_server_error);
PrettyPrint(parsed); PrettyPrint(parsed);
plugin.Dispose(); plugin.Dispose();
} }
@@ -151,7 +151,7 @@ namespace dopt.DeltaBarth.Tests
Assert.AreEqual(0, parsed.status.code); Assert.AreEqual(0, parsed.status.code);
Assert.AreEqual("Erfolg", parsed.status.description); Assert.AreEqual("Erfolg", parsed.status.description);
Assert.AreEqual("", parsed.status.message); Assert.AreEqual("", parsed.status.message);
Assert.IsNull(parsed.status.apiServerError); Assert.IsNull(parsed.status.api_server_error);
// check result // check result
for (int i = 0; i < parsed.response.daten.Length; i++) for (int i = 0; i < parsed.response.daten.Length; i++)
{ {

View File

@@ -6,6 +6,8 @@ namespace dopt.DeltaBarth.Tests
{ {
using System.Text.Encodings.Web; using System.Text.Encodings.Web;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Python.Runtime;
internal class Config internal class Config
{ {
public string apiUrl; public string apiUrl;
@@ -56,6 +58,41 @@ namespace dopt.DeltaBarth.Tests
{ {
base.Setup(datenPfad, basisApiUrl); base.Setup(datenPfad, basisApiUrl);
} }
public void TruststoreInjected()
{
using (Py.GIL())
{
string code = @"
import pip_system_certs.wrapt_requests
pip_system_certs.wrapt_requests.inject_truststore()
import ssl
var1 = str(ssl.create_default_context())
var2 = str(ssl.get_default_verify_paths())
";
dynamic pyScope = Py.CreateScope();
pyScope.Exec(code);
dynamic var1 = pyScope.Get("var1");
dynamic var2 = pyScope.Get("var2");
Console.WriteLine($"Retrieved from Python: {var1}, {var2}");
}
}
public void TruststoreDefault()
{
using (Py.GIL())
{
string code = @"
import ssl
var1 = str(ssl.create_default_context())
var2 = str(ssl.get_default_verify_paths())
";
dynamic pyScope = Py.CreateScope();
pyScope.Exec(code);
dynamic var1 = pyScope.Get("var1");
dynamic var2 = pyScope.Get("var2");
Console.WriteLine($"Retrieved from Python: {var1}, {var2}");
}
}
} }
[TestClass] [TestClass]
public sealed class PluginTest public sealed class PluginTest
@@ -173,16 +210,31 @@ namespace dopt.DeltaBarth.Tests
} }
[TestMethod] [TestMethod]
[TestCategory("ActiveAPI")] [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() public void Umsatzprognose_WithCompanyIdWithoutDate_Test()
{ {
var test = new TPlugin(); var test = new TPlugin();
string apiUrlSet = config.apiUrl, user = config.username, password = config.password, database = config.database, mandant = config.mandant; string apiUrlSet = config.apiUrl, user = config.username, password = config.password, database = config.database, mandant = config.mandant;
test.Startup(baseDataPath, apiUrlSet, user, password, database, mandant); test.Startup(baseDataPath, apiUrlSet, user, password, database, mandant);
var comp_id = 1024; List<int> comp_id = new List<int> { 5661 };
var res = test.Umsatzprognose(comp_id, null); var res = test.Umsatzprognose(comp_id, null);
PrettyPrint(res); PrettyPrint(res);
Assert.AreEqual(0, res.status.code); Assert.AreEqual(4, res.status.code);
Assert.AreEqual((int)StatusCodes.Erfolg, res.status.code); Assert.AreEqual((int)StatusCodes.DatensatzZuWenigeMonatsdatenpunkte, res.status.code);
test.Dispose(); test.Dispose();
} }
[TestMethod] [TestMethod]
@@ -191,7 +243,7 @@ namespace dopt.DeltaBarth.Tests
var test = new TPlugin(); var test = new TPlugin();
string apiUrlSet = config.apiUrl, user = config.username, password = config.password, database = config.database, mandant = config.mandant; string apiUrlSet = config.apiUrl, user = config.username, password = config.password, database = config.database, mandant = config.mandant;
test.Startup(baseDataPath, apiUrlSet, user, password, database, mandant); test.Startup(baseDataPath, apiUrlSet, user, password, database, mandant);
var comp_id = 1024; List<int> comp_id = new List<int> { 5661 };
var res = test.Umsatzprognose(comp_id, null); var res = test.Umsatzprognose(comp_id, null);
PrettyPrint(res); PrettyPrint(res);
Assert.AreEqual(1, res.status.code); Assert.AreEqual(1, res.status.code);
@@ -232,7 +284,7 @@ namespace dopt.DeltaBarth.Tests
var test = new TPlugin(); var test = new TPlugin();
string apiUrlSet = config.apiUrl, user = config.username, password = config.password, database = config.database, mandant = config.mandant; string apiUrlSet = config.apiUrl, user = config.username, password = config.password, database = config.database, mandant = config.mandant;
test.Startup(baseDataPath, apiUrlSet, user, password, database, mandant); test.Startup(baseDataPath, apiUrlSet, user, password, database, mandant);
var date = new DateTime(2015, 1, 1, 12, 45, 30); var date = new DateTime(2021, 1, 1, 12, 45, 30);
var res = test.Umsatzprognose(null, date); var res = test.Umsatzprognose(null, date);
PrettyPrint(res); PrettyPrint(res);
Assert.AreEqual(0, res.status.code); Assert.AreEqual(0, res.status.code);
@@ -252,5 +304,19 @@ namespace dopt.DeltaBarth.Tests
Assert.AreEqual((int)StatusCodes.VerbindungTimeout, res.status.code); Assert.AreEqual((int)StatusCodes.VerbindungTimeout, res.status.code);
test.Dispose(); test.Dispose();
} }
[TestMethod]
public void Set_SSLCertPaths_Inject_Test()
{
var test = new TPlugin();
test.TruststoreInjected();
test.Dispose();
}
[TestMethod]
public void Set_SSLCertPaths_Default_Test()
{
var test = new TPlugin();
test.TruststoreDefault();
test.Dispose();
}
} }
} }

View File

@@ -37,6 +37,10 @@ namespace dopt.DeltaBarth.DataObjects
/// </summary> /// </summary>
public string? title { get; init; } public string? title { get; init; }
/// <summary> /// <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 /// optional: spezifischer ID (vermutlich zur Nachverfolgung) als Text, der vom Server ausgegeben wurde
/// </summary> /// </summary>
public string? traceId { get; init; } public string? traceId { get; init; }
@@ -62,7 +66,7 @@ namespace dopt.DeltaBarth.DataObjects
/// <summary cref="ApiServerError"> /// <summary cref="ApiServerError">
/// optional: eventuell aufgetretener API-Server-Fehler /// optional: eventuell aufgetretener API-Server-Fehler
/// </summary> /// </summary>
public ApiServerError? apiServerError { get; init; } public ApiServerError? api_server_error { get; init; }
} }
/// <summary> /// <summary>

View File

@@ -93,7 +93,7 @@ namespace dopt.DeltaBarth
/// </summary> /// </summary>
/// <param name="runtimePath">Der Pfad zur Python-Runtime. Dieser muss zu dem Ordner zeigen, /// <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> /// in welchem die Runtime in Form eines Ordners mit dem Namen "python" abliegt.</param>
public Plugin(string runtimePath) : base(SharpPython.PyOptimLevels.O, runtimePath: runtimePath, verbose: false) public Plugin(string runtimePath) : base(SharpPython.PyOptimLevels.O, threaded: true, runtimePath: runtimePath, verbose: false)
{ {
base.Initialise(); base.Initialise();
using (Py.GIL()) using (Py.GIL())
@@ -160,20 +160,20 @@ namespace dopt.DeltaBarth
/// Es werden API-Abrufe durchgeführt und somit auch Live-Daten genutzt. /// 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. /// Hierfür muss sichergestellt sein, dass der API-Server erreichbar und abrufbereit ist.
/// </summary> /// </summary>
/// <param name="firmaId">optional: Firmen-ID, für die die Pipeline ausgeführt werden soll. /// <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> /// 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. /// <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. /// 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> /// 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> /// <returns cref="DataObjects.UmsatzPrognoseAusgabe">Umsatzprognose inkl. Status-Objekt zur Nachvollziehbarkeit etwaig aufgetretener Fehler.</returns>
/// <exception cref="PythonParsingException"></exception> /// <exception cref="PythonParsingException"></exception>
public DataObjects.UmsatzPrognoseAusgabe Umsatzprognose(int? firmaId, DateTime? analyseBeginn) public DataObjects.UmsatzPrognoseAusgabe Umsatzprognose(List<int>? firmaIds, DateTime? analyseBeginn)
{ {
AssertNotDisposed(); AssertNotDisposed();
string pyJson; string pyJson;
using (Py.GIL()) using (Py.GIL())
{ {
pyJson = pyModPipeline.pipeline_sales_forecast(firmaId, analyseBeginn); pyJson = pyModPipeline.pipeline_sales_forecast(firmaIds, analyseBeginn);
} }
var parsed = JsonSerializer.Deserialize<DataObjects.UmsatzPrognoseAusgabe>(pyJson) ?? throw new PythonParsingException("Could not correctly parse object from Python"); var parsed = JsonSerializer.Deserialize<DataObjects.UmsatzPrognoseAusgabe>(pyJson) ?? throw new PythonParsingException("Could not correctly parse object from Python");
return parsed; return parsed;

View File

@@ -6,12 +6,12 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<PlatformTarget>x64</PlatformTarget> <PlatformTarget>x64</PlatformTarget>
<Platforms>x64</Platforms> <Platforms>x64</Platforms>
<Version>0.3.3</Version> <Version>0.4.1</Version>
<GenerateDocumentationFile>True</GenerateDocumentationFile> <GenerateDocumentationFile>True</GenerateDocumentationFile>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="dopt.SharpPython" Version="0.4.1" /> <PackageReference Include="dopt.SharpPython" Version="0.4.4" />
</ItemGroup> </ItemGroup>
</Project> </Project>