diff --git a/Elwig/App.xaml.cs b/Elwig/App.xaml.cs index 19f7a7a..dfb8a88 100644 --- a/Elwig/App.xaml.cs +++ b/Elwig/App.xaml.cs @@ -197,10 +197,12 @@ namespace Elwig { var ch = CurrentLastWrite; if (ch > CurrentApp.LastChanged) CurrentApp.LastChanged = ch; - foreach (Window w in CurrentApp.Windows) { - if (w is not ContextWindow c) continue; - MainDispatcher.BeginInvoke(c.HintContextChange); - } + MainDispatcher.Invoke(() => { + foreach (Window w in CurrentApp.Windows) { + if (w is not ContextWindow c) continue; + MainDispatcher.BeginInvoke(c.HintContextChange); + } + }); } private void OnAutoUpdateTimer(object? sender, EventArgs? evt) { diff --git a/Elwig/Helpers/Utils.cs b/Elwig/Helpers/Utils.cs index ac965a2..4dc11e2 100644 --- a/Elwig/Helpers/Utils.cs +++ b/Elwig/Helpers/Utils.cs @@ -496,34 +496,39 @@ namespace Elwig.Helpers { if (App.Config.Smtp == null) return false; - SmtpClient? client = null; - try { - Mouse.OverrideCursor = Cursors.AppStarting; - client = await GetSmtpClient(); + Mouse.OverrideCursor = Cursors.Wait; - using var msg = new MimeMessage(); - msg.From.Add(new MailboxAddress(App.Client.NameFull, App.Config.Smtp.Value.From)); - msg.To.AddRange(member.EmailAddresses.OrderBy(a => a.Nr).Select(a => new MailboxAddress(member.AdministrativeName, a.Address))); - msg.Subject = subject; - var body = new Multipart("mixed") { - new TextPart("plain") { Text = text } - }; - foreach (var doc in docs) { - var name = NormalizeFileName(doc.Title); - body.Add(doc.AsEmailAttachment($"{name}.pdf")); + var success = await Task.Run(async () => { + SmtpClient? client = null; + try { + client = await GetSmtpClient(); + + using var msg = new MimeMessage(); + msg.From.Add(new MailboxAddress(App.Client.NameFull, App.Config.Smtp.Value.From)); + msg.To.AddRange(member.EmailAddresses.OrderBy(a => a.Nr).Select(a => new MailboxAddress(member.AdministrativeName, a.Address))); + msg.Subject = subject; + var body = new Multipart("mixed") { + new TextPart("plain") { Text = text } + }; + foreach (var doc in docs) { + var name = NormalizeFileName(doc.Title); + body.Add(doc.AsEmailAttachment($"{name}.pdf")); + } + msg.Body = body; + await client!.SendAsync(msg); + } catch (Exception exc) { + MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); + return false; + } finally { + if (client != null) + await client.DisconnectAsync(true); + client?.Dispose(); } - msg.Body = body; - await client!.SendAsync(msg); - } catch (Exception exc) { - MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); - return false; - } finally { - if (client != null) - await client.DisconnectAsync(true); - client?.Dispose(); - Mouse.OverrideCursor = null; - } - return true; + return true; + }); + + Mouse.OverrideCursor = null; + return success; } public static async Task ExportDocument(Document doc, ExportMode mode, string? filename = null, (Member, string, string)? emailData = null) { diff --git a/Elwig/Services/MemberService.cs b/Elwig/Services/MemberService.cs index 2a7dd37..79ace5e 100644 --- a/Elwig/Services/MemberService.cs +++ b/Elwig/Services/MemberService.cs @@ -359,51 +359,57 @@ namespace Elwig.Services { } public static async Task GenerateMemberDataSheet(Member m, ExportMode mode) { - Mouse.OverrideCursor = Cursors.AppStarting; - try { - using var ctx = new AppDbContext(); - using var doc = new MemberDataSheet(m, ctx); - await Utils.ExportDocument(doc, mode, emailData: (m, MemberDataSheet.Name, "Im Anhang finden Sie das aktuelle Stammdatenblatt")); - } catch (Exception exc) { - MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); - } + Mouse.OverrideCursor = Cursors.Wait; + await Task.Run(async () => { + try { + using var ctx = new AppDbContext(); + using var doc = new MemberDataSheet(m, ctx); + await Utils.ExportDocument(doc, mode, emailData: (m, MemberDataSheet.Name, "Im Anhang finden Sie das aktuelle Stammdatenblatt")); + } catch (Exception exc) { + MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); + } + }); Mouse.OverrideCursor = null; } public static async Task GenerateDeliveryConfirmation(Member m, int year, ExportMode mode) { - Mouse.OverrideCursor = Cursors.AppStarting; - try { - var b = new Billing(year); - await b.FinishSeason(); - await b.CalculateBuckets(); - App.HintContextChange(); + Mouse.OverrideCursor = Cursors.Wait; + await Task.Run(async () => { + try { + var b = new Billing(year); + await b.FinishSeason(); + await b.CalculateBuckets(); + App.HintContextChange(); - using var ctx = new AppDbContext(); - var data = await DeliveryConfirmationDeliveryData.ForMember(ctx.DeliveryParts, year, m); - using var doc = new DeliveryConfirmation(ctx, year, m, data); - await Utils.ExportDocument(doc, mode, emailData: (m, $"{DeliveryConfirmation.Name} {year}", $"Im Anhang finden Sie die Anlieferungsbestätigung {year}")); - } catch (Exception exc) { - MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); - } + using var ctx = new AppDbContext(); + var data = await DeliveryConfirmationDeliveryData.ForMember(ctx.DeliveryParts, year, m); + using var doc = new DeliveryConfirmation(ctx, year, m, data); + await Utils.ExportDocument(doc, mode, emailData: (m, $"{DeliveryConfirmation.Name} {year}", $"Im Anhang finden Sie die Anlieferungsbestätigung {year}")); + } catch (Exception exc) { + MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); + } + }); Mouse.OverrideCursor = null; } public static async Task GenerateCreditNote(Member m, int year, int avnr, ExportMode mode) { - Mouse.OverrideCursor = Cursors.AppStarting; - try { - using var ctx = new AppDbContext(); - var v = (await ctx.PaymentVariants.FindAsync(year, avnr))!; - var data = await CreditNoteDeliveryData.ForPaymentVariant(ctx.CreditNoteDeliveryRows, ctx.Seasons, year, avnr); - var p = (await ctx.MemberPayments.FindAsync(year, avnr, m.MgNr))!; - var b = BillingData.FromJson((await ctx.PaymentVariants.FindAsync(year, avnr))!.Data); + Mouse.OverrideCursor = Cursors.Wait; + await Task.Run(async () => { + try { + using var ctx = new AppDbContext(); + var v = (await ctx.PaymentVariants.FindAsync(year, avnr))!; + var data = await CreditNoteDeliveryData.ForPaymentVariant(ctx.CreditNoteDeliveryRows, ctx.Seasons, year, avnr); + var p = (await ctx.MemberPayments.FindAsync(year, avnr, m.MgNr))!; + var b = BillingData.FromJson((await ctx.PaymentVariants.FindAsync(year, avnr))!.Data); - using var doc = new CreditNote(ctx, p, data[m.MgNr], - b.ConsiderContractPenalties, b.ConsiderTotalPenalty, b.ConsiderAutoBusinessShares, b.ConsiderCustomModifiers, - await ctx.GetMemberUnderDelivery(year, m.MgNr)); - await Utils.ExportDocument(doc, mode, emailData: (m, $"{CreditNote.Name} {v.Name}", $"Im Anhang finden Sie die Traubengutschrift {v.Name}")); - } catch (Exception exc) { - MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); - } + using var doc = new CreditNote(ctx, p, data[m.MgNr], + b.ConsiderContractPenalties, b.ConsiderTotalPenalty, b.ConsiderAutoBusinessShares, b.ConsiderCustomModifiers, + await ctx.GetMemberUnderDelivery(year, m.MgNr)); + await Utils.ExportDocument(doc, mode, emailData: (m, $"{CreditNote.Name} {v.Name}", $"Im Anhang finden Sie die Traubengutschrift {v.Name}")); + } catch (Exception exc) { + MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); + } + }); Mouse.OverrideCursor = null; } @@ -456,14 +462,16 @@ namespace Elwig.Services { Title = $"{MemberList.Name} speichern unter - Elwig" }; if (d.ShowDialog() == true) { - Mouse.OverrideCursor = Cursors.AppStarting; - try { - var data = await MemberListData.FromQuery(query, filterNames, filterNames.Where(f => f.StartsWith("Flächenbindung")).Select(f => f.Split(' ')[^1])); - 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 = Cursors.Wait; + await Task.Run(async () => { + try { + var data = await MemberListData.FromQuery(query, filterNames, filterNames.Where(f => f.StartsWith("Flächenbindung")).Select(f => f.Split(' ')[^1])); + 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 if (mode == ExportMode.Export) { @@ -474,8 +482,33 @@ namespace Elwig.Services { Title = $"{MemberList.Name} speichern unter - Elwig" }; if (d.ShowDialog() == true) { - Mouse.OverrideCursor = Cursors.AppStarting; + Mouse.OverrideCursor = Cursors.Wait; + await Task.Run(async () => { + try { + var members = await query + .OrderBy(m => m.MgNr) + .Include(m => m.BillingAddress) + .Include(m => m.TelephoneNumbers) + .Include(m => m.EmailAddresses) + .AsSplitQuery() + .ToListAsync(); + var areaComs = await query + .SelectMany(m => m.AreaCommitments) + .Include(c => c.Rd) + .ToListAsync(); + await ElwigData.Export(d.FileName, members, areaComs, filterNames); + } catch (Exception exc) { + MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); + } + }); + Mouse.OverrideCursor = null; + } + } else if (mode == ExportMode.Upload && App.Config.SyncUrl != null) { + Mouse.OverrideCursor = Cursors.Wait; + await Task.Run(async () => { try { + var filename = $"{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{App.ZwstId}.elwig.zip"; + var path = Path.Combine(App.TempPath, filename); var members = await query .OrderBy(m => m.MgNr) .Include(m => m.BillingAddress) @@ -487,99 +520,80 @@ namespace Elwig.Services { .SelectMany(m => m.AreaCommitments) .Include(c => c.Rd) .ToListAsync(); - await ElwigData.Export(d.FileName, members, areaComs, filterNames); + if (members.Count == 0) { + MessageBox.Show("Es wurden keine Mitglieder zum Hochladen ausgewählt!", "Mitglieder hochladen", + MessageBoxButton.OK, MessageBoxImage.Error); + } else { + await ElwigData.Export(path, members, areaComs, filterNames); + await Utils.UploadExportData(path, App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword); + MessageBox.Show($"Hochladen von {members.Count:N0} Mitgliedern erfolgreich!", "Mitglieder hochgeladen", + MessageBoxButton.OK, MessageBoxImage.Information); + } + } catch (HttpRequestException exc) { + MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Mitglieder hochladen", MessageBoxButton.OK, MessageBoxImage.Error); + } catch (TaskCanceledException exc) { + MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Mitglieder hochladen", MessageBoxButton.OK, MessageBoxImage.Error); } catch (Exception exc) { MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); } - Mouse.OverrideCursor = null; - } - } else if (mode == ExportMode.Upload && App.Config.SyncUrl != null) { - Mouse.OverrideCursor = Cursors.AppStarting; - try { - var filename = $"{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{App.ZwstId}.elwig.zip"; - var path = Path.Combine(App.TempPath, filename); - var members = await query - .OrderBy(m => m.MgNr) - .Include(m => m.BillingAddress) - .Include(m => m.TelephoneNumbers) - .Include(m => m.EmailAddresses) - .AsSplitQuery() - .ToListAsync(); - var areaComs = await query - .SelectMany(m => m.AreaCommitments) - .Include(c => c.Rd) - .ToListAsync(); - if (members.Count == 0) { - MessageBox.Show("Es wurden keine Mitglieder zum Hochladen ausgewählt!", "Mitglieder hochladen", - MessageBoxButton.OK, MessageBoxImage.Error); - } else { - await ElwigData.Export(path, members, areaComs, filterNames); - await Utils.UploadExportData(path, App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword); - MessageBox.Show($"Hochladen von {members.Count:N0} Mitgliedern erfolgreich!", "Mitglieder hochgeladen", - MessageBoxButton.OK, MessageBoxImage.Information); - } - } catch (HttpRequestException exc) { - MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Mitglieder hochladen", MessageBoxButton.OK, MessageBoxImage.Error); - } catch (TaskCanceledException exc) { - MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Mitglieder hochladen", MessageBoxButton.OK, MessageBoxImage.Error); - } catch (Exception exc) { - MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); - } + }); Mouse.OverrideCursor = null; } else { - Mouse.OverrideCursor = Cursors.AppStarting; - try { - var data = await MemberListData.FromQuery(query, filterNames, filterNames.Where(f => f.StartsWith("Flächenbindung")).Select(f => f.Split(' ')[^1])); - using var doc = new MemberList(string.Join(" / ", filterNames), data); - await Utils.ExportDocument(doc, mode); - } catch (Exception exc) { - MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); - } + Mouse.OverrideCursor = Cursors.Wait; + await Task.Run(async () => { + try { + var data = await MemberListData.FromQuery(query, filterNames, filterNames.Where(f => f.StartsWith("Flächenbindung")).Select(f => f.Split(' ')[^1])); + using var doc = new MemberList(string.Join(" / ", filterNames), data); + await Utils.ExportDocument(doc, mode); + } catch (Exception exc) { + MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); + } + }); Mouse.OverrideCursor = null; } } public static async Task UpdateMember(this MemberAdminViewModel vm, int? oldMgNr) { var newMgNr = (int)vm.MgNr!; + var m = new Member { + MgNr = oldMgNr ?? newMgNr, + PredecessorMgNr = vm.PredecessorMgNr, + IsJuridicalPerson = vm.IsJuridicalPerson, + Prefix = vm.IsJuridicalPerson || string.IsNullOrWhiteSpace(vm.Prefix) ? null : vm.Prefix, + GivenName = vm.IsJuridicalPerson || string.IsNullOrWhiteSpace(vm.GivenName) ? null : vm.GivenName, + Name = vm.Name!, + Suffix = vm.IsJuridicalPerson || string.IsNullOrWhiteSpace(vm.Suffix) ? null : vm.Suffix, + ForTheAttentionOf = !vm.IsJuridicalPerson || string.IsNullOrWhiteSpace(vm.ForTheAttentionOf) ? null : vm.ForTheAttentionOf, + Birthday = string.IsNullOrEmpty(vm.Birthday) ? null : string.Join("-", vm.Birthday!.Split(".").Reverse()), + IsDeceased = vm.IsDeceased, + CountryNum = 40, // Austria AT AUT + PostalDestId = vm.Ort!.Id, + Address = vm.Address!, - using (var ctx = new AppDbContext()) { - var m = new Member { - MgNr = oldMgNr ?? newMgNr, - PredecessorMgNr = vm.PredecessorMgNr, - IsJuridicalPerson = vm.IsJuridicalPerson, - Prefix = vm.IsJuridicalPerson || string.IsNullOrWhiteSpace(vm.Prefix) ? null : vm.Prefix, - GivenName = vm.IsJuridicalPerson || string.IsNullOrWhiteSpace(vm.GivenName) ? null : vm.GivenName, - Name = vm.Name!, - Suffix = vm.IsJuridicalPerson || string.IsNullOrWhiteSpace(vm.Suffix) ? null : vm.Suffix, - ForTheAttentionOf = !vm.IsJuridicalPerson || string.IsNullOrWhiteSpace(vm.ForTheAttentionOf) ? null : vm.ForTheAttentionOf, - Birthday = string.IsNullOrEmpty(vm.Birthday) ? null : string.Join("-", vm.Birthday!.Split(".").Reverse()), - IsDeceased = vm.IsDeceased, - CountryNum = 40, // Austria AT AUT - PostalDestId = vm.Ort!.Id, - Address = vm.Address!, + Iban = string.IsNullOrEmpty(vm.Iban) ? null : vm.Iban?.Replace(" ", ""), + Bic = string.IsNullOrEmpty(vm.Bic) ? null : vm.Bic, - Iban = string.IsNullOrEmpty(vm.Iban) ? null : vm.Iban?.Replace(" ", ""), - Bic = string.IsNullOrEmpty(vm.Bic) ? null : vm.Bic, + UstIdNr = string.IsNullOrEmpty(vm.UstIdNr) ? null : vm.UstIdNr, + LfbisNr = string.IsNullOrEmpty(vm.LfbisNr) ? null : vm.LfbisNr, + IsBuchführend = vm.IsBuchführend, + IsOrganic = vm.IsOrganic, - UstIdNr = string.IsNullOrEmpty(vm.UstIdNr) ? null : vm.UstIdNr, - LfbisNr = string.IsNullOrEmpty(vm.LfbisNr) ? null : vm.LfbisNr, - IsBuchführend = vm.IsBuchführend, - IsOrganic = vm.IsOrganic, - - EntryDateString = string.IsNullOrEmpty(vm.EntryDate) ? null : string.Join("-", vm.EntryDate.Split(".").Reverse()), - ExitDateString = string.IsNullOrEmpty(vm.ExitDate) ? null : string.Join("-", vm.ExitDate.Split(".").Reverse()), - BusinessShares = (int)vm.BusinessShares!, - AccountingNr = string.IsNullOrEmpty(vm.AccountingNr) ? null : vm.AccountingNr, - IsActive = vm.IsActive, - IsVollLieferant = vm.IsVollLieferant, - IsFunktionär = vm.IsFunktionär, - ZwstId = vm.Branch?.ZwstId, - DefaultKgNr = vm.DefaultKg?.KgNr, - Comment = string.IsNullOrEmpty(vm.Comment) ? null : vm.Comment, - ContactViaPost = vm.ContactViaPost, - ContactViaEmail = vm.ContactViaEmail, - }; + EntryDateString = string.IsNullOrEmpty(vm.EntryDate) ? null : string.Join("-", vm.EntryDate.Split(".").Reverse()), + ExitDateString = string.IsNullOrEmpty(vm.ExitDate) ? null : string.Join("-", vm.ExitDate.Split(".").Reverse()), + BusinessShares = (int)vm.BusinessShares!, + AccountingNr = string.IsNullOrEmpty(vm.AccountingNr) ? null : vm.AccountingNr, + IsActive = vm.IsActive, + IsVollLieferant = vm.IsVollLieferant, + IsFunktionär = vm.IsFunktionär, + ZwstId = vm.Branch?.ZwstId, + DefaultKgNr = vm.DefaultKg?.KgNr, + Comment = string.IsNullOrEmpty(vm.Comment) ? null : vm.Comment, + ContactViaPost = vm.ContactViaPost, + ContactViaEmail = vm.ContactViaEmail, + }; + await Task.Run(async () => { + using var ctx = new AppDbContext(); if (oldMgNr != null) { ctx.Update(m); } else { @@ -662,7 +676,7 @@ namespace Elwig.Services { if (newMgNr != m.MgNr) { await ctx.Database.ExecuteSqlAsync($"UPDATE member SET mgnr = {newMgNr} WHERE mgnr = {oldMgNr}"); } - } + }); App.HintContextChange(); @@ -670,7 +684,8 @@ namespace Elwig.Services { } public static async Task DeleteMember(int mgnr, bool deletePaymentData, bool deleteDeliveries, bool deleteAreaComs) { - using (var ctx = new AppDbContext()) { + await Task.Run(async () => { + using var ctx = new AppDbContext(); var l = (await ctx.Members.FindAsync(mgnr))!; if (deletePaymentData) { ctx.RemoveRange(l.Credits); @@ -683,7 +698,8 @@ namespace Elwig.Services { } ctx.Remove(l); await ctx.SaveChangesAsync(); - } + }); + App.HintContextChange(); } } diff --git a/Elwig/Windows/MemberAdminWindow.xaml.cs b/Elwig/Windows/MemberAdminWindow.xaml.cs index 2633023..376c0ab 100644 --- a/Elwig/Windows/MemberAdminWindow.xaml.cs +++ b/Elwig/Windows/MemberAdminWindow.xaml.cs @@ -389,7 +389,7 @@ namespace Elwig.Windows { } var d = new DeleteMemberDialog(m.MgNr, m.AdministrativeName, areaComs, deliveries, credits); if (d.ShowDialog() == true) { - Mouse.OverrideCursor = Cursors.AppStarting; + Mouse.OverrideCursor = Cursors.Wait; try { await MemberService.DeleteMember(m.MgNr, d.DeletePaymentData, d.DeleteDeliveries, d.DeleteAreaComs); } catch (Exception exc) { @@ -408,7 +408,7 @@ namespace Elwig.Windows { } private async void SaveButton_Click(object? sender, RoutedEventArgs? evt) { - Mouse.OverrideCursor = Cursors.AppStarting; + Mouse.OverrideCursor = Cursors.Wait; SaveButton.IsEnabled = false; int mgnr; @@ -419,9 +419,8 @@ namespace Elwig.Windows { if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message; MessageBox.Show(str, "Mitglied aktualisieren", MessageBoxButton.OK, MessageBoxImage.Error); SaveButton.IsEnabled = true; - return; - } finally { Mouse.OverrideCursor = null; + return; } IsEditing = false; @@ -436,6 +435,7 @@ namespace Elwig.Windows { await RefreshList(); RefreshInputs(); ViewModel.SearchQuery = ""; + Mouse.OverrideCursor = null; if (mgnr is int m) FocusMember(m); } @@ -491,15 +491,17 @@ namespace Elwig.Windows { private async void Menu_Contact_Letterhead_Click(object sender, RoutedEventArgs evt) { if (ViewModel.SelectedMember is not Member m) return; - Mouse.OverrideCursor = Cursors.AppStarting; + Mouse.OverrideCursor = Cursors.Wait; try { - using var doc = new Letterhead(m); - await doc.Generate(); - if (!App.Config.Debug) { - await doc.Print(); - } else { - doc.Show(); - } + await Task.Run(async () => { + using var doc = new Letterhead(m); + await doc.Generate(); + if (!App.Config.Debug) { + await doc.Print(); + } else { + doc.Show(); + } + }); } catch (Exception exc) { MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); }