889 lines
42 KiB
C#
889 lines
42 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>>? 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;
|
||
|
||
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 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, DocumentNonDeliverersInput.IsChecked == true)));
|
||
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() {
|
||
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 m = EmailAllInput.IsChecked == true ? 3 : EmailWishInput.IsChecked == true ? 2 : 1;
|
||
PostalNoEmailCount = PostalAllCount - (m == 3 ? EmailAllCount : m == 2 ? EmailWishCount : 0);
|
||
ResetDocuments();
|
||
}
|
||
|
||
private async Task UpdateTextParameters() {
|
||
var changed = false;
|
||
|
||
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 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.AppStarting;
|
||
GenerateButton.IsEnabled = false;
|
||
|
||
DisposeDocs();
|
||
await UpdateTextParameters();
|
||
|
||
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 details = ((int, bool))doc.Details!;
|
||
var year = details.Item1;
|
||
|
||
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.Seasons, 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 details = ((int, bool))doc.Details!;
|
||
var year = details.Item1;
|
||
var include = details.Item2;
|
||
DeliveryConfirmationDeliveryData data;
|
||
if (dcData[year].TryGetValue(m.MgNr, out var d)) {
|
||
data = d;
|
||
} else if (include) {
|
||
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 == 2 ? 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 printDocs = memberDocs
|
||
.Where(d =>
|
||
printMode == 3 ||
|
||
(printMode == 2 && d.Member.ContactViaPost) ||
|
||
(printMode == 1 && !emailRecipients.Contains(d.Member.MgNr)))
|
||
.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;
|
||
} catch (Exception exc) {
|
||
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
||
UnlockInputs();
|
||
GenerateButton.IsEnabled = true;
|
||
Mouse.OverrideCursor = null;
|
||
return;
|
||
}
|
||
}
|
||
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 void PreviewButton_Click(object sender, RoutedEventArgs evt) {
|
||
var d = new OpenFolderDialog() {
|
||
Title = "Ordner auswählen - Elwig",
|
||
};
|
||
if (d.ShowDialog() == true) {
|
||
Mouse.OverrideCursor = Cursors.AppStarting;
|
||
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) 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.AppStarting;
|
||
if (App.Config.Debug) {
|
||
PrintDocument.Show();
|
||
} else {
|
||
await PrintDocument.Print();
|
||
}
|
||
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.AppStarting;
|
||
client = await 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.AppStarting;
|
||
var subject = EmailSubjectInput.Text;
|
||
var text = EmailBodyInput.Text;
|
||
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);
|
||
}
|
||
|
||
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, DocumentNonDeliverersInput.IsChecked == true)));
|
||
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) {
|
||
ResetDocuments();
|
||
}
|
||
|
||
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();
|
||
}
|
||
}
|
||
}
|