BillingData: Implement elwig json format parsing
This commit is contained in:
@ -1,6 +1,9 @@
|
||||
using Newtonsoft.Json;
|
||||
using NJsonSchema;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Threading.Tasks;
|
||||
@ -8,6 +11,11 @@ using System.Threading.Tasks;
|
||||
namespace Elwig.Helpers.Billing {
|
||||
public class BillingData {
|
||||
|
||||
public enum CalculationMode { Elwig, WgMaster }
|
||||
public enum CurveMode { Oe, Kmw }
|
||||
|
||||
public record struct Curve(CurveMode Mode, Dictionary<double, decimal> Normal, Dictionary<double, decimal>? Gebunden);
|
||||
|
||||
public static JsonSchema? Schema { get; private set; }
|
||||
|
||||
public static async Task Init() {
|
||||
@ -15,11 +23,21 @@ namespace Elwig.Helpers.Billing {
|
||||
Schema = await JsonSchema.FromJsonAsync(stream ?? throw new ArgumentException("JSON schema not found"));
|
||||
}
|
||||
|
||||
private JsonObject Data;
|
||||
private readonly CalculationMode Mode;
|
||||
private readonly JsonObject Data;
|
||||
private readonly Dictionary<int, Curve> Curves;
|
||||
private readonly Dictionary<string, Curve> PaymentData;
|
||||
private readonly Dictionary<string, Curve> QualityData;
|
||||
|
||||
public BillingData(JsonObject data) {
|
||||
public BillingData(JsonObject data, IEnumerable<string> attributeVariants) {
|
||||
if (attributeVariants.Any(e => e.Any(c => c < 'A' || c > 'Z')))
|
||||
throw new ArgumentException("Invalid attributeVariants");
|
||||
Data = data;
|
||||
|
||||
var mode = Data["mode"]?.GetValue<string>();
|
||||
Mode = (mode == "elwig") ? CalculationMode.Elwig : CalculationMode.WgMaster;
|
||||
Curves = GetCurves(data);
|
||||
PaymentData = GetPaymentData(attributeVariants);
|
||||
QualityData = GetQualityData(attributeVariants);
|
||||
}
|
||||
|
||||
public static JsonObject ParseJson(string json) {
|
||||
@ -33,12 +51,170 @@ namespace Elwig.Helpers.Billing {
|
||||
}
|
||||
}
|
||||
|
||||
public static BillingData FromJson(string json) {
|
||||
return new(ParseJson(json));
|
||||
public static BillingData FromJson(string json, IEnumerable<string> attributeVariants) {
|
||||
return new(ParseJson(json), attributeVariants);
|
||||
}
|
||||
|
||||
public decimal CalculatePrice(string sortId, string? attrid, string qualId, bool gebunden, double oe, double kmw, bool minQuw) {
|
||||
return 0m;
|
||||
private static Dictionary<double, decimal> GetCurveData(JsonObject data, CurveMode mode) {
|
||||
var dict = new Dictionary<double, decimal>();
|
||||
foreach (var (index, price) in data) {
|
||||
double idx;
|
||||
bool? gtlt = index.StartsWith('>') ? true : index.StartsWith('<') ? false : null;
|
||||
if (index.EndsWith("kmw")) {
|
||||
idx = double.Parse(index[(gtlt != null ? 1 : 0)..^3], CultureInfo.InvariantCulture);
|
||||
if (mode == CurveMode.Oe) {
|
||||
idx = Utils.KmwToOe(idx);
|
||||
}
|
||||
} else if (index.EndsWith("oe")) {
|
||||
idx = double.Parse(index[(gtlt != null ? 1 : 0)..^2], CultureInfo.InvariantCulture);
|
||||
if (mode == CurveMode.Kmw) {
|
||||
idx = Utils.OeToKmw(idx);
|
||||
}
|
||||
} else {
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
if (gtlt == true) {
|
||||
idx = Math.BitIncrement(idx);
|
||||
} else if (gtlt == false) {
|
||||
idx = Math.BitDecrement(idx);
|
||||
}
|
||||
dict[idx] = price?.AsValue().GetValue<decimal>() ?? throw new InvalidOperationException();
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
|
||||
public static Dictionary<int, Curve> GetCurves(JsonObject data) {
|
||||
var dict = new Dictionary<int, Curve>();
|
||||
var curves = data["curves"]?.AsArray() ?? throw new InvalidOperationException();
|
||||
foreach (var c in curves) {
|
||||
var obj = c?.AsObject() ?? throw new InvalidOperationException();
|
||||
var id = obj["id"]?.GetValue<int>() ?? throw new InvalidOperationException();
|
||||
var cMode = (obj["mode"]?.GetValue<string>() == "kmw") ? CurveMode.Kmw : CurveMode.Oe;
|
||||
|
||||
Dictionary<double, decimal> c1;
|
||||
Dictionary<double, decimal>? c2 = null;
|
||||
var norm = obj["data"];
|
||||
if (norm is JsonObject) {
|
||||
c1 = GetCurveData(norm.AsObject(), cMode);
|
||||
} else if (norm?.AsValue().TryGetValue(out decimal v) == true) {
|
||||
c1 = new() { { cMode == CurveMode.Oe ? 73 : 15, v } };
|
||||
} else {
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
var geb = obj["geb"];
|
||||
if (geb is JsonObject) {
|
||||
c2 = GetCurveData(geb.AsObject(), cMode);
|
||||
} else if (geb?.AsValue().TryGetValue(out decimal v) == true) {
|
||||
c2 = c1.ToDictionary(e => e.Key, e => e.Value + v);
|
||||
}
|
||||
dict.Add(id, new(cMode, c1, c2));
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
|
||||
private Dictionary<string, Curve> GetData(JsonObject data, IEnumerable<string> attributeVariants) {
|
||||
Dictionary<string, Curve> 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<string, Curve> GetPaymentData(IEnumerable<string> attributeVariants) {
|
||||
// TODO parse wgmaster
|
||||
var p = Data["payment"];
|
||||
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<string, Curve> GetQualityData(IEnumerable<string> attributeVariants) {
|
||||
// TODO parse wgmaster
|
||||
var q = Data["quality"]?.AsObject();
|
||||
Dictionary<string, Curve> dict = [];
|
||||
if (q == null) return dict;
|
||||
|
||||
foreach (var (qualid, data) in q) {
|
||||
Dictionary<string, Curve> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,7 @@
|
||||
}
|
||||
},
|
||||
"patternProperties": {
|
||||
"^[A-Z]+$": {
|
||||
"^([A-Z]{2})?(\/[A-Z]*)?$": {
|
||||
"type": ["number", "string"],
|
||||
"pattern": "^curve:[0-9]+$"
|
||||
}
|
||||
@ -40,7 +40,7 @@
|
||||
}
|
||||
},
|
||||
"patternProperties": {
|
||||
"^[A-Z]+$": {
|
||||
"^([A-Z]{2})?(\/[A-Z]*)?$": {
|
||||
"type": ["number", "string"],
|
||||
"pattern": "^curve:[0-9]+$"
|
||||
}
|
||||
@ -128,7 +128,7 @@
|
||||
"additionalProperties": false,
|
||||
"minProperties": 1,
|
||||
"patternProperties": {
|
||||
"^([0-9]+(\\.[0-9]+)?)(oe|kmw)$": {"type": "number"}
|
||||
"^[<>]?([0-9]+(\\.[0-9]+)?)(oe|kmw)$": {"type": "number"}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
305
Tests/Helpers/BillingDataTest.cs
Normal file
305
Tests/Helpers/BillingDataTest.cs
Normal file
@ -0,0 +1,305 @@
|
||||
using Elwig.Helpers;
|
||||
using Elwig.Helpers.Billing;
|
||||
|
||||
namespace Tests.Helpers {
|
||||
[TestFixture]
|
||||
public class BillingDataTest {
|
||||
|
||||
private static readonly string[] AttributeVariants = ["GV", "GVD", "GVK", "GVS", "GVZ", "WR", "WRS", "ZW", "ZWS", "ZWZ"];
|
||||
|
||||
[OneTimeSetUp]
|
||||
public async Task SetupBilling() {
|
||||
await BillingData.Init();
|
||||
}
|
||||
|
||||
private static (string, string?) GetSortIdAttrId(string bucket) {
|
||||
return (bucket[..2], bucket.Length > 2 ? bucket[2..] : null);
|
||||
}
|
||||
|
||||
private static string GetQualId(double kmw) {
|
||||
return kmw switch {
|
||||
>= 17.0 => "KAB",
|
||||
>= 15.0 => "QUW",
|
||||
>= 14.0 => "LDW",
|
||||
>= 10.6 => "RSW",
|
||||
_ => "WEI",
|
||||
};
|
||||
}
|
||||
|
||||
private static void TestCalcOe(BillingData data, string bucket, double oe, decimal expected, string? qualid = null, bool geb = false) {
|
||||
var (sortid, attrid) = GetSortIdAttrId(bucket);
|
||||
var kmw = Utils.OeToKmw(oe);
|
||||
var v = data.CalculatePrice(sortid, attrid, qualid ?? GetQualId(kmw), geb, oe, kmw);
|
||||
Assert.That(Math.Round(v, 6), Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
private static void TestCalcKmw(BillingData data, string bucket, double kmw, decimal expected, string? qualid = null, bool geb = false) {
|
||||
var (sortid, attrid) = GetSortIdAttrId(bucket);
|
||||
var oe = Utils.KmwToOe(kmw);
|
||||
var v = data.CalculatePrice(sortid, attrid, qualid ?? GetQualId(kmw), geb, oe, kmw);
|
||||
Assert.That(Math.Round(v, 6), Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Test_01_Flatrate() {
|
||||
var data = BillingData.FromJson("""
|
||||
{
|
||||
"mode": "elwig",
|
||||
"version": 1,
|
||||
"payment": 0.5,
|
||||
"curves": []
|
||||
}
|
||||
""", AttributeVariants);
|
||||
Assert.Multiple(() => {
|
||||
TestCalcOe(data, "GV", 73, 0.5m);
|
||||
TestCalcOe(data, "WRS", 74, 0.5m);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Test_02_Simple() {
|
||||
var data = BillingData.FromJson("""
|
||||
{
|
||||
"mode": "elwig",
|
||||
"version": 1,
|
||||
"payment": "curve:1",
|
||||
"curves": [{
|
||||
"id": 1,
|
||||
"mode": "oe",
|
||||
"data": {
|
||||
"72.0oe": 0.25,
|
||||
"15.0kmw": 0.5,
|
||||
"83oe": 1
|
||||
},
|
||||
"geb": 0.10
|
||||
}]
|
||||
}
|
||||
""", AttributeVariants);
|
||||
Assert.Multiple(() => {
|
||||
TestCalcOe(data, "GV", 70, 0.25m);
|
||||
TestCalcOe(data, "GV", 72, 0.25m);
|
||||
TestCalcOe(data, "GV", 73, 0.50m);
|
||||
TestCalcOe(data, "GV", 74, 0.55m);
|
||||
TestCalcOe(data, "GV", 80, 0.85m);
|
||||
TestCalcOe(data, "GV", 83, 1.00m);
|
||||
TestCalcOe(data, "GV", 90, 1.00m);
|
||||
TestCalcOe(data, "GV", 73, 0.60m, geb: true);
|
||||
TestCalcOe(data, "GV", 74, 0.65m, geb: true);
|
||||
TestCalcOe(data, "GV", 80, 0.95m, geb: true);
|
||||
TestCalcOe(data, "GV", 83, 1.10m, geb: true);
|
||||
TestCalcOe(data, "GV", 90, 1.10m, geb: true);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Test_03_GreaterThanAndLessThan() {
|
||||
var data = BillingData.FromJson("""
|
||||
{
|
||||
"mode": "elwig",
|
||||
"version": 1,
|
||||
"payment": "curve:1",
|
||||
"curves": [{
|
||||
"id": 1,
|
||||
"mode": "kmw",
|
||||
"data": {
|
||||
"<14kmw": 0.1,
|
||||
"14kmw": 0.2,
|
||||
"<15kmw": 0.25,
|
||||
"15kmw": 0.5,
|
||||
"17kmw": 1,
|
||||
">17kmw": 1.25
|
||||
}
|
||||
}]
|
||||
}
|
||||
""", AttributeVariants);
|
||||
Assert.Multiple(() => {
|
||||
TestCalcKmw(data, "GV", 13.00, 0.10m);
|
||||
TestCalcKmw(data, "GV", 13.50, 0.10m);
|
||||
TestCalcKmw(data, "GV", 13.99, 0.10m);
|
||||
TestCalcKmw(data, "GV", 14.00, 0.20m);
|
||||
TestCalcKmw(data, "GV", 14.50, 0.225m);
|
||||
TestCalcKmw(data, "GV", 15.00, 0.50m);
|
||||
TestCalcKmw(data, "GV", 15.50, 0.625m);
|
||||
TestCalcKmw(data, "GV", 16.00, 0.75m);
|
||||
TestCalcKmw(data, "GV", 16.50, 0.875m);
|
||||
TestCalcKmw(data, "GV", 17.00, 1.00m);
|
||||
TestCalcKmw(data, "GV", 17.01, 1.25m);
|
||||
TestCalcKmw(data, "GV", 17.50, 1.25m);
|
||||
TestCalcKmw(data, "GV", 18.00, 1.25m);
|
||||
TestCalcKmw(data, "GV", 18.50, 1.25m);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Test_04_VariantsAndAttributes() {
|
||||
var data = BillingData.FromJson("""
|
||||
{
|
||||
"mode": "elwig",
|
||||
"version": 1,
|
||||
"payment": {
|
||||
"default": 0.10,
|
||||
"GV/": 0.20,
|
||||
"ZW": 0.25,
|
||||
"/S": 0.15,
|
||||
"GV/K": 0.30
|
||||
},
|
||||
"curves": []
|
||||
}
|
||||
""", AttributeVariants);
|
||||
Assert.Multiple(() => {
|
||||
TestCalcOe(data, "WR", 73, 0.10m);
|
||||
TestCalcOe(data, "WRS", 73, 0.15m);
|
||||
TestCalcOe(data, "GV", 73, 0.20m);
|
||||
TestCalcOe(data, "GVD", 73, 0.10m);
|
||||
TestCalcOe(data, "GVK", 73, 0.30m);
|
||||
TestCalcOe(data, "GVS", 73, 0.15m);
|
||||
TestCalcOe(data, "GVZ", 73, 0.10m);
|
||||
TestCalcOe(data, "ZW", 73, 0.25m);
|
||||
TestCalcOe(data, "ZWS", 73, 0.15m);
|
||||
TestCalcOe(data, "ZWZ", 73, 0.25m);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Test_05_QualityLevel() {
|
||||
var data = BillingData.FromJson("""
|
||||
{
|
||||
"mode": "elwig",
|
||||
"version": 1,
|
||||
"payment": 0.5,
|
||||
"quality": {
|
||||
"WEI": {
|
||||
"default": 0.25,
|
||||
"GV": 0.3,
|
||||
"/S": 0.2
|
||||
}
|
||||
},
|
||||
"curves": []
|
||||
}
|
||||
""", AttributeVariants);
|
||||
Assert.Multiple(() => {
|
||||
TestCalcOe(data, "GV", 75, 0.30m, qualid: "WEI");
|
||||
TestCalcOe(data, "ZW", 76, 0.25m, qualid: "WEI");
|
||||
TestCalcOe(data, "GVS", 75, 0.20m, qualid: "WEI");
|
||||
TestCalcOe(data, "GVK", 74, 0.30m, qualid: "WEI");
|
||||
TestCalcOe(data, "ZWS", 73, 0.20m, qualid: "WEI");
|
||||
TestCalcOe(data, "GV", 70, 0.5m);
|
||||
TestCalcOe(data, "GV", 72, 0.5m);
|
||||
TestCalcOe(data, "GV", 73, 0.5m);
|
||||
TestCalcOe(data, "ZWS", 74, 0.5m);
|
||||
TestCalcOe(data, "GVK", 80, 0.5m);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Test_06_ModeOeAndKmw() {
|
||||
var data = BillingData.FromJson("""
|
||||
{
|
||||
"mode": "elwig",
|
||||
"version": 1,
|
||||
"payment": {
|
||||
"default": 1.0,
|
||||
"GV": "curve:1",
|
||||
"ZW": "curve:2"
|
||||
},
|
||||
"curves": [{
|
||||
"id": 1,
|
||||
"mode": "oe",
|
||||
"data": {
|
||||
"73oe": 2.0,
|
||||
"17kmw": 3.0
|
||||
}
|
||||
}, {
|
||||
"id": 2,
|
||||
"mode": "kmw",
|
||||
"data": {
|
||||
"73oe": 2.0,
|
||||
"17kmw": 3.0
|
||||
}
|
||||
}]
|
||||
}
|
||||
""", AttributeVariants);
|
||||
Assert.Multiple(() => {
|
||||
TestCalcKmw(data, "GV", 15.0, 2.0m);
|
||||
TestCalcKmw(data, "GV", 15.5, 2.272727m);
|
||||
TestCalcKmw(data, "GV", 16.0, 2.454545m);
|
||||
TestCalcKmw(data, "GV", 16.5, 2.727273m);
|
||||
TestCalcKmw(data, "GV", 17.0, 3.0m);
|
||||
TestCalcKmw(data, "ZW", 15.0, 2.0m);
|
||||
TestCalcKmw(data, "ZW", 15.5, 2.25m);
|
||||
TestCalcKmw(data, "ZW", 16.0, 2.50m);
|
||||
TestCalcKmw(data, "ZW", 16.5, 2.75m);
|
||||
TestCalcKmw(data, "ZW", 17.0, 3.0m);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Test_07_MultipleCurves() {
|
||||
var data = BillingData.FromJson("""
|
||||
{
|
||||
"mode": "elwig",
|
||||
"version": 1,
|
||||
"payment": {
|
||||
"default": 0.25,
|
||||
"/S": "curve:1",
|
||||
"GV/": 0.75,
|
||||
"GV/K": "curve:2",
|
||||
"WR/S": "curve:3"
|
||||
},
|
||||
"curves": [{
|
||||
"id": 3,
|
||||
"mode": "kmw",
|
||||
"data": {
|
||||
"73oe": 0.7,
|
||||
"17kmw": 0.8
|
||||
},
|
||||
"geb": {
|
||||
"15kmw": 0.8,
|
||||
"17kmw": 0.95
|
||||
}
|
||||
}, {
|
||||
"id": 1,
|
||||
"mode": "kmw",
|
||||
"data": {
|
||||
"73oe": 0.5,
|
||||
"17kmw": 0.6
|
||||
},
|
||||
"geb": 0.1
|
||||
}, {
|
||||
"id": 2,
|
||||
"mode": "kmw",
|
||||
"data": {
|
||||
"15kmw": 0.6,
|
||||
"17kmw": 0.7
|
||||
},
|
||||
"geb": {
|
||||
"73oe": 0.65,
|
||||
"17kmw": 0.80
|
||||
}
|
||||
}]
|
||||
}
|
||||
""", AttributeVariants);
|
||||
Assert.Multiple(() => {
|
||||
TestCalcKmw(data, "GV", 15.0, 0.75m);
|
||||
TestCalcKmw(data, "GVS", 15.0, 0.50m);
|
||||
TestCalcKmw(data, "GVS", 16.0, 0.55m);
|
||||
TestCalcKmw(data, "GVS", 17.0, 0.60m);
|
||||
TestCalcKmw(data, "GVS", 15.0, 0.60m, geb: true);
|
||||
TestCalcKmw(data, "GVS", 16.0, 0.65m, geb: true);
|
||||
TestCalcKmw(data, "GVS", 17.0, 0.70m, geb: true);
|
||||
TestCalcKmw(data, "GVK", 15.0, 0.60m);
|
||||
TestCalcKmw(data, "GVK", 16.0, 0.65m);
|
||||
TestCalcKmw(data, "GVK", 17.0, 0.70m);
|
||||
TestCalcKmw(data, "GVK", 15.0, 0.65m, geb: true);
|
||||
TestCalcKmw(data, "GVK", 16.0, 0.725m, geb: true);
|
||||
TestCalcKmw(data, "GVK", 17.0, 0.80m, geb: true);
|
||||
TestCalcKmw(data, "WRS", 15.0, 0.70m);
|
||||
TestCalcKmw(data, "WRS", 16.0, 0.75m);
|
||||
TestCalcKmw(data, "WRS", 17.0, 0.80m);
|
||||
TestCalcKmw(data, "WRS", 15.0, 0.80m, geb: true);
|
||||
TestCalcKmw(data, "WRS", 16.0, 0.875m, geb: true);
|
||||
TestCalcKmw(data, "WRS", 17.0, 0.95m, geb: true);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user