Billing: Add functionality to collapse curves

This commit is contained in:
2024-01-22 23:05:54 +01:00
parent 3642c5ac07
commit 05909919e2
6 changed files with 314 additions and 36 deletions

View File

@ -7,6 +7,7 @@ using System.Linq;
using System.Reflection;
using System.Text.Json.Nodes;
using System.Threading.Tasks;
using System.Windows;
namespace Elwig.Helpers.Billing {
public class BillingData {
@ -206,30 +207,41 @@ namespace Elwig.Helpers.Billing {
return curve[min] * p2 + curve[max] * p1;
}
protected static JsonNode GraphToJson(Graph graph, string mode) {
protected static JsonObject GraphToJson(Graph graph, string mode) {
var x = graph.DataX;
var y = graph.DataY;
if (y.Distinct().Count() == 1) {
return JsonValue.Create((decimal)graph.DataY[0]);
}
var prec = graph.Precision;
try {
return new JsonObject() {
["15kmw"] = Math.Round(x.Distinct().Single(), prec)
};
} catch { }
var data = new JsonObject();
if (y[0] != y[1]) {
data[$"{x[0]}{mode}"] = Math.Round(y[0], graph.Precision);
data[$"{x[0]}{mode}"] = Math.Round(y[0], prec);
}
for (int i = 1; i < x.Length - 1; i++) {
if (Math.Round(y[i] - y[i - 1], 10) != Math.Round(y[i + 1] - y[i], 10)) {
data[$"{x[i]}{mode}"] = Math.Round(y[i], graph.Precision);
var d1 = Math.Round(y[i] - y[i - 1], prec);
var d2 = Math.Round(y[i + 1] - y[i], prec);
if (d1 != d2) {
data[$"{x[i]}{mode}"] = Math.Round(y[i], prec);
}
}
if (y[^1] != y[^2]) {
data[$"{x[^1]}{mode}"] = Math.Round(y[^1], graph.Precision);
data[$"{x[^1]}{mode}"] = Math.Round(y[^1], prec);
}
return data;
}
protected static JsonObject GraphEntryToJson(GraphEntry entry) {
protected static JsonNode GraphEntryToJson(GraphEntry entry) {
try {
if (entry.GebundenFlatBonus == null) {
return JsonValue.Create((decimal)entry.DataGraph.DataY.Distinct().Single());
}
} catch { }
var curve = new JsonObject {
["id"] = entry.Id,
["mode"] = entry.Mode.ToString().ToLower(),
@ -238,7 +250,7 @@ namespace Elwig.Helpers.Billing {
curve["data"] = GraphToJson(entry.DataGraph, entry.Mode.ToString().ToLower());
if (entry.GebundenFlatBonus != null) {
curve["geb"] = entry.GebundenFlatBonus;
curve["geb"] = (decimal)entry.GebundenFlatBonus;
} else if (entry.GebundenGraph != null) {
curve["geb"] = GraphToJson(entry.GebundenGraph, entry.Mode.ToString().ToLower());
}
@ -246,31 +258,122 @@ namespace Elwig.Helpers.Billing {
return curve;
}
public JsonObject FromGraphEntries(IEnumerable<GraphEntry> graphEntries) {
protected static void CollapsePaymentData(JsonObject data) {
Dictionary<string, List<string>> rev1 = [];
Dictionary<decimal, List<string>> rev2 = [];
foreach (var (k, v) in data) {
if (k == "default" || k.StartsWith('/') || !k.Contains('/') || v is not JsonValue val) {
continue;
} else if (val.TryGetValue<decimal>(out var dec)) {
rev2[dec] = rev2.GetValueOrDefault(dec) ?? [];
rev2[dec].Add(k);
} else if (val.TryGetValue<string>(out var cur)) {
rev1[cur] = rev1.GetValueOrDefault(cur) ?? [];
rev1[cur].Add(k);
}
}
if (!data.ContainsKey("default")) {
foreach (var (v, ks) in rev1) {
if (ks.Count >= data.Count / 2.0) {
foreach (var k in ks) data.Remove(k);
data["default"] = v;
CollapsePaymentData(data);
return;
}
}
foreach (var (v, ks) in rev2) {
if (ks.Count >= data.Count / 2.0) {
foreach (var k in ks) data.Remove(k);
data["default"] = v;
CollapsePaymentData(data);
return;
}
}
}
var attributes = data
.Select(e => e.Key)
.Where(k => k.Length > 3 && k.Contains('/'))
.Select(k => "/" + k.Split('/')[1])
.Distinct()
.ToList();
foreach (var idx in attributes) {
var len = data.Count(e => e.Key.EndsWith(idx));
foreach (var (v, ks) in rev1) {
var myKs = ks.Where(k => k.EndsWith(idx)).ToList();
if (myKs.Count > 1 && myKs.Count >= len / 2.0) {
foreach (var k in myKs) data.Remove(k);
data[idx] = v;
}
}
foreach (var (v, ks) in rev2) {
var myKs = ks.Where(k => k.EndsWith(idx)).ToList();
if (myKs.Count > 1 && myKs.Count >= len / 2.0) {
foreach (var k in myKs) data.Remove(k);
data[idx] = v;
}
}
}
}
public static JsonObject FromGraphEntries(IEnumerable<GraphEntry> graphEntries, BillingData? origData = null) {
var payment = new JsonObject();
var qualityWei = new JsonObject();
var curves = new JsonArray();
int curveId = 0;
foreach (var entry in graphEntries) {
var curve = GraphEntryToJson(entry);
JsonValue node;
if (curve is JsonObject obj) {
obj["id"] = ++curveId;
node = JsonValue.Create($"curve:{curveId}");
curves.Add(obj);
} else if (curve is JsonValue val && val.TryGetValue<decimal>(out var flat)) {
node = JsonValue.Create(flat);
} else {
continue;
}
foreach (var c in entry.Contracts) {
if (entry.Abgewertet) {
qualityWei[$"{c.Variety?.SortId}/{c.Attribute?.AttrId}"] = node.DeepClone();
} else {
payment[$"{c.Variety?.SortId}/{c.Attribute?.AttrId}"] = node.DeepClone();
}
}
}
CollapsePaymentData(payment);
CollapsePaymentData(qualityWei);
var data = new JsonObject {
["mode"] = "elwig",
["version"] = 1,
};
if (ConsiderDelieryModifiers)
if (origData?.ConsiderDelieryModifiers == true)
data["consider_delivery_modifiers"] = true;
if (ConsiderContractPenalties)
if (origData?.ConsiderContractPenalties == true)
data["consider_contract_penalties"] = true;
if (ConsiderTotalPenalty)
if (origData?.ConsiderTotalPenalty == true)
data["consider_total_penalty"] = true;
if (ConsiderAutoBusinessShares)
if (origData?.ConsiderAutoBusinessShares == true)
data["consider_auto_business_shares"] = true;
var payment = new JsonObject();
var curves = new JsonArray();
foreach (var entry in graphEntries) {
curves.Add(GraphEntryToJson(entry));
foreach (var contract in entry.Contracts) {
payment[$"{contract.Variety?.SortId}/{contract.Attribute?.AttrId}"] = $"curve:{entry.Id}";
}
if (payment.Count == 0) {
data["payment"] = 0;
} else if (payment.Count == 1) {
data["payment"] = payment.Single().Value?.DeepClone();
} else {
data["payment"] = payment;
}
if (qualityWei.Count == 1) {
data["quality"] = new JsonObject() {
["WEI"] = qualityWei.Single().Value
};
} else if (qualityWei.Count > 1) {
data["quality"] = new JsonObject() {
["WEI"] = qualityWei
};
}
data["payment"] = payment;
data["curves"] = curves;
return data;