From 626724fe87b9b285004f000ed68fc9372541dbec Mon Sep 17 00:00:00 2001 From: Lorenz Stechauner <lorenz.stechauner@necronda.net> Date: Fri, 19 Jan 2024 13:35:53 +0100 Subject: [PATCH] [#29] DeliveryAdminWindow: Only show sums of filtered parts when filtering --- Elwig/Models/Entities/Delivery.cs | 15 +++++- Elwig/Windows/DeliveryAdminWindow.xaml | 6 +-- Elwig/Windows/DeliveryAdminWindow.xaml.cs | 65 +++++++++++++---------- 3 files changed, 53 insertions(+), 33 deletions(-) diff --git a/Elwig/Models/Entities/Delivery.cs b/Elwig/Models/Entities/Delivery.cs index f7721a5..c05f079 100644 --- a/Elwig/Models/Entities/Delivery.cs +++ b/Elwig/Models/Entities/Delivery.cs @@ -68,19 +68,32 @@ namespace Elwig.Models.Entities { [InverseProperty("Delivery")] public virtual ISet<DeliveryPart> Parts { get; private set; } + [NotMapped] + public IEnumerable<DeliveryPart> FilteredParts => PartFilter == null ? Parts : Parts.Where(p => PartFilter(p)); + + [NotMapped] + public Predicate<DeliveryPart>? PartFilter { get; set; } public int Weight => Parts.Select(p => p.Weight).Sum(); + public int FilteredWeight => FilteredParts.Select(p => p.Weight).Sum(); public IEnumerable<string> SortIds => Parts .GroupBy(p => p.SortId) .OrderByDescending(g => g.Select(p => p.Weight).Sum()) - .Select(g => g.Select(p => p.SortId).First()); + .Select(g => g.Key); + public IEnumerable<string> FilteredSortIds => FilteredParts + .GroupBy(p => p.SortId) + .OrderByDescending(g => g.Select(p => p.Weight).Sum()) + .Select(g => g.Key); public string SortIdString => string.Join(", ", SortIds); + public string FilteredSortIdString => string.Join(", ", FilteredSortIds); public double Kmw => Utils.AggregateDeliveryPartsKmw(Parts); + public double FilteredKmw => Utils.AggregateDeliveryPartsKmw(FilteredParts); public double Oe => Utils.KmwToOe(Kmw); + public double FilteredOe => Utils.KmwToOe(FilteredKmw); public int SearchScore(IEnumerable<string> keywords) { var list = new string?[] { diff --git a/Elwig/Windows/DeliveryAdminWindow.xaml b/Elwig/Windows/DeliveryAdminWindow.xaml index a1ac8c5..001149e 100644 --- a/Elwig/Windows/DeliveryAdminWindow.xaml +++ b/Elwig/Windows/DeliveryAdminWindow.xaml @@ -148,21 +148,21 @@ </Style> </DataGridTextColumn.CellStyle> </DataGridTextColumn> - <DataGridTextColumn Header="Sorte" Binding="{Binding SortIdString}" Width="50"> + <DataGridTextColumn Header="Sorte" Binding="{Binding FilteredSortIdString}" Width="50"> <DataGridTextColumn.CellStyle> <Style> <Setter Property="TextBlock.TextAlignment" Value="Center"/> </Style> </DataGridTextColumn.CellStyle> </DataGridTextColumn> - <DataGridTextColumn Header="Gewicht" Binding="{Binding Weight, StringFormat='{}{0:N0} kg '}" Width="75"> + <DataGridTextColumn Header="Gewicht" Binding="{Binding FilteredWeight, StringFormat='{}{0:N0} kg '}" Width="75"> <DataGridTextColumn.CellStyle> <Style> <Setter Property="TextBlock.TextAlignment" Value="Right"/> </Style> </DataGridTextColumn.CellStyle> </DataGridTextColumn> - <DataGridTextColumn Header="Gradation" Binding="{Binding Kmw, StringFormat='{}{0:N1}° '}" Width="50"> + <DataGridTextColumn Header="Gradation" Binding="{Binding FilteredKmw, StringFormat='{}{0:N1}° '}" Width="50"> <DataGridTextColumn.CellStyle> <Style> <Setter Property="TextBlock.TextAlignment" Value="Right"/> diff --git a/Elwig/Windows/DeliveryAdminWindow.xaml.cs b/Elwig/Windows/DeliveryAdminWindow.xaml.cs index 110fb9f..8201564 100644 --- a/Elwig/Windows/DeliveryAdminWindow.xaml.cs +++ b/Elwig/Windows/DeliveryAdminWindow.xaml.cs @@ -10,6 +10,7 @@ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Linq.Expressions; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; @@ -168,7 +169,7 @@ namespace Elwig.Windows { private async void Menu_Print_DeliveryJournal_ShowFilter_Click(object sender, RoutedEventArgs evt) { Mouse.OverrideCursor = Cursors.AppStarting; - var (f, _, d, _) = await GetFilters(); + var (f, _, d, _, _) = await GetFilters(); var doc = new DeliveryJournal(string.Join(" / ", f), d); await doc.Generate(); Mouse.OverrideCursor = null; @@ -177,7 +178,7 @@ namespace Elwig.Windows { private async void Menu_Print_DeliveryJournal_PrintFilter_Click(object sender, RoutedEventArgs evt) { Mouse.OverrideCursor = Cursors.AppStarting; - var (f, _, d, _) = await GetFilters(); + var (f, _, d, _, _) = await GetFilters(); var doc = new DeliveryJournal(string.Join(" / ", f), d); await doc.Generate(); Mouse.OverrideCursor = null; @@ -296,7 +297,7 @@ namespace Elwig.Windows { await RefreshDeliveryListQuery(); } - private async Task<(List<string>, IQueryable<Delivery>, IQueryable<DeliveryPart>, List<string>)> GetFilters() { + private async Task<(List<string>, IQueryable<Delivery>, IQueryable<DeliveryPart>, Predicate<DeliveryPart>, List<string>)> GetFilters() { List<string> filterNames = []; IQueryable<Delivery> deliveryQuery = Context.Deliveries; if (IsReceipt && App.BranchNum > 1) { @@ -316,12 +317,8 @@ namespace Elwig.Windows { deliveryQuery = deliveryQuery.Where(d => d.Year == SeasonInput.Value); filterNames.Add(SeasonInput.Value.ToString() ?? ""); } - IQueryable<DeliveryPart> dpq = deliveryQuery - .SelectMany(d => d.Parts) - .OrderBy(p => p.Delivery.DateString) - .ThenBy(p => p.Delivery.TimeString) - .ThenBy(p => p.Delivery.LsNr) - .ThenBy(p => p.DPNr); + + Expression<Func<DeliveryPart, bool>> prd = p => true; var filterVar = new List<string>(); var filterNotVar = new List<string>(); @@ -487,32 +484,32 @@ namespace Elwig.Windows { } } - if (filterYearGt > 0) dpq = dpq.Where(p => p.Year >= filterYearGt); - if (filterYearLt > 0) dpq = dpq.Where(p => p.Year < filterYearLt); - if (filterMgNr.Count > 0) dpq = dpq.Where(p => filterMgNr.Contains(p.Delivery.MgNr)); + if (filterYearGt > 0) prd = prd.And(p => p.Year >= filterYearGt); + if (filterYearLt > 0) prd = prd.And(p => p.Year < filterYearLt); + if (filterMgNr.Count > 0) prd = prd.And(p => filterMgNr.Contains(p.Delivery.MgNr)); if (filterDate.Count > 0) { var pr = PredicateBuilder.New<DeliveryPart>(false); foreach (var (d1, d2) in filterDate) pr.Or(p => (d1 == null || d1.CompareTo(p.Delivery.DateString.Substring(10 - d1.Length)) <= 0) && (d2 == null || d2.CompareTo(p.Delivery.DateString.Substring(10 - d2.Length)) >= 0)); - dpq = dpq.Where(pr); + prd = prd.And(pr); } if (filterTime.Count > 0) { var pr = PredicateBuilder.New<DeliveryPart>(false); foreach (var (t1, t2) in filterTime) pr.Or(p => (t1 == null || t1.CompareTo(p.Delivery.TimeString) <= 0) && (t2 == null || t2.CompareTo(p.Delivery.TimeString) > 0)); - dpq = dpq.Where(p => p.Delivery.TimeString != null).Where(pr); + prd = prd.And(p => p.Delivery.TimeString != null).And(pr); } - if (filterVar.Count > 0) dpq = dpq.Where(p => filterVar.Contains(p.SortId)); - if (filterNotVar.Count > 0) dpq = dpq.Where(p => !filterNotVar.Contains(p.SortId)); - if (filterQual.Count > 0) dpq = dpq.Where(p => filterQual.Contains(p.QualId)); - if (filterNotQual.Count > 0) dpq = dpq.Where(p => !filterNotQual.Contains(p.QualId)); - if (filterZwst.Count > 0) dpq = dpq.Where(p => filterZwst.Contains(p.Delivery.ZwstId)); - if (filterAttr.Count > 0) dpq = dpq.Where(p => p.AttrId != null && filterAttr.Contains(p.AttrId)); - if (filterNotAttr.Count > 0) dpq = dpq.Where(p => p.AttrId == null || !filterNotAttr.Contains(p.AttrId)); - if (filterKmwGt > 0) dpq = dpq.Where(p => p.Kmw >= filterKmwGt); - if (filterKmwLt > 0) dpq = dpq.Where(p => p.Kmw < filterKmwLt); - if (filterOeGt > 0) dpq = dpq.Where(p => p.Kmw * (4.54 + 0.022 * p.Kmw) >= filterOeGt); - if (filterOeLt > 0) dpq = dpq.Where(p => p.Kmw * (4.54 + 0.022 * p.Kmw) < filterOeLt); + if (filterVar.Count > 0) prd = prd.And(p => filterVar.Contains(p.SortId)); + if (filterNotVar.Count > 0) prd = prd.And(p => !filterNotVar.Contains(p.SortId)); + if (filterQual.Count > 0) prd = prd.And(p => filterQual.Contains(p.QualId)); + if (filterNotQual.Count > 0) prd = prd.And(p => !filterNotQual.Contains(p.QualId)); + if (filterZwst.Count > 0) prd = prd.And(p => filterZwst.Contains(p.Delivery.ZwstId)); + if (filterAttr.Count > 0) prd = prd.And(p => p.AttrId != null && filterAttr.Contains(p.AttrId)); + if (filterNotAttr.Count > 0) prd = prd.And(p => p.AttrId == null || !filterNotAttr.Contains(p.AttrId)); + if (filterKmwGt > 0) prd = prd.And(p => p.Kmw >= filterKmwGt); + if (filterKmwLt > 0) prd = prd.And(p => p.Kmw < filterKmwLt); + if (filterOeGt > 0) prd = prd.And(p => p.Kmw * (4.54 + 0.022 * p.Kmw) >= filterOeGt); + if (filterOeLt > 0) prd = prd.And(p => p.Kmw * (4.54 + 0.022 * p.Kmw) < filterOeLt); if (filterYearGt > 0 && filterYearLt > 0) { filterNames.Insert(0, $"{filterYearGt}–{filterYearLt - 1}"); @@ -537,7 +534,15 @@ namespace Elwig.Windows { } } - return (filterNames, dpq.Select(p => p.Delivery).Distinct().OrderBy(d => d.DateString).ThenBy(d => d.TimeString), dpq, filter); + IQueryable<DeliveryPart> dpq = deliveryQuery + .SelectMany(d => d.Parts) + .Where(prd) + .OrderBy(p => p.Delivery.DateString) + .ThenBy(p => p.Delivery.TimeString) + .ThenBy(p => p.Delivery.LsNr) + .ThenBy(p => p.DPNr); + + return (filterNames, dpq.Select(p => p.Delivery).Distinct().OrderBy(d => d.DateString).ThenBy(d => d.TimeString), dpq, prd.Invoke, filter); } private static void AddToolTipCell(Grid grid, string text, int row, int col, int colSpan = 1, bool bold = false, bool alignRight = false, bool alignCenter = false) { @@ -573,7 +578,7 @@ namespace Elwig.Windows { } private async Task RefreshDeliveryListQuery(bool updateSort = false) { - var (_, deliveryQuery, deliveryPartsQuery, filter) = await GetFilters(); + var (_, deliveryQuery, deliveryPartsQuery, predicate, filter) = await GetFilters(); var deliveries = await deliveryQuery.ToListAsync(); deliveries.Reverse(); @@ -589,8 +594,10 @@ namespace Elwig.Windows { .ToList(); } + deliveries.ForEach(d => { d.PartFilter = predicate; }); ControlUtils.RenewItemsSource(DeliveryList, deliveries, d => ((d as Delivery)?.Year, (d as Delivery)?.DId), DeliveryList_SelectionChanged, filter.Count > 0 ? ControlUtils.RenewSourceDefault.IfOnly : ControlUtils.RenewSourceDefault.None, !updateSort); + await RefreshDeliveryParts(); var members = deliveries.Select(d => d.Member).DistinctBy(m => m.MgNr).ToList(); StatusMembers.Text = $"Mitglieder: {members.Count}" + (members.Count > 0 && members.Count <= 4 ? $" ({string.Join(", ", members.Select(m => m.AdministrativeName))})" : ""); @@ -760,7 +767,7 @@ namespace Elwig.Windows { private async Task RefreshDeliveryParts() { if (DeliveryList.SelectedItem is Delivery d) { ControlUtils.RenewItemsSource(ModifiersInput, await Context.Modifiers.Where(m => m.Year == d.Year).OrderBy(m => m.Ordering).ToListAsync(), i => (i as Modifier)?.ModId); - ControlUtils.RenewItemsSource(DeliveryPartList, d.Parts.OrderBy(p => p.DPNr).ToList(), i => ((i as DeliveryPart)?.Year, (i as DeliveryPart)?.DId, (i as DeliveryPart)?.DPNr), DeliveryPartList_SelectionChanged, ControlUtils.RenewSourceDefault.First); + ControlUtils.RenewItemsSource(DeliveryPartList, d.FilteredParts.OrderBy(p => p.DPNr).ToList(), i => ((i as DeliveryPart)?.Year, (i as DeliveryPart)?.DId, (i as DeliveryPart)?.DPNr), DeliveryPartList_SelectionChanged, ControlUtils.RenewSourceDefault.First); } else { ControlUtils.RenewItemsSource(ModifiersInput, await Context.Modifiers.Where(m => m.Year == Utils.CurrentLastSeason).OrderBy(m => m.Ordering).ToListAsync(), i => (i as Modifier)?.ModId); DeliveryPartList.ItemsSource = null; @@ -1134,7 +1141,7 @@ namespace Elwig.Windows { } else { // switch to last delivery part DeliveryPartList.IsEnabled = true; - DeliveryPartList.SelectedItem = d.Parts.Last(); + DeliveryPartList.SelectedItem = d.FilteredParts.Last(); } }