From 7f21b7b2312a55f90cfeb54e509a1a4761c82e85 Mon Sep 17 00:00:00 2001 From: Lorenz Stechauner Date: Wed, 27 Mar 2024 16:10:28 +0100 Subject: [PATCH] [#13][#31] DeliveryAdminWindow: Rework menu and add DeliveryJournal export --- Elwig/Documents/DeliveryJournal.cs | 26 +-- Elwig/Documents/DeliveryJournal.cshtml | 16 +- Elwig/Models/Dtos/DeliveryJournalData.cs | 107 ++++++++++ Elwig/Windows/DeliveryAdminWindow.xaml | 58 ++++-- Elwig/Windows/DeliveryAdminWindow.xaml.cs | 233 +++++++++++++++------- 5 files changed, 317 insertions(+), 123 deletions(-) create mode 100644 Elwig/Models/Dtos/DeliveryJournalData.cs diff --git a/Elwig/Documents/DeliveryJournal.cs b/Elwig/Documents/DeliveryJournal.cs index 9ae2db4..293ed42 100644 --- a/Elwig/Documents/DeliveryJournal.cs +++ b/Elwig/Documents/DeliveryJournal.cs @@ -1,9 +1,5 @@ -using Elwig.Helpers; -using Elwig.Models.Entities; -using Microsoft.EntityFrameworkCore; -using System; +using Elwig.Models.Dtos; using System.Collections.Generic; -using System.Linq; namespace Elwig.Documents { public class DeliveryJournal : Document { @@ -11,25 +7,15 @@ namespace Elwig.Documents { public new static string Name => "Lieferjournal"; public string Filter; - public IEnumerable Deliveries; + public IEnumerable Deliveries; - public DeliveryJournal(string filter, IEnumerable deliveries) : base($"{Name} {filter}") { + public DeliveryJournal(string filter, IEnumerable deliveries) : base($"{Name} {filter}") { Filter = filter; Deliveries = deliveries; } - public DeliveryJournal(string filter, IQueryable deliveries) : - this(filter, deliveries - .Include(p => p.Delivery).ThenInclude(d => d.Member) - .Include(p => p.Variety) - .ToList()) { } - - public DeliveryJournal(AppDbContext ctx, DateOnly date) : - this(date.ToString("dd.MM.yyyy"), ctx.DeliveryParts - .Where(p => p.Delivery.DateString == date.ToString("yyy-MM-dd")) - .OrderBy(p => p.Delivery.DateString) - .ThenBy(p => p.Delivery.TimeString) - .ThenBy(p => p.Delivery.LsNr) - .ThenBy(p => p.DPNr)) { } + public DeliveryJournal(string filter, DeliveryJournalData data) : + this(filter, data.Rows) { + } } } diff --git a/Elwig/Documents/DeliveryJournal.cshtml b/Elwig/Documents/DeliveryJournal.cshtml index cc6c8df..cb8054b 100644 --- a/Elwig/Documents/DeliveryJournal.cshtml +++ b/Elwig/Documents/DeliveryJournal.cshtml @@ -40,13 +40,13 @@ @foreach (var p in Model.Deliveries) { - @p.Delivery.LsNr - @p.DPNr - @($"{p.Delivery.Date:dd.MM.yyyy}") - @($"{p.Delivery.Time:HH:mm}") - @p.Delivery.Member.MgNr - @p.Delivery.Member.AdministrativeName - @p.Variety.Name + @p.LsNr + @p.Pos + @($"{p.Date:dd.MM.yyyy}") + @($"{p.Time:HH:mm}") + @p.MgNr + @p.AdministrativeName + @p.Variety @($"{p.Oe:N0}") @($"{p.Kmw:N1}") @($"{p.Weight:N0}") @@ -58,7 +58,7 @@ var oe = Elwig.Helpers.Utils.KmwToOe(kmw); } Gesamt: - (Teil-)Lieferungen: @($"{Model.Deliveries.DistinctBy(p => p.Delivery).Count():N0}") (@($"{Model.Deliveries.Count():N0}")) + (Teil-)Lieferungen: @($"{Model.Deliveries.DistinctBy(p => p.LsNr).Count():N0}") (@($"{Model.Deliveries.Count():N0}")) @($"{oe:N0}") @($"{kmw:N1}") @($"{Model.Deliveries.Sum(p => p.Weight):N0}") diff --git a/Elwig/Models/Dtos/DeliveryJournalData.cs b/Elwig/Models/Dtos/DeliveryJournalData.cs new file mode 100644 index 0000000..3aad33a --- /dev/null +++ b/Elwig/Models/Dtos/DeliveryJournalData.cs @@ -0,0 +1,107 @@ +using Elwig.Documents; +using Elwig.Models.Entities; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Elwig.Models.Dtos { + public class DeliveryJournalData : DataTable { + + private static readonly (string, string, string?, int?)[] FieldNames = [ + ("LsNr", "LsNr.", null, 30), + ("Pos", "Pos.", null, 10), + ("Date", "Datum", null, 20), + ("Time", "Zeit", null, 20), + ("MgNr", "MgNr.", null, 12), + ("Name1", "Name", null, 40), + ("Name2", "Vorname", null, 40), + ("SortId", "Sorte", null, 10), + ("AttrId", "Attr.", null, 15), + ("CultId", "Bewirt.", null, 15), + ("QualId", "Qualität", null, 15), + ("Gradation", "Gradation", "°Oe|°KMW", 40), + ("Weight", "Gewicht", "kg", 20), + ("NetGross", "bto./nto.", null, 20), + ("HkId", "Herkunft", null, 20), + ("Modifiers", "Zu-/Abschläge", null, 40), + ("Comment", "Anmerkung", null, 60), + ]; + + public DeliveryJournalData(IEnumerable rows, List filterNames) : + base(DeliveryJournal.Name, DeliveryJournal.Name, string.Join(" / ", filterNames), rows, FieldNames) { + } + + public static async Task FromQuery(IQueryable query, List filterNames) { + return new((await query + .Include(p => p.Delivery.Member) + .Include(p => p.Delivery.Branch) + .Include(p => p.PartModifiers).ThenInclude(m => m.Modifier) + .Include(p => p.Variety) + .Include(p => p.Attribute) + .Include(p => p.Cultivation) + .Include(p => p.Origin) + .Include(p => p.Quality) + .AsSplitQuery() + .ToListAsync()).Select(d => new DeliveryJournalRow(d)), filterNames); + } + } + + public class DeliveryJournalRow : IDelivery { + public string LsNr; + public int Pos; + public DateOnly Date; + public TimeOnly? Time; + public int MgNr; + public string Name1; + public string Name2; + public string AdministrativeName; + public string SortId; + public string Variety; + public string? AttrId; + public string? Attribute; + public string? CultId; + public string? Cultivation; + public string HkId; + public string QualId; + public string Quality; + public (double Oe, double Kmw) Gradation; + public double Kmw => Gradation.Kmw; + public double Oe => Gradation.Oe; + public int Weight { get; set; } + public bool IsNetWeight; + public string NetGross => IsNetWeight ? "n" : "b"; + public string? Modifiers; + public string? Comment; + + public DeliveryJournalRow(DeliveryPart p) { + var d = p.Delivery; + var m = d.Member; + + LsNr = d.LsNr; + Pos = p.DPNr; + Date = d.Date; + Time = d.Time; + MgNr = m.MgNr; + Name1 = m.FamilyName; + Name2 = m.AdministrativeName2; + AdministrativeName = m.AdministrativeName; + + SortId = p.SortId; + Variety = p.Variety.Name; + AttrId = p.AttrId; + Attribute = p.Attribute?.Name; + CultId = p.CultId; + Cultivation = p.Cultivation?.Name; + HkId = p.HkId; + QualId = p.QualId; + Quality = p.Quality.Name; + Gradation = (p.Oe, p.Kmw); + Weight = p.Weight; + IsNetWeight = p.IsNetWeight; + Modifiers = string.Join(" / ", p.Modifiers.Order()); + Comment = d.Comment == null && p.Comment == null ? null : (d.Comment + (d.Comment != null && p.Comment != null ? " / " : "") + p.Comment); + } + } +} diff --git a/Elwig/Windows/DeliveryAdminWindow.xaml b/Elwig/Windows/DeliveryAdminWindow.xaml index d768557..c564e38 100644 --- a/Elwig/Windows/DeliveryAdminWindow.xaml +++ b/Elwig/Windows/DeliveryAdminWindow.xaml @@ -1,8 +1,6 @@ - - - - - - - - - + + + + - - + + + + + + + + + + + + + + + + + + + + TextFilter = []; private readonly RoutedCommand CtrlF = new("CtrlF", typeof(DeliveryAdminWindow), [new KeyGesture(Key.F, ModifierKeys.Control)]); + private readonly RoutedCommand CtrlL = new("CtrlL", typeof(DeliveryAdminWindow), [new KeyGesture(Key.L, ModifierKeys.Control)]); private readonly RoutedCommand CtrlP = new("CtrlP", typeof(DeliveryAdminWindow), [new KeyGesture(Key.P, ModifierKeys.Control)]); + private readonly RoutedCommand CtrlO = new("CtrlO", typeof(DeliveryAdminWindow), [new KeyGesture(Key.O, ModifierKeys.Control)]); + private readonly RoutedCommand CtrlJ = new("CtrlJ", typeof(DeliveryAdminWindow), [new KeyGesture(Key.J, ModifierKeys.Control)]); + private readonly RoutedCommand CtrlQ = new("CtrlQ", typeof(DeliveryAdminWindow), [new KeyGesture(Key.Q, ModifierKeys.Control)]); private readonly RoutedCommand CtrlShiftP = new("CtrlShiftP", typeof(DeliveryAdminWindow), [new KeyGesture(Key.P, ModifierKeys.Control | ModifierKeys.Shift)]); + private readonly RoutedCommand CtrlShiftO = new("CtrlShiftO", typeof(DeliveryAdminWindow), [new KeyGesture(Key.O, ModifierKeys.Control | ModifierKeys.Shift)]); private string? LastScaleError = null; private string? ManualWeighingReason = null; @@ -43,8 +49,13 @@ namespace Elwig.Windows { public DeliveryAdminWindow(bool receipt = false) { InitializeComponent(); CommandBindings.Add(new CommandBinding(CtrlF, FocusSearchInput)); - CommandBindings.Add(new CommandBinding(CtrlP, Menu_Print_ShowDeliveryNote_Click)); - CommandBindings.Add(new CommandBinding(CtrlShiftP, Menu_Print_PrintDeliveryNote_Click)); + CommandBindings.Add(new CommandBinding(CtrlL, Menu_DeliveryJournal_SaveFilters_Click)); + CommandBindings.Add(new CommandBinding(CtrlP, Menu_DeliveryNote_Show_Click)); + CommandBindings.Add(new CommandBinding(CtrlO, Menu_DeliveryJournal_ShowFilters_Click)); + CommandBindings.Add(new CommandBinding(CtrlJ, Menu_DeliveryJournal_PrintToday_Click)); + CommandBindings.Add(new CommandBinding(CtrlQ, Menu_WineQualityStatistics_PrintToday_Click)); + CommandBindings.Add(new CommandBinding(CtrlShiftP, Menu_DeliveryNote_Print_Click)); + CommandBindings.Add(new CommandBinding(CtrlShiftO, Menu_DeliveryJournal_PrintFilters_Click)); RequiredInputs = [ MgNrInput, MemberInput, LsNrInput, DateInput, BranchInput, @@ -132,35 +143,48 @@ namespace Elwig.Windows { } } - private async void Menu_Print_ShowDeliveryNote_Click(object sender, RoutedEventArgs evt) { - if (DeliveryList.SelectedItem is not Delivery d) return; + private async void Menu_DeliveryNote_Show_Click(object sender, RoutedEventArgs evt) { + if (DeliveryList.SelectedItem is not Delivery d) + return; + await GenerateDeliveryNote(d.Year, d.DId, 0); + } + + private async void Menu_DeliveryNote_Print_Click(object sender, RoutedEventArgs evt) { + if (DeliveryList.SelectedItem is not Delivery d) + return; + await GenerateDeliveryNote(d.Year, d.DId, 1); + } + + private async void Menu_DeliveryNote_Email_Click(object sender, RoutedEventArgs evt) { + if (DeliveryList.SelectedItem is not Delivery d) + return; + await GenerateDeliveryNote(d.Year, d.DId, 2); + } + + private static async Task GenerateDeliveryNote(int year, int did, int mode) { Mouse.OverrideCursor = Cursors.AppStarting; try { using var ctx = new AppDbContext(); - using var doc = new DeliveryNote((await ctx.Deliveries.FindAsync(d.Year, d.DId))!, ctx); + var d = (await ctx.Deliveries.FindAsync(year, did))!; + using var doc = new DeliveryNote(d, ctx); await doc.Generate(); - doc.Show(); + if (mode == 1 && !App.Config.Debug) { + await doc.Print(); + } else if (mode == 2) { + var success = await Utils.SendEmail(d.Member, $"{DeliveryNote.Name} Nr. {d.LsNr}", $"Im Anhang finden Sie den {DeliveryNote.Name} Nr. {d.LsNr}", [doc]); + if (success) + MessageBox.Show("Die E-Mail wurde erfolgreich verschickt!", "E-Mail verschickt", + MessageBoxButton.OK, MessageBoxImage.Information); + } else { + doc.Show(); + } } catch (Exception exc) { MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); } Mouse.OverrideCursor = null; } - private async void Menu_Print_PrintDeliveryNote_Click(object sender, RoutedEventArgs evt) { - if (DeliveryList.SelectedItem is not Delivery d) return; - Mouse.OverrideCursor = Cursors.AppStarting; - try { - using var ctx = new AppDbContext(); - using var doc = new DeliveryNote((await ctx.Deliveries.FindAsync(d.Year, d.DId))!, ctx); - await doc.Generate(); - await doc.Print(); - } catch (Exception exc) { - MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); - } - Mouse.OverrideCursor = null; - } - - private async void Menu_Export_Bki_Click(object sender, RoutedEventArgs evt) { + private async void Menu_Bki_SaveList_Click(object sender, RoutedEventArgs evt) { if (sender is not MenuItem m) return; var year = int.Parse(m.Header.ToString()?.Split(" ")[^1] ?? Utils.CurrentLastSeason.ToString()); var d = new SaveFileDialog() { @@ -177,58 +201,113 @@ namespace Elwig.Windows { } } - private async void Menu_Print_DeliveryJournal_ShowToday_Click(object sender, RoutedEventArgs evt) { - Mouse.OverrideCursor = Cursors.AppStarting; - try { - using var ctx = new AppDbContext(); - using var doc = new DeliveryJournal(ctx, DateOnly.FromDateTime(Utils.Today)); - await doc.Generate(); - doc.Show(); - } catch (Exception exc) { - MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); - } - Mouse.OverrideCursor = null; + private async void Menu_DeliveryJournal_SaveToday_Click(object sender, RoutedEventArgs evt) { + await GenerateDeliveryJournal(1, 0); } - private async void Menu_Print_DeliveryJournal_PrintToday_Click(object sender, RoutedEventArgs evt) { - Mouse.OverrideCursor = Cursors.AppStarting; - try { - using var ctx = new AppDbContext(); - using var doc = new DeliveryJournal(ctx, DateOnly.FromDateTime(Utils.Today)); - await doc.Generate(); - await doc.Print(); - } catch (Exception exc) { - MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); - } - Mouse.OverrideCursor = null; + private async void Menu_DeliveryJournal_ShowToday_Click(object sender, RoutedEventArgs evt) { + await GenerateDeliveryJournal(1, 1); } - private async void Menu_Print_DeliveryJournal_ShowFilter_Click(object sender, RoutedEventArgs evt) { - Mouse.OverrideCursor = Cursors.AppStarting; - try { - using var ctx = new AppDbContext(); - var (f, _, d, _, _) = await GetFilters(ctx); - var doc = new DeliveryJournal(string.Join(" / ", f), d); - await doc.Generate(); - doc.Show(); - } catch (Exception exc) { - MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); - } - Mouse.OverrideCursor = null; + private async void Menu_DeliveryJournal_PrintToday_Click(object sender, RoutedEventArgs evt) { + await GenerateDeliveryJournal(1, 2); } - private async void Menu_Print_DeliveryJournal_PrintFilter_Click(object sender, RoutedEventArgs evt) { - Mouse.OverrideCursor = Cursors.AppStarting; - try { - using var ctx = new AppDbContext(); - var (f, _, d, _, _) = await GetFilters(ctx); - var doc = new DeliveryJournal(string.Join(" / ", f), d); - await doc.Generate(); - doc.Show(); - } catch (Exception exc) { - MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); + private async void Menu_DeliveryJournal_SaveFilters_Click(object sender, RoutedEventArgs evt) { + await GenerateDeliveryJournal(0, 0); + } + + private async void Menu_DeliveryJournal_ShowFilters_Click(object sender, RoutedEventArgs evt) { + await GenerateDeliveryJournal(0, 1); + } + + private async void Menu_DeliveryJournal_PrintFilters_Click(object sender, RoutedEventArgs evt) { + await GenerateDeliveryJournal(0, 2); + } + + private async Task GenerateDeliveryJournal(int modeWho, int modeWhat) { + using var ctx = new AppDbContext(); + IQueryable query; + List filterNames = []; + if (modeWho == 0) { + var (f, _, q, _, _) = await GetFilters(ctx); + query = q; + filterNames.AddRange(f); + } else { + var date = $"{Utils.Today:yyyy-MM-dd}"; + query = ctx.DeliveryParts + .Where(p => p.Delivery.DateString == date); + filterNames.Add($"{Utils.Today:dd.MM.yyyy}"); } - Mouse.OverrideCursor = null; + + query = query + .OrderBy(p => p.Delivery.DateString) + .ThenBy(p => p.Delivery.TimeString) + .ThenBy(p => p.Delivery.LsNr) + .ThenBy(p => p.DPNr); + + if (modeWhat == 0) { + var d = new SaveFileDialog() { + FileName = $"{DeliveryJournal.Name}.ods", + DefaultExt = "ods", + Filter = "OpenDocument Format Spreadsheet (*.ods)|*.ods", + Title = $"{DeliveryJournal.Name} speichern unter - Elwig" + }; + if (d.ShowDialog() == true) { + Mouse.OverrideCursor = Cursors.AppStarting; + try { + var data = await DeliveryJournalData.FromQuery(query, filterNames); + using var ods = new OdsFile(d.FileName); + await ods.AddTable(data); + } catch (Exception exc) { + MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); + } + Mouse.OverrideCursor = null; + } + } else { + Mouse.OverrideCursor = Cursors.AppStarting; + try { + var data = await DeliveryJournalData.FromQuery(query, filterNames); + using var doc = new DeliveryJournal(string.Join(" / ", filterNames), data); + await doc.Generate(); + if (modeWhat == 2 && !App.Config.Debug) { + await doc.Print(); + } else { + doc.Show(); + } + } catch (Exception exc) { + MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); + } + Mouse.OverrideCursor = null; + } + } + + private async void Menu_WineQualityStatistics_SaveToday_Click(object sender, RoutedEventArgs evt) { + await GenerateWineQualityStatistics(1, 0); + } + + private async void Menu_WineQualityStatistics_ShowToday_Click(object sender, RoutedEventArgs evt) { + await GenerateWineQualityStatistics(1, 1); + } + + private async void Menu_WineQualityStatistics_PrintToday_Click(object sender, RoutedEventArgs evt) { + await GenerateWineQualityStatistics(1, 2); + } + + private async void Menu_WineQualityStatistics_SaveFilters_Click(object sender, RoutedEventArgs evt) { + await GenerateWineQualityStatistics(0, 0); + } + + private async void Menu_WineQualityStatistics_ShowFilters_Click(object sender, RoutedEventArgs evt) { + await GenerateWineQualityStatistics(0, 1); + } + + private async void Menu_WineQualityStatistics_PrintFilters_Click(object sender, RoutedEventArgs evt) { + await GenerateWineQualityStatistics(0, 2); + } + + private async Task GenerateWineQualityStatistics(int modeWho, int modeWhat) { + // TODO } private void Menu_Settings_EnableFreeEditing_Checked(object sender, RoutedEventArgs evt) { @@ -753,7 +832,7 @@ namespace Elwig.Windows { AddGradationToolTipRow(1, "Gradation", null, kmwMin, kmwAvg, kmwMax); var attrGroups = await deliveryParts - .GroupBy(p => new { Attr = p.Attribute.Name, Cult = p.Cultivation.Name }) + .GroupBy(p => new { Attr = p.Attribute!.Name, Cult = p.Cultivation!.Name }) .Select(g => new { g.Key.Attr, g.Key.Cult, @@ -779,8 +858,8 @@ namespace Elwig.Windows { .ToListAsync(); var groups = await deliveryParts .GroupBy(p => new { - Attr = p.Attribute.Name, - Cult = p.Cultivation.Name, + Attr = p.Attribute!.Name, + Cult = p.Cultivation!.Name, p.SortId, }) .Select(g => new { @@ -856,13 +935,13 @@ namespace Elwig.Windows { Title = $"Lieferungen - {Member.AdministrativeName} - Elwig"; } - Menu_Export_Bki.Items.Clear(); + Menu_Bki_SaveList.Items.Clear(); foreach (var s in await ctx.Seasons.OrderByDescending(s => s.Year).ToListAsync()) { var i = new MenuItem { Header = $"Saison {s.Year}", }; - i.Click += Menu_Export_Bki_Click; - Menu_Export_Bki.Items.Add(i); + i.Click += Menu_Bki_SaveList_Click; + Menu_Bki_SaveList.Items.Add(i); } await RefreshDeliveryList(); @@ -1176,12 +1255,14 @@ namespace Elwig.Windows { await RefreshDeliveryParts(); if (DeliveryList.SelectedItem != null) { DeleteDeliveryButton.IsEnabled = true; - Menu_Print_ShowDeliveryNote.IsEnabled = !IsEditing && !IsCreating; - Menu_Print_PrintDeliveryNote.IsEnabled = !IsEditing && !IsCreating; + Menu_DeliveryNote_Show.IsEnabled = !IsEditing && !IsCreating; + Menu_DeliveryNote_Print.IsEnabled = !IsEditing && !IsCreating; + Menu_DeliveryNote_Email.IsEnabled = !IsEditing && !IsCreating; } else { DeleteDeliveryButton.IsEnabled = false; - Menu_Print_ShowDeliveryNote.IsEnabled = false; - Menu_Print_PrintDeliveryNote.IsEnabled = false; + Menu_DeliveryNote_Show.IsEnabled = false; + Menu_DeliveryNote_Print.IsEnabled = false; + Menu_DeliveryNote_Email.IsEnabled = false; } }