1000 lines
		
	
	
		
			47 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			1000 lines
		
	
	
		
			47 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using Elwig.Documents;
 | ||
| using Elwig.Helpers;
 | ||
| using Elwig.Helpers.Billing;
 | ||
| using Elwig.Models.Dtos;
 | ||
| using Elwig.Models.Entities;
 | ||
| using MailKit.Net.Smtp;
 | ||
| using Microsoft.EntityFrameworkCore;
 | ||
| using Microsoft.Win32;
 | ||
| using MimeKit;
 | ||
| using System;
 | ||
| using System.Collections.Generic;
 | ||
| using System.Collections.ObjectModel;
 | ||
| using System.Diagnostics;
 | ||
| using System.IO;
 | ||
| using System.Linq;
 | ||
| using System.Threading.Tasks;
 | ||
| using System.Windows;
 | ||
| using System.Windows.Controls;
 | ||
| using System.Windows.Input;
 | ||
| 
 | ||
| namespace Elwig.Windows {
 | ||
|     public partial class MailWindow : ContextWindow {
 | ||
| 
 | ||
|         // used for document sorting while generating!
 | ||
|         public enum DocType { Undefined, Custom, MemberDataSheet, DeliveryConfirmation, CreditNote }
 | ||
| 
 | ||
|         public class SelectedDoc(DocType type, string name, object? details = null) {
 | ||
|             public DocType Type = type;
 | ||
|             public string Name { get; set; } = name;
 | ||
|             public object? Details = details;
 | ||
|         }
 | ||
| 
 | ||
|         public class GeneratedDoc {
 | ||
|             public DocType Type;
 | ||
|             public Document Doc;
 | ||
| 
 | ||
|             public GeneratedDoc(string pdfPath) {
 | ||
|                 Type = DocType.Custom;
 | ||
|                 Doc = Document.FromPdf(pdfPath);
 | ||
|             }
 | ||
| 
 | ||
|             public GeneratedDoc(Document doc) {
 | ||
|                 Type = doc is MemberDataSheet ? DocType.MemberDataSheet :
 | ||
|                     doc is DeliveryConfirmation ? DocType.DeliveryConfirmation :
 | ||
|                     doc is CreditNote ? DocType.CreditNote : DocType.Undefined;
 | ||
|                 Doc = doc;
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|         public static readonly string[] AvaiableDocuments = [
 | ||
|             MemberDataSheet.Name,
 | ||
|             DeliveryConfirmation.Name,
 | ||
|             CreditNote.Name,
 | ||
|         ];
 | ||
| 
 | ||
|         public readonly int Year;
 | ||
|         public ObservableCollection<SelectedDoc> SelectedDocs = [];
 | ||
|         public IEnumerable<Member> Recipients = [];
 | ||
| 
 | ||
|         protected Document? PrintDocument;
 | ||
|         protected Dictionary<Member, List<Document>>? PrintMemberDocuments;
 | ||
|         protected Dictionary<Member, List<Document>>? EmailDocuments;
 | ||
| 
 | ||
|         public static readonly DependencyProperty PostalAllCountProperty = DependencyProperty.Register(nameof(PostalAllCount), typeof(int), typeof(MailWindow));
 | ||
|         public int PostalAllCount {
 | ||
|             get => (int)GetValue(PostalAllCountProperty);
 | ||
|             private set => SetValue(PostalAllCountProperty, value);
 | ||
|         }
 | ||
| 
 | ||
|         public static readonly DependencyProperty PostalWishCountProperty = DependencyProperty.Register(nameof(PostalWishCount), typeof(int), typeof(MailWindow));
 | ||
|         public int PostalWishCount {
 | ||
|             get => (int)GetValue(PostalWishCountProperty);
 | ||
|             private set => SetValue(PostalWishCountProperty, value);
 | ||
|         }
 | ||
| 
 | ||
|         public static readonly DependencyProperty PostalNoEmailCountProperty = DependencyProperty.Register(nameof(PostalNoEmailCount), typeof(int), typeof(MailWindow));
 | ||
|         public int PostalNoEmailCount {
 | ||
|             get => (int)GetValue(PostalNoEmailCountProperty);
 | ||
|             private set => SetValue(PostalNoEmailCountProperty, value);
 | ||
|         }
 | ||
| 
 | ||
|         public static readonly DependencyProperty EmailAllCountProperty = DependencyProperty.Register(nameof(EmailAllCount), typeof(int), typeof(MailWindow));
 | ||
|         public int EmailAllCount {
 | ||
|             get => (int)GetValue(EmailAllCountProperty);
 | ||
|             private set => SetValue(EmailAllCountProperty, value);
 | ||
|         }
 | ||
| 
 | ||
|         public static readonly DependencyProperty EmailWishCountProperty = DependencyProperty.Register(nameof(EmailWishCount), typeof(int), typeof(MailWindow));
 | ||
|         public int EmailWishCount {
 | ||
|             get => (int)GetValue(EmailWishCountProperty);
 | ||
|             private set => SetValue(EmailWishCountProperty, value);
 | ||
|         }
 | ||
| 
 | ||
|         private ICommand? _deleteCommand;
 | ||
|         public ICommand DeleteCommand => _deleteCommand ??= new ActionCommand(() => {
 | ||
|             var idx = SelectedDocumentsList.SelectedIndex;
 | ||
|             if (idx == -1)
 | ||
|                 return;
 | ||
|             SelectedDocs.RemoveAt(SelectedDocumentsList.SelectedIndex);
 | ||
|             SelectedDocumentsList.SelectedIndex = idx < SelectedDocumentsList.Items.Count ? idx : idx - 1;
 | ||
|         });
 | ||
| 
 | ||
|         // powershell -Command "$(Get-WmiObject -Class Win32_Printer | Where-Object {$_.Default -eq $True}).Name"
 | ||
|         public MailWindow(int? year = null) {
 | ||
|             InitializeComponent();
 | ||
|             using (var ctx = new AppDbContext()) {
 | ||
|                 Year = year ?? ctx.Seasons.OrderBy(s => s.Year).LastOrDefault()?.Year ?? Utils.Today.Year;
 | ||
|                 Title = $"Rundschreiben - Lese {Year} - Elwig";
 | ||
|             }
 | ||
| 
 | ||
|             AvaiableDocumentsList.ItemsSource = AvaiableDocuments;
 | ||
|             SelectedDocumentsList.ItemsSource = SelectedDocs;
 | ||
| 
 | ||
|             DocumentNonDeliverersInput.Visibility = Visibility.Hidden;
 | ||
|             DocumentFooterLabel.Visibility = Visibility.Hidden;
 | ||
|             DeliveryConfirmationFooterInput.Visibility = Visibility.Hidden;
 | ||
|             CreditNoteFooterInput.Visibility = Visibility.Hidden;
 | ||
|             RecipientsActiveMembersInput.IsChecked = true;
 | ||
| 
 | ||
|             MemberOrganicIndifferentInput.IsChecked = true;
 | ||
|             MemberFunktionärIndifferentInput.IsChecked = true;
 | ||
| 
 | ||
|             DeliveryConfirmationFooterInput.Text = App.Client.TextDeliveryConfirmation;
 | ||
|             CreditNoteFooterInput.Text = App.Client.TextCreditNote;
 | ||
| 
 | ||
|             DocumentNonDeliverersInput.IsChecked = App.Client.MailIncludeNonDeliverers;
 | ||
|             DoublePagedInput.IsChecked = App.Client.MailDoublePaged;
 | ||
| 
 | ||
|             switch (App.Client.MailSendPostal) {
 | ||
|                 case 0: PostalNobodyInput.IsChecked = true; break;
 | ||
|                 case 1: PostalNoEmailInput.IsChecked = true; break;
 | ||
|                 case 2: PostalWishInput.IsChecked = true; break;
 | ||
|                 case 3: PostalAllInput.IsChecked = true; break;
 | ||
|             }
 | ||
|             switch (App.Client.MailSendEmail) {
 | ||
|                 case 0: EmailNobodyInput.IsChecked = true; break;
 | ||
|                 case 1: EmailWishInput.IsChecked = true; break;
 | ||
|                 case 2: EmailAllInput.IsChecked = true; break;
 | ||
|             }
 | ||
|             switch (App.Client.MailOrdering) {
 | ||
|                 case 0: OrderMgNrInput.IsChecked = true; break;
 | ||
|                 case 1: OrderNameInput.IsChecked = true; break;
 | ||
|                 case 2: OrderPlzInput.IsChecked = true; break;
 | ||
|             }
 | ||
| 
 | ||
|             PostalSender1.Text = App.Client.Sender1;
 | ||
|             PostalSender2.Text = App.Client.Sender2;
 | ||
|             PostalLocation.Text = App.BranchLocation;
 | ||
|             PostalDate.Text = $"{Utils.Today:dd.MM.yyyy}";
 | ||
|             EmailSubjectInput.Text = App.Client.TextEmailSubject ?? "Rundschreiben";
 | ||
|             EmailBodyInput.Text = App.Client.TextEmailBody ?? "Sehr geehrtes Mitglied,\n\nim Anhang finden Sie das aktuelle Rundschreiben.\n\nIhre Winzergenossenschaft\n";
 | ||
|         }
 | ||
| 
 | ||
|         protected override async Task OnRenewContext(AppDbContext ctx) {
 | ||
|             var season = await ctx.Seasons.FindAsync(Year);
 | ||
|             var l = new List<string> {
 | ||
|                 MemberDataSheet.Name
 | ||
|             };
 | ||
|             if (season != null) {
 | ||
|                 l.Add($"{DeliveryConfirmation.Name} {Year}");
 | ||
|                 l.AddRange(season.PaymentVariants.OrderBy(v => v.AvNr).Select(v => $"{CreditNote.Name} – {v.Name}"));
 | ||
|             }
 | ||
|             AvaiableDocumentsList.ItemsSource = l;
 | ||
| 
 | ||
|             ControlUtils.RenewItemsSource(MemberBranchInput, await ctx.Branches
 | ||
|                 .Where(b => b.Members.Count != 0)
 | ||
|                 .OrderBy(b => b.Name)
 | ||
|                 .ToListAsync(), MemberInput_SelectionChanged);
 | ||
|             if (MemberBranchInput.SelectedItems.Count == 0) {
 | ||
|                 MemberBranchInput.SelectionChanged -= MemberInput_SelectionChanged;
 | ||
|                 MemberBranchInput.SelectAll();
 | ||
|                 MemberBranchInput.SelectionChanged += MemberInput_SelectionChanged;
 | ||
|             }
 | ||
|             ControlUtils.RenewItemsSource(MemberKgInput, await ctx.Katastralgemeinden
 | ||
|                 .Where(k => k.WbKg!.Members.Count != 0)
 | ||
|                 .OrderBy(k => k.Name)
 | ||
|                 .ToListAsync(), MemberInput_SelectionChanged);
 | ||
|             if (MemberKgInput.SelectedItems.Count == 0) {
 | ||
|                 MemberKgInput.SelectionChanged -= MemberInput_SelectionChanged;
 | ||
|                 MemberKgInput.SelectAll();
 | ||
|                 MemberKgInput.SelectionChanged += MemberInput_SelectionChanged;
 | ||
|             }
 | ||
|             ControlUtils.RenewItemsSource(MemberAreaComInput, await ctx.AreaCommitmentTypes
 | ||
|                 .OrderBy(a => a.VtrgId)
 | ||
|                 .ToListAsync(), MemberInput_SelectionChanged);
 | ||
|             if (MemberAreaComInput.SelectedItems.Count == 0) {
 | ||
|                 MemberAreaComInput.SelectionChanged -= MemberInput_SelectionChanged;
 | ||
|                 MemberAreaComInput.SelectAll();
 | ||
|                 MemberAreaComInput.SelectionChanged += MemberInput_SelectionChanged;
 | ||
|             }
 | ||
|             ControlUtils.RenewItemsSource(MemberDeliveryAncmtInput, await ctx.DeliverySchedules
 | ||
|                 .Where(s => s.Year == Year)
 | ||
|                 .OrderBy(s => s.DateString)
 | ||
|                 .ThenBy(s => s.Branch.Name)
 | ||
|                 .ThenBy(s => s.Description)
 | ||
|                 .ToListAsync(), MemberInput_SelectionChanged);
 | ||
|             if (MemberDeliveryAncmtInput.SelectedItems.Count == 0) {
 | ||
|                 MemberDeliveryAncmtInput.SelectionChanged -= MemberInput_SelectionChanged;
 | ||
|                 MemberDeliveryAncmtInput.SelectAll();
 | ||
|                 MemberDeliveryAncmtInput.SelectionChanged += MemberInput_SelectionChanged;
 | ||
|             }
 | ||
|             ControlUtils.RenewItemsSource(MemberCustomInput, await ctx.Members
 | ||
|                 .Where(m => m.IsActive)
 | ||
|                 .OrderBy(m => m.Name)
 | ||
|                 .ThenBy(m => m.GivenName)
 | ||
|                 .Include(m => m.Branch)
 | ||
|                 .Include(m => m.DefaultWbKg!.AtKg)
 | ||
|                 .Include(m => m.EmailAddresses)
 | ||
|                 .Include(m => m.TelephoneNumbers)
 | ||
|                 .Include(m => m.PostalDest.AtPlz!.Ort)
 | ||
|                 .Include(m => m.PostalDest.AtPlz!.Country)
 | ||
|                 .Include(m => m.BillingAddress!.PostalDest.AtPlz!.Ort)
 | ||
|                 .Include(m => m.BillingAddress!.PostalDest.AtPlz!.Country)
 | ||
|                 .ToListAsync(), MemberInput_SelectionChanged);
 | ||
|             if (MemberCustomInput.SelectedItems.Count == 0) {
 | ||
|                 MemberCustomInput.SelectionChanged -= MemberInput_SelectionChanged;
 | ||
|                 MemberCustomInput.SelectAll();
 | ||
|                 MemberCustomInput.SelectionChanged += MemberInput_SelectionChanged;
 | ||
|             }
 | ||
| 
 | ||
|             await UpdateRecipients(ctx);
 | ||
|         }
 | ||
| 
 | ||
|         private void ResetDocuments() {
 | ||
|             DisposeDocs();
 | ||
|             if (IsLoaded) {
 | ||
|                 PreviewButton.IsEnabled = false;
 | ||
|                 PrintButton.IsEnabled = false;
 | ||
|                 EmailButton.IsEnabled = false;
 | ||
|                 ProgressBar.Value = 0;
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|         private void LockInputs() {
 | ||
|             DocumentAddButton.IsEnabled = false;
 | ||
|             DocumentRemoveButton.IsEnabled = false;
 | ||
|             SelectDocumentButton.IsEnabled = false;
 | ||
|             foreach (var tb in ControlUtils.FindAllChildren<TextBox>(this, []))
 | ||
|                 tb.IsReadOnly = true;
 | ||
|             foreach (var cb in ControlUtils.FindAllChildren<ComboBox>(this, []))
 | ||
|                 cb.IsEnabled = false;
 | ||
|             foreach (var cb in ControlUtils.FindAllChildren<CheckBox>(this, []))
 | ||
|                 cb.IsEnabled = false;
 | ||
|             foreach (var lb in ControlUtils.FindAllChildren<ListBox>(this, []))
 | ||
|                 lb.IsEnabled = false;
 | ||
|             foreach (var rb in ControlUtils.FindAllChildren<RadioButton>(this, []))
 | ||
|                 rb.IsEnabled = false;
 | ||
|         }
 | ||
| 
 | ||
|         private void UnlockInputs() {
 | ||
|             DocumentAddButton.IsEnabled = true;
 | ||
|             DocumentRemoveButton.IsEnabled = true;
 | ||
|             SelectDocumentButton.IsEnabled = true;
 | ||
|             foreach (var tb in ControlUtils.FindAllChildren<TextBox>(this, []))
 | ||
|                 tb.IsReadOnly = false;
 | ||
|             foreach (var cb in ControlUtils.FindAllChildren<ComboBox>(this, []))
 | ||
|                 cb.IsEnabled = true;
 | ||
|             foreach (var cb in ControlUtils.FindAllChildren<CheckBox>(this, []))
 | ||
|                 cb.IsEnabled = true;
 | ||
|             foreach (var lb in ControlUtils.FindAllChildren<ListBox>(this, []))
 | ||
|                 lb.IsEnabled = true;
 | ||
|             foreach (var rb in ControlUtils.FindAllChildren<RadioButton>(this, []))
 | ||
|                 rb.IsEnabled = true;
 | ||
|         }
 | ||
| 
 | ||
|         private void Menu_Help_Log_Click(object sender, RoutedEventArgs evt) {
 | ||
|             var w = new MailLogWindow();
 | ||
|             w.Show();
 | ||
|         }
 | ||
| 
 | ||
|         private void ContinueButton_Click(object sender, RoutedEventArgs evt) {
 | ||
|             TabControl.SelectedIndex = 1;
 | ||
|             TabControl.AllowDrop = false;
 | ||
|         }
 | ||
| 
 | ||
|         private void BackButton_Click(object sender, RoutedEventArgs evt) {
 | ||
|             TabControl.SelectedIndex = 0;
 | ||
|             TabControl.AllowDrop = true;
 | ||
|         }
 | ||
| 
 | ||
|         private async void Document_Drop(object sender, DragEventArgs evt) {
 | ||
|             if (evt.Data.GetDataPresent(DataFormats.FileDrop)) {
 | ||
|                 var files = (string[])evt.Data.GetData(DataFormats.FileDrop);
 | ||
|                 foreach (var file in files) {
 | ||
|                     if (Path.GetExtension(file) == ".pdf") {
 | ||
|                         SelectedDocs.Add(new(DocType.Custom, Path.GetFileName(file), file));
 | ||
|                     }
 | ||
|                 }
 | ||
|                 using var ctx = new AppDbContext();
 | ||
|                 await UpdateRecipients(ctx);
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|         private void Document_PreviwDragOver(object sender, DragEventArgs evt) {
 | ||
|             evt.Handled = TabControl.SelectedIndex == 0;
 | ||
|         }
 | ||
| 
 | ||
|         private void AvaiableDocumentsList_SelectionChanged(object sender, RoutedEventArgs evt) {
 | ||
|             DocumentAddButton.IsEnabled = AvaiableDocumentsList.SelectedIndex != -1;
 | ||
|         }
 | ||
| 
 | ||
|         private void SelectedDocumentsList_SelectionChanged(object sender, RoutedEventArgs evt) {
 | ||
|             DocumentRemoveButton.IsEnabled = SelectedDocumentsList.SelectedIndex != -1;
 | ||
|             if (SelectedDocumentsList.SelectedItem is SelectedDoc doc) {
 | ||
|                 DocumentBox.Header = doc.Name;
 | ||
|                 if (doc.Type == DocType.DeliveryConfirmation) {
 | ||
|                     DocumentNonDeliverersInput.Visibility = Visibility.Visible;
 | ||
|                     DocumentFooterLabel.Visibility = Visibility.Visible;
 | ||
|                     DeliveryConfirmationFooterInput.Visibility = Visibility.Visible;
 | ||
|                     CreditNoteFooterInput.Visibility = Visibility.Hidden;
 | ||
|                     DocumentFooterLabel.Margin = new(10, 40, 0, 10);
 | ||
|                 } else if (doc.Type == DocType.CreditNote) {
 | ||
|                     DocumentNonDeliverersInput.Visibility = Visibility.Hidden;
 | ||
|                     DocumentFooterLabel.Visibility = Visibility.Visible;
 | ||
|                     DeliveryConfirmationFooterInput.Visibility = Visibility.Hidden;
 | ||
|                     CreditNoteFooterInput.Visibility = Visibility.Visible;
 | ||
|                     DocumentFooterLabel.Margin = new(10, 10, 0, 10);
 | ||
|                 } else {
 | ||
|                     DocumentNonDeliverersInput.Visibility = Visibility.Hidden;
 | ||
|                     DocumentFooterLabel.Visibility = Visibility.Hidden;
 | ||
|                     DeliveryConfirmationFooterInput.Visibility = Visibility.Hidden;
 | ||
|                     CreditNoteFooterInput.Visibility = Visibility.Hidden;
 | ||
|                 }
 | ||
|             } else {
 | ||
|                 DocumentBox.Header = "Dokument";
 | ||
|                 DocumentNonDeliverersInput.Visibility = Visibility.Hidden;
 | ||
|                 DocumentFooterLabel.Visibility = Visibility.Hidden;
 | ||
|                 DeliveryConfirmationFooterInput.Visibility = Visibility.Hidden;
 | ||
|                 CreditNoteFooterInput.Visibility = Visibility.Hidden;
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|         private async void DocumentAddButton_Click(object sender, RoutedEventArgs evt) {
 | ||
|             var idx = AvaiableDocumentsList.SelectedIndex;
 | ||
|             using var ctx = new AppDbContext();
 | ||
|             if (AvaiableDocumentsList.SelectedItem is not string s)
 | ||
|                 return;
 | ||
|             if (idx == 0) {
 | ||
|                 SelectedDocs.Add(new(DocType.MemberDataSheet, s, null));
 | ||
|             } else if (idx == 1) {
 | ||
|                 SelectedDocs.Add(new(DocType.DeliveryConfirmation, s, Year));
 | ||
|                 RecipientsDeliveryMembersInput.IsChecked = true;
 | ||
|             } else if (idx >= 2) {
 | ||
|                 var name = s.Split(" – ")[^1];
 | ||
|                 var pv = await ctx.PaymentVariants.SingleAsync(v => v.Year == Year && v.Name == name)!;
 | ||
|                 SelectedDocs.Add(new(DocType.CreditNote, s, (pv.Year, pv.AvNr)));
 | ||
|                 RecipientsDeliveryMembersInput.IsChecked = true;
 | ||
|             }
 | ||
|             SelectedDocumentsList.SelectedIndex = SelectedDocs.Count - 1;
 | ||
|             await UpdateRecipients(ctx);
 | ||
|         }
 | ||
| 
 | ||
|         private async void DocumentRemoveButton_Click(object sender, RoutedEventArgs evt) {
 | ||
|             DeleteCommand.Execute(null);
 | ||
|             using var ctx = new AppDbContext();
 | ||
|             await UpdateRecipients(ctx);
 | ||
|         }
 | ||
| 
 | ||
|         private async void SelectDocumentButton_Click(object sender, RoutedEventArgs evt) {
 | ||
|             var d = new OpenFileDialog() {
 | ||
|                 Title = "Dokument auswählen - Elwig",
 | ||
|                 DefaultExt = "pdf",
 | ||
|                 Filter = "PDF-Dokument (*.pdf)|*.pdf",
 | ||
|                 Multiselect = true,
 | ||
|             };
 | ||
|             if (d.ShowDialog() == true) {
 | ||
|                 foreach (var file in d.FileNames) {
 | ||
|                     if (Path.GetExtension(file) == ".pdf") {
 | ||
|                         SelectedDocs.Add(new(DocType.Custom, Path.GetFileName(file), file));
 | ||
|                     }
 | ||
|                 }
 | ||
|                 using var ctx = new AppDbContext();
 | ||
|                 await UpdateRecipients(ctx);
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|         private async void RecipientsInput_Changed(object sender, RoutedEventArgs evt) {
 | ||
|             var vis = RecipientsCustomInput.IsChecked == true ? Visibility.Hidden : Visibility.Visible;
 | ||
|             MemberBranchLabel.Visibility = vis;
 | ||
|             MemberBranchInput.Visibility = vis;
 | ||
|             MemberKgLabel.Visibility = vis;
 | ||
|             MemberKgInput.Visibility = vis;
 | ||
|             MemberOrganicLabel.Visibility = vis;
 | ||
|             MemberOrganicYesInput.Visibility = vis;
 | ||
|             MemberOrganicNoInput.Visibility = vis;
 | ||
|             MemberOrganicIndifferentInput.Visibility = vis;
 | ||
|             MemberFunktionärLabel.Visibility = vis;
 | ||
|             MemberFunktionärYesInput.Visibility = vis;
 | ||
|             MemberFunktionärNoInput.Visibility = vis;
 | ||
|             MemberFunktionärIndifferentInput.Visibility = vis;
 | ||
|             MemberAreaComInput.Visibility = RecipientsAreaComMembersInput.IsChecked == true ? Visibility.Visible : Visibility.Hidden;
 | ||
|             MemberAreaComLabel.Visibility = RecipientsAreaComMembersInput.IsChecked == true ? Visibility.Visible : Visibility.Hidden;
 | ||
|             MemberDeliveryAncmtInput.Visibility = RecipientsDeliveryAncmtMembersInput.IsChecked == true ? Visibility.Visible : Visibility.Hidden;
 | ||
|             MemberDeliveryAncmtLabel.Visibility = RecipientsDeliveryAncmtMembersInput.IsChecked == true ? Visibility.Visible : Visibility.Hidden;
 | ||
|             MemberCustomInput.Visibility = RecipientsCustomInput.IsChecked == true ? Visibility.Visible : Visibility.Hidden;
 | ||
|             using var ctx = new AppDbContext();
 | ||
|             await UpdateRecipients(ctx);
 | ||
|         }
 | ||
| 
 | ||
|         private async void MemberInput_SelectionChanged(object sender, SelectionChangedEventArgs evt) {
 | ||
|             using var ctx = new AppDbContext();
 | ||
|             await UpdateRecipients(ctx);
 | ||
|         }
 | ||
| 
 | ||
|         private async void MemberInput_Checked(object sender, RoutedEventArgs evt) {
 | ||
|             using var ctx = new AppDbContext();
 | ||
|             await UpdateRecipients(ctx);
 | ||
|         }
 | ||
| 
 | ||
|         private void Date_TextChanged(object sender, RoutedEventArgs evt) {
 | ||
|             Validator.CheckDate((TextBox)sender, true);
 | ||
|             ResetDocuments();
 | ||
|         }
 | ||
| 
 | ||
|         private void Date_LostFocus(object sender, RoutedEventArgs evt) {
 | ||
|             var res = Validator.CheckDate((TextBox)sender, true);
 | ||
|             if (!res.IsValid) ((TextBox)sender).Text = $"{Utils.Today:dd.MM.yyyy}";
 | ||
|         }
 | ||
| 
 | ||
|         private async Task UpdateRecipients(AppDbContext ctx) {
 | ||
|             if (RecipientsCustomInput.IsChecked == true) {
 | ||
|                 Recipients = MemberCustomInput.SelectedItems.Cast<Member>().ToList();
 | ||
|             } else {
 | ||
|                 IQueryable<Member> query = ctx.Members;
 | ||
|                 if (MemberBranchInput.SelectedItems.Count != MemberBranchInput.Items.Count) {
 | ||
|                     var zwst = MemberBranchInput.SelectedItems.Cast<Branch>().Select(b => b.ZwstId).ToList();
 | ||
|                     query = query.Where(m => zwst.Contains(m.ZwstId!));
 | ||
|                 }
 | ||
|                 if (MemberKgInput.SelectedItems.Count != MemberKgInput.Items.Count) {
 | ||
|                     var kgs = MemberKgInput.SelectedItems.Cast<AT_Kg>().Select(k => k.KgNr).ToList();
 | ||
|                     query = query.Where(m => kgs.Contains((int)m.DefaultKgNr!));
 | ||
|                 }
 | ||
|                 if (MemberOrganicYesInput.IsChecked == true) {
 | ||
|                     query = query.Where(m => m.IsOrganic);
 | ||
|                 } else if (MemberOrganicNoInput.IsChecked == true) {
 | ||
|                     query = query.Where(m => !m.IsOrganic);
 | ||
|                 }
 | ||
|                 if (MemberFunktionärYesInput.IsChecked == true) {
 | ||
|                     query = query.Where(m => m.IsFunktionär);
 | ||
|                 } else if (MemberFunktionärNoInput.IsChecked == true) {
 | ||
|                     query = query.Where(m => !m.IsFunktionär);
 | ||
|                 }
 | ||
| 
 | ||
|                 if (RecipientsAreaComMembersInput.IsChecked == true) {
 | ||
|                     var vtrg = MemberAreaComInput.SelectedItems.Cast<AreaComType>().Select(a => a.VtrgId).ToList();
 | ||
|                     query = query.Where(m => m.IsActive && m.AreaCommitments.AsQueryable().Where(Utils.ActiveAreaCommitments(Year)).Any(c => vtrg.Contains(c.VtrgId)));
 | ||
|                 } else if (RecipientsDeliveryAncmtMembersInput.IsChecked == true) {
 | ||
|                     var dsnrs = MemberDeliveryAncmtInput.SelectedItems.Cast<DeliverySchedule>().Select(s => s.DsNr).ToList();
 | ||
|                     query = query.Where(m => m.Announcements.Any(a => a.Year == Year && dsnrs.Contains(a.DsNr)));
 | ||
|                 } else if (RecipientsDeliveryMembersInput.IsChecked == true) {
 | ||
|                     query = query.Where(m => m.Deliveries.Any(d => d.Year == Year));
 | ||
|                 } else if (RecipientsNonDeliveryMembersInput.IsChecked == true) {
 | ||
|                     query = query.Where(m => m.IsActive && !m.Deliveries.Any(d => d.Year == Year));
 | ||
|                 } else if  (RecipientsActiveMembersInput.IsChecked == true && SelectedDocs.Any(d => d.Type == DocType.DeliveryConfirmation || d.Type == DocType.CreditNote)) {
 | ||
|                     query = query.Where(m => m.IsActive || m.Deliveries.Any(d => d.Year == Year));
 | ||
|                 } else {
 | ||
|                     query = query.Where(m => m.IsActive);
 | ||
|                 }
 | ||
|                 Recipients = await query
 | ||
|                     .Include(m => m.Branch)
 | ||
|                     .Include(m => m.DefaultWbKg!.AtKg)
 | ||
|                     .Include(m => m.EmailAddresses)
 | ||
|                     .Include(m => m.TelephoneNumbers)
 | ||
|                     .Include(m => m.PostalDest.AtPlz!.Ort)
 | ||
|                     .Include(m => m.PostalDest.AtPlz!.Country)
 | ||
|                     .Include(m => m.BillingAddress!.PostalDest.AtPlz!.Ort)
 | ||
|                     .Include(m => m.BillingAddress!.PostalDest.AtPlz!.Country)
 | ||
|                     .ToListAsync();
 | ||
|             }
 | ||
|             UpdatePostalEmailRecipients();
 | ||
|         }
 | ||
| 
 | ||
|         private void EmailInput_Changed(object sender, RoutedEventArgs evt) {
 | ||
|             UpdatePostalEmailRecipients();
 | ||
|         }
 | ||
| 
 | ||
|         private void UpdatePostalEmailRecipients() {
 | ||
|             var modeEmail = EmailAllInput.IsChecked == true ? 2 : EmailWishInput.IsChecked == true ? 1 : 0;
 | ||
|             var modePostal = PostalAllInput.IsChecked == true ? 3 : PostalWishInput.IsChecked == true ? 2 : PostalNoEmailInput.IsChecked == true ? 1 : 0;
 | ||
|             EmailAllCount = Recipients.Count(m => m.EmailAddresses.Count > 0);
 | ||
|             EmailWishCount = Recipients.Count(m => m.EmailAddresses.Count > 0 && m.ContactViaEmail);
 | ||
|             PostalAllCount = Recipients.Count();
 | ||
|             PostalWishCount = Recipients.Count(m => m.ContactViaPost);
 | ||
|             var countEmail = (modeEmail == 2 ? EmailAllCount : modeEmail == 1 ? EmailWishCount : 0);
 | ||
|             PostalNoEmailCount = PostalAllCount - countEmail;
 | ||
|             var countPostal = (modePostal == 3 ? PostalAllCount : modePostal == 2 ? PostalWishCount : modePostal == 1 ? PostalNoEmailCount : 0);
 | ||
|             if (IsLoaded) {
 | ||
|                 StatusRecipients.Text = $"{Recipients.Count():N0}";
 | ||
|                 StatusPostalRecipients.Text = $"{countPostal:N0}";
 | ||
|                 StatusEmailRecipients.Text = $"{countEmail:N0}";
 | ||
|             }
 | ||
|             ResetDocuments();
 | ||
|         }
 | ||
| 
 | ||
|         private async Task UpdateClientParameters() {
 | ||
|             var changed = false;
 | ||
| 
 | ||
|             var dcInclude = DocumentNonDeliverersInput.IsChecked ?? false;
 | ||
|             if (dcInclude != App.Client.MailIncludeNonDeliverers) {
 | ||
|                 App.Client.MailIncludeNonDeliverers = dcInclude;
 | ||
|                 changed = true;
 | ||
|             }
 | ||
| 
 | ||
|             var dcText = DeliveryConfirmationFooterInput.Text.Trim();
 | ||
|             if (dcText.Length == 0) dcText = null;
 | ||
|             if (dcText != App.Client.TextDeliveryConfirmation) {
 | ||
|                 App.Client.TextDeliveryConfirmation = dcText;
 | ||
|                 changed = true;
 | ||
|             }
 | ||
| 
 | ||
|             var cdText = CreditNoteFooterInput.Text.Trim();
 | ||
|             if (cdText.Length == 0) cdText = null;
 | ||
|             if (cdText != App.Client.TextCreditNote) {
 | ||
|                 App.Client.TextCreditNote = cdText;
 | ||
|                 changed = true;
 | ||
|             }
 | ||
| 
 | ||
|             var sendPostal = 0;
 | ||
|             if (PostalAllInput.IsChecked ?? false) {
 | ||
|                 sendPostal = 3;
 | ||
|             } else if (PostalWishInput.IsChecked ?? false) {
 | ||
|                 sendPostal = 2;
 | ||
|             } else if (PostalNoEmailInput.IsChecked ?? false) {
 | ||
|                 sendPostal = 1;
 | ||
|             }
 | ||
|             if (sendPostal != App.Client.MailSendPostal) {
 | ||
|                 App.Client.MailSendPostal = sendPostal;
 | ||
|                 changed = true;
 | ||
|             }
 | ||
| 
 | ||
|             var sendEmail = 0;
 | ||
|             if (EmailAllInput.IsChecked ?? false) {
 | ||
|                 sendEmail = 2;
 | ||
|             } else if (EmailWishInput.IsChecked ?? false) {
 | ||
|                 sendEmail = 1;
 | ||
|             }
 | ||
|             if (sendEmail != App.Client.MailSendEmail) {
 | ||
|                 App.Client.MailSendEmail = sendEmail;
 | ||
|                 changed = true;
 | ||
|             }
 | ||
| 
 | ||
|             var ordering = 0;
 | ||
|             if (OrderNameInput.IsChecked ?? false) {
 | ||
|                 ordering = 1;
 | ||
|             } else if (OrderPlzInput.IsChecked ?? false) {
 | ||
|                 ordering = 2;
 | ||
|             }
 | ||
|             if (ordering != App.Client.MailOrdering) {
 | ||
|                 App.Client.MailOrdering = ordering;
 | ||
|                 changed = true;
 | ||
|             }
 | ||
| 
 | ||
|             var mailDoublePaged = DoublePagedInput.IsChecked ?? false;
 | ||
|             if (mailDoublePaged != App.Client.MailDoublePaged) {
 | ||
|                 App.Client.MailDoublePaged = mailDoublePaged;
 | ||
|                 changed = true;
 | ||
|             }
 | ||
| 
 | ||
|             var sender2 = PostalSender2.Text.Trim();
 | ||
|             if (sender2 != App.Client.Sender2) {
 | ||
|                 App.Client.Sender2 = sender2;
 | ||
|                 changed = true;
 | ||
|             }
 | ||
| 
 | ||
|             var emailSubject = EmailSubjectInput.Text.Trim();
 | ||
|             if (emailSubject.Length == 0) emailSubject = null;
 | ||
|             if (emailSubject != App.Client.TextEmailSubject) {
 | ||
|                 App.Client.TextEmailSubject = emailSubject;
 | ||
|                 changed = true;
 | ||
|             }
 | ||
| 
 | ||
|             var emailBody = EmailBodyInput.Text.Trim();
 | ||
|             if (emailBody.Length == 0) emailBody = null;
 | ||
|             if (emailBody != App.Client.TextEmailBody) {
 | ||
|                 App.Client.TextEmailBody = emailBody;
 | ||
|                 changed = true;
 | ||
|             }
 | ||
| 
 | ||
|             if (changed)
 | ||
|                 await App.Client.UpdateValues();
 | ||
|         }
 | ||
| 
 | ||
|         private void DisposeDocs() {
 | ||
|             PrintDocument?.Dispose();
 | ||
|             PrintDocument = null;
 | ||
|             if (EmailDocuments != null) {
 | ||
|                 foreach (var (m, docs) in EmailDocuments) {
 | ||
|                     foreach (var d in docs) {
 | ||
|                         d.Dispose();
 | ||
|                     }
 | ||
|                 }
 | ||
|                 EmailDocuments = null;
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|         private void Window_Closed(object sender, EventArgs evt) {
 | ||
|             DisposeDocs();
 | ||
|         }
 | ||
| 
 | ||
|         private async void GenerateButton_Click(object sender, RoutedEventArgs evt) {
 | ||
|             LockInputs();
 | ||
|             PreviewButton.IsEnabled = false;
 | ||
|             PrintButton.IsEnabled = false;
 | ||
|             EmailButton.IsEnabled = false;
 | ||
|             Mouse.OverrideCursor = Cursors.Wait;
 | ||
|             GenerateButton.IsEnabled = false;
 | ||
| 
 | ||
|             DisposeDocs();
 | ||
|             await UpdateClientParameters();
 | ||
| 
 | ||
|             using var ctx = new AppDbContext();
 | ||
| 
 | ||
|             var doublePaged = DoublePagedInput.IsChecked == true;
 | ||
|             var location = PostalLocation.Text.Trim();
 | ||
|             var docs = SelectedDocs.OrderByDescending(d => d.Type).ToList();
 | ||
| 
 | ||
|             IEnumerable<Member> recipients = Recipients;
 | ||
|             if (OrderMgNrInput.IsChecked == true) {
 | ||
|                 recipients = recipients
 | ||
|                     .OrderBy(m => m.MgNr)
 | ||
|                     .ToList();
 | ||
|             } else if (OrderNameInput.IsChecked == true) {
 | ||
|                 recipients = recipients
 | ||
|                     .OrderBy(m => m.Name)
 | ||
|                     .ThenBy(m => m.GivenName)
 | ||
|                     .ThenBy(m => m.MgNr)
 | ||
|                     .ToList();
 | ||
|             } else if (OrderPlzInput.IsChecked == true) {
 | ||
|                 if (docs.Any(d => d.Type == DocType.DeliveryConfirmation || d.Type == DocType.CreditNote)) {
 | ||
|                     recipients = recipients
 | ||
|                         .OrderBy(m => m.BillingAddress?.PostalDest.AtPlz?.Plz ?? m.PostalDest.AtPlz?.Plz)
 | ||
|                         .ThenBy(m => m.BillingAddress?.PostalDest.AtPlz?.Ort.Name ?? m.PostalDest.AtPlz?.Ort.Name)
 | ||
|                         .ThenBy(m => m.Name)
 | ||
|                         .ThenBy(m => m.GivenName)
 | ||
|                         .ThenBy(m => m.MgNr)
 | ||
|                         .ToList();
 | ||
|                 } else {
 | ||
|                     recipients = recipients
 | ||
|                         .OrderBy(m => m.PostalDest.AtPlz?.Plz)
 | ||
|                         .ThenBy(m => m.PostalDest.AtPlz?.Ort.Name)
 | ||
|                         .ThenBy(m => m.Name)
 | ||
|                         .ThenBy(m => m.GivenName)
 | ||
|                         .ThenBy(m => m.MgNr)
 | ||
|                         .ToList();
 | ||
|                 }
 | ||
|             }
 | ||
| 
 | ||
|             Dictionary<int, IDictionary<int, DeliveryConfirmationDeliveryData>> dcData = [];
 | ||
|             Dictionary<(int, int), (IDictionary<int, CreditNoteDeliveryData>, IDictionary<int, PaymentMember>, BillingData)> cnData = [];
 | ||
|             foreach (var doc in docs) {
 | ||
|                 if (doc.Type == DocType.DeliveryConfirmation) {
 | ||
|                     var year = (int)doc.Details!;
 | ||
| 
 | ||
|                     try {
 | ||
|                         var b = new Billing(year);
 | ||
|                         await b.FinishSeason();
 | ||
|                         await b.CalculateBuckets();
 | ||
|                         App.HintContextChange();
 | ||
| 
 | ||
|                         dcData[year] = await DeliveryConfirmationDeliveryData.ForSeason(ctx.DeliveryParts, year);
 | ||
|                     } catch (Exception exc) {
 | ||
|                         MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
 | ||
|                         UnlockInputs();
 | ||
|                         GenerateButton.IsEnabled = true;
 | ||
|                         Mouse.OverrideCursor = null;
 | ||
|                         return;
 | ||
|                     }
 | ||
|                 } else if (doc.Type == DocType.CreditNote) {
 | ||
|                     var details = ((int, int))doc.Details!;
 | ||
|                     var year = details.Item1;
 | ||
|                     var avnr = details.Item2;
 | ||
|                     try {
 | ||
|                         cnData[(year, avnr)] = (
 | ||
|                             await CreditNoteDeliveryData.ForPaymentVariant(ctx.CreditNoteDeliveryRows, ctx.PaymentVariants, year, avnr),
 | ||
|                             await ctx.MemberPayments.Where(p => p.Year == year && p.AvNr == avnr).ToDictionaryAsync(c => c.MgNr),
 | ||
|                             BillingData.FromJson((await ctx.PaymentVariants.FindAsync(year, avnr))!.Data)
 | ||
|                         );
 | ||
|                     } catch (Exception exc) {
 | ||
|                         MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
 | ||
|                         UnlockInputs();
 | ||
|                         GenerateButton.IsEnabled = true;
 | ||
|                         Mouse.OverrideCursor = null;
 | ||
|                         return;
 | ||
|                     }
 | ||
|                     await ctx.GetMemberAreaCommitmentBuckets(year, 0);
 | ||
|                 }
 | ||
|             }
 | ||
| 
 | ||
|             var postalDate = DateOnly.ParseExact(PostalDate.Text, "dd.MM.yyyy");
 | ||
|             var memberDocs = recipients.Select(m => new {
 | ||
|                 Member = m,
 | ||
|                 Docs = docs.SelectMany<SelectedDoc, GeneratedDoc>(doc => {
 | ||
|                     try {
 | ||
|                         if (doc.Type == DocType.Custom) {
 | ||
|                             return [new GeneratedDoc((string)doc.Details!)];
 | ||
|                         } else if (doc.Type == DocType.MemberDataSheet) {
 | ||
|                             return [new GeneratedDoc(new MemberDataSheet(m, ctx) { Date = postalDate })];
 | ||
|                         } else if (doc.Type == DocType.DeliveryConfirmation) {
 | ||
|                             var year = (int)doc.Details!;
 | ||
|                             DeliveryConfirmationDeliveryData data;
 | ||
|                             if (dcData[year].TryGetValue(m.MgNr, out var d)) {
 | ||
|                                 data = d;
 | ||
|                             } else if (App.Client.MailIncludeNonDeliverers) {
 | ||
|                                 data = DeliveryConfirmationDeliveryData.CreateEmpty(year, m);
 | ||
|                             } else {
 | ||
|                                 return [];
 | ||
|                             }
 | ||
|                             return [new GeneratedDoc(new DeliveryConfirmation(ctx, year, m, data) { Date = postalDate })];
 | ||
|                         } else if (doc.Type == DocType.CreditNote) {
 | ||
|                             var details = ((int, int))doc.Details!;
 | ||
|                             var year = details.Item1;
 | ||
|                             var avnr = details.Item2;
 | ||
|                             var data = cnData[(year, avnr)];
 | ||
|                             try {
 | ||
|                                 return [new GeneratedDoc(new CreditNote(
 | ||
|                                     ctx, data.Item2[m.MgNr], data.Item1[m.MgNr],
 | ||
|                                     data.Item3.ConsiderContractPenalties,
 | ||
|                                     data.Item3.ConsiderTotalPenalty,
 | ||
|                                     data.Item3.ConsiderAutoBusinessShares,
 | ||
|                                     data.Item3.ConsiderCustomModifiers,
 | ||
|                                     ctx.GetMemberUnderDelivery(year, m.MgNr).GetAwaiter().GetResult()
 | ||
|                                 ) { Date = postalDate })];
 | ||
|                             } catch (Exception) {
 | ||
|                                 return [];
 | ||
|                             }
 | ||
|                         } else {
 | ||
|                             throw new NotImplementedException("Invalid DocType");
 | ||
|                         }
 | ||
|                     } catch (Exception exc) {
 | ||
|                         MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
 | ||
|                         return [];
 | ||
|                     }
 | ||
|                 }).ToList()
 | ||
|             }).ToList();
 | ||
| 
 | ||
|             var printMode = PostalAllInput.IsChecked == true ? 3 :
 | ||
|                 PostalWishInput.IsChecked == true ? 2 :
 | ||
|                 PostalNoEmailInput.IsChecked == true ? 1 : 0;
 | ||
|             var emailMode = EmailAllInput.IsChecked == true ? 2 : EmailWishInput.IsChecked == true ? 1 : 0;
 | ||
| 
 | ||
|             double printNum = printMode == 3 ? PostalAllCount : printMode == 2 ? PostalWishCount : printMode == 1 ? PostalNoEmailCount : 0;
 | ||
|             double emailNum = emailMode == 2 ? EmailAllCount : emailMode == 1 ? EmailWishCount : 0;
 | ||
|             double totalNum = printNum + emailNum;
 | ||
| 
 | ||
|             var email = memberDocs
 | ||
|                 .Where(d => d.Member.EmailAddresses.Count > 0 && (emailMode == 2 || (emailMode == 1 && d.Member.ContactViaEmail)))
 | ||
|                 .ToDictionary(d => d.Member, m => {
 | ||
|                     var docs = m.Docs.Select(d => d.Doc).ToList();
 | ||
|                     foreach (var doc in docs) {
 | ||
|                         doc!.DoublePaged = false;
 | ||
|                         if (doc is BusinessDocument b) {
 | ||
|                             b.IncludeSender = false;
 | ||
|                             b.Location = location;
 | ||
|                         }
 | ||
|                     };
 | ||
|                     return docs;
 | ||
|                 });
 | ||
|             var emailRecipients = email.Select(d => d.Key.MgNr).ToHashSet();
 | ||
|             try {
 | ||
|                 foreach (var item1 in email.Select((e, i) => new { Index = i, e.Key, e.Value })) {
 | ||
|                     foreach (var item2 in item1.Value.Select((d, i) => new { Index = i, Doc = d })) {
 | ||
|                         await item2.Doc.Generate(new Progress<double>(v => {
 | ||
|                             ProgressBar.Value = v * (item2.Index + 1) / item1.Value.Count / totalNum + 100.0 * item1.Index / totalNum;
 | ||
|                         }));
 | ||
|                     }
 | ||
|                 }
 | ||
|             } catch (Exception exc) {
 | ||
|                 MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
 | ||
|                 UnlockInputs();
 | ||
|                 GenerateButton.IsEnabled = true;
 | ||
|                 Mouse.OverrideCursor = null;
 | ||
|                 return;
 | ||
|             }
 | ||
|             if (email.Count > 0) {
 | ||
|                 EmailDocuments = email;
 | ||
|             }
 | ||
| 
 | ||
|             var printMemberDocs = memberDocs
 | ||
|                 .Where(d =>
 | ||
|                     printMode == 3 ||
 | ||
|                     (printMode == 2 && d.Member.ContactViaPost) ||
 | ||
|                     (printMode == 1 && !emailRecipients.Contains(d.Member.MgNr)))
 | ||
|                 .ToList();
 | ||
|             var printDocs = printMemberDocs
 | ||
|                 .SelectMany(m => {
 | ||
|                     var docs = m.Docs.Select(d => d.Doc).ToList();
 | ||
|                     if (docs.Count == 0 || m.Docs[0].Type == DocType.Custom) {
 | ||
|                         docs.Insert(0, new Letterhead(m.Member));
 | ||
|                     }
 | ||
|                     docs.ForEach(doc => {
 | ||
|                         doc.DoublePaged = doublePaged;
 | ||
|                         if (doc is BusinessDocument b)
 | ||
|                             b.Location = location;
 | ||
|                     });
 | ||
|                     if (docs.Count > 0 && docs[0] is BusinessDocument b)
 | ||
|                         b.IncludeSender = true;
 | ||
|                     return docs;
 | ||
|                 })
 | ||
|                 .ToList();
 | ||
| 
 | ||
|             if (printDocs.Count > 0) {
 | ||
|                 try {
 | ||
|                     var print = Document.Merge(printDocs);
 | ||
|                     print.DoublePaged = doublePaged;
 | ||
|                     await print.Generate(new Progress<double>(v => {
 | ||
|                         ProgressBar.Value = 100.0 * emailNum / totalNum + v * printNum / totalNum;
 | ||
|                     }));
 | ||
|                     PrintDocument = print;
 | ||
|                     PrintMemberDocuments = printMemberDocs.ToDictionary(m => m.Member, m => m.Docs.Select(d => d.Doc).ToList());
 | ||
|                 } catch (Exception exc) {
 | ||
|                     MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
 | ||
|                     UnlockInputs();
 | ||
|                     GenerateButton.IsEnabled = true;
 | ||
|                     Mouse.OverrideCursor = null;
 | ||
|                     return;
 | ||
|                 }
 | ||
|             } else {
 | ||
|                 PrintDocument = null;
 | ||
|                 PrintMemberDocuments = null;
 | ||
|             }
 | ||
|             ProgressBar.Value = 100.0;
 | ||
| 
 | ||
|             UnlockInputs();
 | ||
|             GenerateButton.IsEnabled = true;
 | ||
|             Mouse.OverrideCursor = null;
 | ||
|             PreviewButton.IsEnabled = true;
 | ||
|             PrintButton.IsEnabled = PrintDocument != null;
 | ||
|             EmailButton.IsEnabled = EmailDocuments != null && App.Config.Smtp != null;
 | ||
|         }
 | ||
| 
 | ||
|         private async void PreviewButton_Click(object sender, RoutedEventArgs evt) {
 | ||
|             var d = new OpenFolderDialog() {
 | ||
|                 Title = "Ordner auswählen - Elwig",
 | ||
|             };
 | ||
|             if (d.ShowDialog() == true) {
 | ||
|                 Mouse.OverrideCursor = Cursors.Wait;
 | ||
|                 await Task.Run(() => {
 | ||
|                     PrintDocument?.SaveTo($"{d.FolderName}/Print.pdf");
 | ||
|                     if (EmailDocuments != null) {
 | ||
|                         foreach (var (m, docs) in EmailDocuments) {
 | ||
|                             var folder = $"{d.FolderName}/E-Mail/{m.AdministrativeName.Trim()}";
 | ||
|                             Directory.CreateDirectory(folder);
 | ||
|                             foreach (var item in docs.Select((d, i) => new { Index = i, Doc = d })) {
 | ||
|                                 var doc = item.Doc;
 | ||
|                                 var name = Utils.NormalizeFileName(doc.Title);
 | ||
|                                 doc.SaveTo($"{folder}/{item.Index + 1:00}.{name}.pdf");
 | ||
|                             }
 | ||
| 
 | ||
|                         }
 | ||
|                     }
 | ||
|                 });
 | ||
|                 Mouse.OverrideCursor = null;
 | ||
|                 Process.Start("explorer.exe", d.FolderName);
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|         private async void PrintButton_Click(object sender, RoutedEventArgs evt) {
 | ||
|             if (PrintDocument == null || PrintMemberDocuments == null) return;
 | ||
| 
 | ||
|             PrintButton.IsEnabled = false;
 | ||
|             GenerateButton.IsEnabled = false;
 | ||
|             LockInputs();
 | ||
| 
 | ||
|             var res = MessageBox.Show($"Sollen {PrintDocument.Pages} Blätter ({PrintDocument.TotalPages} Seiten) gedruckt werden?",
 | ||
|                 "Rundschreiben drucken", MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No);
 | ||
|             if (res == MessageBoxResult.Yes) {
 | ||
|                 Mouse.OverrideCursor = Cursors.Wait;
 | ||
|                 await Task.Run(async () => {
 | ||
|                     if (App.Config.Debug) {
 | ||
|                         PrintDocument.Show();
 | ||
|                     } else {
 | ||
|                         await PrintDocument.Print();
 | ||
|                         await Utils.AddSentMails(
 | ||
|                             PrintMemberDocuments.Select(d => (
 | ||
|                                 "postal", d.Key.MgNr, d.Key.AdministrativeName,
 | ||
|                                 new string[] { d.Value.Select(d => (d as BusinessDocument)?.Address).FirstOrDefault(a => a != null) ?? d.Key.FullAddress },
 | ||
|                                 d.Value.Select(d => d.Title).FirstOrDefault("Briefkopf"),
 | ||
|                                 d.Value.Select(d => d.Title).ToArray()
 | ||
|                             ))
 | ||
|                         );
 | ||
|                     }
 | ||
|                 });
 | ||
|                 Mouse.OverrideCursor = null;
 | ||
|             }
 | ||
| 
 | ||
|             PrintButton.IsEnabled = true;
 | ||
|             GenerateButton.IsEnabled = true;
 | ||
|             UnlockInputs();
 | ||
|         }
 | ||
| 
 | ||
|         private async void EmailButton_Click(object sender, RoutedEventArgs evt) {
 | ||
|             if (App.Config.Smtp == null || EmailDocuments == null) return;
 | ||
| 
 | ||
|             EmailButton.IsEnabled = false;
 | ||
|             GenerateButton.IsEnabled = false;
 | ||
|             LockInputs();
 | ||
| 
 | ||
|             SmtpClient? client = null;
 | ||
|             try {
 | ||
|                 Mouse.OverrideCursor = Cursors.Wait;
 | ||
|                 client = await Task.Run(Utils.GetSmtpClient);
 | ||
|                 Mouse.OverrideCursor = null;
 | ||
| 
 | ||
|                 var res = MessageBox.Show($"Sollen {EmailDocuments.Count:N0} E-Mails verschickt werden?",
 | ||
|                     "Rundschreiben verschicken", MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No);
 | ||
|                 if (res != MessageBoxResult.Yes) {
 | ||
|                     return;
 | ||
|                 }
 | ||
| 
 | ||
|                 Mouse.OverrideCursor = Cursors.Wait;
 | ||
|                 var subject = EmailSubjectInput.Text;
 | ||
|                 var text = EmailBodyInput.Text;
 | ||
|                 await Task.Run(async () => {
 | ||
|                     await Utils.AddSentMailBody(subject, text, EmailDocuments.Count);
 | ||
|                     foreach (var (m, docs) in EmailDocuments) {
 | ||
|                         using var msg = new MimeMessage();
 | ||
|                         msg.From.Add(new MailboxAddress(App.Client.NameFull, App.Config.Smtp.Value.From));
 | ||
|                         msg.To.AddRange(m.EmailAddresses.OrderBy(a => a.Nr).Select(a => new MailboxAddress(m.AdministrativeName, a.Address)));
 | ||
|                         msg.Subject = subject;
 | ||
|                         var body = new Multipart("mixed") {
 | ||
|                             new TextPart("plain") { Text = text }
 | ||
|                         };
 | ||
|                         foreach (var doc in docs) {
 | ||
|                             var name = Utils.NormalizeFileName(doc.Title);
 | ||
|                             body.Add(doc.AsEmailAttachment($"{name}.pdf"));
 | ||
|                         }
 | ||
|                         msg.Body = body;
 | ||
|                         await client!.SendAsync(msg);
 | ||
|                         await Utils.AddSentMails([(
 | ||
|                             "email", m.MgNr, m.AdministrativeName,
 | ||
|                             m.EmailAddresses.OrderBy(a => a.Nr).Select(a => a.Address).ToArray(),
 | ||
|                             subject,
 | ||
|                             docs.Select(d => d.Title).ToArray()
 | ||
|                         )]);
 | ||
|                     }
 | ||
|                 });
 | ||
| 
 | ||
|                 MessageBox.Show("Erfolgreich alle E-Mails verschickt!", "Rundschreiben verschicken", MessageBoxButton.OK, MessageBoxImage.Information);
 | ||
|             } catch (Exception exc) {
 | ||
|                 MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
 | ||
|             } finally {
 | ||
|                 if (client != null)
 | ||
|                     await client.DisconnectAsync(true);
 | ||
|                 client?.Dispose();
 | ||
|                 EmailButton.IsEnabled = true;
 | ||
|                 GenerateButton.IsEnabled = true;
 | ||
|                 UnlockInputs();
 | ||
|                 Mouse.OverrideCursor = null;
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|         public void AddDeliveryConfirmation() {
 | ||
|             if (!GenerateButton.IsEnabled) return;
 | ||
|             AvaiableDocumentsList.SelectedIndex = 1;
 | ||
|             if (AvaiableDocumentsList.SelectedItem is not string s || SelectedDocs.Any(d => d.Type == DocType.DeliveryConfirmation))
 | ||
|                 return;
 | ||
|             SelectedDocs.Add(new(DocType.DeliveryConfirmation, s, Year));
 | ||
|             SelectedDocumentsList.SelectedIndex = SelectedDocs.Count - 1;
 | ||
|             RecipientsDeliveryMembersInput.IsChecked = true;
 | ||
|         }
 | ||
| 
 | ||
|         public void AddCreditNote(int index) {
 | ||
|             if (!GenerateButton.IsEnabled) return;
 | ||
|             AvaiableDocumentsList.SelectedIndex = 2 + index;
 | ||
|             if (AvaiableDocumentsList.SelectedItem is not string s || SelectedDocs.Any(d => d.Type == DocType.CreditNote))
 | ||
|                 return;
 | ||
|             var name = s.Split(" – ")[^1];
 | ||
|             using var ctx = new AppDbContext();
 | ||
|             var pv = ctx.PaymentVariants.Single(v => v.Year == Year && v.Name == name)!;
 | ||
|             SelectedDocs.Add(new(DocType.CreditNote, s, (pv.Year, pv.AvNr)));
 | ||
|             SelectedDocumentsList.SelectedIndex = SelectedDocs.Count - 1;
 | ||
|             RecipientsDeliveryMembersInput.IsChecked = true;
 | ||
|         }
 | ||
| 
 | ||
|         private void DocumentInput_TextChanged(object sender, TextChangedEventArgs evt) {
 | ||
|             ResetDocuments();
 | ||
|         }
 | ||
| 
 | ||
|         private void PostalLocation_TextChanged(object sender, TextChangedEventArgs evt) {
 | ||
|             ResetDocuments();
 | ||
|         }
 | ||
| 
 | ||
|         private void PostalInput_Changed(object sender, RoutedEventArgs evt) {
 | ||
|             UpdatePostalEmailRecipients();
 | ||
|         }
 | ||
| 
 | ||
|         private void OrderInput_Changed(object sender, RoutedEventArgs evt) {
 | ||
|             ResetDocuments();
 | ||
|         }
 | ||
| 
 | ||
|         private void DoublePagedInput_Changed(object sender, RoutedEventArgs evt) {
 | ||
|             ResetDocuments();
 | ||
|         }
 | ||
| 
 | ||
|         private void PostalSender_TextChanged(object sender, TextChangedEventArgs evt) {
 | ||
|             ResetDocuments();
 | ||
|         }
 | ||
|     }
 | ||
| }
 |