From f886888ccc6b4f9a2c96283f62cbc2dcc87bd029 Mon Sep 17 00:00:00 2001 From: Lorenz Stechauner Date: Wed, 17 Jan 2024 22:49:53 +0100 Subject: [PATCH] Billing: Split BillingData into BillingData and PaymentBillingData --- Elwig/Helpers/Billing/BillingData.cs | 135 +++----------------- Elwig/Helpers/Billing/BillingVariant.cs | 4 +- Elwig/Helpers/Billing/Graph.cs | 1 - Elwig/Helpers/Billing/PaymentBillingData.cs | 131 +++++++++++++++++++ Elwig/Windows/ChartWindow.xaml.cs | 2 +- 5 files changed, 149 insertions(+), 124 deletions(-) create mode 100644 Elwig/Helpers/Billing/PaymentBillingData.cs diff --git a/Elwig/Helpers/Billing/BillingData.cs b/Elwig/Helpers/Billing/BillingData.cs index cb9259b..f32f371 100644 --- a/Elwig/Helpers/Billing/BillingData.cs +++ b/Elwig/Helpers/Billing/BillingData.cs @@ -13,7 +13,6 @@ namespace Elwig.Helpers.Billing { public enum CalculationMode { Elwig, WgMaster } public enum CurveMode { Oe, Kmw } - public record struct Curve(CurveMode Mode, Dictionary Normal, Dictionary? Gebunden); public static JsonSchema? Schema { get; private set; } @@ -24,11 +23,7 @@ namespace Elwig.Helpers.Billing { } public readonly JsonObject Data; - - private readonly CalculationMode Mode; - private readonly Dictionary Curves; - private readonly Dictionary PaymentData; - private readonly Dictionary QualityData; + public readonly CalculationMode Mode; public bool ConsiderDelieryModifiers { get => GetConsider("consider_delivery_modifiers"); @@ -61,15 +56,10 @@ namespace Elwig.Helpers.Billing { } } - public BillingData(JsonObject data, IEnumerable attributeVariants) { - if (attributeVariants.Any(e => e.Any(c => c < 'A' || c > 'Z'))) - throw new ArgumentException("Invalid attributeVariants"); + public BillingData(JsonObject data) { Data = data; var mode = Data["mode"]?.GetValue(); Mode = (mode == "elwig") ? CalculationMode.Elwig : CalculationMode.WgMaster; - Curves = GetCurves(Data, Mode); - PaymentData = GetPaymentData(attributeVariants); - QualityData = GetQualityData(attributeVariants); } public static JsonObject ParseJson(string json) { @@ -84,11 +74,19 @@ namespace Elwig.Helpers.Billing { } public static BillingData FromJson(string json) { - return FromJson(json, []); + return new(ParseJson(json)); } - public static BillingData FromJson(string json, IEnumerable attributeVariants) { - return new(ParseJson(json), attributeVariants); + protected JsonArray GetCurvesEntry() { + return Data[Mode == CalculationMode.Elwig ? "curves" : "Kurven"]?.AsArray() ?? throw new InvalidOperationException(); + } + + protected JsonNode GetPaymentEntry() { + return Data[Mode == CalculationMode.Elwig ? "payment" : "AuszahlungSorten"] ?? throw new InvalidOperationException(); + } + + protected JsonObject? GetQualityEntry() { + return Data[Mode == CalculationMode.Elwig ? "quality" : "AuszahlungSortenQualitätsstufe"]?.AsObject(); } private static Dictionary GetCurveData(JsonObject data, CurveMode mode) { @@ -119,9 +117,9 @@ namespace Elwig.Helpers.Billing { return dict; } - public static Dictionary GetCurves(JsonObject data, CalculationMode mode) { + public Dictionary GetCurves() { var dict = new Dictionary(); - var curves = data[mode == CalculationMode.Elwig ? "curves" : "Kurven"]?.AsArray() ?? throw new InvalidOperationException(); + var curves = GetCurvesEntry(); foreach (var c in curves) { var obj = c?.AsObject() ?? throw new InvalidOperationException(); var id = obj["id"]?.GetValue() ?? throw new InvalidOperationException(); @@ -147,108 +145,5 @@ namespace Elwig.Helpers.Billing { } return dict; } - - private Dictionary GetData(JsonObject data, IEnumerable attributeVariants) { - Dictionary dict; - if (data["default"] is JsonValue def) { - var c = LookupCurve(def); - dict = attributeVariants.ToDictionary(e => e, _ => c); - } else { - dict = []; - } - - var variants = data.Where(p => !p.Key.StartsWith('/') && p.Key.Length == 2); - var attributes = data.Where(p => p.Key.StartsWith('/')); - var others = data.Where(p => !p.Key.StartsWith('/') && p.Key.Length > 2); - foreach (var (idx, v) in variants) { - var curve = LookupCurve(v?.AsValue() ?? throw new InvalidOperationException()); - foreach (var i in attributeVariants.Where(e => e.StartsWith(idx[..^1]))) { - dict[i] = curve; - } - } - foreach (var (idx, v) in attributes) { - var curve = LookupCurve(v?.AsValue() ?? throw new InvalidOperationException()); - foreach (var i in attributeVariants.Where(e => e[2..] == idx[1..])) { - dict[i] = curve; - } - } - foreach (var (idx, v) in others) { - var curve = LookupCurve(v?.AsValue() ?? throw new InvalidOperationException()); - dict[idx.Replace("/", "")] = curve; - } - - return dict; - } - - public Dictionary GetPaymentData(IEnumerable attributeVariants) { - var p = Data[Mode == CalculationMode.Elwig ? "payment" : "AuszahlungSorten"]; - if (p is JsonValue val) { - var c = LookupCurve(val); - return attributeVariants.ToDictionary(e => e, _ => c); - } - return GetData(p?.AsObject() ?? throw new InvalidOperationException(), attributeVariants); - } - - public Dictionary GetQualityData(IEnumerable attributeVariants) { - var q = Data[Mode == CalculationMode.Elwig ? "quality" : "AuszahlungSortenQualitätsstufe"]?.AsObject(); - Dictionary dict = []; - if (q == null) return dict; - - foreach (var (qualid, data) in q) { - Dictionary qualDict; - if (data is JsonValue val) { - var c = LookupCurve(val); - qualDict = attributeVariants.ToDictionary(e => e, _ => c); - } else { - qualDict = GetData(data?.AsObject() ?? throw new InvalidOperationException(), attributeVariants); - } - foreach (var (idx, d) in qualDict) { - dict[$"{qualid}/{idx}"] = d; - } - } - - return dict; - } - - public decimal CalculatePrice(string sortid, string? attrid, string qualid, bool gebunden, double oe, double kmw) { - var curve = GetQualityCurve(qualid, sortid, attrid) ?? GetCurve(sortid, attrid); - var d = (gebunden ? curve.Gebunden : null) ?? curve.Normal; - if (d.Count == 1) return d.First().Value; - - var r = curve.Mode == CurveMode.Oe ? oe : kmw; - var lt = d.Keys.Where(v => v <= r); - var gt = d.Keys.Where(v => v >= r); - if (!lt.Any()) { - return d[gt.Min()]; - } else if (!gt.Any()) { - return d[lt.Max()]; - } - - var max = lt.Max(); - var min = gt.Min(); - if (max == min) return d[r]; - - var p1 = ((decimal)r - (decimal)min) / ((decimal)max - (decimal)min); - var p2 = 1 - p1; - return d[min] * p2 + d[max] * p1; - } - - private Curve LookupCurve(JsonValue val) { - if (val.TryGetValue(out string? curve)) { - var curveId = int.Parse(curve.Split(":")[1]); - return Curves[curveId]; - } else if (val.TryGetValue(out decimal value)) { - return new(CurveMode.Oe, new() { { 73, value } }, null); - } - throw new InvalidOperationException(); - } - - public Curve GetCurve(string sortid, string? attrid) { - return PaymentData[$"{sortid}{attrid ?? ""}"]; - } - - public Curve? GetQualityCurve(string qualid, string sortid, string? attrid) { - return QualityData.TryGetValue($"{qualid}/{sortid}{attrid ?? ""}", out var curve) ? curve : null; - } } } diff --git a/Elwig/Helpers/Billing/BillingVariant.cs b/Elwig/Helpers/Billing/BillingVariant.cs index 028cb38..12216c6 100644 --- a/Elwig/Helpers/Billing/BillingVariant.cs +++ b/Elwig/Helpers/Billing/BillingVariant.cs @@ -10,7 +10,7 @@ namespace Elwig.Helpers.Billing { protected readonly int AvNr; protected readonly PaymentVar PaymentVariant; - protected readonly BillingData Data; + protected readonly PaymentBillingData Data; public BillingVariant(int year, int avnr) : base(year) { AvNr = avnr; @@ -22,7 +22,7 @@ namespace Elwig.Helpers.Billing { .ToList() .Union(Context.WineVarieties.Select(v => v.SortId)) .ToList(); - Data = BillingData.FromJson(PaymentVariant.Data, attrVariants); + Data = PaymentBillingData.FromJson(PaymentVariant.Data, attrVariants); } public async Task Calculate() { diff --git a/Elwig/Helpers/Billing/Graph.cs b/Elwig/Helpers/Billing/Graph.cs index da4f76b..7e213ea 100644 --- a/Elwig/Helpers/Billing/Graph.cs +++ b/Elwig/Helpers/Billing/Graph.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; using System.Linq; using System.Text.Json.Nodes; -using System.Windows.Documents; namespace Elwig.Helpers.Billing { public class Graph : ICloneable { diff --git a/Elwig/Helpers/Billing/PaymentBillingData.cs b/Elwig/Helpers/Billing/PaymentBillingData.cs new file mode 100644 index 0000000..696258d --- /dev/null +++ b/Elwig/Helpers/Billing/PaymentBillingData.cs @@ -0,0 +1,131 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text.Json.Nodes; + +namespace Elwig.Helpers.Billing { + public class PaymentBillingData : BillingData { + + protected readonly Dictionary Curves; + protected readonly Dictionary PaymentData; + protected readonly Dictionary QualityData; + protected readonly IEnumerable AttributeVariants; + + public PaymentBillingData(JsonObject data, IEnumerable attributeVariants) : + base(data) { + if (attributeVariants.Any(e => e.Any(c => c < 'A' || c > 'Z'))) + throw new ArgumentException("Invalid attributeVariants"); + AttributeVariants = attributeVariants; + Curves = GetCurves(); + PaymentData = GetPaymentData(); + QualityData = GetQualityData(); + } + + public static PaymentBillingData FromJson(string json, IEnumerable attributeVariants) { + return new(ParseJson(json), attributeVariants); + } + + private Dictionary GetData(JsonObject data) { + Dictionary dict; + if (data["default"] is JsonValue def) { + var c = LookupCurve(def); + dict = AttributeVariants.ToDictionary(e => e, _ => c); + } else { + dict = []; + } + + var variants = data.Where(p => !p.Key.StartsWith('/') && p.Key.Length == 2); + var attributes = data.Where(p => p.Key.StartsWith('/')); + var others = data.Where(p => !p.Key.StartsWith('/') && p.Key.Length > 2); + foreach (var (idx, v) in variants) { + var curve = LookupCurve(v?.AsValue() ?? throw new InvalidOperationException()); + foreach (var i in AttributeVariants.Where(e => e.StartsWith(idx[..^1]))) { + dict[i] = curve; + } + } + foreach (var (idx, v) in attributes) { + var curve = LookupCurve(v?.AsValue() ?? throw new InvalidOperationException()); + foreach (var i in AttributeVariants.Where(e => e[2..] == idx[1..])) { + dict[i] = curve; + } + } + foreach (var (idx, v) in others) { + var curve = LookupCurve(v?.AsValue() ?? throw new InvalidOperationException()); + dict[idx.Replace("/", "")] = curve; + } + + return dict; + } + + protected Dictionary GetPaymentData() { + var p = GetPaymentEntry(); + if (p is JsonValue val) { + var c = LookupCurve(val); + return AttributeVariants.ToDictionary(e => e, _ => c); + } + return GetData(p?.AsObject() ?? throw new InvalidOperationException()); + } + + protected Dictionary GetQualityData() { + Dictionary dict = []; + var q = GetQualityEntry(); + + foreach (var (qualid, data) in q) { + Dictionary qualDict; + if (data is JsonValue val) { + var c = LookupCurve(val); + qualDict = AttributeVariants.ToDictionary(e => e, _ => c); + } else { + qualDict = GetData(data?.AsObject() ?? throw new InvalidOperationException()); + } + foreach (var (idx, d) in qualDict) { + dict[$"{qualid}/{idx}"] = d; + } + } + + return dict; + } + + public decimal CalculatePrice(string sortid, string? attrid, string qualid, bool gebunden, double oe, double kmw) { + var curve = GetQualityCurve(qualid, sortid, attrid) ?? GetCurve(sortid, attrid); + var d = (gebunden ? curve.Gebunden : null) ?? curve.Normal; + if (d.Count == 1) return d.First().Value; + + var r = curve.Mode == CurveMode.Oe ? oe : kmw; + var lt = d.Keys.Where(v => v <= r); + var gt = d.Keys.Where(v => v >= r); + if (!lt.Any()) { + return d[gt.Min()]; + } else if (!gt.Any()) { + return d[lt.Max()]; + } + + var max = lt.Max(); + var min = gt.Min(); + if (max == min) return d[r]; + + var p1 = ((decimal)r - (decimal)min) / ((decimal)max - (decimal)min); + var p2 = 1 - p1; + return d[min] * p2 + d[max] * p1; + } + + private Curve LookupCurve(JsonValue val) { + if (val.TryGetValue(out string? curve)) { + var curveId = int.Parse(curve.Split(":")[1]); + return Curves[curveId]; + } else if (val.TryGetValue(out decimal value)) { + return new(CurveMode.Oe, new() { { 73, value } }, null); + } + throw new InvalidOperationException(); + } + + protected Curve GetCurve(string sortid, string? attrid) { + return PaymentData[$"{sortid}{attrid ?? ""}"]; + } + + protected Curve? GetQualityCurve(string qualid, string sortid, string? attrid) { + return QualityData.TryGetValue($"{qualid}/{sortid}{attrid ?? ""}", out var curve) ? curve : null; + } + } +} diff --git a/Elwig/Windows/ChartWindow.xaml.cs b/Elwig/Windows/ChartWindow.xaml.cs index bc745f8..c97bd34 100644 --- a/Elwig/Windows/ChartWindow.xaml.cs +++ b/Elwig/Windows/ChartWindow.xaml.cs @@ -71,7 +71,7 @@ namespace Elwig.Windows { var data = ParseData(PaymentVar); if (data == null) return; - var curves = BillingData.GetCurves(data, BillingData.CalculationMode.Elwig); + var curves = PaymentBillingData.GetCurves(data, BillingData.CalculationMode.Elwig); foreach (var (id, curve) in curves) { GraphEntries.Add(new GraphEntry(id, curve.Mode, curve.Normal, MinOechsle, MaxOechsle));