ChartWindow: Use BillingData and Curve

This commit is contained in:
2024-01-17 14:33:21 +01:00
parent b52c09a176
commit b6fd62f8ca
3 changed files with 159 additions and 136 deletions

View File

@ -7,18 +7,18 @@ using System.Text.Json.Nodes;
namespace Elwig.Helpers.Billing { namespace Elwig.Helpers.Billing {
public class Graph : ICloneable { public class Graph : ICloneable {
public string Type { get; set; } public BillingData.CurveMode Mode { get; set; }
public int Num { get; set; } public int Id { get; set; }
private int MinX { get; set; } private int MinX { get; set; }
private int MaxX { get; set; } private int MaxX { get; set; }
public string Contracts { get; set; } public List<Tuple<string, string>> Contracts { get; set; }
public double[] DataX { get; set; } public double[] DataX { get; set; }
public double[] DataY { get; set; } public double[] DataY { get; set; }
public Graph(int num, int minX, int maxX) { public Graph(int id, BillingData.CurveMode mode, int minX, int maxX) {
Type = "oe"; Id = id;
Num = num; Mode = mode;
Contracts = ""; Contracts = new List<Tuple<string, string>>();
MinX = minX; MinX = minX;
MaxX = maxX; MaxX = maxX;
@ -26,21 +26,21 @@ namespace Elwig.Helpers.Billing {
DataY = DataGen.Zeros(MaxX - MinX + 1); DataY = DataGen.Zeros(MaxX - MinX + 1);
} }
public Graph(string type, int num, JsonObject graphData, string contracts, int minX, int maxX) { public Graph(int id, BillingData.CurveMode mode, Dictionary<double, decimal> data, int minX, int maxX) {
Type = type; Id = id;
Num = num; Mode = mode;
Contracts = contracts; Contracts = new List<Tuple<string, string>>();
MinX = minX; MinX = minX;
MaxX = maxX; MaxX = maxX;
DataX = DataGen.Range(MinX, MaxX + 1); DataX = DataGen.Range(MinX, MaxX + 1);
DataY = DataGen.Zeros(MaxX - MinX + 1); DataY = DataGen.Zeros(MaxX - MinX + 1);
ParseGraphData(graphData); ParseGraphData(data);
} }
public Graph(string type, int num, int minX, int maxX, string contracts, double[] dataX, double[] dataY) { public Graph(int id, BillingData.CurveMode mode, int minX, int maxX, List<Tuple<string, string>> contracts, double[] dataX, double[] dataY) {
Type = type; Id = id;
Num = num; Mode = mode;
MinX = minX; MinX = minX;
MaxX = maxX; MaxX = maxX;
Contracts = contracts; Contracts = contracts;
@ -48,72 +48,78 @@ namespace Elwig.Helpers.Billing {
DataY = dataY; DataY = dataY;
} }
private void ParseGraphData(JsonObject graphData) { private void ParseGraphData(Dictionary<double, decimal> graphPoints) {
var GraphPoints = graphData.ToDictionary(p => int.Parse(p.Key[..^2]), p => (double)p.Value?.AsValue()); if (graphPoints.Keys.Count < 1) {
if (GraphPoints.Keys.Count < 1) {
return; return;
} }
var minKey = GraphPoints.Keys.Order().First(); var minKey = graphPoints.Keys.Order().First();
var maxKey = GraphPoints.Keys.OrderDescending().First(); var maxKey = graphPoints.Keys.OrderDescending().First();
if (!GraphPoints.ContainsKey(MinX)) { if (!graphPoints.ContainsKey(MinX)) {
GraphPoints.Add(MinX, GraphPoints.GetValueOrDefault(minKey)); graphPoints.Add(MinX, graphPoints.GetValueOrDefault(minKey));
} }
if (!GraphPoints.ContainsKey(MaxX)) { if (!graphPoints.ContainsKey(MaxX)) {
GraphPoints.Add(MaxX, GraphPoints.GetValueOrDefault(maxKey)); graphPoints.Add(MaxX, graphPoints.GetValueOrDefault(maxKey));
} }
var keys = GraphPoints.Keys.Order().ToArray(); var keys = graphPoints.Keys.Order().ToArray();
for (int i = 0; i < keys.Length; i++) { for (int i = 0; i < keys.Length; i++) {
double point1Value = GraphPoints[keys[i]]; decimal point1Value = graphPoints[keys[i]];
if (i + 1 < keys.Length) { if (i + 1 < keys.Length) {
double point2Value = GraphPoints[keys[i + 1]]; decimal point2Value = graphPoints[keys[i + 1]];
if (point1Value == point2Value) { if (point1Value == point2Value) {
for (int j = keys[i] - MinX; j < keys[i + 1] - MinX; j++) { for (int j = (int)(keys[i] - MinX); j < keys[i + 1] - MinX; j++) {
DataY[j] = point1Value; DataY[j] = (double)point1Value;
} }
} else { } else {
int steps = Math.Abs(keys[i + 1] - keys[i]); int steps = (int)Math.Abs(keys[i + 1] - keys[i]);
double step = (point2Value - point1Value) / steps; decimal step = (point2Value - point1Value) / steps;
DataY[keys[i] - MinX] = point1Value; DataY[(int)(keys[i] - MinX)] = (double)point1Value;
DataY[keys[i + 1] - MinX] = point2Value; DataY[(int)(keys[i + 1] - MinX)] = (double)point2Value;
for (int j = keys[i] - MinX; j < keys[i + 1] - MinX - 1; j++) { for (int j = (int)(keys[i] - MinX); j < keys[i + 1] - MinX - 1; j++) {
DataY[j + 1] = Math.Round(DataY[j] + step, 4); // TODO richtig runden DataY[j + 1] = Math.Round(DataY[j] + (double)step, 4); // TODO richtig runden
} }
} }
} }
else { else {
for (int j = keys[i] - MinX; j < DataX.Length; j++) { for (int j = (int)(keys[i] - MinX); j < DataX.Length; j++) {
DataY[j] = point1Value; DataY[j] = (double)point1Value;
} }
} }
} }
} }
public JsonObject ToJson() { public JsonObject ToJson() {
JsonObject graph = new(); var graph = new JsonObject {
["id"] = Id,
["mode"] = Mode.ToString().ToLower(),
};
var data = new JsonObject();
if (DataY[0] != DataY[1]) { if (DataY[0] != DataY[1]) {
graph.Add(new KeyValuePair<string, JsonNode?>(DataX[0] + Type.ToLower(), Math.Round(DataY[0], 4))); data.Add(new KeyValuePair<string, JsonNode?>(DataX[0] + Mode.ToString().ToLower(), Math.Round(DataY[0], 4)));
} }
for (int i = 1; i < DataX.Length - 1; i++) { for (int i = 1; i < DataX.Length - 1; i++) {
if (Math.Round(DataY[i] - DataY[i - 1], 4) != Math.Round(DataY[i + 1] - DataY[i], 4)) { if (Math.Round(DataY[i] - DataY[i - 1], 10) != Math.Round(DataY[i + 1] - DataY[i], 10)) {
graph.Add(new KeyValuePair<string, JsonNode?>(DataX[i] + Type.ToLower(), Math.Round(DataY[i], 4))); data.Add(new KeyValuePair<string, JsonNode?>(DataX[i] + Mode.ToString().ToLower(), Math.Round(DataY[i], 4)));
} }
} }
if (DataY[^1] != DataY[^2]) { if (DataY[^1] != DataY[^2]) {
graph.Add(new KeyValuePair<string, JsonNode?>(DataX[^1] + Type.ToLower(), Math.Round(DataY[^1], 4))); data.Add(new KeyValuePair<string, JsonNode?>(DataX[^1] + Mode.ToString().ToLower(), Math.Round(DataY[^1], 4)));
} }
graph["data"] = data;
return graph; return graph;
} }
public object Clone() { public object Clone() {
return new Graph(Type, Num, MinX, MaxX, Contracts, (double[])DataX.Clone(), (double[])DataY.Clone()); return new Graph(Id, Mode, MinX, MaxX, Contracts.ConvertAll(item => new Tuple<string, string>(item.Item1, item.Item2)), (double[])DataX.Clone(), (double[])DataY.Clone());
} }
} }
} }

View File

@ -68,14 +68,14 @@
SelectionChanged="GraphList_SelectionChanged" SelectionChanged="GraphList_SelectionChanged"
Margin="5,15,5,0" Grid.Row="0" FontSize="14" Grid.ColumnSpan="3"> Margin="5,15,5,0" Grid.Row="0" FontSize="14" Grid.ColumnSpan="3">
<DataGrid.Columns> <DataGrid.Columns>
<DataGridTextColumn Header="Nr." Binding="{Binding Num}" Width="40"> <DataGridTextColumn Header="Nr." Binding="{Binding Id}" Width="40">
<DataGridTextColumn.ElementStyle> <DataGridTextColumn.ElementStyle>
<Style> <Style>
<Setter Property="TextBlock.TextWrapping" Value="Wrap" /> <Setter Property="TextBlock.TextWrapping" Value="Wrap" />
</Style> </Style>
</DataGridTextColumn.ElementStyle> </DataGridTextColumn.ElementStyle>
</DataGridTextColumn> </DataGridTextColumn>
<DataGridTextColumn Header="Typ" Binding="{Binding Type}" Width="40"/> <DataGridTextColumn Header="Modus" Binding="{Binding Mode}" Width="40"/>
<DataGridTextColumn Header="Angewandte Verträge" Binding="{Binding Contracts}" Width="4*"/> <DataGridTextColumn Header="Angewandte Verträge" Binding="{Binding Contracts}" Width="4*"/>
</DataGrid.Columns> </DataGrid.Columns>
</DataGrid> </DataGrid>

View File

@ -75,27 +75,15 @@ namespace Elwig.Windows {
var data = ParseData(paymentVar); var data = ParseData(paymentVar);
if (data == null) return; if (data == null) return;
var auszahlungsSorten = data["AuszahlungSorten"]?.AsObject(); var curves = BillingData.GetCurves(data, BillingData.CalculationMode.Elwig);
if (auszahlungsSorten == null) { List<Graph> graphs = [];
return;
foreach (var (id, curve) in curves) {
graphs.Add(new Graph(id, curve.Mode, curve.Normal, MinOechsle, MaxOechsle));
} }
var Graphs = auszahlungsSorten["Kurven"]?.AsArray(); ControlUtils.RenewItemsSource(GraphList, graphs, g => (g as Graph)?.Id);
if (graphs.Count == 1) {
if (Graphs == null) {
return;
}
List<Graph> GraphsList = [];
int i = 1;
foreach (var graph in Graphs) {
GraphsList.Add(new Graph("Oe", i, graph?.AsObject(), ParseContracts(auszahlungsSorten, i - 1), 50, 140));
i++;
}
ControlUtils.RenewItemsSource(GraphList, GraphsList, g => (g as Graph)?.Num);
if (GraphsList.Count == 1) {
GraphList.SelectedIndex = 0; GraphList.SelectedIndex = 0;
} }
@ -125,46 +113,63 @@ namespace Elwig.Windows {
var data = ParseData(paymentVar); var data = ParseData(paymentVar);
if (data == null) return false; if (data == null) return false;
var auszahlungsSorten = data["AuszahlungSorten"]?.AsObject(); MessageBox.Show("1");
if (auszahlungsSorten == null) {
JsonArray? curves;
JsonObject? payment;
if (data["mode"]?.GetValue<string>() == "elwig") {
curves = data["curves"]?.AsArray();
payment = data["payment"]?.AsObject();
} else if (data["mode"]?.GetValue<string>() == "wgmaster") {
curves = data["Kurven"]?.AsArray();
payment = data["AuszahlungSorten"]?.AsObject();
} else {
return false; return false;
} }
var Graphs = auszahlungsSorten["Kurven"]?.AsObject(); MessageBox.Show("2");
if (Graphs == null) {
if (curves == null || payment == null) {
return false; return false;
} }
int i = 1; MessageBox.Show("3");
foreach (var graph in Graphs) {
if (i == num) { foreach (var curve in curves) {
Graphs.Remove(graph.Key); MessageBox.Show("LOOP");
if (curve?.AsObject()?["id"]?.GetValue<int>() == num) {
MessageBox.Show(curve.ToJsonString());
curves.Remove(curve);
break; break;
} }
i++;
} }
foreach (var sorte in auszahlungsSorten) { MessageBox.Show("4");
if (sorte.Key == "Kurven") continue;
foreach (var attribut in sorte.Value.AsObject()) { var keysToRemove = new List<string>();
var bindungen = attribut.Value.AsObject(); foreach (var sorte in payment) {
foreach (var bindung in bindungen) { MessageBox.Show(sorte.Value.GetType().ToString());
int v = (int)bindung.Value; if (sorte.Value.AsValue().TryGetValue(out string? curve) && curve.Equals($"curve:{num}")) {
if (v == num - 1) { keysToRemove.Add(sorte.Key);
bindungen.Remove(bindung.Key);
} else if (v > num - 1) {
bindungen[bindung.Key] = v - 1;
}
} }
} }
foreach (var key in keysToRemove) {
payment.Remove(key);
} }
MessageBox.Show("5");
EntityEntry<PaymentVar>? tr = null; EntityEntry<PaymentVar>? tr = null;
try { try {
paymentVar.Data = data.ToString(); paymentVar.Data = data.ToString();
tr = Context.Update(paymentVar); tr = Context.Update(paymentVar);
await Context.SaveChangesAsync(); await Context.SaveChangesAsync();
await App.HintContextChange();
} catch (Exception exc) { } catch (Exception exc) {
if (tr != null) await tr.ReloadAsync(); if (tr != null) await tr.ReloadAsync();
var str = "Der Eintrag konnte nicht in der Datenbank gelöscht werden!\n\n" + exc.Message; var str = "Der Eintrag konnte nicht in der Datenbank gelöscht werden!\n\n" + exc.Message;
@ -175,6 +180,62 @@ namespace Elwig.Windows {
return true; return true;
} }
private async Task<int?> UpdateGraph(Graph g) {
var paymentVar = await Context.PaymentVariants.FindAsync(Year, AvNr);
if (paymentVar == null) return null;
var data = ParseData(paymentVar);
if (data == null) return null;
JsonArray? curves;
JsonObject? payment;
if (data["mode"]?.GetValue<string>() == "elwig") {
curves = data["curves"]?.AsArray();
payment = data["payment"]?.AsObject();
} else if (data["mode"]?.GetValue<string>() == "wgmaster") {
curves = data["Kurven"]?.AsArray();
payment = data["AuszahlungSorten"]?.AsObject();
} else {
return null;
}
if (curves == null || payment == null) {
return null;
}
if (IsEditing) {
int i = 0;
foreach (var curve in curves) {
if (curve?.AsObject()?["id"]?.GetValue<int>() == g.Id) {
curves[i] = g.ToJson();
break;
}
i++;
}
} else if(IsCreating) {
curves.Add(g.ToJson());
} else {
return null;
}
EntityEntry<PaymentVar>? tr = null;
try {
paymentVar.Data = data.ToString();
tr = Context.Update(paymentVar);
await Context.SaveChangesAsync();
await App.HintContextChange();
} catch (Exception exc) {
if (tr != null) await tr.ReloadAsync();
var str = "Der Eintrag konnte nicht in der Datenbank gelöscht werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Graph löschen", MessageBoxButton.OK, MessageBoxImage.Error);
}
return g.Id;
}
private void RefreshInputs(bool validate = false) { private void RefreshInputs(bool validate = false) {
ResetPlot(); ResetPlot();
ClearInputStates(); ClearInputStates();
@ -199,10 +260,10 @@ namespace Elwig.Windows {
Graph = (Graph)g.Clone(); Graph = (Graph)g.Clone();
GraphNumberInput.Text = Graph.Num.ToString(); GraphNumberInput.Text = Graph.Id.ToString();
if (Graph.Type == "oe") { if (Graph.Mode == BillingData.CurveMode.Oe) {
OechsleGraphType_Input.IsChecked = true; OechsleGraphType_Input.IsChecked = true;
} else if (Graph.Type == "kmw") { } else if (Graph.Mode == BillingData.CurveMode.Kmw) {
KmwGraphType_Input.IsChecked = true; KmwGraphType_Input.IsChecked = true;
} }
@ -604,7 +665,7 @@ namespace Elwig.Windows {
PriceInput.IsReadOnly = false; PriceInput.IsReadOnly = false;
OechsleInput.IsReadOnly = false; OechsleInput.IsReadOnly = false;
InitInputs(); InitInputs();
FillInputs(new Graph(GraphList.Items.Count + 1, MinOechsle, MaxOechsle)); FillInputs(new Graph(GraphList.Items.Count + 1, BillingData.CurveMode.Oe, MinOechsle, MaxOechsle)); //TODO not hardcode oe
EnableOptionButtons(); EnableOptionButtons();
} }
@ -629,10 +690,10 @@ namespace Elwig.Windows {
if (g == null) return; if (g == null) return;
var r = MessageBox.Show( var r = MessageBox.Show(
$"Soll der Graph {g.Num} (verwendet in folgenden Verträgen: {g.Contracts}) wirklich unwiderruflich gelöscht werden?", $"Soll der Graph {g.Id} (verwendet in folgenden Verträgen: {g.Contracts}) wirklich unwiderruflich gelöscht werden?",
"Graph löschen", MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No); "Graph löschen", MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No);
if (r == MessageBoxResult.Yes) { if (r == MessageBoxResult.Yes) {
bool success = await RemoveGraph(g.Num); bool success = await RemoveGraph(g.Id);
if (!success) { if (!success) {
MessageBox.Show("Der Graph konnte nicht gelöscht werden", "Graph löschen", MessageBoxButton.OK, MessageBoxImage.Error); MessageBox.Show("Der Graph konnte nicht gelöscht werden", "Graph löschen", MessageBoxButton.OK, MessageBoxImage.Error);
} }
@ -658,50 +719,6 @@ namespace Elwig.Windows {
GraphList.SelectedIndex = index.Value; GraphList.SelectedIndex = index.Value;
} }
private async Task<int?> UpdateGraph(Graph g) {
List<PaymentVar> paymentVars = await Context.PaymentVariants.Where(p => p.Year == Year && p.AvNr == AvNr).ToListAsync();
if (paymentVars.Count != 1) {
return null;
}
PaymentVar paymentVar = paymentVars[0];
var data = JsonNode.Parse(paymentVar.Data).AsObject();
var auszahlungsSorten = data["AuszahlungSorten"];
if (auszahlungsSorten == null) {
return null;
}
var Graphs = auszahlungsSorten["Kurven"].AsArray();
if (Graphs == null) {
return null;
}
if (IsEditing) {
Graphs[g.Num - 1] = g.ToJson();
} else if(IsCreating) {
Graphs.Add(g.ToJson());
} else {
return null;
}
EntityEntry<PaymentVar>? tr = null;
try {
paymentVar.Data = data.ToString();
tr = Context.Update(paymentVar);
await Context.SaveChangesAsync();
} catch (Exception exc) {
if (tr != null) await tr.ReloadAsync();
var str = "Der Eintrag konnte nicht in der Datenbank gelöscht werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Graph löschen", MessageBoxButton.OK, MessageBoxImage.Error);
}
return g.Num - 1;
}
private void ResetButton_Click(object sender, RoutedEventArgs e) { private void ResetButton_Click(object sender, RoutedEventArgs e) {
if (IsEditing) { if (IsEditing) {
RefreshInputs(); RefreshInputs();