diff --git a/Elwig/Documents/WineQualityStatistics.cshtml b/Elwig/Documents/WineQualityStatistics.cshtml index 8eb0db9..b9d69de 100644 --- a/Elwig/Documents/WineQualityStatistics.cshtml +++ b/Elwig/Documents/WineQualityStatistics.cshtml @@ -1,4 +1,5 @@ @using RazorLight +@using Elwig.Helpers @inherits TemplatePage @model Elwig.Documents.WineQualityStatistics @{ Layout = "Document"; } @@ -32,7 +33,7 @@ @foreach (var qualId in qualIds) {

@(Model.QualityLevels.GetValueOrDefault(qualId, qualId))

- @foreach (var (grad, num, weight) in sec.Data.GetValueOrDefault(qualId, Array.Empty<(double, int, int)>())) { + @foreach (var (grad, avgKmw, num, weight) in sec.Data.GetValueOrDefault(qualId, Array.Empty<(double, double, int, int)>())) {
@(Model.UseOe ? $"{grad:N0}" : $"{grad:N1}") @($"{num:N0}") @@ -45,13 +46,13 @@ @foreach (var qualIds in Model.QualIds) { - var quals = qualIds.Select(q => sec.Data.GetValueOrDefault(q, Array.Empty<(double Grad, int Num, int Weight)>())); + var quals = qualIds.Select(q => sec.Data.GetValueOrDefault(q, Array.Empty<(double Grad, double AvgKmw, int Num, int Weight)>())); var weight = quals.Sum(q => q.Sum(kv => kv.Weight)); var num = quals.Sum(q => q.Sum(kv => kv.Num)); - var grad = quals.Sum(q => q.Sum(kv => kv.Grad * kv.Weight)) / weight; + var kmw = quals.Sum(q => q.Sum(kv => kv.AvgKmw * kv.Weight)) / weight;
- @(weight == 0 ? "-" : Model.UseOe ? $"{grad:N0}" : $"{grad:N1}") + @(weight == 0 ? "-" : Model.UseOe ? $"{Utils.KmwToOe(kmw):N0}" : $"{kmw:N1}") @($"{num:N0}") @($"{weight:N0}")
@@ -64,11 +65,11 @@ @{ var totalWeight = sec.Data.Values.Sum(q => q.Sum(kv => kv.Weight)); var totalNum = sec.Data.Values.Sum(q => q.Sum(kv => kv.Num)); - var totalGrad = sec.Data.Values.Sum(q => q.Sum(kv => kv.Grad * kv.Weight)) / totalWeight; + var totalKmw = sec.Data.Values.Sum(q => q.Sum(kv => kv.AvgKmw * kv.Weight)) / totalWeight; }
- @(totalWeight == 0 ? "-" : Model.UseOe ? $"{totalGrad:N0}" : $"{totalGrad:N1}") + @(totalWeight == 0 ? "-" : Model.UseOe ? $"{Utils.KmwToOe(totalKmw):N0}" : $"{totalKmw:N1}") @($"{totalNum:N0}") @($"{totalWeight:N0}")
diff --git a/Elwig/Helpers/ClientParameters.cs b/Elwig/Helpers/ClientParameters.cs index dd66a4d..c560c24 100644 --- a/Elwig/Helpers/ClientParameters.cs +++ b/Elwig/Helpers/ClientParameters.cs @@ -57,6 +57,7 @@ namespace Elwig.Helpers { public string? Website; public int ModeDeliveryNoteStats; + public int ModeWineQualityStatistics; public int OrderingMemberList; public string? TextDeliveryNote; @@ -103,6 +104,13 @@ namespace Elwig.Helpers { case "SHORT": ModeDeliveryNoteStats = 2; break; case "FULL": ModeDeliveryNoteStats = 3; break; } + switch (parameters.GetValueOrDefault("MODE_WINEQUALITYSTATISTICS", "OE")?.ToUpper()) { + case "OE": ModeWineQualityStatistics = 0; break; + case "KMW/1": ModeWineQualityStatistics = 1; break; + case "KMW/2": ModeWineQualityStatistics = 2; break; + case "KMW/5": ModeWineQualityStatistics = 3; break; + case "KMW/10": ModeWineQualityStatistics = 4; break; + } switch (parameters.GetValueOrDefault("ORDERING_MEMBERLIST", "")?.ToUpper()) { case "MGNR": OrderingMemberList = 0; break; case "NAME": OrderingMemberList = 1; break; @@ -133,6 +141,14 @@ namespace Elwig.Helpers { case 2: deliveryNoteStats = "SHORT"; break; case 3: deliveryNoteStats = "FULL"; break; } + string modeWineQualityStatistics = "OE"; + switch (ModeWineQualityStatistics) { + case 0: modeWineQualityStatistics = "OE"; break; + case 1: modeWineQualityStatistics = "KMW/1"; break; + case 2: modeWineQualityStatistics = "KMW/2"; break; + case 3: modeWineQualityStatistics = "KMW/5"; break; + case 4: modeWineQualityStatistics = "KMW/10"; break; + } string orderingMemberList = "MGNR"; switch (OrderingMemberList) { case 0: orderingMemberList = "MGNR"; break; @@ -157,6 +173,7 @@ namespace Elwig.Helpers { ("CLIENT_BIC", Bic), ("CLIENT_IBAN", Iban), ("MODE_DELIVERYNOTE_STATS", deliveryNoteStats), + ("MODE_WINEQUALITYSTATISTICS", modeWineQualityStatistics), ("ORDERING_MEMBERLIST", orderingMemberList), ("DOCUMENT_SENDER", Sender2), ("TEXT_DELIVERYNOTE", TextDeliveryNote), diff --git a/Elwig/Models/Dtos/WineQualityStatisticsData.cs b/Elwig/Models/Dtos/WineQualityStatisticsData.cs index ba7a892..27e4aab 100644 --- a/Elwig/Models/Dtos/WineQualityStatisticsData.cs +++ b/Elwig/Models/Dtos/WineQualityStatisticsData.cs @@ -9,8 +9,8 @@ using System.Threading.Tasks; namespace Elwig.Models.Dtos { public class WineQualityStatisticsData { - public record struct QualityRow(string? Variety, string? Attribute, string? Cultivation, string? Type, string QualId, double Grad, int Num, int Weight); - public record struct QualitySection(string Name, string? Type, Dictionary Data); + public record struct QualityRow(string? Variety, string? Attribute, string? Cultivation, string? Type, string QualId, double AvgKmw, double Grad, int Num, int Weight); + public record struct QualitySection(string Name, string? Type, Dictionary Data); public bool UseOe = true; public QualitySection[] Sections; @@ -21,8 +21,8 @@ namespace Elwig.Models.Dtos { private static QualitySection[] GetQualitySections(IEnumerable rows) { var data = new List(); - var currentQual = new Dictionary(); - var current = new Dictionary(); + var currentQual = new Dictionary(); + var current = new Dictionary(); string? lastSection = null; string? lastType = null; string? lastQual = null; @@ -31,25 +31,25 @@ namespace Elwig.Models.Dtos { $"{(row.Attribute != null ? " / " : "")}{row.Attribute}" + $"{(row.Cultivation != null ? " / " : "")}{row.Cultivation}"; if (lastQual != null && lastQual != row.QualId) { - current[lastQual] = currentQual.Select(kv => (kv.Key, kv.Value.Num, kv.Value.Weight)).ToArray(); + current[lastQual] = currentQual.Select(kv => (kv.Key, kv.Value.AvgKmw, kv.Value.Num, kv.Value.Weight)).ToArray(); currentQual.Clear(); } if (lastSection != null && lastSection != sec) { if (!current.ContainsKey(lastQual!)) { - current[lastQual!] = currentQual.Select(kv => (kv.Key, kv.Value.Num, kv.Value.Weight)).ToArray(); + current[lastQual!] = currentQual.Select(kv => (kv.Key, kv.Value.AvgKmw, kv.Value.Num, kv.Value.Weight)).ToArray(); currentQual.Clear(); } data.Add(new(lastSection, lastType, current)); current = []; currentQual.Clear(); } - currentQual[row.Grad] = (row.Num, row.Weight); + currentQual[row.Grad] = (row.AvgKmw, row.Num, row.Weight); lastSection = sec; lastType = row.Type; lastQual = row.QualId; } if (lastQual != null) { - current[lastQual] = currentQual.Select(kv => (kv.Key, kv.Value.Num, kv.Value.Weight)).ToArray(); + current[lastQual] = currentQual.Select(kv => (kv.Key, kv.Value.AvgKmw, kv.Value.Num, kv.Value.Weight)).ToArray(); currentQual.Clear(); } if (lastSection != null) { @@ -60,7 +60,7 @@ namespace Elwig.Models.Dtos { return [.. data]; } - public static async Task FromQuery(IQueryable query, bool useOe = true) { + public static async Task FromQuery(IQueryable query, int mode = 0) { var rows = (await query .GroupBy(p => new { p.Variety.Type, @@ -68,15 +68,24 @@ namespace Elwig.Models.Dtos { Attribute = p.Attribute!.Name, Cultivation = p.Cultivation!.Name, p.QualId, - Oe = useOe ? Math.Round(p.Kmw * (4.54 + 0.022 * p.Kmw), 0) : Math.Round(p.Kmw, 1), - }, (k, g) => new { Key = k, Num = g.Count(), Weight = g.Sum(p => p.Weight) }) + Grad = mode == 0 ? Math.Round(p.Kmw * (4.54 + 0.022 * p.Kmw), 0) : + mode == 1 ? Math.Floor(p.Kmw) : + mode == 2 ? Math.Floor(p.Kmw * 2) / 2 : + mode == 3 ? Math.Floor(p.Kmw * 5) / 5 : + Math.Round(p.Kmw, 1), + }, (k, g) => new { + Key = k, + Num = g.Count(), + Weight = g.Sum(p => p.Weight), + AvgKmw = g.Sum(p => p.Weight * p.Kmw) / g.Sum(p => p.Weight), + }) .OrderBy(g => g.Key.Variety) .ThenBy(g => g.Key.Attribute) .ThenBy(g => g.Key.Cultivation) .ThenBy(g => g.Key.QualId) - .ThenBy(g => g.Key.Oe) + .ThenBy(g => g.Key.Grad) .ToListAsync()) - .Select(r => new QualityRow(r.Key.Variety, r.Key.Attribute, r.Key.Cultivation, r.Key.Type, r.Key.QualId, r.Key.Oe, r.Num, r.Weight)) + .Select(r => new QualityRow(r.Key.Variety, r.Key.Attribute, r.Key.Cultivation, r.Key.Type, r.Key.QualId, r.AvgKmw, r.Key.Grad, r.Num, r.Weight)) .ToList(); var data = GetQualitySections(rows); @@ -84,7 +93,14 @@ namespace Elwig.Models.Dtos { return new(data); var typeRows = rows - .GroupBy(s => new { s.Type, s.QualId, s.Grad }, (k, g) => new QualityRow(null, null, null, k.Type, k.QualId, k.Grad, g.Sum(g => g.Num), g.Sum(p => p.Weight))) + .GroupBy(s => new { s.Type, s.QualId, s.Grad }, (k, g) => new QualityRow( + null, null, null, + k.Type, k.QualId, + g.Sum(p => p.Weight * p.AvgKmw) / g.Sum(p => p.Weight), + k.Grad, + g.Sum(p => p.Num), + g.Sum(p => p.Weight) + )) .OrderBy(g => g.Type) .ThenBy(g => g.QualId) .ThenBy(g => g.Grad) @@ -94,12 +110,19 @@ namespace Elwig.Models.Dtos { return new([.. typeData, .. data]); var totalRows = rows - .GroupBy(s => new { s.QualId, s.Grad }, (k, g) => new QualityRow(null, null, null, null, k.QualId, k.Grad, g.Sum(p => p.Num), g.Sum(p => p.Weight))) + .GroupBy(s => new { s.QualId, s.Grad }, (k, g) => new QualityRow( + null, null, null, null, + k.QualId, + g.Sum(p => p.Weight * p.AvgKmw) / g.Sum(p => p.Weight), + k.Grad, + g.Sum(p => p.Num), + g.Sum(p => p.Weight) + )) .OrderBy(g => g.QualId) .ThenBy(g => g.Grad) .ToList(); var totalData = GetQualitySections(totalRows); - return new([.. totalData, .. typeData, .. data]) { UseOe = useOe }; + return new([.. totalData, .. typeData, .. data]) { UseOe = mode == 0 }; } } } diff --git a/Elwig/Windows/DeliveryAdminWindow.xaml b/Elwig/Windows/DeliveryAdminWindow.xaml index 5db0098..775aa8b 100644 --- a/Elwig/Windows/DeliveryAdminWindow.xaml +++ b/Elwig/Windows/DeliveryAdminWindow.xaml @@ -81,7 +81,7 @@ - + + + + + + + diff --git a/Elwig/Windows/DeliveryAdminWindow.xaml.cs b/Elwig/Windows/DeliveryAdminWindow.xaml.cs index 1b1f4cf..4debf93 100644 --- a/Elwig/Windows/DeliveryAdminWindow.xaml.cs +++ b/Elwig/Windows/DeliveryAdminWindow.xaml.cs @@ -108,6 +108,19 @@ namespace Elwig.Windows { WeighingCButton.Visibility = Visibility.Hidden; WeighingDButton.Visibility = Visibility.Hidden; } + + Menu_WineQualityStatistics_ModeOe.IsChecked = false; + Menu_WineQualityStatistics_ModeKmw1.IsChecked = false; + Menu_WineQualityStatistics_ModeKmw2.IsChecked = false; + Menu_WineQualityStatistics_ModeKmw5.IsChecked = false; + Menu_WineQualityStatistics_ModeKmw10.IsChecked = false; + switch (App.Client.OrderingMemberList) { + case 0: Menu_WineQualityStatistics_ModeOe.IsChecked = true; break; + case 1: Menu_WineQualityStatistics_ModeKmw1.IsChecked = true; break; + case 2: Menu_WineQualityStatistics_ModeKmw2.IsChecked = true; break; + case 3: Menu_WineQualityStatistics_ModeKmw5.IsChecked = true; break; + case 4: Menu_WineQualityStatistics_ModeKmw10.IsChecked = true; break; + } } public DeliveryAdminWindow(int mgnr) : this() { @@ -322,7 +335,7 @@ namespace Elwig.Windows { Mouse.OverrideCursor = Cursors.AppStarting; try { - var data = await WineQualityStatisticsData.FromQuery(query); + var data = await WineQualityStatisticsData.FromQuery(query, App.Client.OrderingMemberList); using var doc = new WineQualityStatistics(string.Join(" / ", filterNames), data); await Utils.ExportDocument(doc, exportMode); } catch (Exception exc) { @@ -331,6 +344,27 @@ namespace Elwig.Windows { Mouse.OverrideCursor = null; } + private async void Menu_WineQualityStatistics_Mode_Click(object sender, RoutedEventArgs evt) { + Menu_WineQualityStatistics.IsSubmenuOpen = true; + if (sender == Menu_WineQualityStatistics_ModeOe) { + App.Client.OrderingMemberList = 0; + } else if (sender == Menu_WineQualityStatistics_ModeKmw1) { + App.Client.OrderingMemberList = 1; + } else if (sender == Menu_WineQualityStatistics_ModeKmw2) { + App.Client.OrderingMemberList = 2; + } else if (sender == Menu_WineQualityStatistics_ModeKmw5) { + App.Client.OrderingMemberList = 3; + } else if (sender == Menu_WineQualityStatistics_ModeKmw10) { + App.Client.OrderingMemberList = 4; + } + Menu_WineQualityStatistics_ModeOe.IsChecked = App.Client.OrderingMemberList == 0; + Menu_WineQualityStatistics_ModeKmw1.IsChecked = App.Client.OrderingMemberList == 1; + Menu_WineQualityStatistics_ModeKmw2.IsChecked = App.Client.OrderingMemberList == 2; + Menu_WineQualityStatistics_ModeKmw5.IsChecked = App.Client.OrderingMemberList == 3; + Menu_WineQualityStatistics_ModeKmw10.IsChecked = App.Client.OrderingMemberList == 4; + await App.Client.UpdateValues(); + } + private void Menu_Settings_EnableFreeEditing_Checked(object sender, RoutedEventArgs evt) { if (IsEditing || IsCreating) { DateInput.IsReadOnly = false;