Compare commits
27 Commits
182b367811
...
v0.6.2
| Author | SHA1 | Date | |
|---|---|---|---|
| 31b0ae245d | |||
| 46498ce337 | |||
| 0fff698a5d | |||
| a71c6685f0 | |||
| ab41702f6c | |||
| 2bbf4dd1fd | |||
| 8909b4a3a8 | |||
| f8d776c028 | |||
| 2154e253ad | |||
| df83430c35 | |||
| d59a713a8c | |||
| 5e48d8e8d1 | |||
| 4f95d3fe16 | |||
| ce3185842a | |||
| e1d19fd9e5 | |||
| 3931a4084c | |||
| 1a492e4eff | |||
| 58a13eb3cc | |||
| d5124829de | |||
| 37658869e4 | |||
| 24a43ff37d | |||
| 16cf055834 | |||
| ef0b913063 | |||
| 05909919e2 | |||
| 3642c5ac07 | |||
| 6cee604448 | |||
| 89d20f4c42 |
+2
-2
@@ -7,7 +7,7 @@
|
||||
<UseWPF>true</UseWPF>
|
||||
<PreserveCompilationContext>true</PreserveCompilationContext>
|
||||
<ApplicationIcon>Resources\Images\Elwig.ico</ApplicationIcon>
|
||||
<Version>0.6.0</Version>
|
||||
<Version>0.6.1</Version>
|
||||
<SatelliteResourceLanguages>de-AT</SatelliteResourceLanguages>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.2210.55" />
|
||||
<PackageReference Include="NJsonSchema" Version="11.0.0" />
|
||||
<PackageReference Include="RazorLight" Version="2.3.1" />
|
||||
<PackageReference Include="ScottPlot.WPF" Version="4.1.68" />
|
||||
<PackageReference Include="ScottPlot.WPF" Version="5.0.19" />
|
||||
<PackageReference Include="System.IO.Ports" Version="8.0.0" />
|
||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="8.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -206,30 +206,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(graph.DataY[0]);
|
||||
}
|
||||
var prec = graph.Precision;
|
||||
|
||||
try {
|
||||
return new JsonObject() {
|
||||
["15kmw"] = Math.Round(y.Distinct().Single(), prec)
|
||||
};
|
||||
} catch { }
|
||||
|
||||
var data = new JsonObject();
|
||||
|
||||
if (y[0] != y[1]) {
|
||||
data.Add(new KeyValuePair<string, JsonNode?>(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.Add(new KeyValuePair<string, JsonNode?>(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.Add(new KeyValuePair<string, JsonNode?>(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 +249,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 +257,122 @@ namespace Elwig.Helpers.Billing {
|
||||
return curve;
|
||||
}
|
||||
|
||||
public JsonObject FromGraphEntries(IEnumerable<GraphEntry> graphEntries) {
|
||||
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}";
|
||||
protected static void CollapsePaymentData(JsonObject data, IEnumerable<string> attributeVariants) {
|
||||
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 >= attributeVariants.Count() / 2.0) {
|
||||
foreach (var k in ks) data.Remove(k);
|
||||
data["default"] = v;
|
||||
CollapsePaymentData(data, attributeVariants);
|
||||
return;
|
||||
}
|
||||
}
|
||||
foreach (var (v, ks) in rev2) {
|
||||
if (ks.Count >= attributeVariants.Count() / 2.0) {
|
||||
foreach (var k in ks) data.Remove(k);
|
||||
data["default"] = v;
|
||||
CollapsePaymentData(data, attributeVariants);
|
||||
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 = attributeVariants.Count(e => e.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, IEnumerable<string>? attributeVariants = 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, attributeVariants ?? payment.Select(e => e.Key).ToList());
|
||||
CollapsePaymentData(qualityWei, attributeVariants ?? qualityWei.Select(e => e.Key).ToList());
|
||||
|
||||
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;
|
||||
|
||||
data["payment"] = payment;
|
||||
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?.DeepClone()
|
||||
};
|
||||
} else if (qualityWei.Count > 1) {
|
||||
data["quality"] = new JsonObject() {
|
||||
["WEI"] = qualityWei
|
||||
};
|
||||
}
|
||||
data["curves"] = curves;
|
||||
|
||||
return data;
|
||||
|
||||
@@ -15,14 +15,7 @@ namespace Elwig.Helpers.Billing {
|
||||
public BillingVariant(int year, int avnr) : base(year) {
|
||||
AvNr = avnr;
|
||||
PaymentVariant = Context.PaymentVariants.Find(Year, AvNr) ?? throw new ArgumentException("PaymentVar not found");
|
||||
var attrVariants = Context.DeliveryParts
|
||||
.Where(d => d.Year == Year)
|
||||
.Select(d => $"{d.SortId}{d.AttrId}")
|
||||
.Distinct()
|
||||
.ToList()
|
||||
.Union(Context.WineVarieties.Select(v => v.SortId))
|
||||
.ToList();
|
||||
Data = PaymentBillingData.FromJson(PaymentVariant.Data, attrVariants);
|
||||
Data = PaymentBillingData.FromJson(PaymentVariant.Data, Utils.GetAttributeVarieties(Context, Year, onlyDelivered: false));
|
||||
}
|
||||
|
||||
public async Task Calculate() {
|
||||
@@ -31,9 +24,10 @@ namespace Elwig.Helpers.Billing {
|
||||
await DeleteInDb(cnx);
|
||||
await SetCalcTime(cnx);
|
||||
await CalculatePrices(cnx);
|
||||
if (Data.ConsiderDelieryModifiers)
|
||||
if (Data.ConsiderDelieryModifiers) {
|
||||
await CalculateDeliveryModifiers(cnx);
|
||||
await CalculateMemberModifiers(cnx);
|
||||
await CalculateMemberModifiers(cnx);
|
||||
}
|
||||
await tx.CommitAsync();
|
||||
}
|
||||
|
||||
@@ -146,10 +140,10 @@ namespace Elwig.Helpers.Billing {
|
||||
}
|
||||
|
||||
protected async Task CalculatePrices(SqliteConnection cnx) {
|
||||
var parts = new List<(int Year, int DId, int DPNr, int BktNr, string SortId, string Discr, int Value, double Oe, double Kmw, string QualId)>();
|
||||
var parts = new List<(int Year, int DId, int DPNr, int BktNr, string SortId, string? AttrId, string Discr, int Value, double Oe, double Kmw, string QualId)>();
|
||||
using (var cmd = cnx.CreateCommand()) {
|
||||
cmd.CommandText = $"""
|
||||
SELECT d.year, d.did, d.dpnr, b.bktnr, d.sortid, b.discr, b.value, d.oe, d.kmw, d.qualid
|
||||
SELECT d.year, d.did, d.dpnr, b.bktnr, d.sortid, d.attrid, b.discr, b.value, d.oe, d.kmw, d.qualid
|
||||
FROM delivery_part_bucket b
|
||||
JOIN v_delivery d ON (d.year, d.did, d.dpnr) = (b.year, b.did, b.dpnr)
|
||||
WHERE b.year = {Year}
|
||||
@@ -158,16 +152,18 @@ namespace Elwig.Helpers.Billing {
|
||||
while (await reader.ReadAsync()) {
|
||||
parts.Add((
|
||||
reader.GetInt32(0), reader.GetInt32(1), reader.GetInt32(2), reader.GetInt32(3),
|
||||
reader.GetString(4), reader.GetString(5), reader.GetInt32(6),
|
||||
reader.GetDouble(7), reader.GetDouble(8), reader.GetString(9)
|
||||
reader.GetString(4), reader.IsDBNull(5) ? null : reader.GetString(5), reader.GetString(6),
|
||||
reader.GetInt32(7), reader.GetDouble(8), reader.GetDouble(9), reader.GetString(10)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
var inserts = new List<(int Year, int DId, int DPNr, int BktNr, long Price, long Amount)>();
|
||||
foreach (var part in parts) {
|
||||
var attrId = (part.Discr == "_" || part.Discr == "") ? null : part.Discr;
|
||||
var price = Data.CalculatePrice(part.SortId, attrId, part.QualId, part.Discr != "_", part.Oe, part.Kmw);
|
||||
var ungeb = part.Discr == "_";
|
||||
var payAttrId = (part.Discr is "" or "_") ? null : part.Discr;
|
||||
var geb = !ungeb && payAttrId == part.AttrId;
|
||||
var price = Data.CalculatePrice(part.SortId, part.AttrId, part.QualId, geb, part.Oe, part.Kmw);
|
||||
var priceL = PaymentVariant.Season.DecToDb(price);
|
||||
inserts.Add((part.Year, part.DId, part.DPNr, part.BktNr, priceL, priceL * part.Value));
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
using Elwig.Models.Entities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Elwig.Helpers.Billing {
|
||||
public class ContractSelection : IComparable<ContractSelection> {
|
||||
@@ -16,18 +14,6 @@ namespace Elwig.Helpers.Billing {
|
||||
Attribute = attr;
|
||||
}
|
||||
|
||||
public static List<ContractSelection> GetContractsForYear(AppDbContext context, int year) {
|
||||
return context.DeliveryParts
|
||||
.Where(p => p.Year == year)
|
||||
.Select(d => new ContractSelection(d.Variant, d.Attribute))
|
||||
.Distinct()
|
||||
.ToList()
|
||||
.Union(context.WineVarieties.Select(v => new ContractSelection(v, null)))
|
||||
.DistinctBy(c => c.Listing)
|
||||
.Order()
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return Listing;
|
||||
}
|
||||
|
||||
@@ -18,11 +18,10 @@ namespace Elwig.Helpers.Billing {
|
||||
return new(ParseJson(json), attributeVariants);
|
||||
}
|
||||
|
||||
public IEnumerable<GraphEntry> GetPaymentGraphEntries(AppDbContext context, Season season) {
|
||||
private (Dictionary<int, Curve>, Dictionary<int, List<string>>) GetGraphEntries(JsonNode root) {
|
||||
Dictionary<int, List<string>> dict1 = [];
|
||||
Dictionary<decimal, List<string>> dict2 = [];
|
||||
var p = GetPaymentEntry();
|
||||
if (p is JsonObject paymentObj) {
|
||||
if (root is JsonObject paymentObj) {
|
||||
foreach (var (selector, node) in paymentObj) {
|
||||
var val = node?.AsValue();
|
||||
if (val == null) {
|
||||
@@ -36,13 +35,18 @@ namespace Elwig.Helpers.Billing {
|
||||
dict1[idx].Add(selector);
|
||||
}
|
||||
}
|
||||
} else if (p is JsonValue paymentVal) {
|
||||
var idx = paymentVal.GetValue<decimal>();
|
||||
if (!dict2.ContainsKey(idx)) dict2[idx] = [];
|
||||
dict2[idx].Add("default");
|
||||
} else if (root is JsonValue paymentVal) {
|
||||
if (paymentVal.TryGetValue<decimal>(out var price)) {
|
||||
if (!dict2.ContainsKey(price)) dict2[price] = [];
|
||||
dict2[price].Add("default");
|
||||
} else if (paymentVal.TryGetValue<string>(out var curve)) {
|
||||
var idx = int.Parse(curve.Split(":")[1] ?? "0");
|
||||
if (!dict1.ContainsKey(idx)) dict1[idx] = [];
|
||||
dict1[idx].Add("default");
|
||||
}
|
||||
}
|
||||
|
||||
var virtOffset = dict1.Count;
|
||||
var virtOffset = dict1.Count > 0 ? dict1.Max(e => e.Key) + 1 : 1;
|
||||
Dictionary<int, Curve> curves = GetCurves();
|
||||
decimal[] virtCurves = [.. dict2.Keys.Order()];
|
||||
for (int i = 0; i < virtCurves.Length; i++) {
|
||||
@@ -52,7 +56,7 @@ namespace Elwig.Helpers.Billing {
|
||||
}
|
||||
|
||||
Dictionary<int, List<string>> dict3 = curves.ToDictionary(c => c.Key, _ => new List<string>());
|
||||
foreach (var (selector, value) in GetSelection(p, AttributeVariants)) {
|
||||
foreach (var (selector, value) in GetSelection(root, AttributeVariants)) {
|
||||
int? idx = null;
|
||||
if (value.TryGetValue<decimal>(out var val)) {
|
||||
idx = Array.IndexOf(virtCurves, val) + virtOffset;
|
||||
@@ -63,45 +67,35 @@ namespace Elwig.Helpers.Billing {
|
||||
dict3[(int)idx].Add(selector);
|
||||
}
|
||||
|
||||
var vars = context.WineVarieties.ToDictionary(v => v.SortId, v => v);
|
||||
var attrs = context.WineAttributes.ToDictionary(a => a.AttrId, a => a);
|
||||
return (curves, dict3);
|
||||
}
|
||||
|
||||
return dict3
|
||||
.Select(e => new GraphEntry(e.Key, season.Precision, curves[e.Key], e.Value
|
||||
private static List<GraphEntry> CreateGraphEntries(AppDbContext ctx, int precision, Dictionary<int, Curve> curves, Dictionary<int, List<string>> entries) {
|
||||
var vars = ctx.WineVarieties.ToDictionary(v => v.SortId, v => v);
|
||||
var attrs = ctx.WineAttributes.ToDictionary(a => a.AttrId, a => a);
|
||||
return entries
|
||||
.Select(e => new GraphEntry(e.Key, precision, curves[e.Key], e.Value
|
||||
.Select(s => new ContractSelection(vars[s[..2]], s.Length > 2 ? attrs[s[2..]] : null))
|
||||
.ToList(), 50, 73, 140))
|
||||
.ToList()))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public IEnumerable<GraphEntry> GetQualityGraphEntries(AppDbContext context, Season season) {
|
||||
Dictionary<int, List<string>> dict1 = [];
|
||||
Dictionary<decimal, List<string>> dict2 = [];
|
||||
foreach (var (qualid, q) in GetQualityEntry() ?? []) {
|
||||
if (q is JsonObject qualityObj) {
|
||||
foreach (var (selector, node) in qualityObj) {
|
||||
var val = node?.AsValue();
|
||||
if (val == null) {
|
||||
continue;
|
||||
} else if (val.TryGetValue<decimal>(out var price)) {
|
||||
if (!dict2.ContainsKey(price)) dict2[price] = [];
|
||||
dict2[price].Add(selector);
|
||||
} else if (val.TryGetValue<string>(out var curve)) {
|
||||
var idx = int.Parse(curve.Split(":")[1] ?? "0");
|
||||
if (!dict1.ContainsKey(idx)) dict1[idx] = [];
|
||||
dict1[idx].Add(selector);
|
||||
}
|
||||
}
|
||||
} else if (q is JsonValue qualityVal) {
|
||||
var idx = qualityVal.GetValue<decimal>();
|
||||
if (!dict2.ContainsKey(idx)) dict2[idx] = [];
|
||||
dict2[idx].Add($"{qualid}/");
|
||||
}
|
||||
public IEnumerable<GraphEntry> GetPaymentGraphEntries(AppDbContext ctx, Season season) {
|
||||
var root = GetPaymentEntry();
|
||||
var (curves, entries) = GetGraphEntries(root);
|
||||
return CreateGraphEntries(ctx, season.Precision, curves, entries).Where(e => e.Contracts.Count > 0);
|
||||
}
|
||||
|
||||
public IEnumerable<GraphEntry> GetQualityGraphEntries(AppDbContext ctx, Season season, int idOffset = 0) {
|
||||
var root = GetQualityEntry();
|
||||
if (root == null || root["WEI"] is not JsonNode qualityWei)
|
||||
return [];
|
||||
var (curves, entries) = GetGraphEntries(qualityWei);
|
||||
var list = CreateGraphEntries(ctx, season.Precision, curves, entries).Where(e => e.Contracts.Count > 0);
|
||||
foreach (var e in list) {
|
||||
e.Id += idOffset;
|
||||
e.Abgewertet = true;
|
||||
}
|
||||
|
||||
// TODO
|
||||
|
||||
List<GraphEntry> list = [];
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using ScottPlot;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -16,18 +15,26 @@ namespace Elwig.Helpers.Billing {
|
||||
Precision = precision;
|
||||
MinX = minX;
|
||||
MaxX = maxX;
|
||||
DataX = DataGen.Range(minX, maxX + 1);
|
||||
DataY = DataGen.Zeros(maxX - minX + 1);
|
||||
DataX = Enumerable.Range(minX, maxX - minX + 1).Select(n => (double)n).ToArray();
|
||||
DataY = new double[DataX.Length];
|
||||
}
|
||||
|
||||
public Graph(Dictionary<double, decimal> data, int precision, int minX, int maxX) {
|
||||
Precision = precision;
|
||||
MinX = minX;
|
||||
MaxX = maxX;
|
||||
DataX = DataGen.Range(minX, maxX + 1);
|
||||
DataX = Enumerable.Range(minX, maxX - minX + 1).Select(n => (double)n).ToArray();
|
||||
DataY = DataX.Select(i => (double)BillingData.GetCurveValueAt(data, i)).ToArray();
|
||||
}
|
||||
|
||||
public Graph(double[] values, int precision, int minX, int maxX) {
|
||||
Precision = precision;
|
||||
MinX = minX;
|
||||
MaxX = maxX;
|
||||
DataX = Enumerable.Range(MinX, MaxX - MinX + 1).Select(i => (double)i).ToArray();
|
||||
DataY = values;
|
||||
}
|
||||
|
||||
private Graph(double[] dataX, double[] dataY, int precision, int minX, int maxX) {
|
||||
Precision = precision;
|
||||
MinX = minX;
|
||||
@@ -52,6 +59,10 @@ namespace Elwig.Helpers.Billing {
|
||||
return DataY[index];
|
||||
}
|
||||
|
||||
public double GetPriceAtOe(double oe) {
|
||||
return DataY[Array.IndexOf(DataX, oe)];
|
||||
}
|
||||
|
||||
private void FlattenGraph(int begin, int end, double value) {
|
||||
for (int i = begin; i <= end; i++) {
|
||||
DataY[i] = value;
|
||||
|
||||
@@ -1,77 +1,88 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Elwig.Helpers.Billing {
|
||||
public class GraphEntry {
|
||||
|
||||
public const int MinX = 50;
|
||||
public const int MinXGeb = 73;
|
||||
public const int MaxX = 140;
|
||||
|
||||
public int Id { get; set; }
|
||||
private readonly int Precision;
|
||||
public BillingData.CurveMode Mode { get; set; }
|
||||
public bool Abgewertet { get; set; }
|
||||
|
||||
public Graph DataGraph { get; set; }
|
||||
public Graph? GebundenGraph { get; set; }
|
||||
public decimal? GebundenFlatBonus { get; set; }
|
||||
public List<ContractSelection> Contracts { get; set; }
|
||||
public string ContractsStringSimple => Contracts.Any() ? string.Join(", ", Contracts.Select(c => c.Listing)) : "-";
|
||||
public string ContractsString => Contracts.Any() ? string.Join("\n", Contracts.Select(c => c.FullName)) : "-";
|
||||
private int MinX { get; set; }
|
||||
private int MinXGebunden { get; set; }
|
||||
private int MaxX { get; set; }
|
||||
public double? GebundenFlatBonus {
|
||||
get {
|
||||
try {
|
||||
var val = GebundenGraph?.DataX.Zip(GebundenGraph.DataY)
|
||||
.Select(e => Math.Round(e.Second - DataGraph.GetPriceAtOe(e.First), Precision))
|
||||
.Distinct()
|
||||
.Single();
|
||||
return (val == 0) ? null : val;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
set {
|
||||
if (value is not double v) return;
|
||||
var values = Enumerable.Range(MinXGeb, MaxX - MinXGeb + 1)
|
||||
.Select(i => Math.Round(DataGraph.GetPriceAtOe(i) + v, Precision))
|
||||
.ToArray();
|
||||
GebundenGraph = new Graph(values, Precision, MinXGeb, MaxX);
|
||||
}
|
||||
}
|
||||
|
||||
public GraphEntry(int id, int precision, BillingData.CurveMode mode, int minX, int minXGebunden, int maxX) {
|
||||
public List<ContractSelection> Contracts { get; set; }
|
||||
public string ContractsStringSimple => (Abgewertet ? "Abgew.: " : "") + (Contracts.Count != 0 ? (Contracts.Count >= 25 ? "Restliche Sorten" : string.Join(", ", Contracts.Select(c => c.Listing))) : "-");
|
||||
public string ContractsString => Contracts.Count != 0 ? string.Join("\n", Contracts.Select(c => c.FullName)) : "-";
|
||||
public string ContractsStringChange => (Abgewertet ? "A." : "") + string.Join(",", Contracts.Select(c => c.Listing));
|
||||
private readonly int Precision;
|
||||
|
||||
public GraphEntry(int id, int precision, BillingData.CurveMode mode) {
|
||||
Id = id;
|
||||
Precision = precision;
|
||||
Mode = mode;
|
||||
Abgewertet = false;
|
||||
MinX = minX;
|
||||
MinXGebunden = minXGebunden;
|
||||
MaxX = maxX;
|
||||
DataGraph = new Graph(precision, minX, maxX);
|
||||
DataGraph = new Graph(precision, MinX, MaxX); ;
|
||||
Contracts = [];
|
||||
}
|
||||
|
||||
public GraphEntry(int id, int precision, BillingData.CurveMode mode, Dictionary<double, decimal> data, Dictionary<double, decimal>? gebunden,
|
||||
int minX, int minXGebunden, int maxX) : this(id, precision, mode, minX, minXGebunden, maxX) {
|
||||
DataGraph = new Graph(data, precision, minX, maxX);
|
||||
if (gebunden != null) GebundenGraph = new Graph(gebunden, precision, minXGebunden, maxX);
|
||||
public GraphEntry(int id, int precision, BillingData.CurveMode mode, Dictionary<double, decimal> data, Dictionary<double, decimal>? gebunden) :
|
||||
this(id, precision, mode) {
|
||||
DataGraph = new Graph(data, precision, MinX, MaxX);
|
||||
if (gebunden != null) GebundenGraph = new Graph(gebunden, precision, MinXGeb, MaxX);
|
||||
}
|
||||
|
||||
public GraphEntry(int id, int precision, BillingData.Curve curve, List<ContractSelection> contracts, int minX, int minXGebunden, int maxX) :
|
||||
this(id, precision, curve.Mode, minX, minXGebunden, maxX) {
|
||||
DataGraph = new Graph(curve.Normal, precision, minX, maxX);
|
||||
public GraphEntry(int id, int precision, BillingData.Curve curve, List<ContractSelection> contracts) :
|
||||
this(id, precision, curve.Mode) {
|
||||
DataGraph = new Graph(curve.Normal, precision, MinX, MaxX);
|
||||
if (curve.Gebunden != null)
|
||||
GebundenGraph = new Graph(curve.Gebunden, precision, minXGebunden, maxX);
|
||||
GebundenGraph = new Graph(curve.Gebunden, precision, MinXGeb, MaxX);
|
||||
Contracts = contracts;
|
||||
}
|
||||
|
||||
private GraphEntry(int id, int precision, BillingData.CurveMode mode, Graph dataGraph, Graph? gebundenGraph,
|
||||
decimal? gebundenFlatPrice, List<ContractSelection> contracts, int minX, int minXGebunden, int maxX) {
|
||||
private GraphEntry(int id, int precision, BillingData.CurveMode mode, Graph dataGraph, Graph? gebundenGraph, List<ContractSelection> contracts) {
|
||||
Id = id;
|
||||
Precision = precision;
|
||||
Mode = mode;
|
||||
MinX = minX;
|
||||
MinXGebunden = minXGebunden;
|
||||
MaxX = maxX;
|
||||
DataGraph = dataGraph;
|
||||
GebundenGraph = gebundenGraph;
|
||||
GebundenFlatBonus = gebundenFlatPrice;
|
||||
Contracts = contracts;
|
||||
}
|
||||
|
||||
public void AddGebundenGraph() {
|
||||
GebundenGraph ??= new Graph(Precision, MinXGebunden, MaxX);
|
||||
GebundenGraph ??= new Graph(Precision, MinXGeb, MaxX);
|
||||
}
|
||||
|
||||
public void RemoveGebundenGraph() {
|
||||
GebundenGraph = null;
|
||||
}
|
||||
|
||||
public void SetGebundenFlatBonus(decimal? value) {
|
||||
GebundenFlatBonus = value;
|
||||
}
|
||||
|
||||
public GraphEntry Copy(int id) {
|
||||
return new GraphEntry(id, Precision, Mode, (Graph)DataGraph.Clone(), (Graph?)GebundenGraph?.Clone(), GebundenFlatBonus, [], MinX, MinXGebunden, MaxX);
|
||||
return new GraphEntry(id, Precision, Mode, (Graph)DataGraph.Clone(), (Graph?)GebundenGraph?.Clone(), []);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,11 +63,11 @@ namespace Elwig.Helpers.Billing {
|
||||
}
|
||||
|
||||
protected Curve GetCurve(string sortid, string? attrid) {
|
||||
return PaymentData[$"{sortid}{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;
|
||||
return QualityData.TryGetValue($"{qualid}/{sortid}{attrid}", out var curve) ? curve : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,12 +74,16 @@ namespace Elwig.Helpers.Printing {
|
||||
}
|
||||
|
||||
public static async Task Print(string path, int copies = 1) {
|
||||
var p = new Process() { StartInfo = new() { FileName = PdfToPrinter } };
|
||||
p.StartInfo.ArgumentList.Add(path);
|
||||
p.StartInfo.ArgumentList.Add("/s");
|
||||
p.StartInfo.ArgumentList.Add($"copies={copies}");
|
||||
p.Start();
|
||||
await p.WaitForExitAsync();
|
||||
try {
|
||||
var p = new Process() { StartInfo = new() { FileName = PdfToPrinter } };
|
||||
p.StartInfo.ArgumentList.Add(path);
|
||||
p.StartInfo.ArgumentList.Add("/s");
|
||||
p.StartInfo.ArgumentList.Add($"copies={copies}");
|
||||
p.Start();
|
||||
await p.WaitForExitAsync();
|
||||
} catch (Exception e) {
|
||||
MessageBox.Show("Beim Drucken ist ein Fehler aufgetreten:\n\n" + e.Message, "Fehler beim Drucken");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ using System.Text;
|
||||
using System.Numerics;
|
||||
using Elwig.Models.Entities;
|
||||
using System.IO;
|
||||
using ScottPlot.TickGenerators.TimeUnits;
|
||||
using Elwig.Helpers.Billing;
|
||||
|
||||
namespace Elwig.Helpers {
|
||||
public static partial class Utils {
|
||||
@@ -359,5 +361,23 @@ namespace Elwig.Helpers {
|
||||
}
|
||||
return output.OrderByDescending(l => l.Count());
|
||||
}
|
||||
|
||||
public static List<string> GetAttributeVarieties(AppDbContext ctx, int year, bool withSlash = false, bool onlyDelivered = true) {
|
||||
var varieties = ctx.WineVarieties.Select(v => v.SortId).ToList();
|
||||
var delivered = ctx.DeliveryParts
|
||||
.Where(d => d.Year == year)
|
||||
.Select(d => $"{d.SortId}{(withSlash ? "/" : "")}{d.AttrId}")
|
||||
.Distinct()
|
||||
.ToList();
|
||||
return [.. (onlyDelivered ? delivered : delivered.Union(varieties)).Order()];
|
||||
}
|
||||
|
||||
public static List<ContractSelection> GetContractsForYear(AppDbContext ctx, int year, bool onlyDelivered = true) {
|
||||
var varieties = ctx.WineVarieties.ToDictionary(v => v.SortId, v => v);
|
||||
var attributes = ctx.WineAttributes.ToDictionary(a => a.AttrId, a => a);
|
||||
return GetAttributeVarieties(ctx, year, false, onlyDelivered)
|
||||
.Select(s => new ContractSelection(varieties[s[..2]], s.Length > 2 ? attributes[s[2..]] : null))
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,13 @@ namespace Elwig.Models.Entities {
|
||||
[Column("fill_lower")]
|
||||
public int FillLower { get; set; }
|
||||
|
||||
public WineAttr() { }
|
||||
|
||||
public WineAttr(string attrId, string name) {
|
||||
AttrId = attrId;
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return Name;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,13 @@ namespace Elwig.Models.Entities {
|
||||
public bool IsRed => Type == "R";
|
||||
public bool IsWhite => Type == "W";
|
||||
|
||||
public WineVar() { }
|
||||
|
||||
public WineVar(string sortId, string name) {
|
||||
SortId = sortId;
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return Name;
|
||||
}
|
||||
|
||||
@@ -7,10 +7,11 @@
|
||||
xmlns:local="clr-namespace:Elwig.Windows"
|
||||
xmlns:ctrl="clr-namespace:Elwig.Controls"
|
||||
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
|
||||
xmlns:ScottPlot="clr-namespace:ScottPlot;assembly=ScottPlot.WPF"
|
||||
xmlns:ScottPlot="clr-namespace:ScottPlot.WPF;assembly=ScottPlot.WPF"
|
||||
mc:Ignorable="d"
|
||||
Title="Auszahlung - Elwig" Height="700" Width="1500" MinWidth="1000" MinHeight="500"
|
||||
Loaded="Window_Loaded">
|
||||
Loaded="Window_Loaded"
|
||||
Closing="Window_Closing">
|
||||
|
||||
<Window.Resources>
|
||||
<Style TargetType="Label">
|
||||
@@ -48,7 +49,7 @@
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="230"/>
|
||||
<ColumnDefinition Width="300"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="200"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
@@ -59,7 +60,7 @@
|
||||
<ColumnDefinition Width="100"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label Content="Für:" Margin="10,0,0,0" FontSize="14" Grid.Column="0" VerticalAlignment="Center"/>
|
||||
<Label Content="Für:" Margin="10,-2,0,0" FontSize="14" Grid.Column="0" VerticalAlignment="Center"/>
|
||||
<xctk:CheckComboBox x:Name="ContractInput" Margin="50,0,0,0" Grid.Column="0"
|
||||
Delimiter=", " AllItemsSelectedContent="Alle" IsEnabled="False" ItemSelectionChanged="ContractInput_Changed"
|
||||
Width="500" Height="25" HorizontalAlignment="Left">
|
||||
@@ -73,23 +74,23 @@
|
||||
</xctk:CheckComboBox.ItemTemplate>
|
||||
</xctk:CheckComboBox>
|
||||
|
||||
<CheckBox x:Name="AbgewertetInput" Content="Abgewertet" IsEnabled="False" Checked="AbgewertetInput_Changed"
|
||||
<CheckBox x:Name="AbgewertetInput" Content="Abgewertet" IsEnabled="False" Checked="AbgewertetInput_Changed" Unchecked="AbgewertetInput_Changed"
|
||||
VerticalAlignment="Center" HorizontalAlignment="Left" Margin="0,0,0,0" Grid.Column="1"/>
|
||||
</Grid>
|
||||
|
||||
<ListBox x:Name="GraphList" Margin="10,10,35,50" Grid.Column="0" Grid.Row="0" Grid.RowSpan="2" SelectionChanged="GraphList_SelectionChanged">
|
||||
<ListBox x:Name="GraphList" Margin="10,10,35,42" Grid.Column="0" Grid.Row="0" Grid.RowSpan="2" SelectionChanged="GraphList_SelectionChanged">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding Id}" Width="30"/>
|
||||
<TextBlock Text="{Binding ContractsStringSimple}" Width="140" ToolTip="{Binding ContractsString}"/>
|
||||
<TextBlock Text="{Binding ContractsStringSimple}" ToolTip="{Binding ContractsString}"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
|
||||
<Button x:Name="SaveButton" Content="Speichern" IsEnabled="True"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="10,5,35,15" Grid.Column="0" Grid.Row="2"
|
||||
<Button x:Name="SaveButton" Content="Speichern" IsEnabled="False"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="10,5,35,10" Grid.Column="0" Grid.Row="2"
|
||||
Click="SaveButton_Click"/>
|
||||
|
||||
<Button x:Name="AddButton" Content="" FontFamily="Segoe MDL2 Assets" FontSize="11" Padding="0,1.5,0,0" ToolTip="Neue Auszahlungsvariante hinzufügen"
|
||||
@@ -102,8 +103,9 @@
|
||||
VerticalAlignment="Center" HorizontalAlignment="Right" Width="25" Height="25" Margin="5,60,5,0" Grid.Column="0" Grid.RowSpan="2" Grid.Row="0"
|
||||
Click="DeleteButton_Click"/>
|
||||
|
||||
<Grid Grid.Row="1" Grid.Column="1">
|
||||
<ScottPlot:WpfPlot x:Name="OechslePricePlot" MouseMove="OechslePricePlot_MouseMove" MouseDown="OechslePricePlot_MouseDown" IsEnabled="False"/>
|
||||
<Grid Grid.Row="1" Grid.Column="1" Margin="0,0,10,10">
|
||||
<ScottPlot:WpfPlot x:Name="OechslePricePlot" IsEnabled="False"
|
||||
MouseWheel="OechslePricePlot_MouseWheel" MouseMove="OechslePricePlot_MouseMove" MouseDown="OechslePricePlot_MouseDown"/>
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Row="1" Grid.Column="2" Margin="0,0,5,36">
|
||||
@@ -133,41 +135,30 @@
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Header="Gebunden" Grid.Row="1" Margin="0,5,5,5">
|
||||
<GroupBox Header="Gebunden Aufschlag" Grid.Row="1" Margin="0,5,5,5">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="85"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<StackPanel Margin="10,10,0,0">
|
||||
<RadioButton x:Name="GebundenTypeFixed" GroupName="GebundenType" Checked="GebundenType_Checked" IsEnabled="False">Fix</RadioButton>
|
||||
<RadioButton x:Name="GebundenTypeGraph" GroupName="GebundenType" Checked="GebundenType_Checked" IsEnabled="False">Graph</RadioButton>
|
||||
<RadioButton x:Name="GebundenTypeGraph" GroupName="GebundenType" Checked="GebundenType_Checked" IsEnabled="False">Frei</RadioButton>
|
||||
<RadioButton x:Name="GebundenTypeNone" GroupName="GebundenType" Checked="GebundenType_Checked" IsEnabled="False">Nein</RadioButton>
|
||||
</StackPanel>
|
||||
|
||||
<ctrl:UnitTextBox x:Name="GebundenFlatBonus" Unit="€/kg" TextChanged="GebundenFlatBonus_TextChanged" IsEnabled="False"
|
||||
Width="90" Margin="0,5,0,0" HorizontalAlignment="Left" VerticalAlignment="Top" Grid.Column="1"/>
|
||||
Width="90" Margin="5,5,5,5" HorizontalAlignment="Right" VerticalAlignment="Top" Grid.Column="1"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Header="Aktionen" Grid.Row="2" Margin="0,5,5,5">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Button x:Name="LeftFlatButton" Content="Links flach" Click="LeftFlatButton_Click" IsEnabled="False"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Top" Margin="10,10,10,10"/>
|
||||
|
||||
<Button x:Name="RightFlatButton" Content="Rechts flach" Click="RightFlatButton_Click" IsEnabled="False"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Top" Margin="10,50,10,10"/>
|
||||
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Top" Margin="10,45,10,10"/>
|
||||
<Button x:Name="InterpolateButton" Content="Interpolieren" Click="InterpolateButton_Click" IsEnabled="False"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Top" Margin="10,90,10,10"/>
|
||||
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Top" Margin="10,80,10,10"/>
|
||||
<Button x:Name="LinearIncreaseButton" Content="Linear wachsen" Click="LinearIncreaseButton_Click" IsEnabled="False"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Top" Margin="10,130,10,10"/>
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Top" Margin="10,115,10,10"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
|
||||
+289
-154
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
@@ -10,29 +9,35 @@ using Elwig.Controls;
|
||||
using Elwig.Helpers;
|
||||
using Elwig.Helpers.Billing;
|
||||
using Elwig.Models.Entities;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
||||
using ScottPlot.Plottables;
|
||||
using ScottPlot;
|
||||
using ScottPlot.Plottable;
|
||||
using Xceed.Wpf.Toolkit.Primitives;
|
||||
using ScottPlot.Control;
|
||||
|
||||
namespace Elwig.Windows {
|
||||
public partial class ChartWindow : ContextWindow {
|
||||
|
||||
public static readonly Color ColorUngebunden = Color.Blue;
|
||||
public static readonly Color ColorGebunden = Color.Gold;
|
||||
public static readonly Color ColorUngebunden = Colors.Blue;
|
||||
public static readonly Color ColorGebunden = Colors.Gold;
|
||||
|
||||
public readonly int Year;
|
||||
public readonly int AvNr;
|
||||
public Season Season;
|
||||
private PaymentVar PaymentVar;
|
||||
private bool HasChanged = false;
|
||||
|
||||
private ScatterPlot DataPlot;
|
||||
private ScatterPlot? GebundenPlot;
|
||||
private MarkerPlot HighlightedPointPlot;
|
||||
private MarkerPlot PrimaryMarkedPointPlot;
|
||||
private MarkerPlot SecondaryMarkedPointPlot;
|
||||
private Tooltip TooltipPlot;
|
||||
private Scatter DataPlot;
|
||||
private Scatter? GebundenPlot;
|
||||
private Marker HighlightedPointPlot;
|
||||
private Marker PrimaryMarkedPointPlot;
|
||||
private Marker SecondaryMarkedPointPlot;
|
||||
private Text TooltipPlot;
|
||||
private LegendItem UngebundenLegend;
|
||||
private LegendItem GebundenLegend;
|
||||
private LegendItem LDWLegend;
|
||||
private LegendItem QUWLegend;
|
||||
private LegendItem KABLegend;
|
||||
|
||||
private (Graph? graph, int index) LastHighlighted = (null, -1);
|
||||
private (Graph? graph, int index) Highlighted = (null, -1);
|
||||
@@ -43,12 +48,8 @@ namespace Elwig.Windows {
|
||||
private bool HoverActive = false;
|
||||
private bool FillingInputs = false;
|
||||
|
||||
private const int MinOechsle = 50;
|
||||
private const int MinOechsleGebunden = 73;
|
||||
private const int MaxOechsle = 140;
|
||||
|
||||
private List<GraphEntry> GraphEntries = [];
|
||||
private GraphEntry? SelectedGraphEntry;
|
||||
private GraphEntry? SelectedGraphEntry => (GraphEntry)GraphList.SelectedItem;
|
||||
|
||||
public ChartWindow(int year, int avnr) {
|
||||
InitializeComponent();
|
||||
@@ -57,33 +58,44 @@ namespace Elwig.Windows {
|
||||
Season = Context.Seasons.Find(year) ?? throw new ArgumentException("Season not found");
|
||||
PaymentVar = Context.PaymentVariants.Find(year, avnr) ?? throw new ArgumentException("PaymentVar not found");
|
||||
Title = $"{PaymentVar?.Name} - Lese {year} - Elwig";
|
||||
LockContext = true;
|
||||
}
|
||||
|
||||
private void Window_Loaded(object sender, RoutedEventArgs evt) {
|
||||
OechslePricePlot.IsEnabled = false;
|
||||
}
|
||||
|
||||
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) {
|
||||
if (HasChanged) {
|
||||
var r = MessageBox.Show("Soll das Fenster wirklich geschlossen werden? Nicht gespeicherte Änderungen werden NICHT übernommen!", "Schließen bestätigen",
|
||||
MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No);
|
||||
if (r != MessageBoxResult.Yes) {
|
||||
e.Cancel = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetHasChanged(bool hasChanged = true) {
|
||||
HasChanged = hasChanged;
|
||||
SaveButton.IsEnabled = hasChanged;
|
||||
}
|
||||
|
||||
private async Task RefreshGraphList() {
|
||||
PaymentVar = await Context.PaymentVariants.FindAsync(Year, AvNr) ?? throw new ArgumentException("PaymentVar not found");
|
||||
Season = await Context.Seasons.FindAsync(Year) ?? throw new ArgumentException("Season not found");
|
||||
|
||||
var attrVariants = (await Context.DeliveryParts
|
||||
.Where(d => d.Year == Year)
|
||||
.Select(d => $"{d.SortId}{d.AttrId}")
|
||||
.Distinct()
|
||||
.ToListAsync())
|
||||
.Union(Context.WineVarieties.Select(v => v.SortId))
|
||||
.Order()
|
||||
.ToList();
|
||||
var data = EditBillingData.FromJson(PaymentVar.Data, attrVariants);
|
||||
GraphEntries = [ ..data.GetPaymentGraphEntries(Context, Season), ..data.GetQualityGraphEntries(Context, Season)];
|
||||
var data = EditBillingData.FromJson(PaymentVar.Data, Utils.GetAttributeVarieties(Context, Year));
|
||||
var paymentEntries = data.GetPaymentGraphEntries(Context, Season);
|
||||
GraphEntries = [
|
||||
..paymentEntries,
|
||||
..data.GetQualityGraphEntries(Context, Season, paymentEntries.Max(e => e.Id))
|
||||
];
|
||||
|
||||
var contracts = ContractSelection.GetContractsForYear(Context, Year);
|
||||
var contracts = Utils.GetContractsForYear(Context, Year);
|
||||
FillingInputs = true;
|
||||
ControlUtils.RenewItemsSource(ContractInput, contracts, g => (g as ContractSelection)?.Listing);
|
||||
FillingInputs = false;
|
||||
ControlUtils.RenewItemsSource(GraphList, GraphEntries, g => (g as GraphEntry)?.Id, GraphList_SelectionChanged, ControlUtils.RenewSourceDefault.First);
|
||||
SelectedGraphEntry = GraphList.SelectedItem as GraphEntry;
|
||||
ControlUtils.RenewItemsSource(GraphList, GraphEntries, g => (g as GraphEntry)?.ContractsStringChange, GraphList_SelectionChanged, ControlUtils.RenewSourceDefault.First);
|
||||
|
||||
RefreshInputs();
|
||||
}
|
||||
@@ -93,7 +105,6 @@ namespace Elwig.Windows {
|
||||
if (SelectedGraphEntry != null) {
|
||||
CopyButton.IsEnabled = true;
|
||||
DeleteButton.IsEnabled = true;
|
||||
//EnableUnitTextBox(OechsleInput);
|
||||
GebundenTypeFixed.IsEnabled = true;
|
||||
GebundenTypeGraph.IsEnabled = true;
|
||||
GebundenTypeNone.IsEnabled = true;
|
||||
@@ -125,12 +136,16 @@ namespace Elwig.Windows {
|
||||
private void FillInputs() {
|
||||
FillingInputs = true;
|
||||
|
||||
if (SelectedGraphEntry?.GebundenFlatBonus != null) {
|
||||
AbgewertetInput.IsChecked = SelectedGraphEntry?.Abgewertet;
|
||||
if (SelectedGraphEntry?.GebundenFlatBonus is double bonus) {
|
||||
GebundenTypeFixed.IsChecked = true;
|
||||
GebundenFlatBonus.Text = $"{bonus}";
|
||||
} else if (SelectedGraphEntry?.GebundenGraph != null) {
|
||||
GebundenTypeGraph.IsChecked = true;
|
||||
GebundenFlatBonus.Text = "";
|
||||
} else {
|
||||
GebundenTypeNone.IsChecked = true;
|
||||
GebundenFlatBonus.Text = "";
|
||||
}
|
||||
|
||||
ControlUtils.SelectCheckComboBoxItems(ContractInput, SelectedGraphEntry?.Contracts ?? [], i => (i as ContractSelection)?.Listing);
|
||||
@@ -145,55 +160,98 @@ namespace Elwig.Windows {
|
||||
}
|
||||
|
||||
private void InitPlot() {
|
||||
UngebundenLegend = new LegendItem() {
|
||||
Label = "Ungebunden",
|
||||
LineWidth = 1,
|
||||
LineColor = ColorUngebunden,
|
||||
Marker = new MarkerStyle(MarkerShape.FilledCircle, 5, ColorUngebunden)
|
||||
};
|
||||
|
||||
GebundenLegend = new LegendItem() {
|
||||
Label = "Gebunden",
|
||||
LineWidth = 1,
|
||||
LineColor = ColorGebunden,
|
||||
Marker = new MarkerStyle(MarkerShape.FilledCircle, 5, ColorGebunden)
|
||||
};
|
||||
|
||||
LDWLegend = new LegendItem() {
|
||||
Label = "68 °Oe (LDW)",
|
||||
LineWidth = 2,
|
||||
LineColor = Colors.Red,
|
||||
Marker = MarkerStyle.None
|
||||
};
|
||||
|
||||
QUWLegend = new LegendItem() {
|
||||
Label = "73 °Oe (QUW)",
|
||||
LineWidth = 2,
|
||||
LineColor = Colors.Orange,
|
||||
Marker = MarkerStyle.None
|
||||
};
|
||||
|
||||
KABLegend = new LegendItem() {
|
||||
Label = "84 °Oe (KAB)",
|
||||
LineWidth = 2,
|
||||
LineColor = Colors.Green,
|
||||
Marker = MarkerStyle.None
|
||||
};
|
||||
|
||||
RefreshGradationLines();
|
||||
|
||||
if (SelectedGraphEntry?.GebundenGraph != null) {
|
||||
GebundenPlot = OechslePricePlot.Plot.AddScatter(SelectedGraphEntry.GebundenGraph.DataX, SelectedGraphEntry.GebundenGraph.DataY, label: "Gebunden");
|
||||
GebundenPlot.LineColor = ColorGebunden;
|
||||
GebundenPlot.MarkerColor = ColorGebunden;
|
||||
GebundenPlot.MarkerSize = 9;
|
||||
GebundenPlot = OechslePricePlot.Plot.Add.Scatter(SelectedGraphEntry.GebundenGraph.DataX, SelectedGraphEntry.GebundenGraph.DataY);
|
||||
GebundenPlot.LineStyle.Color = ColorGebunden;
|
||||
GebundenPlot.Color = ColorGebunden;
|
||||
GebundenPlot.MarkerStyle = new MarkerStyle(MarkerShape.FilledCircle, 9, ColorGebunden);
|
||||
}
|
||||
|
||||
DataPlot = OechslePricePlot.Plot.AddScatter(SelectedGraphEntry!.DataGraph.DataX, SelectedGraphEntry!.DataGraph.DataY, label: "Ungebunden");
|
||||
DataPlot.LineColor = ColorUngebunden;
|
||||
DataPlot.MarkerColor = ColorUngebunden;
|
||||
DataPlot.MarkerSize = 9;
|
||||
DataPlot = OechslePricePlot.Plot.Add.Scatter(SelectedGraphEntry!.DataGraph.DataX, SelectedGraphEntry!.DataGraph.DataY);
|
||||
DataPlot.LineStyle.Color = ColorUngebunden;
|
||||
DataPlot.Color = ColorUngebunden;
|
||||
DataPlot.MarkerStyle = new MarkerStyle(MarkerShape.FilledCircle, 9, ColorUngebunden);
|
||||
|
||||
if (SelectedGraphEntry?.GebundenGraph == null) {
|
||||
ChangeActiveGraph(SelectedGraphEntry?.DataGraph);
|
||||
}
|
||||
|
||||
OechslePricePlot.RightClicked -= OechslePricePlot.DefaultRightClickEvent;
|
||||
OechslePricePlot.Configuration.DoubleClickBenchmark = false;
|
||||
//OechslePricePlot.Plot.XAxis.ManualTickSpacing(1);
|
||||
OechslePricePlot.Plot.YAxis.ManualTickSpacing(0.1);
|
||||
OechslePricePlot.Plot.SetAxisLimits(Math.Min(MinOechsle, MinOechsleGebunden) - 1, MaxOechsle + 1, -0.1, 2);
|
||||
|
||||
OechslePricePlot.Plot.Layout(padding: 0);
|
||||
OechslePricePlot.Plot.XAxis2.Layout(padding: 0);
|
||||
OechslePricePlot.Plot.YAxis.Layout(padding: 0);
|
||||
OechslePricePlot.Plot.YAxis2.Layout(padding: 0);
|
||||
OechslePricePlot.Interaction.Enable(new PlotActions() {
|
||||
ZoomIn = StandardActions.ZoomIn,
|
||||
ZoomOut = StandardActions.ZoomOut,
|
||||
PanUp = StandardActions.PanUp,
|
||||
PanDown = StandardActions.PanDown,
|
||||
PanLeft = StandardActions.PanLeft,
|
||||
PanRight = StandardActions.PanRight,
|
||||
DragPan = StandardActions.DragPan,
|
||||
DragZoom = StandardActions.DragZoom,
|
||||
DragZoomRectangle = StandardActions.DragZoomRectangle,
|
||||
ZoomRectangleClear = StandardActions.ZoomRectangleClear,
|
||||
ZoomRectangleApply = StandardActions.ZoomRectangleApply,
|
||||
AutoScale = StandardActions.AutoScale,
|
||||
});
|
||||
|
||||
HighlightedPointPlot = OechslePricePlot.Plot.AddPoint(0, 0);
|
||||
HighlightedPointPlot.Color = Color.Red;
|
||||
HighlightedPointPlot.MarkerSize = 10;
|
||||
HighlightedPointPlot.MarkerShape = MarkerShape.openCircle;
|
||||
//OechslePricePlot.Plot.XAxis.ManualTickSpacing(1);
|
||||
//OechslePricePlot.Plot.YAxis.ManualTickSpacing(0.1);
|
||||
OechslePricePlot.Plot.Axes.SetLimits(Math.Min(GraphEntry.MinX, GraphEntry.MinXGeb) - 1, GraphEntry.MaxX + 1, -0.1, 2);
|
||||
|
||||
//OechslePricePlot.Plot.Layout(padding: 0);
|
||||
//OechslePricePlot.Plot.XAxis2.Layout(padding: 0);
|
||||
//OechslePricePlot.Plot.YAxis.Layout(padding: 0);
|
||||
//OechslePricePlot.Plot.YAxis2.Layout(padding: 0);
|
||||
|
||||
HighlightedPointPlot = OechslePricePlot.Plot.Add.Marker(0, 0, MarkerShape.OpenCircle, 10, Colors.Red);
|
||||
HighlightedPointPlot.IsVisible = false;
|
||||
|
||||
PrimaryMarkedPointPlot = OechslePricePlot.Plot.AddPoint(0, 0);
|
||||
PrimaryMarkedPointPlot.Color = Color.Red;
|
||||
PrimaryMarkedPointPlot.MarkerSize = 6;
|
||||
PrimaryMarkedPointPlot.MarkerShape = MarkerShape.filledCircle;
|
||||
PrimaryMarkedPointPlot = OechslePricePlot.Plot.Add.Marker(0, 0, MarkerShape.FilledCircle, 6, Colors.Red);
|
||||
PrimaryMarkedPointPlot.IsVisible = false;
|
||||
|
||||
SecondaryMarkedPointPlot = OechslePricePlot.Plot.AddPoint(0, 0);
|
||||
SecondaryMarkedPointPlot.Color = Color.Red;
|
||||
SecondaryMarkedPointPlot.MarkerSize = 6;
|
||||
SecondaryMarkedPointPlot.MarkerShape = MarkerShape.filledCircle;
|
||||
SecondaryMarkedPointPlot = OechslePricePlot.Plot.Add.Marker(0, 0, MarkerShape.FilledCircle, 6, Colors.Red);
|
||||
SecondaryMarkedPointPlot.IsVisible = false;
|
||||
|
||||
|
||||
|
||||
OechslePricePlot.Refresh();
|
||||
|
||||
RefreshFreeZoom();
|
||||
RefreshGradationLines();
|
||||
OechslePricePlot.Refresh();
|
||||
}
|
||||
|
||||
private void ResetPlot() {
|
||||
@@ -202,22 +260,20 @@ namespace Elwig.Windows {
|
||||
ChangeActiveGraph(null);
|
||||
HideGradationLines();
|
||||
OechslePricePlot.Plot.Remove(DataPlot);
|
||||
OechslePricePlot.Plot.Remove(GebundenPlot);
|
||||
if (GebundenPlot != null) {
|
||||
OechslePricePlot.Plot.Remove(GebundenPlot);
|
||||
GebundenPlot = null;
|
||||
}
|
||||
OechslePricePlot.Plot.Clear();
|
||||
OechslePricePlot.Reset();
|
||||
OechslePricePlot.Refresh();
|
||||
}
|
||||
|
||||
private void ChangeMarker(MarkerPlot point, bool visible, double x = 0, double y = 0) {
|
||||
point.X = x;
|
||||
point.Y = y;
|
||||
private void ChangeMarker(Marker point, bool visible, double x = 0, double y = 0) {
|
||||
point.Location = new Coordinates(x, y);
|
||||
point.IsVisible = visible;
|
||||
}
|
||||
|
||||
private void LinearIncreaseGraph(int begin, int end, double inc) {
|
||||
|
||||
}
|
||||
|
||||
private void EnableActionButtons() {
|
||||
if (PaymentVar.TestVariant) {
|
||||
LeftFlatButton.IsEnabled = true;
|
||||
@@ -247,18 +303,32 @@ namespace Elwig.Windows {
|
||||
}
|
||||
|
||||
private void LockZoom() {
|
||||
OechslePricePlot.Plot.XAxis.SetBoundary(MinOechsle - 1, MaxOechsle + 1);
|
||||
OechslePricePlot.Plot.YAxis.SetBoundary(-0.1, 2);
|
||||
OechslePricePlot.Plot.XAxis.SetZoomOutLimit(MaxOechsle - MinOechsle + 2);
|
||||
OechslePricePlot.Plot.YAxis.SetZoomOutLimit(2.1);
|
||||
OechslePricePlot.Plot.SetAxisLimits(MinOechsle - 1, MaxOechsle + 1, -0.1, 2);
|
||||
ScottPlot.AxisRules.MaximumBoundary BoundaryRule = new(
|
||||
xAxis: OechslePricePlot.Plot.Axes.Bottom,
|
||||
yAxis: OechslePricePlot.Plot.Axes.Left,
|
||||
limits: new AxisLimits(GraphEntry.MinX - 1, GraphEntry.MaxX + 1, -0.1, 2));
|
||||
|
||||
ScottPlot.AxisRules.MaximumSpan SpanRule = new(
|
||||
xAxis: OechslePricePlot.Plot.Axes.Bottom,
|
||||
yAxis: OechslePricePlot.Plot.Axes.Left,
|
||||
xSpan: GraphEntry.MaxX - GraphEntry.MinX + 2,
|
||||
ySpan: 2.1);
|
||||
|
||||
OechslePricePlot.Plot.Axes.Rules.Clear();
|
||||
OechslePricePlot.Plot.Axes.Rules.Add(BoundaryRule);
|
||||
OechslePricePlot.Plot.Axes.Rules.Add(SpanRule);
|
||||
OechslePricePlot.Plot.Axes.SetLimits(GraphEntry.MinX - 1, GraphEntry.MaxX + 1, -0.1, 2);
|
||||
}
|
||||
|
||||
private void UnlockZoom() {
|
||||
OechslePricePlot.Plot.XAxis.SetBoundary();
|
||||
OechslePricePlot.Plot.YAxis.SetBoundary();
|
||||
OechslePricePlot.Plot.XAxis.SetZoomOutLimit((MaxOechsle - MinOechsle) * 1.5);
|
||||
OechslePricePlot.Plot.YAxis.SetZoomOutLimit(3.5);
|
||||
ScottPlot.AxisRules.MaximumSpan SpanRule = new(
|
||||
xAxis: OechslePricePlot.Plot.Axes.Bottom,
|
||||
yAxis: OechslePricePlot.Plot.Axes.Left,
|
||||
xSpan: (GraphEntry.MaxX - GraphEntry.MinX) * 1.5,
|
||||
ySpan: 3.5);
|
||||
|
||||
OechslePricePlot.Plot.Axes.Rules.Clear();
|
||||
OechslePricePlot.Plot.Axes.Rules.Add(SpanRule);
|
||||
}
|
||||
|
||||
private void EnableOptionButtons() {
|
||||
@@ -278,7 +348,7 @@ namespace Elwig.Windows {
|
||||
}
|
||||
|
||||
private void RefreshGradationLines() {
|
||||
if (GradationLinesInput.IsChecked == true && SelectedGraphEntry != null && !OechslePricePlot.Plot.GetPlottables().OfType<VLine>().Any()) {
|
||||
if (GradationLinesInput.IsChecked == true && SelectedGraphEntry != null && !OechslePricePlot.Plot.PlottableList.OfType<VerticalLine>().Any()) {
|
||||
ShowGradationLines();
|
||||
ShowLegend();
|
||||
} else if (GradationLinesInput.IsChecked == false) {
|
||||
@@ -289,21 +359,29 @@ namespace Elwig.Windows {
|
||||
}
|
||||
|
||||
private void ShowGradationLines() {
|
||||
OechslePricePlot.Plot.AddVerticalLine(68, Color.Red, 2, label: "68 °Oe (LDW)");
|
||||
OechslePricePlot.Plot.AddVerticalLine(73, Color.Orange, 2, label: "73 °Oe (QUW)");
|
||||
OechslePricePlot.Plot.AddVerticalLine(84, Color.Green, 2, label: "84 °Oe (KAB)");
|
||||
OechslePricePlot.Plot.Add.VerticalLine(68, 2, Colors.Red);
|
||||
OechslePricePlot.Plot.Add.VerticalLine(73, 2, Colors.Orange);
|
||||
OechslePricePlot.Plot.Add.VerticalLine(84, 2, Colors.Green);
|
||||
}
|
||||
|
||||
private void HideGradationLines() {
|
||||
OechslePricePlot.Plot.Clear(typeof(VLine));
|
||||
OechslePricePlot.Plot.PlottableList.RemoveAll(p => p is VerticalLine);
|
||||
}
|
||||
|
||||
private void ShowLegend() {
|
||||
OechslePricePlot.Plot.Legend(true, Alignment.UpperLeft);
|
||||
OechslePricePlot.Plot.Legend.Location = Alignment.UpperLeft;
|
||||
OechslePricePlot.Plot.Legend.IsVisible = true;
|
||||
|
||||
OechslePricePlot.Plot.Legend.ManualItems.Add(LDWLegend);
|
||||
OechslePricePlot.Plot.Legend.ManualItems.Add(QUWLegend);
|
||||
OechslePricePlot.Plot.Legend.ManualItems.Add(KABLegend);
|
||||
OechslePricePlot.Plot.Legend.ManualItems.Add(UngebundenLegend);
|
||||
if (SelectedGraphEntry?.GebundenGraph != null) OechslePricePlot.Plot.Legend.ManualItems.Add(GebundenLegend);
|
||||
}
|
||||
|
||||
private void HideLegend() {
|
||||
OechslePricePlot.Plot.Legend(false, Alignment.UpperLeft);
|
||||
OechslePricePlot.Plot.Legend.IsVisible = false;
|
||||
OechslePricePlot.Plot.Legend.ManualItems.Clear();
|
||||
}
|
||||
|
||||
private void OechsleInput_TextChanged(object sender, TextChangedEventArgs evt) {
|
||||
@@ -321,33 +399,33 @@ namespace Elwig.Windows {
|
||||
PrimaryMarkedPoint = oechsle - ActiveGraph.MinX;
|
||||
ChangeMarker(PrimaryMarkedPointPlot, true, ActiveGraph.GetOechsleAt(PrimaryMarkedPoint), ActiveGraph.GetPriceAt(PrimaryMarkedPoint));
|
||||
|
||||
PriceInput.Text = ActiveGraph.GetPriceAt(PrimaryMarkedPoint).ToString();
|
||||
PriceInput.Text = Math.Round(ActiveGraph.GetPriceAt(PrimaryMarkedPoint), Season.Precision).ToString();
|
||||
|
||||
EnableActionButtons();
|
||||
OechslePricePlot.Render();
|
||||
OechslePricePlot.Refresh();
|
||||
EnableUnitTextBox(PriceInput);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
PrimaryMarkedPoint = -1;
|
||||
//ChangeActiveGraph(null);
|
||||
ChangeMarker(PrimaryMarkedPointPlot, false);
|
||||
DisableActionButtons();
|
||||
PriceInput.Text = "";
|
||||
DisableUnitTextBox(PriceInput);
|
||||
OechslePricePlot.Render();
|
||||
OechslePricePlot.Refresh();
|
||||
DisableUnitTextBox(PriceInput);
|
||||
}
|
||||
|
||||
private void PriceInput_TextChanged(object sender, TextChangedEventArgs evt) {
|
||||
if (PrimaryMarkedPoint != -1 && ActiveGraph != null) {
|
||||
bool success = double.TryParse(PriceInput.Text, out double price);
|
||||
|
||||
if (success) {
|
||||
if (PrimaryMarkedPoint != -1 && ActiveGraph != null && PriceInput.IsKeyboardFocusWithin == true) {
|
||||
var res = Validator.CheckDecimal(PriceInput.TextBox, true, 2, Season.Precision);
|
||||
if (res.IsValid && double.TryParse(PriceInput.Text, out double price)) {
|
||||
ActiveGraph.SetPriceAt(PrimaryMarkedPoint, price);
|
||||
PrimaryMarkedPointPlot.Y = price;
|
||||
PrimaryMarkedPointPlot.Location = new Coordinates(PrimaryMarkedPointPlot.Location.X, price);
|
||||
SetHasChanged();
|
||||
OechslePricePlot.Refresh();
|
||||
CheckGebundenTypeFixed();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -357,7 +435,9 @@ namespace Elwig.Windows {
|
||||
return;
|
||||
}
|
||||
ActiveGraph.FlattenGraphLeft(PrimaryMarkedPoint);
|
||||
OechslePricePlot.Render();
|
||||
SetHasChanged();
|
||||
OechslePricePlot.Refresh();
|
||||
CheckGebundenTypeFixed();
|
||||
}
|
||||
|
||||
private void RightFlatButton_Click(object sender, RoutedEventArgs evt) {
|
||||
@@ -365,7 +445,9 @@ namespace Elwig.Windows {
|
||||
return;
|
||||
}
|
||||
ActiveGraph.FlattenGraphRight(PrimaryMarkedPoint);
|
||||
OechslePricePlot.Render();
|
||||
SetHasChanged();
|
||||
OechslePricePlot.Refresh();
|
||||
CheckGebundenTypeFixed();
|
||||
}
|
||||
|
||||
private void InterpolateButton_Click(object sender, RoutedEventArgs evt) {
|
||||
@@ -373,7 +455,9 @@ namespace Elwig.Windows {
|
||||
return;
|
||||
}
|
||||
ActiveGraph.InterpolateGraph(PrimaryMarkedPoint, SecondaryMarkedPoint);
|
||||
OechslePricePlot.Render();
|
||||
SetHasChanged();
|
||||
OechslePricePlot.Refresh();
|
||||
CheckGebundenTypeFixed();
|
||||
}
|
||||
|
||||
private void LinearIncreaseButton_Click(object sender, RoutedEventArgs e) {
|
||||
@@ -385,7 +469,9 @@ namespace Elwig.Windows {
|
||||
return;
|
||||
}
|
||||
ActiveGraph.LinearIncreaseGraphToEnd(PrimaryMarkedPoint, priceIncrease.Value);
|
||||
OechslePricePlot.Render();
|
||||
SetHasChanged();
|
||||
OechslePricePlot.Refresh();
|
||||
CheckGebundenTypeFixed();
|
||||
}
|
||||
|
||||
private void OechslePricePlot_MouseDown(object sender, MouseEventArgs e) {
|
||||
@@ -394,7 +480,7 @@ namespace Elwig.Windows {
|
||||
}
|
||||
|
||||
if (HoverActive) {
|
||||
if (PaymentVar.TestVariant && Keyboard.IsKeyDown(Key.LeftCtrl)) {
|
||||
if (PaymentVar.TestVariant && Keyboard.IsKeyDown(System.Windows.Input.Key.LeftCtrl)) {
|
||||
if (PrimaryMarkedPoint == -1 || ActiveGraph == null || ActiveGraph != Highlighted.graph) {
|
||||
return;
|
||||
}
|
||||
@@ -408,7 +494,7 @@ namespace Elwig.Windows {
|
||||
}
|
||||
|
||||
PrimaryMarkedPoint = Highlighted.index;
|
||||
ChangeActiveGraph(Highlighted.graph);
|
||||
if (ActiveGraph != Highlighted.graph) ChangeActiveGraph(Highlighted.graph);
|
||||
|
||||
ChangeMarker(PrimaryMarkedPointPlot, true, ActiveGraph.GetOechsleAt(PrimaryMarkedPoint), ActiveGraph.GetPriceAt(PrimaryMarkedPoint));
|
||||
|
||||
@@ -433,32 +519,21 @@ namespace Elwig.Windows {
|
||||
}
|
||||
}
|
||||
|
||||
private (double, double, int)? MouseOnPlot(ScatterPlot? plot) {
|
||||
if (plot == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
(double mouseCoordX, double mouseCoordY) = OechslePricePlot.GetMouseCoordinates();
|
||||
(double mousePixelX, double mousePixelY) = OechslePricePlot.GetMousePixel();
|
||||
double xyRatio = OechslePricePlot.Plot.XAxis.Dims.PxPerUnit / OechslePricePlot.Plot.YAxis.Dims.PxPerUnit;
|
||||
|
||||
(double pointX, double pointY, int pointIndex) = plot.GetPointNearest(mouseCoordX, mouseCoordY, xyRatio);
|
||||
(double pointPixelX, double pointPixelY) = OechslePricePlot.Plot.GetPixel(pointX, pointY);
|
||||
|
||||
if (Math.Abs(mousePixelX - pointPixelX) < 3 && Math.Abs(mousePixelY - pointPixelY) < 3) {
|
||||
return (pointX, pointY, pointIndex);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
private void OechslePricePlot_MouseMove(object sender, MouseEventArgs e) {
|
||||
MouseChange(e);
|
||||
}
|
||||
|
||||
private void OechslePricePlot_MouseMove(object sender, MouseEventArgs e) {
|
||||
private void OechslePricePlot_MouseWheel(object sender, MouseWheelEventArgs e) {
|
||||
MouseChange(e);
|
||||
}
|
||||
|
||||
private void MouseChange(MouseEventArgs e) {
|
||||
if (GraphList.SelectedItem == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
(double x, double y, int index)? mouseOnData = MouseOnPlot(DataPlot);
|
||||
(double x, double y , int index)? mouseOnGebunden = MouseOnPlot(GebundenPlot);
|
||||
(double x, double y, int index)? mouseOnData = MouseOnPlot(DataPlot, e.GetPosition(OechslePricePlot));
|
||||
(double x, double y, int index)? mouseOnGebunden = MouseOnPlot(GebundenPlot, e.GetPosition(OechslePricePlot));
|
||||
|
||||
Highlighted = LastHighlighted;
|
||||
|
||||
@@ -467,31 +542,57 @@ namespace Elwig.Windows {
|
||||
HighlightedPointPlot.IsVisible = true;
|
||||
HoverChanged = true ^ HoverActive;
|
||||
HoverActive = true;
|
||||
HandleTooltip(mouseOnData.Value.x, mouseOnData.Value.y, mouseOnData.Value.index, SelectedGraphEntry!.DataGraph);
|
||||
HandleTooltip(mouseOnData.Value.x, mouseOnData.Value.y, mouseOnData.Value.index, SelectedGraphEntry!.DataGraph, e.GetPosition(OechslePricePlot), e is MouseWheelEventArgs);
|
||||
} else if (mouseOnGebunden != null) {
|
||||
ChangeMarker(HighlightedPointPlot, true, mouseOnGebunden.Value.x, mouseOnGebunden.Value.y);
|
||||
HighlightedPointPlot.IsVisible = true;
|
||||
HoverChanged = true ^ HoverActive;
|
||||
HoverActive = true;
|
||||
HandleTooltip(mouseOnGebunden.Value.x, mouseOnGebunden.Value.y, mouseOnGebunden.Value.index, SelectedGraphEntry!.GebundenGraph!);
|
||||
HandleTooltip(mouseOnGebunden.Value.x, mouseOnGebunden.Value.y, mouseOnGebunden.Value.index, SelectedGraphEntry!.GebundenGraph!, e.GetPosition(OechslePricePlot), e is MouseWheelEventArgs);
|
||||
} else {
|
||||
ChangeMarker(HighlightedPointPlot, false);
|
||||
HoverChanged = false ^ HoverActive;
|
||||
HoverActive = false;
|
||||
OechslePricePlot.Plot.Remove(TooltipPlot);
|
||||
OechslePricePlot.Render();
|
||||
OechslePricePlot.Plot.PlottableList.Remove(TooltipPlot);
|
||||
OechslePricePlot.Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleTooltip(double pointX, double pointY, int pointIndex, Graph g) {
|
||||
if (LastHighlighted != Highlighted || HoverChanged) {
|
||||
OechslePricePlot.Plot.Remove(TooltipPlot);
|
||||
private (double, double, int)? MouseOnPlot(Scatter? plot, Point p) {
|
||||
if (plot == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
OechslePricePlot.Refresh();
|
||||
Pixel mousePixel = new(p.X, p.Y);
|
||||
Coordinates mouseLocation = OechslePricePlot.Plot.GetCoordinates(mousePixel);
|
||||
DataPoint nearestPoint = plot.Data.GetNearest(mouseLocation, OechslePricePlot.Plot.LastRender, 3);
|
||||
|
||||
if (nearestPoint.IsReal) {
|
||||
return (nearestPoint.X, nearestPoint.Y, nearestPoint.Index);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleTooltip(double pointX, double pointY, int pointIndex, Graph g, Point p, bool force) {
|
||||
if (force || LastHighlighted != Highlighted || HoverChanged) {
|
||||
OechslePricePlot.Plot.PlottableList.Remove(TooltipPlot);
|
||||
if (TooltipInput.IsChecked == true) {
|
||||
TooltipPlot = OechslePricePlot.Plot.AddTooltip($"Oechsle: {pointX:N2}, Preis: {Math.Round(pointY, Season.Precision)}€/kg)", pointX, pointY);
|
||||
Pixel mousePixel = new(p.X, p.Y - 30);
|
||||
Coordinates mouseLocation = OechslePricePlot.Plot.GetCoordinates(mousePixel);
|
||||
TooltipPlot = OechslePricePlot.Plot.Add.Text($"Oechsle: {pointX:N2}, Preis: {Math.Round(pointY, Season.Precision)}€/kg", mouseLocation.X, mouseLocation.Y);
|
||||
TooltipPlot.Label.FontSize = 12;
|
||||
TooltipPlot.Label.Bold = true;
|
||||
TooltipPlot.Label.BorderColor = Colors.Black;
|
||||
TooltipPlot.Label.BorderWidth = 2;
|
||||
TooltipPlot.Label.BackColor = Colors.White;
|
||||
TooltipPlot.Label.Padding = 10;
|
||||
TooltipPlot.Label.Alignment = Alignment.MiddleLeft;
|
||||
}
|
||||
LastHighlighted = (g, pointIndex);
|
||||
HoverChanged = false;
|
||||
OechslePricePlot.Render();
|
||||
OechslePricePlot.Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -500,8 +601,9 @@ namespace Elwig.Windows {
|
||||
}
|
||||
|
||||
private void AddButton_Click(object sender, RoutedEventArgs e) {
|
||||
GraphEntry newGraphEntry = new(GetMaxGraphId() + 1, Season.Precision, BillingData.CurveMode.Oe, MinOechsle, MinOechsleGebunden, MaxOechsle);
|
||||
GraphEntry newGraphEntry = new(GetMaxGraphId() + 1, Season.Precision, BillingData.CurveMode.Oe);
|
||||
GraphEntries.Add(newGraphEntry);
|
||||
SetHasChanged();
|
||||
GraphList.Items.Refresh();
|
||||
GraphList.SelectedItem = newGraphEntry;
|
||||
}
|
||||
@@ -511,6 +613,7 @@ namespace Elwig.Windows {
|
||||
|
||||
GraphEntry newGraphEntry = SelectedGraphEntry.Copy(GetMaxGraphId() + 1);
|
||||
GraphEntries.Add(newGraphEntry);
|
||||
SetHasChanged();
|
||||
GraphList.Items.Refresh();
|
||||
GraphList.SelectedItem = newGraphEntry;
|
||||
}
|
||||
@@ -519,18 +622,20 @@ namespace Elwig.Windows {
|
||||
if (SelectedGraphEntry == null) return;
|
||||
|
||||
var r = MessageBox.Show(
|
||||
$"Soll der Graph {SelectedGraphEntry.Id} (verwendet in folgenden Verträgen: {SelectedGraphEntry.Contracts}) wirklich gelöscht werden?",
|
||||
$"Soll der Graph {SelectedGraphEntry.Id} (verwendet in folgenden Verträgen: {SelectedGraphEntry.ContractsStringSimple}) wirklich gelöscht werden?",
|
||||
"Graph löschen", MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No);
|
||||
|
||||
if (r == MessageBoxResult.Yes) {
|
||||
GraphEntries.Remove(SelectedGraphEntry);
|
||||
SetHasChanged();
|
||||
GraphList.Items.Refresh();
|
||||
OechslePricePlot.IsEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async void SaveButton_Click(object sender, RoutedEventArgs e) {
|
||||
var origData = BillingData.FromJson(PaymentVar.Data);
|
||||
var data = origData.FromGraphEntries(GraphEntries);
|
||||
var data = BillingData.FromGraphEntries(GraphEntries, origData, Utils.GetAttributeVarieties(Context, Year, withSlash: true));
|
||||
|
||||
EntityEntry<PaymentVar>? tr = null;
|
||||
try {
|
||||
@@ -538,6 +643,7 @@ namespace Elwig.Windows {
|
||||
tr = Context.Update(PaymentVar);
|
||||
await Context.SaveChangesAsync();
|
||||
LockContext = false;
|
||||
tr = null;
|
||||
await App.HintContextChange();
|
||||
} catch (Exception exc) {
|
||||
if (tr != null) await tr.ReloadAsync();
|
||||
@@ -546,6 +652,7 @@ namespace Elwig.Windows {
|
||||
MessageBox.Show(str, "Auszahlungsvariante speichern", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
LockContext = true;
|
||||
SetHasChanged(false);
|
||||
}
|
||||
|
||||
private void EnableUnitTextBox(UnitTextBox u) {
|
||||
@@ -563,7 +670,7 @@ namespace Elwig.Windows {
|
||||
private void ChangeActiveGraph(Graph? g) {
|
||||
if (g != null && g == SelectedGraphEntry?.DataGraph) {
|
||||
EnableUnitTextBox(OechsleInput);
|
||||
ChangeLineWidth(DataPlot, 4);
|
||||
if (SelectedGraphEntry?.GebundenGraph != null) ChangeLineWidth(DataPlot, 4);
|
||||
ChangeLineWidth(GebundenPlot, 1);
|
||||
} else if (g != null && g == SelectedGraphEntry?.GebundenGraph) {
|
||||
EnableUnitTextBox(OechsleInput);
|
||||
@@ -580,14 +687,13 @@ namespace Elwig.Windows {
|
||||
ActiveGraph = g;
|
||||
}
|
||||
|
||||
private void ChangeLineWidth(ScatterPlot? p, double lineWidth) {
|
||||
private void ChangeLineWidth(Scatter? p, double lineWidth) {
|
||||
if (p != null) {
|
||||
p.LineWidth = lineWidth;
|
||||
p.LineWidth = (float)lineWidth;
|
||||
}
|
||||
}
|
||||
|
||||
private void GraphList_SelectionChanged(object sender, SelectionChangedEventArgs e) {
|
||||
SelectedGraphEntry = GraphList.SelectedItem as GraphEntry;
|
||||
RefreshInputs();
|
||||
}
|
||||
|
||||
@@ -600,34 +706,52 @@ namespace Elwig.Windows {
|
||||
}
|
||||
|
||||
private void GebundenFlatBonus_TextChanged(object sender, TextChangedEventArgs e) {
|
||||
var r = Validator.CheckDecimal(GebundenFlatBonus.TextBox, true, 2, 8);
|
||||
if (r.IsValid) {
|
||||
SelectedGraphEntry?.SetGebundenFlatBonus(decimal.Parse(GebundenFlatBonus.Text));
|
||||
if (FillingInputs) return;
|
||||
var r = Validator.CheckDecimal(GebundenFlatBonus.TextBox, true, 2, Season.Precision);
|
||||
if (r.IsValid && SelectedGraphEntry != null) {
|
||||
SelectedGraphEntry.GebundenFlatBonus = double.Parse(GebundenFlatBonus.Text);
|
||||
ResetPlot();
|
||||
InitPlot();
|
||||
}
|
||||
}
|
||||
|
||||
private void ContractInput_Changed(object sender, ItemSelectionChangedEventArgs e) {
|
||||
if (FillingInputs) return;
|
||||
if (e.IsSelected == true) {
|
||||
RemoveContractFromOtherGraphEntries(e.Item.ToString());
|
||||
bool success = RemoveContractFromOtherGraphEntries(e.Item.ToString());
|
||||
if (!success) {
|
||||
ContractInput.SelectedItems.Remove(e.Item);
|
||||
}
|
||||
}
|
||||
var r = ContractInput.SelectedItems.Cast<ContractSelection>();
|
||||
SelectedGraphEntry!.Contracts = r.ToList();
|
||||
SetHasChanged();
|
||||
GraphList.Items.Refresh();
|
||||
}
|
||||
|
||||
private void RemoveContractFromOtherGraphEntries(string? contract) {
|
||||
if (contract == null) return;
|
||||
private bool RemoveContractFromOtherGraphEntries(string? contract) {
|
||||
if (contract == null) return true;
|
||||
foreach (var ge in GraphEntries) {
|
||||
if (ge != SelectedGraphEntry) {
|
||||
if (ge != SelectedGraphEntry && ge.Abgewertet == SelectedGraphEntry?.Abgewertet) {
|
||||
var toRemove = ge.Contracts.Where(c => c.Listing.Equals(contract)).ToList();
|
||||
if (toRemove.Count == 0) continue;
|
||||
var r = MessageBox.Show($"Achtung: {string.Join(", ", toRemove)} ist bereits in Graph {ge.Id} in Verwendung!\nSoll die Zuweisung dort entfernt werden?", "Entfernen bestätigen",
|
||||
MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No);
|
||||
if (r != MessageBoxResult.Yes) {
|
||||
return false;
|
||||
}
|
||||
ge.Contracts.RemoveAll(c => c.Listing.Equals(contract));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void AbgewertetInput_Changed(object sender, RoutedEventArgs e) {
|
||||
if (FillingInputs) return;
|
||||
if (SelectedGraphEntry == null) return;
|
||||
SelectedGraphEntry.Abgewertet = AbgewertetInput.IsChecked == true;
|
||||
SetHasChanged();
|
||||
GraphList.Items.Refresh();
|
||||
}
|
||||
|
||||
private void GebundenType_Checked(object sender, RoutedEventArgs e) {
|
||||
@@ -635,23 +759,34 @@ namespace Elwig.Windows {
|
||||
if (SelectedGraphEntry == null) {
|
||||
DisableUnitTextBox(GebundenFlatBonus);
|
||||
return;
|
||||
} else if (GebundenTypeNone.IsChecked == true) {
|
||||
SelectedGraphEntry.SetGebundenFlatBonus(null);
|
||||
}
|
||||
if (GebundenTypeNone.IsChecked == true) {
|
||||
SelectedGraphEntry.RemoveGebundenGraph();
|
||||
DisableUnitTextBox(GebundenFlatBonus);
|
||||
RefreshInputs();
|
||||
} else if (GebundenTypeFixed.IsChecked == true) {
|
||||
SelectedGraphEntry.SetGebundenFlatBonus(0);
|
||||
SelectedGraphEntry.RemoveGebundenGraph();
|
||||
SelectedGraphEntry.GebundenFlatBonus = double.TryParse(GebundenFlatBonus.Text, out var val) ? val : 0.1;
|
||||
SelectedGraphEntry.AddGebundenGraph();
|
||||
EnableUnitTextBox(GebundenFlatBonus);
|
||||
RefreshInputs();
|
||||
} else if (GebundenTypeGraph.IsChecked == true) {
|
||||
GebundenFlatBonus.Text = "";
|
||||
SelectedGraphEntry.SetGebundenFlatBonus(null);
|
||||
SelectedGraphEntry.AddGebundenGraph();
|
||||
DisableUnitTextBox(GebundenFlatBonus);
|
||||
RefreshInputs();
|
||||
}
|
||||
SetHasChanged();
|
||||
RefreshInputs();
|
||||
}
|
||||
|
||||
private void CheckGebundenTypeFixed() {
|
||||
FillingInputs = true;
|
||||
if (SelectedGraphEntry?.GebundenFlatBonus is double bonus) {
|
||||
GebundenTypeFixed.IsChecked = true;
|
||||
GebundenFlatBonus.Text = $"{bonus}";
|
||||
EnableUnitTextBox(GebundenFlatBonus);
|
||||
} else if (SelectedGraphEntry?.GebundenGraph != null) {
|
||||
GebundenTypeGraph.IsChecked = true;
|
||||
GebundenFlatBonus.Text = "";
|
||||
DisableUnitTextBox(GebundenFlatBonus);
|
||||
}
|
||||
FillingInputs = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,6 +52,8 @@ namespace Elwig.Windows {
|
||||
Arrow3.Content = locked ? "\xF0B0" : "\xF0AF";
|
||||
CopyButton.IsEnabled = true;
|
||||
EditButton.Content = locked ? "Ansehen" : "Bearbeiten";
|
||||
EditButton.IsEnabled = true;
|
||||
SaveButton.IsEnabled = !locked;
|
||||
ShowButton.IsEnabled = true;
|
||||
PrintButton.IsEnabled = true;
|
||||
ExportButton.IsEnabled = locked;
|
||||
@@ -67,30 +69,27 @@ namespace Elwig.Windows {
|
||||
try {
|
||||
BillingData = BillingData.FromJson(v.Data);
|
||||
ConsiderModifiersInput.IsChecked = BillingData.ConsiderDelieryModifiers;
|
||||
ConsiderModifiersInput.IsEnabled = !locked;
|
||||
ConsiderPenaltiesInput.IsChecked = BillingData.ConsiderContractPenalties;
|
||||
ConsiderPenaltiesInput.IsEnabled = !locked;
|
||||
ConsiderPenaltyInput.IsChecked = BillingData.ConsiderTotalPenalty;
|
||||
ConsiderPenaltyInput.IsEnabled = !locked;
|
||||
ConsiderAutoInput.IsChecked = BillingData.ConsiderAutoBusinessShares;
|
||||
ConsiderAutoInput.IsEnabled = !locked;
|
||||
DataInput.Text = JsonSerializer.Serialize(BillingData.Data, JsonOpt);
|
||||
DataInput.IsReadOnly = locked;
|
||||
} catch {
|
||||
BillingData = null;
|
||||
ConsiderModifiersInput.IsChecked = false;
|
||||
ConsiderModifiersInput.IsEnabled = false;
|
||||
ConsiderPenaltiesInput.IsChecked = false;
|
||||
ConsiderPenaltiesInput.IsEnabled = false;
|
||||
ConsiderPenaltyInput.IsChecked = false;
|
||||
ConsiderPenaltyInput.IsEnabled = false;
|
||||
ConsiderAutoInput.IsChecked = false;
|
||||
ConsiderAutoInput.IsEnabled = false;
|
||||
DataInput.Text = v.Data;
|
||||
DataInput.IsEnabled = false;
|
||||
}
|
||||
ConsiderModifiersInput.IsEnabled = !locked;
|
||||
ConsiderPenaltiesInput.IsEnabled = !locked;
|
||||
ConsiderPenaltyInput.IsEnabled = !locked;
|
||||
ConsiderAutoInput.IsEnabled = !locked;
|
||||
DataInput.IsReadOnly = locked;
|
||||
} else {
|
||||
EditButton.Content = "Bearbeiten";
|
||||
EditButton.IsEnabled = false;
|
||||
SaveButton.IsEnabled = false;
|
||||
CopyButton.IsEnabled = false;
|
||||
CalculateButton.IsEnabled = false;
|
||||
CommitButton.IsEnabled = false;
|
||||
@@ -130,11 +129,12 @@ namespace Elwig.Windows {
|
||||
private void UpdateSaveButton() {
|
||||
SaveButton.IsEnabled = PaymentVariantList.SelectedItem != null &&
|
||||
((DataChanged && DataValid) || NameChanged || CommentChanged ||
|
||||
(TransferDateChanged && TransferDateValid)) ||
|
||||
(TransferDateChanged && TransferDateValid) ||
|
||||
(ConsiderModifiersInput.IsChecked != BillingData?.ConsiderDelieryModifiers) ||
|
||||
(ConsiderPenaltiesInput.IsChecked != BillingData?.ConsiderContractPenalties) ||
|
||||
(ConsiderPenaltyInput.IsChecked != BillingData?.ConsiderTotalPenalty) ||
|
||||
(ConsiderAutoInput.IsChecked != BillingData?.ConsiderAutoBusinessShares);
|
||||
(ConsiderAutoInput.IsChecked != BillingData?.ConsiderAutoBusinessShares));
|
||||
CalculateButton.IsEnabled = !SaveButton.IsEnabled && PaymentVariantList.SelectedItem is PaymentVar { TestVariant: true };
|
||||
}
|
||||
|
||||
private void UpdateSums() {
|
||||
@@ -173,7 +173,7 @@ namespace Elwig.Windows {
|
||||
v.Name = "Neue Auszahlungsvariante";
|
||||
v.TestVariant = true;
|
||||
v.DateString = $"{DateTime.Today:yyyy-MM-dd}";
|
||||
v.Data = "{\"mode\": \"elwig\", \"version\": 1, \"payment\": 1.0, \"curves\": []}";
|
||||
v.Data = "{\"mode\": \"elwig\", \"version\": 1, \"payment\": 1.0, \"quality\": {\"WEI\": 0}, \"curves\": []}";
|
||||
|
||||
await Context.AddAsync(v);
|
||||
await Context.SaveChangesAsync();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
::mkdir "C:\Program Files\Elwig"
|
||||
::curl -s "http://www.columbia.edu/~em36/PDFtoPrinter.exe" -z "C:\Program Files\Elwig\PDFtoPrinter.exe" -o "C:\Program Files\Elwig\PDFtoPrinter.exe"
|
||||
::curl -s -L "http://www.columbia.edu/~em36/PDFtoPrinter.exe" -z "C:\Program Files\Elwig\PDFtoPrinter.exe" -o "C:\Program Files\Elwig\PDFtoPrinter.exe"
|
||||
mkdir "C:\ProgramData\Elwig\resources"
|
||||
copy /b /y Documents\*.css "C:\ProgramData\Elwig\resources"
|
||||
copy /b /y Documents\*.cshtml "C:\ProgramData\Elwig\resources"
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
</Task>
|
||||
</UsingTask>
|
||||
<Target Name="CustomBeforeBuild" BeforeTargets="BeforeBuild">
|
||||
<Exec Command="curl -s "http://www.columbia.edu/~em36/PDFtoPrinter.exe" -z "$(TargetDir)PDFtoPrinter.exe" -o "$(TargetDir)PDFtoPrinter.exe"" />
|
||||
<Exec Command="curl -s -L "http://www.columbia.edu/~em36/PDFtoPrinter.exe" -z "$(TargetDir)PDFtoPrinter.exe" -o "$(TargetDir)PDFtoPrinter.exe"" />
|
||||
<Exec Command="dotnet publish "$(SolutionDir)Elwig\Elwig.csproj" "/p:PublishProfile=$(SolutionDir)\Elwig\Properties\PublishProfiles\FolderProfile.pubxml"" />
|
||||
<GetFileVersion AssemblyPath="..\Elwig\bin\Publish\Elwig.exe">
|
||||
<Output TaskParameter="Version" PropertyName="ElwigFileVersion" />
|
||||
|
||||
+2
-2
@@ -5,8 +5,8 @@
|
||||
<Cultures>de-AT</Cultures>
|
||||
</PropertyGroup>
|
||||
<Target Name="CustomBeforeBuild" BeforeTargets="BeforeBuild">
|
||||
<Exec Command='curl -L -s "https://go.microsoft.com/fwlink/p/?LinkId=2124703" -z "$(TargetDir)MicrosoftEdgeWebview2Setup.exe" -o "$(TargetDir)MicrosoftEdgeWebview2Setup.exe"' />
|
||||
<Exec Command='curl -L -s "https://aka.ms/vs/17/release/vc_redist.x86.exe" -z "$(TargetDir)VC_redist.x86.exe" -o "$(TargetDir)VC_redist.x86.exe"' />
|
||||
<Exec Command='curl -s -L "https://go.microsoft.com/fwlink/p/?LinkId=2124703" -z "$(TargetDir)MicrosoftEdgeWebview2Setup.exe" -o "$(TargetDir)MicrosoftEdgeWebview2Setup.exe"' />
|
||||
<Exec Command='curl -s -L "https://aka.ms/vs/17/release/vc_redist.x86.exe" -z "$(TargetDir)VC_redist.x86.exe" -o "$(TargetDir)VC_redist.x86.exe"' />
|
||||
<PropertyGroup>
|
||||
<DefineConstants>ElwigProjectDir=..\Elwig</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
using Elwig.Helpers;
|
||||
using Elwig.Helpers.Billing;
|
||||
using Elwig.Models.Entities;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace Tests.Helpers {
|
||||
namespace Tests.HelperTests {
|
||||
[TestFixture]
|
||||
public class BillingDataTest {
|
||||
|
||||
private static readonly JsonSerializerOptions JsonOpts = new() { WriteIndented = true };
|
||||
private static readonly string[] AttributeVariants = ["GV", "GVD", "GVK", "GVS", "GVZ", "WR", "WRS", "ZW", "ZWS", "ZWZ"];
|
||||
|
||||
[OneTimeSetUp]
|
||||
@@ -41,7 +44,7 @@ namespace Tests.Helpers {
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Test_01_Flatrate() {
|
||||
public void TestRead_01_Flatrate() {
|
||||
var data = PaymentBillingData.FromJson("""
|
||||
{
|
||||
"mode": "elwig",
|
||||
@@ -57,7 +60,7 @@ namespace Tests.Helpers {
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Test_02_Simple() {
|
||||
public void TestRead_02_Simple() {
|
||||
var data = PaymentBillingData.FromJson("""
|
||||
{
|
||||
"mode": "elwig",
|
||||
@@ -92,7 +95,7 @@ namespace Tests.Helpers {
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Test_03_GreaterThanAndLessThan() {
|
||||
public void TestRead_03_GreaterThanAndLessThan() {
|
||||
var data = PaymentBillingData.FromJson("""
|
||||
{
|
||||
"mode": "elwig",
|
||||
@@ -131,7 +134,7 @@ namespace Tests.Helpers {
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Test_04_VariantsAndAttributes() {
|
||||
public void TestRead_04_VariantsAndAttributes() {
|
||||
var data = PaymentBillingData.FromJson("""
|
||||
{
|
||||
"mode": "elwig",
|
||||
@@ -161,7 +164,7 @@ namespace Tests.Helpers {
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Test_05_QualityLevel() {
|
||||
public void TestRead_05_QualityLevel() {
|
||||
var data = PaymentBillingData.FromJson("""
|
||||
{
|
||||
"mode": "elwig",
|
||||
@@ -192,7 +195,7 @@ namespace Tests.Helpers {
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Test_06_ModeOeAndKmw() {
|
||||
public void TestRead_06_ModeOeAndKmw() {
|
||||
var data = PaymentBillingData.FromJson("""
|
||||
{
|
||||
"mode": "elwig",
|
||||
@@ -234,7 +237,7 @@ namespace Tests.Helpers {
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Test_07_MultipleCurves() {
|
||||
public void TestRead_07_MultipleCurves() {
|
||||
var data = PaymentBillingData.FromJson("""
|
||||
{
|
||||
"mode": "elwig",
|
||||
@@ -303,7 +306,7 @@ namespace Tests.Helpers {
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Test_08_WgMaster() {
|
||||
public void TestRead_08_WgMaster() {
|
||||
var data = PaymentBillingData.FromJson("""
|
||||
{
|
||||
"mode": "wgmaster",
|
||||
@@ -345,5 +348,162 @@ namespace Tests.Helpers {
|
||||
TestCalcOe(data, "GVK", 115, 0.065m);
|
||||
});
|
||||
}
|
||||
|
||||
private static List<ContractSelection> GetSelection(IEnumerable<string> attVars) {
|
||||
return attVars.Select(s => {
|
||||
var sortid = s[..2];
|
||||
var attrid = s.Length > 2 ? s[2..] : null;
|
||||
return new ContractSelection(
|
||||
new WineVar(sortid, sortid),
|
||||
attrid == null ? null : new WineAttr(attrid, attrid)
|
||||
);
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestWrite_01_Empty() {
|
||||
List<GraphEntry> entries = [
|
||||
new GraphEntry(1, 4, BillingData.CurveMode.Oe, new() {
|
||||
[73] = 0.5m
|
||||
}, null)
|
||||
];
|
||||
var updated = BillingData.FromGraphEntries(entries);
|
||||
Assert.That(updated.ToJsonString(JsonOpts), Is.EqualTo("""
|
||||
{
|
||||
"mode": "elwig",
|
||||
"version": 1,
|
||||
"payment": 0,
|
||||
"curves": []
|
||||
}
|
||||
"""));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestWrite_02_Flatrate() {
|
||||
List<GraphEntry> entries = [
|
||||
new GraphEntry(0, 4, new BillingData.Curve(BillingData.CurveMode.Oe, new() {
|
||||
[73] = 0.5m
|
||||
}, null), GetSelection(["GV"]))
|
||||
];
|
||||
var data = BillingData.FromGraphEntries(entries);
|
||||
Assert.That(data.ToJsonString(JsonOpts), Is.EqualTo("""
|
||||
{
|
||||
"mode": "elwig",
|
||||
"version": 1,
|
||||
"payment": 0.5,
|
||||
"curves": []
|
||||
}
|
||||
"""));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestWrite_03_SingleCurve() {
|
||||
List<GraphEntry> entries = [
|
||||
new GraphEntry(0, 4, new BillingData.Curve(BillingData.CurveMode.Oe, new() {
|
||||
[73] = 0.5m,
|
||||
[83] = 1.0m
|
||||
}, null), GetSelection(["GV"]))
|
||||
];
|
||||
var data = BillingData.FromGraphEntries(entries);
|
||||
Assert.That(data.ToJsonString(JsonOpts), Is.EqualTo("""
|
||||
{
|
||||
"mode": "elwig",
|
||||
"version": 1,
|
||||
"payment": "curve:1",
|
||||
"curves": [
|
||||
{
|
||||
"id": 1,
|
||||
"mode": "oe",
|
||||
"data": {
|
||||
"73oe": 0.5,
|
||||
"83oe": 1
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
"""));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestWrite_04_Simple() {
|
||||
List<GraphEntry> entries = [
|
||||
new GraphEntry(0, 4, new BillingData.Curve(BillingData.CurveMode.Oe, new() {
|
||||
[73] = 0.5m,
|
||||
[84] = 1.0m
|
||||
}, null), GetSelection(["GV", "ZW"])),
|
||||
new GraphEntry(10, 4, new BillingData.Curve(BillingData.CurveMode.Oe, new() {
|
||||
[73] = 0.75m,
|
||||
}, null), GetSelection(["WR"]))
|
||||
];
|
||||
var data = BillingData.FromGraphEntries(entries);
|
||||
Assert.That(data.ToJsonString(JsonOpts), Is.EqualTo("""
|
||||
{
|
||||
"mode": "elwig",
|
||||
"version": 1,
|
||||
"payment": {
|
||||
"WR/": 0.75,
|
||||
"default": "curve:1"
|
||||
},
|
||||
"curves": [
|
||||
{
|
||||
"id": 1,
|
||||
"mode": "oe",
|
||||
"data": {
|
||||
"73oe": 0.5,
|
||||
"84oe": 1
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
"""));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestWrite_05_Attribute() {
|
||||
List<GraphEntry> entries = [
|
||||
new GraphEntry(0, 4, new BillingData.Curve(BillingData.CurveMode.Oe, new() {
|
||||
[73] = 0.5m,
|
||||
[84] = 1.0m
|
||||
}, null), GetSelection(["GVB", "ZWB"])),
|
||||
new GraphEntry(2, 4, new BillingData.Curve(BillingData.CurveMode.Oe, new() {
|
||||
[73] = 0.75m,
|
||||
}, null), GetSelection(["WR", "BL", "RR", "FV"])),
|
||||
new GraphEntry(4, 4, new BillingData.Curve(BillingData.CurveMode.Oe, new() {
|
||||
[73] = 0.65m,
|
||||
[84] = 1.2m
|
||||
}, null), GetSelection(["BP", "SA"]))
|
||||
];
|
||||
var data = BillingData.FromGraphEntries(entries);
|
||||
Assert.That(data.ToJsonString(JsonOpts), Is.EqualTo("""
|
||||
{
|
||||
"mode": "elwig",
|
||||
"version": 1,
|
||||
"payment": {
|
||||
"BP/": "curve:2",
|
||||
"SA/": "curve:2",
|
||||
"default": 0.75,
|
||||
"/B": "curve:1"
|
||||
},
|
||||
"curves": [
|
||||
{
|
||||
"id": 1,
|
||||
"mode": "oe",
|
||||
"data": {
|
||||
"73oe": 0.5,
|
||||
"84oe": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"mode": "oe",
|
||||
"data": {
|
||||
"73oe": 0.65,
|
||||
"84oe": 1.2
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
"""));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
using Microsoft.Data.Sqlite;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Tests.Helpers {
|
||||
namespace Tests.HelperTests {
|
||||
[TestFixture]
|
||||
public class BillingTest {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using Elwig.Helpers;
|
||||
|
||||
namespace Tests.Helpers {
|
||||
namespace Tests.HelperTests {
|
||||
[TestFixture]
|
||||
public class UtilsTest {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using Elwig.Helpers;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Tests.Helpers {
|
||||
namespace Tests.HelperTests {
|
||||
[TestFixture]
|
||||
[Apartment(ApartmentState.STA)]
|
||||
public class ValidatorTest {
|
||||
@@ -1 +1 @@
|
||||
curl -s "https://www.necronda.net/elwig/files/create.sql?v=13" -u "elwig:ganzGeheim123!" -o "Resources\Create.sql"
|
||||
curl -s -L "https://www.necronda.net/elwig/files/create.sql?v=13" -u "elwig:ganzGeheim123!" -o "Resources\Create.sql"
|
||||
|
||||
Reference in New Issue
Block a user