using Elwig.Helpers; using Elwig.Helpers.Billing; using Elwig.Models.Dtos; using Elwig.Models.Entities; using Microsoft.EntityFrameworkCore; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; namespace Elwig.Windows { public partial class PaymentAdjustmentWindow : ContextWindow { public readonly int Year; public readonly bool SeasonLocked; public Dictionary? CustomPayments; public PaymentAdjustmentWindow(int year) { InitializeComponent(); Year = year; using (var ctx = new AppDbContext()) { SeasonLocked = ctx.Seasons.Find(Year + 1) != null; } Title = $"Auszahlung anpassen - Lese {Year} - Elwig"; AutoAdjustBsButton.IsEnabled = !SeasonLocked; UnAdjustBsButton.IsEnabled = !SeasonLocked; SaveCustomButton.IsEnabled = !SeasonLocked; RemoveCustomButton.IsEnabled = !SeasonLocked; CustomAmountInput.IsEnabled = !SeasonLocked; CustomCommentInput.IsEnabled = !SeasonLocked; AllowanceKgInput.Text = $"{App.Client.AutoAdjustBs.AllowanceKg}"; AllowanceBsInput.Text = $"{App.Client.AutoAdjustBs.AllowanceBs}"; AllowanceKgPerBsInput.Text = $"{App.Client.AutoAdjustBs.AllowanceKgPerBs}"; AllowancePercentInput.Text = $"{App.Client.AutoAdjustBs.AllowancePercent}"; MinBsInput.Text = $"{App.Client.AutoAdjustBs.MinBs}"; } protected override async Task OnRenewContext(AppDbContext ctx) { var members = await ctx.Members .Select(m => new { m.MgNr, m.Name, m.GivenName, m.BusinessShares, m.IsActive, }) .OrderBy(m => m.Name) .ThenBy(m => m.GivenName) .ThenBy(m => m.MgNr) .ToListAsync(); var season = (await ctx.Seasons.FindAsync(Year))!; var contracts = await ctx.AreaCommitmentTypes.ToDictionaryAsync(t => t.VtrgId, t => t); var tbl1 = await OverUnderDeliveryData.ForSeason(ctx.OverUnderDeliveryRows, Year); var tbl2 = await AreaComUnderDeliveryData.ForSeason(ctx.AreaComUnderDeliveryRows, Year); var weight = tbl1.Rows.ToDictionary(r => r.MgNr, r => r.Weight); var areaComs = tbl2.Rows.ToDictionary(r => r.MgNr, r => r.VtrgIds.Zip(r.UnderDeliveries).ToDictionary(r => r.First, r => r.Second)); CustomPayments = await ctx.CustomPayments.Where(p => p.Year == Year).ToDictionaryAsync(p => p.MgNr, p => p); var history = await ctx.MemberHistory .Where(h => h.DateString.CompareTo($"{Year}-01-01") >= 0 && h.DateString.CompareTo($"{Year}-12-31") <= 0 && h.Type == "auto" && h.BusinessShares > 0) .GroupBy(h => h.Member) .ToDictionaryAsync(h => h.Key.MgNr, h => h.Sum(g => g.BusinessShares)); var list = members .Select(m => new { m.MgNr, m.Name, m.GivenName, m.IsActive, BusinessShares = m.BusinessShares - history.GetValueOrDefault(m.MgNr, 0), DeliveryObligation = (m.BusinessShares - history.GetValueOrDefault(m.MgNr, 0)) * season.MinKgPerBusinessShare, DeliveryRight = (m.BusinessShares - history.GetValueOrDefault(m.MgNr, 0)) * season.MaxKgPerBusinessShare, Adjust = history.TryGetValue(m.MgNr, out int v2) ? (int?)v2 : null, }) .Select(m => new { m.MgNr, m.Name, m.GivenName, m.BusinessShares, Weight = weight.GetValueOrDefault(m.MgNr, 0), OverUnder = weight.TryGetValue(m.MgNr, out int v1) ? (v1 < m.DeliveryObligation ? (int?)v1 - m.DeliveryObligation : v1 > m.DeliveryRight ? (int?)v1 - m.DeliveryRight : null) : (m.IsActive ? -m.DeliveryObligation : null), m.Adjust, AdjustAmount = m.Adjust * -season.BusinessShareValue, }) .Select(m => new { m.MgNr, m.Name, m.GivenName, m.BusinessShares, m.Weight, m.OverUnder, PenaltyBs = m.OverUnder != null && m.OverUnder < 0 ? (season.PenaltyPerKg * m.OverUnder ?? 0) + (-season.PenaltyAmount ?? 0) + (season.PenaltyPerBsAmount * Math.Floor(m.OverUnder / season.MinKgPerBusinessShare ?? 0m) ?? 0) + (m.Weight == 0 ? (-season.PenaltyNone ?? 0) + (-season.PenaltyPerBsNone * m.BusinessShares ?? 0) : 0) : (decimal?)null, PenaltyAc = areaComs.TryGetValue(m.MgNr, out var c) ? c.Select(r => { var con = contracts[r.Key]; return (r.Value.Kg * con.PenaltyPerKg ?? 0) + (r.Value.Kg < 0 ? con.PenaltyAmount ?? 0 : 0) + (r.Value.Percent == -100 ? con.PenaltyNone ?? 0 : 0); }).Sum() : (decimal?)null, m.Adjust, m.AdjustAmount, Custom = CustomPayments!.GetValueOrDefault(m.MgNr, null), }) .Select(m => new { m.MgNr, m.Name, m.GivenName, m.BusinessShares, m.Weight, m.OverUnder, PenaltyBs = m.PenaltyBs == null || m.PenaltyBs == 0 ? (decimal?)null : Math.Round((decimal)m.PenaltyBs, 2), PenaltyAc = m.PenaltyAc == null ? (decimal?)null : Math.Round((decimal)m.PenaltyAc, 2), m.Adjust, AdjustAmount = m.AdjustAmount == null ? (decimal?)null : Math.Round((decimal)m.AdjustAmount, 2), CustomAmount = m.Custom?.Amount, ModAbs = m.Custom?.ModAbs, ModRel = m.Custom?.ModRel, }) .Select(m => new { m.MgNr, m.Name, m.GivenName, m.BusinessShares, m.Weight, m.OverUnder, m.PenaltyBs, m.PenaltyAc, m.Adjust, m.AdjustAmount, m.CustomAmount, m.ModAbs, m.ModRel, Total = (m.PenaltyBs ?? 0) + (m.PenaltyAc ?? 0) + (m.AdjustAmount ?? 0) + (m.CustomAmount ?? 0), }) .Select(m => new { m.MgNr, m.Name, m.GivenName, m.BusinessShares, m.Weight, m.OverUnder, m.PenaltyBs, m.PenaltyAc, m.Adjust, m.AdjustAmount, m.CustomAmount, m.ModAbs, m.ModRel, m.Total, Background = m.Weight == 0 ? Brushes.Orange : m.Weight / 2 < -m.Total ? Brushes.Red : Brushes.White, Foreground = m.Total == 0 ? Brushes.Gray : Brushes.Black, }) .Where(m => m.OverUnder != null || m.Adjust != null || m.PenaltyBs != null || m.PenaltyAc != null || m.CustomAmount != null || m.ModAbs != null || m.ModRel != null) .OrderByDescending(m => m.OverUnder ?? 0) .ThenBy(m => m.Name) .ThenBy(m => m.GivenName) .ThenBy(m => m.MgNr) .ToList(); MemberList.ItemsSource = list; var sym = season.Currency.Symbol ?? season.Currency.Code; PenaltyBusinessShares.Text = $"{list.Count(r => r.PenaltyBs != null && r.PenaltyBs != 0)} Mg. / {list.Sum(r => r.PenaltyBs):N2} {sym}"; PenaltyAreaCommitments.Text = $"{list.Count(r => r.PenaltyAc != null && r.PenaltyAc != 0)} Mg. / {list.Sum(r => r.PenaltyAc):N2} {sym}"; AutoBusinessShareAdjustment.Text = $"{list.Count(r => r.Adjust > 0)} Mg. / {list.Sum(r => r.Adjust)} GA / {list.Sum(r => r.AdjustAmount):N2} {sym}"; CustomModifiers.Text = $"{list.Count(r => r.CustomAmount != null)} Mg. / {list.Sum(r => r.CustomAmount):N2} {sym}"; TotalModifiers.Text = $"{list.Count(r => r.Total != 0)} Mg. / {list.Sum(r => r.Total):N2} {sym}"; NonDeliveries.Text = $"{list.Count(r => r.Weight == 0):N0}"; ControlUtils.RenewItemsSource(MemberInput, await ctx.Members .OrderBy(m => m.Name) .ThenBy(m => m.GivenName) .ThenBy(m => m.MgNr) .ToListAsync()); CustomAmountInput.Unit = sym; } private async void AutoAdjustBsButton_Click(object sender, RoutedEventArgs evt) { Mouse.OverrideCursor = Cursors.AppStarting; try { int? kg = AllowanceKgInput.Text == "" ? null : int.Parse(AllowanceKgInput.Text); double? bs = AllowanceBsInput.Text == "" ? null : double.Parse(AllowanceBsInput.Text); int? kgPerBs = AllowanceKgPerBsInput.Text == "" ? null : int.Parse(AllowanceKgPerBsInput.Text); double? percent = AllowancePercentInput.Text == "" ? null : double.Parse(AllowancePercentInput.Text); int? minBs = MinBsInput.Text == "" ? null : int.Parse(MinBsInput.Text); App.Client.AutoAdjustBs.AllowanceKg = kg; App.Client.AutoAdjustBs.AllowanceBs = bs; App.Client.AutoAdjustBs.AllowanceKgPerBs = kgPerBs; App.Client.AutoAdjustBs.AllowancePercent = percent; App.Client.AutoAdjustBs.MinBs = minBs; await App.Client.UpdateValues(); var b = new Billing(Year); await b.AutoAdjustBusinessShares(new DateOnly(Year, 11, 30), kg ?? default, bs ?? default, kgPerBs ?? default, percent / 100.0 ?? default, minBs ?? default); await App.HintContextChange(); } catch (Exception exc) { var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message; if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message; MessageBox.Show(str, "GA Nachzeichnen", MessageBoxButton.OK, MessageBoxImage.Error); } Mouse.OverrideCursor = null; } private async void UnAdjustBsButton_Click(object sender, RoutedEventArgs evt) { Mouse.OverrideCursor = Cursors.AppStarting; try { var b = new Billing(Year); await b.UnAdjustBusinessShares(); await App.HintContextChange(); } catch (Exception exc) { var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message; if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message; MessageBox.Show(str, "GA Nachzeichnen", MessageBoxButton.OK, MessageBoxImage.Error); } Mouse.OverrideCursor = null; } private void SeasonButton_Click(object sender, RoutedEventArgs evt) { App.FocusBaseDataSeason(Year); } private void KgInput_TextChanged(object sender, TextChangedEventArgs evt) { Validator.CheckInteger((TextBox)sender, false, 6); } private void BsInput_TextChanged(object sender, TextChangedEventArgs evt) { Validator.CheckInteger((TextBox)sender, false, 3); } private void PercentInput_TextChanged(object sender, TextChangedEventArgs evt) { Validator.CheckDecimal((TextBox)sender, false, 3, 2); } private void MemberList_SelectionChanged(object sender, SelectionChangedEventArgs evt) { if (MemberList.SelectedItem != null) { var i = MemberList.SelectedItem; var t = i.GetType(); MgNrInput.Text = t.GetProperty("MgNr")?.GetValue(i)?.ToString(); } } private void MgNrInput_TextChanged(object sender, TextChangedEventArgs evt) { var res = Validator.CheckMgNr((TextBox)sender, true); ControlUtils.SelectItemWithPk(MemberInput, res.IsValid ? int.Parse(MgNrInput.Text) : null); } private void MgNrInput_LostFocus(object sender, RoutedEventArgs evt) { var res = Validator.CheckMgNr((TextBox)sender, true); ControlUtils.SelectItemWithPk(MemberInput, res.IsValid ? int.Parse(MgNrInput.Text) : null); } private void MemberInput_SelectionChanged(object sender, SelectionChangedEventArgs evt) { if (MemberInput.SelectedItem is Member m) { MgNrInput.Text = m.MgNr.ToString(); MemberList.SelectedItem = MemberList.ItemsSource.Cast().FirstOrDefault(i => { var t = i.GetType(); return (int?)t.GetProperty("MgNr")?.GetValue(i) == m.MgNr; }); if (MemberList.SelectedItem != null) MemberList.ScrollIntoView(MemberList.SelectedItem); if (CustomPayments?.TryGetValue(m.MgNr, out var p) == true) { CustomModAbsInput.Text = $"{p.ModAbs:N2}"; CustomModRelInput.Text = $"{p.ModRel * 100:N2}"; CustomModCommentInput.Text = p.ModComment ?? ""; CustomAmountInput.Text = $"{p.Amount:N2}"; CustomCommentInput.Text = p.Comment ?? ""; } else { CustomModAbsInput.Text = ""; CustomModRelInput.Text = ""; CustomModCommentInput.Text = ""; CustomAmountInput.Text = ""; CustomCommentInput.Text = ""; } } else { CustomModAbsInput.Text = ""; CustomModRelInput.Text = ""; CustomModCommentInput.Text = ""; CustomAmountInput.Text = ""; CustomCommentInput.Text = ""; } } private void MemberReferenceButton_Click(object sender, RoutedEventArgs evt) { if (MemberInput.SelectedItem is not Member m) return; App.FocusMember(m.MgNr); } private void CustomModAbsInput_TextChanged(object sender, TextChangedEventArgs evt) { Validator.CheckDecimal((TextBox)sender, false, 4, 2, true); } private void CustomModRelInput_TextChanged(object sender, TextChangedEventArgs evt) { Validator.CheckDecimal((TextBox)sender, false, 3, 2, true); } private void CustomAmountInput_TextChanged(object sender, TextChangedEventArgs evt) { Validator.CheckDecimal((TextBox)sender, false, 4, 2, true); } private async void CustomButton_Click(object sender, RoutedEventArgs evt) { if (MemberInput.SelectedItem is not Member m) return; Mouse.OverrideCursor = Cursors.AppStarting; try { using var ctx = new AppDbContext(); if (CustomPayments?.TryGetValue(m.MgNr, out var p) == true) { ctx.Remove(p); } if (sender == SaveCustomButton) { var modAbs = decimal.TryParse(CustomModAbsInput.Text, out var n1) ? (decimal?)n1 : null; var modRel = decimal.TryParse(CustomModRelInput.Text, out var n2) ? (decimal?)n2 / 100 : null; var amount = decimal.TryParse(CustomAmountInput.Text, out var n3) ? (decimal?)n3 : null; var modText = CustomModCommentInput.Text.Trim(); var text = CustomCommentInput.Text.Trim(); ctx.Add(new PaymentCustom { MgNr = m.MgNr, Year = Year, ModAbs = modAbs, ModRel = modRel, ModComment = modText == "" ? null : modText, Amount = amount, Comment = text == "" ? null : text, }); } await ctx.SaveChangesAsync(); } catch (Exception exc) { var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message; if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message; MessageBox.Show(str, "Benutzerdefinierten Zu-/Abschlag speichern", MessageBoxButton.OK, MessageBoxImage.Error); } await App.HintContextChange(); Mouse.OverrideCursor = null; } } }