From ba3f66591efa478ef946d536b77683c430567c84 Mon Sep 17 00:00:00 2001 From: Lorenz Stechauner Date: Wed, 24 Jun 2026 13:20:46 +0200 Subject: [PATCH] BilllingVariant: Allow for credits with negative value --- Elwig/Helpers/Billing/BillingVariant.cs | 2 +- Elwig/Services/PaymentVariantService.cs | 42 ++++++++++++++++++++++--- 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/Elwig/Helpers/Billing/BillingVariant.cs b/Elwig/Helpers/Billing/BillingVariant.cs index 4ccfb07..c8b7f7f 100644 --- a/Elwig/Helpers/Billing/BillingVariant.cs +++ b/Elwig/Helpers/Billing/BillingVariant.cs @@ -98,7 +98,7 @@ namespace Elwig.Helpers.Billing { LEFT JOIN v_penalty_area_commitments u ON (u.year, u.mgnr) = (s.year, m.mgnr) LEFT JOIN v_auto_business_shares a ON (a.year, a.mgnr) = (s.year, m.mgnr) LEFT JOIN payment_custom x ON (x.year, x.mgnr) = (s.year, m.mgnr) - WHERE s.year = {Year} AND v.avnr = {AvNr} AND p.amount > COALESCE(lp.amount, 0); + WHERE s.year = {Year} AND v.avnr = {AvNr} AND p.amount != COALESCE(lp.amount, 0); """); await cnx.ExecuteBatch($""" UPDATE payment_variant SET test_variant = FALSE WHERE (year, avnr) = ({Year}, {AvNr}); diff --git a/Elwig/Services/PaymentVariantService.cs b/Elwig/Services/PaymentVariantService.cs index 8d0c6d8..583e519 100644 --- a/Elwig/Services/PaymentVariantService.cs +++ b/Elwig/Services/PaymentVariantService.cs @@ -8,6 +8,7 @@ using Elwig.ViewModels; using Microsoft.EntityFrameworkCore; using Microsoft.Win32; using System; +using System.Collections.Generic; using System.Linq; using System.Text.Json; using System.Threading.Tasks; @@ -142,7 +143,7 @@ namespace Elwig.Services { }); var credits = ctx.Credits.Where(c => c.Year == v.Year && c.AvNr == v.AvNr); - if (!credits.Any()) { + if (!(await credits.AnyAsync())) { long lastTotalSum = 0; decimal vatSum = 0; var currentPayments = await ctx.MemberPayments @@ -150,8 +151,7 @@ namespace Elwig.Services { .ToDictionaryAsync(p => p.MgNr); var lastV = await ctx.PaymentVariants .Where(l => l.Year == v.Year && !l.TestVariant) - .OrderByDescending(l => l.TransferDateString ?? l.DateString) - .ThenByDescending(l => l.AvNr) + .OrderByDescending(l => l.TransferDateString ?? l.DateString).ThenByDescending(l => l.AvNr) .FirstOrDefaultAsync(); if (lastV != null) { var lastPayments = await ctx.MemberPayments @@ -160,8 +160,8 @@ namespace Elwig.Services { lastTotalSum = lastPayments.Sum(e => e.Value.AmountValue); foreach (int mgnr in currentPayments.Keys) { var c = currentPayments[mgnr]; - var l = lastPayments[mgnr]; - vatSum += (c.Amount - l.Amount) * (decimal)(c.Member.IsBuchführend ? v.Season.VatNormal : v.Season.VatFlatrate); + var l = lastPayments.GetValueOrDefault(mgnr); + vatSum += (c.Amount - (l?.Amount ?? 0)) * (decimal)(c.Member.IsBuchführend ? v.Season.VatNormal : v.Season.VatFlatrate); } } else { vatSum = currentPayments.Sum(e => e.Value.Amount * (decimal)(e.Value.Member.IsBuchführend ? v.Season.VatNormal : v.Season.VatFlatrate)); @@ -369,10 +369,42 @@ namespace Elwig.Services { } public static async Task Commit(int year, int avnr) { + List membersLess = []; + using (var ctx = new AppDbContext()) { + var lastAvNr = await ctx.PaymentVariants + .Where(v => v.Year == year && !v.TestVariant) + .OrderByDescending(v => v.TransferDateString ?? v.DateString).ThenByDescending(v => v.AvNr) + .Select(v => v.AvNr) + .FirstOrDefaultAsync(); + if (lastAvNr != 0) { + var cur = await ctx.MemberPayments.Include(p => p.Member).Where(p => p.Year == year && p.AvNr == avnr).ToDictionaryAsync(p => p.Member.MgNr, p => p); + var last = await ctx.MemberPayments.Include(p => p.Member).Where(p => p.Year == year && p.AvNr == lastAvNr).ToDictionaryAsync(p => p.Member.MgNr, p => p); + membersLess = [.. last.Where(p => (cur.TryGetValue(p.Key, out var c) ? c.Amount : 0) < p.Value.Amount).Select(p => p.Value.Member)]; + } + } + if (membersLess.Count > 0) { + var res = MessageBox.Show($"Achtung: Bei {membersLess.Count:N0} Mitglied(ern) ist der Soll-Betrag der Auszahlung (\"Gesamtbetrag\") kleiner als bei der letzten Auszahlung. Das sollte nicht vorkommen!\n\n" + + $"{string.Join(", ", membersLess.Select(m => $"{m.AdministrativeName} ({m.MgNr})"))}\n\n" + + "Soll trotzdem forgefahren werden?", + "Kleinerer Gesamtbetrag", MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel); + if (res != MessageBoxResult.OK) + return; + } + await Task.Run(async () => { var b = await BillingVariant.Create(year, avnr); await b.Commit(); }); + + List membersNeg = []; + using (var ctx = new AppDbContext()) { + membersNeg = await ctx.Credits.Where(c => c.Year == year && c.AvNr == avnr && c.AmountValue < 0).Select(c => c.Member).ToListAsync(); + } + if (membersNeg.Count > 0) { + var res = MessageBox.Show($"Achtung: Bei {membersNeg.Count:N0} Mitglied(ern) ist der Auszahlungsbetrag negativ!\n\n" + + $"{string.Join(", ", membersNeg.Select(m => $"{m.AdministrativeName} ({m.MgNr})"))}", + "Negativer Auszahlungsbetrag", MessageBoxButton.OK, MessageBoxImage.Warning); + } } public static async Task Revert(int year, int avnr) {