diff --git a/.gitea/workflows/test.yaml b/.gitea/workflows/test.yaml index 8801bb7..399ff0b 100644 --- a/.gitea/workflows/test.yaml +++ b/.gitea/workflows/test.yaml @@ -23,6 +23,16 @@ jobs: echo "No files with BOM found" exit 0 } + - name: Check for code smells + shell: powershell + run: | + git grep -IEn "\.(Single|First|Min|Max|Any)(OrDefault)?Async\([^)]|^using System.Data.Entity;" + if ( $lastexitcode -ne 1 ) { + exit 1 + } else { + echo "No files with code smells found" + exit 0 + } - name: Setup MSBuild uses: microsoft/setup-msbuild@v1.1 - name: Setup NuGet diff --git a/Elwig/App.xaml.cs b/Elwig/App.xaml.cs index 5b49877..2e3c567 100644 --- a/Elwig/App.xaml.cs +++ b/Elwig/App.xaml.cs @@ -105,9 +105,9 @@ namespace Elwig { Dictionary branches = []; using (var ctx = new AppDbContext()) { - branches = ctx.Branches - .Include(b => b.PostalDest) - .ToDictionary(b => b.Name.ToLower(), b => (b.ZwstId, b.Name, b.PostalDest?.AtPlz?.Plz, b.PostalDest?.AtPlz?.Ort.Name, b.Address, b.PhoneNr, b.FaxNr, b.MobileNr)); + branches = ctx.FetchBranches() + .ToDictionaryAsync(b => b.Name.ToLower(), b => (b.ZwstId, b.Name, b.PostalDest?.AtPlz?.Plz, b.PostalDest?.AtPlz?.Ort.Name, b.Address, b.PhoneNr, b.FaxNr, b.MobileNr)) + .GetAwaiter().GetResult(); try { Client = new(ctx); } catch (Exception e) { diff --git a/Elwig/Dialogs/DeliverySplittingDialog.xaml.cs b/Elwig/Dialogs/DeliverySplittingDialog.xaml.cs index f42b481..9a7f2f0 100644 --- a/Elwig/Dialogs/DeliverySplittingDialog.xaml.cs +++ b/Elwig/Dialogs/DeliverySplittingDialog.xaml.cs @@ -44,11 +44,7 @@ namespace Elwig.Dialogs { } protected override async Task OnRenewContext(AppDbContext ctx) { - ControlUtils.RenewItemsSource(MemberInput, await ctx.Members - .Where(m => m.IsActive) - .OrderBy(m => m.Name) - .ThenBy(m => m.GivenName) - .ToListAsync()); + ControlUtils.RenewItemsSource(MemberInput, await ctx.FetchMembers().ToListAsync()); ControlUtils.RenewItemsSource(DeliveryInput, await ctx.Deliveries .Where(d => d.DateString == $"{_delivery.Date:yyyy-MM-dd}" && d.ZwstId == _delivery.ZwstId) .OrderBy(d => d.LsNr) diff --git a/Elwig/Documents/CreditNote.cs b/Elwig/Documents/CreditNote.cs index a41360c..f4be43c 100644 --- a/Elwig/Documents/CreditNote.cs +++ b/Elwig/Documents/CreditNote.cs @@ -76,7 +76,7 @@ namespace Elwig.Documents { _data ??= (await CreditNoteDeliveryData.ForPaymentVariant(ctx.CreditNoteDeliveryRows, ctx.PaymentVariants, Payment.Year, Payment.AvNr))[Member.MgNr]; _underDeliveries ??= await ctx.GetMemberUnderDelivery(Payment.Year, Member.MgNr); - var mod = App.Client.IsMatzen ? await ctx.Modifiers.Where(m => m.Year == season.Year && m.Name.StartsWith("Treue")).FirstOrDefaultAsync() : null; + var mod = App.Client.IsMatzen ? await ctx.FetchModifiers(season.Year).Where(m => m.Name.StartsWith("Treue")).FirstOrDefaultAsync() : null; if (CustomPayment?.ModComment != null) { MemberModifier = CustomPayment.ModComment; } else if (mod != null) { @@ -102,8 +102,8 @@ namespace Elwig.Documents { MemberAutoBusinessSharesAmount = MemberAutoBusinessShares * (-season.BusinessShareValue ?? 0); } if (ConsiderContractPenalties) { - var varieties = await ctx.WineVarieties.ToDictionaryAsync(v => v.SortId, v => v); - var attributes = await ctx.WineAttributes.ToDictionaryAsync(a => a.AttrId, a => a); + var varieties = await ctx.FetchWineVarieties().ToDictionaryAsync(v => v.SortId, v => v); + var attributes = await ctx.FetchWineAttributes().ToDictionaryAsync(a => a.AttrId, a => a); var comTypes = await ctx.AreaCommitmentTypes.ToDictionaryAsync(t => t.VtrgId, t => t); MemberUnderDeliveries = _underDeliveries? .OrderBy(u => u.Key) diff --git a/Elwig/Documents/DeliveryConfirmation.cs b/Elwig/Documents/DeliveryConfirmation.cs index 5e828c2..54c9321 100644 --- a/Elwig/Documents/DeliveryConfirmation.cs +++ b/Elwig/Documents/DeliveryConfirmation.cs @@ -35,7 +35,7 @@ namespace Elwig.Documents { protected override async Task LoadData(AppDbContext ctx) { await base.LoadData(ctx); - Season = ctx.Seasons.Find(_year) ?? throw new ArgumentException("invalid season"); + Season = await ctx.FetchSeasons(_year).SingleOrDefaultAsync() ?? throw new ArgumentException("Invalid season"); MemberDeliveredWeight = await ctx.Deliveries .Where(d => d.Year == Season.Year && d.MgNr == Member.MgNr) .SelectMany(d => d.Parts) diff --git a/Elwig/Documents/MemberDataSheet.cs b/Elwig/Documents/MemberDataSheet.cs index fde9036..22b53c8 100644 --- a/Elwig/Documents/MemberDataSheet.cs +++ b/Elwig/Documents/MemberDataSheet.cs @@ -29,16 +29,12 @@ namespace Elwig.Documents { public static async Task Initialize(int mgnr) { using var ctx = new AppDbContext(); - return new MemberDataSheet(await ctx.Members - .Include(m => m.EmailAddresses) - .Include(m => m.TelephoneNumbers) - .Where(m => m.MgNr == mgnr) - .SingleAsync()); + return new MemberDataSheet(await ctx.FetchMembers(mgnr, true, true).SingleAsync()); } protected override async Task LoadData(AppDbContext ctx) { await base.LoadData(ctx); - Season = await ctx.Seasons.OrderBy(s => s.Year).LastOrDefaultAsync() ?? throw new ArgumentException("invalid season"); + Season = await ctx.FetchSeasons().FirstOrDefaultAsync() ?? throw new ArgumentException("Invalid season"); MemberBuckets = await ctx.GetMemberBuckets(Utils.CurrentYear, Member.MgNr); ActiveAreaCommitments = await Member.ActiveAreaCommitments(ctx) .Include(c => c.Contract).ThenInclude(c => c.Revisions) diff --git a/Elwig/Documents/PaymentVariantSummary.cs b/Elwig/Documents/PaymentVariantSummary.cs index 2b156aa..210952e 100644 --- a/Elwig/Documents/PaymentVariantSummary.cs +++ b/Elwig/Documents/PaymentVariantSummary.cs @@ -56,7 +56,7 @@ namespace Elwig.Documents { DeliveryPartNum = await ctx.DeliveryParts.Where(d => d.Year == Variant.Year).CountAsync(); Data ??= await PaymentVariantSummaryData.ForPaymentVariant(Variant, ctx.PaymentVariantSummaryRows); ModifierStat = await AppDbContext.GetModifierStats(Variant.Year, Variant.AvNr); - Modifiers = await ctx.Modifiers.Where(m => m.Year == Variant.Year).ToDictionaryAsync(m => m.ModId); + Modifiers = await ctx.FetchModifiers(Variant.Year).ToDictionaryAsync(m => m.ModId); } protected override void RenderBody(iText.Layout.Document doc, PdfDocument pdf) { diff --git a/Elwig/Helpers/AppDbContext.cs b/Elwig/Helpers/AppDbContext.cs index b18ebd8..ec90fe4 100644 --- a/Elwig/Helpers/AppDbContext.cs +++ b/Elwig/Helpers/AppDbContext.cs @@ -3,6 +3,8 @@ using Elwig.Models.Entities; using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; +using ScottPlot.TickGenerators.Financial; +using ScottPlot.TickGenerators.TimeUnits; using System; using System.Collections.Generic; using System.Data; @@ -11,6 +13,7 @@ using System.Linq; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Windows; +using System.Windows.Media.Converters; namespace Elwig.Helpers { @@ -82,6 +85,70 @@ namespace Elwig.Helpers { public static string? ConnectionStringOverride { get; set; } = null; public static string ConnectionString => ConnectionStringOverride ?? $"Data Source=\"{App.Config.DatabaseFile}\"; Mode=ReadWrite; Foreign Keys=True; Cache=Default; Pooling=False"; + private static readonly Func> _compiledQueryBranches = + EF.CompileAsyncQuery((ctx, zwstid, includeWithoutMembers) => ctx.Branches + .Where(b => includeWithoutMembers || b.Members.Count > 0) + .Where(b => zwstid == null || b.ZwstId == zwstid) + .Include(b => b.PostalDest) + .OrderBy(b => b.Name)); + + private static readonly Func> _compiledQueryWineVarieties = + EF.CompileAsyncQuery((ctx, sortid) => ctx.WineVarieties + .Where(v => sortid == null || v.SortId == sortid) + .OrderBy(v => v.Name)); + + private static readonly Func> _compiledQueryWineAttributes = + EF.CompileAsyncQuery((ctx, attrid, includeNotActive) => ctx.WineAttributes + .Where(a => includeNotActive || a.IsActive) + .Where(a => attrid == null || a.AttrId == attrid) + .OrderBy(a => a.Name)); + + private static readonly Func> _compiledQueryWineCultivations = + EF.CompileAsyncQuery((ctx, cultid) => ctx.WineCultivations + .Where(c => cultid == null || c.CultId == cultid) + .OrderBy(v => v.Name)); + + private static readonly Func> _compiledQueryWineQualityLevels = + EF.CompileAsyncQuery((ctx, includePredicate) => ctx.WineQualityLevels + .Where(l => includePredicate || !l.IsPredicate) + .OrderBy(l => l.MinKmw)); + + private static readonly Func> _compiledQueryModifiers = + EF.CompileAsyncQuery((ctx, year, incudeNotActive) => ctx.Modifiers + .Where(m => m.Year == year && (incudeNotActive || m.IsActive)) + .OrderBy(m => m.Ordering).ThenBy(m => m.Name)); + + private static readonly Func> _compiledQueryMembers = + EF.CompileAsyncQuery((ctx, mgnr, includeNotActive) => ctx.Members + .Where(m => includeNotActive || m.IsActive) + .Where(m => mgnr == null || m.MgNr == mgnr) + .OrderBy(m => m.Name).ThenBy(m => m.GivenName).ThenBy(m => m.MgNr)); + + private static readonly Func> _compiledQueryMembersContactInfo = + EF.CompileAsyncQuery((ctx, mgnr, includeNotActive) => ctx.Members + .Where(m => includeNotActive || m.IsActive) + .Where(m => mgnr == null || m.MgNr == mgnr) + .Include(m => m.EmailAddresses) + .Include(m => m.TelephoneNumbers) + .OrderBy(m => m.Name).ThenBy(m => m.GivenName).ThenBy(m => m.MgNr) + .AsSplitQuery()); + + private static readonly Func> _compiledQueryAreaCommitments = + EF.CompileAsyncQuery((ctx, fbnr) => ctx.AreaCommitments + .Where(c => fbnr == null || c.FbNr == fbnr) + .OrderBy(c => c.FbNr).ThenBy(c => c.RevNr)); + + private static readonly Func> _compiledQuerySeasons = + EF.CompileAsyncQuery((ctx, year) => ctx.Seasons + .Where(s => year == null || s.Year == year) + .OrderByDescending(s => s.Year)); + + private static readonly Func> _compiledQuerySeasonsModifiers = + EF.CompileAsyncQuery((ctx, year) => ctx.Seasons + .Where(s => year == null || s.Year == year) + .Include(s => s.Modifiers) + .OrderByDescending(s => s.Year)); + private readonly Dictionary>> _memberAreaCommitmentBuckets = []; private readonly Dictionary>> _memberDeliveryBuckets = []; private readonly Dictionary>> _memberDeliveryBucketsStrict = []; @@ -183,23 +250,23 @@ namespace Elwig.Helpers { } public async Task MgNrExists(int mgnr) { - return await Members.FindAsync(mgnr) != null; + return await _compiledQueryMembers.Invoke(this, mgnr, true).AnyAsync(); } public async Task FbNrExists(int fbnr) { - return await AreaCommitmentContracts.FindAsync(fbnr) != null; + return await _compiledQueryAreaCommitments.Invoke(this, fbnr).AnyAsync(); } public async Task SortIdExists(string sortId) { - return await WineVarieties.FindAsync(sortId) != null; + return await _compiledQueryWineVarieties.Invoke(this, sortId).AnyAsync(); } public async Task AttrIdExists(string attrId) { - return await WineAttributes.FindAsync(attrId) != null; + return await _compiledQueryWineAttributes.Invoke(this, attrId, true).AnyAsync(); } public async Task CultIdExists(string cultId) { - return await WineCultivations.FindAsync(cultId) != null; + return await _compiledQueryWineCultivations.Invoke(this, cultId).AnyAsync(); } public async Task NextMgNr() { @@ -217,88 +284,107 @@ namespace Elwig.Helpers { } public async Task NextRevNr(int fbnr) { - int c = 0; - (await AreaCommitments.Where(c => c.FbNr == fbnr).Select(c => c.RevNr).ToListAsync()) - .ForEach(a => { if (a <= c + 100) c = a; }); - return c + 1; + return (await AreaCommitments.Where(c => c.FbNr == fbnr).Select(c => (int?)c.RevNr).MaxAsync() ?? 0) + 1; } public async Task NextLNr(DateOnly date, string zwstid) { var dateStr = date.ToString("yyyy-MM-dd"); - int c = 0; - (await Deliveries.Where(d => d.DateString == dateStr && d.ZwstId == zwstid).Select(d => d.LNr).ToListAsync()) - .ForEach(a => { if (a <= c + 100) c = a; }); - return c + 1; + return (await Deliveries.Where(d => d.DateString == dateStr && d.ZwstId == zwstid).Select(d => (int?)d.LNr).MaxAsync() ?? 0) + 1; } public async Task NextDId(int year) { - int c = 0; - (await Deliveries.Where(d => d.Year == year).Select(d => d.DId).ToListAsync()) - .ForEach(a => { if (a <= c + 100) c = a; }); - return c + 1; + return (await Deliveries.Where(d => d.Year == year).Select(d => (int?)d.DId).MaxAsync() ?? 0) + 1; } public async Task NextDPNr(int year, int did) { - int c = 0; - (await DeliveryParts.Where(p => p.Year == year && p.DId == did).Select(d => d.DPNr).ToListAsync()) - .ForEach(a => { if (a <= c + 100) c = a; }); - return c + 1; + return (await DeliveryParts.Where(p => p.Year == year && p.DId == did).Select(p => (int?)p.DPNr).MaxAsync() ?? 0) + 1; } public async Task NextRdNr(int kgnr) { - int c = 0; - (await WbRde.Where(r => r.KgNr == kgnr).Select(r => r.RdNr).ToListAsync()) - .ForEach(a => { if (a <= c + 100) c = a; }); - return c + 1; + return (await WbRde.Where(r => r.KgNr == kgnr).Select(r => (int?)r.RdNr).MaxAsync() ?? 0) + 1; } public async Task NextAvNr(int year) { - int c = 0; - (await PaymentVariants.Where(v => v.Year == year).Select(v => v.AvNr).ToListAsync()) - .ForEach(a => { if (a <= c + 100) c = a; }); - return c + 1; + return (await PaymentVariants.Where(v => v.Year == year).Select(v => (int?)v.AvNr).MaxAsync() ?? 0) + 1; } public async Task NextDsNr(int year) { - int c = 0; - (await DeliverySchedules.Where(s => s.Year == year).Select(s => s.DsNr).ToListAsync()) - .ForEach(a => { if (a <= c + 100) c = a; }); - return c + 1; + return (await DeliverySchedules.Where(s => s.Year == year).Select(v => (int?)v.DsNr).MaxAsync() ?? 0) + 1; } - public void UpdateDeliveryPartModifiers(DeliveryPart part, IEnumerable oldModifiers, IEnumerable newModifiers) { - foreach (var m in Modifiers.Where(m => m.Year == part.Year)) { + public IAsyncEnumerable FetchBranches(string? zwstid = null, bool includeWithoutMembers = true) { + return _compiledQueryBranches.Invoke(this, zwstid, includeWithoutMembers); + } + + public IAsyncEnumerable FetchWineVarieties() { + return _compiledQueryWineVarieties.Invoke(this, null); + } + + public IAsyncEnumerable FetchWineAttributes(bool incudeNotActive = true) { + return _compiledQueryWineAttributes.Invoke(this, null, incudeNotActive); + } + + public IAsyncEnumerable FetchWineCultivations() { + return _compiledQueryWineCultivations.Invoke(this, null); + } + + public IAsyncEnumerable FetchWineQualityLevels(bool includePredicate = true) { + return _compiledQueryWineQualityLevels.Invoke(this, includePredicate); + } + + public IAsyncEnumerable FetchModifiers(int? year, bool incudeNotActive = true) { + return _compiledQueryModifiers.Invoke(this, year ?? 0, incudeNotActive); + } + + public IAsyncEnumerable FetchMembers(int? mgnr = null, bool includeNotActive = false, bool includeContactInfo = false) { + if (includeContactInfo) { + return _compiledQueryMembersContactInfo.Invoke(this, mgnr, includeNotActive); + } else { + return _compiledQueryMembers.Invoke(this, mgnr, includeNotActive); + } + } + + public IAsyncEnumerable FetchSeasons(int? year = null, bool includeModifiers = false) { + if (includeModifiers) { + return _compiledQuerySeasonsModifiers.Invoke(this, year); + } else { + return _compiledQuerySeasons.Invoke(this, year); + } + } + + public async Task UpdateDeliveryPartModifiers(DeliveryPart part, IEnumerable oldModIds, IEnumerable newModIds) { + foreach (var m in await FetchModifiers(part.Year).ToListAsync()) { var mod = new DeliveryPartModifier { Year = part.Year, DId = part.DId, DPNr = part.DPNr, ModId = m.ModId, }; - var old = oldModifiers.Where(pa => pa.ModId == m.ModId).FirstOrDefault(); - if (newModifiers.Any(md => md.ModId == m.ModId)) { - if (old == null) { + var old = oldModIds.Contains(m.ModId); + if (newModIds.Contains(m.ModId)) { + if (!old) { Add(mod); } else { Update(mod); } } else { - if (old != null) { + if (old) { Remove(mod); } } } } - public void UpdateDeliveryScheduleWineVarieties(DeliverySchedule schedule, IEnumerable<(WineVar, int)> oldVarieties, IEnumerable<(WineVar, int)> newVarieties) { - foreach (var v in WineVarieties) { + public async Task UpdateDeliveryScheduleWineVarieties(DeliverySchedule schedule, IEnumerable<(string, int)> oldVarieties, IEnumerable<(string, int)> newVarieties) { + foreach (var v in await FetchWineVarieties().ToArrayAsync()) { var e = new DeliveryScheduleWineVar { Year = schedule.Year, DsNr = schedule.DsNr, SortId = v.SortId, Priority = 1, }; - var o = oldVarieties.Where(x => x.Item1.SortId == e.SortId).Select(x => x.Item2).FirstOrDefault(-1); - var n = newVarieties.Where(x => x.Item1.SortId == e.SortId).Select(x => x.Item2).FirstOrDefault(-1); + var o = oldVarieties.Where(x => x.Item1 == e.SortId).Select(x => x.Item2).FirstOrDefault(-1); + var n = newVarieties.Where(x => x.Item1 == e.SortId).Select(x => x.Item2).FirstOrDefault(-1); if (n != -1) { e.Priority = n; if (o == -1) { diff --git a/Elwig/Helpers/Billing/Billing.cs b/Elwig/Helpers/Billing/Billing.cs index aa53d68..6f8eaed 100644 --- a/Elwig/Helpers/Billing/Billing.cs +++ b/Elwig/Helpers/Billing/Billing.cs @@ -1,6 +1,5 @@ using Elwig.Models.Entities; using Microsoft.Data.Sqlite; -using Microsoft.EntityFrameworkCore; using System; using System.Collections.Generic; using System.Globalization; @@ -16,13 +15,30 @@ namespace Elwig.Helpers.Billing { protected readonly Dictionary Modifiers; protected readonly Dictionary AreaComTypes; - public Billing(int year) { + protected Billing(int year, Season season, + Dictionary attributes, + Dictionary modifiers, + Dictionary areaComTypes + ) { Year = year; + Season = season; + Attributes = attributes; + Modifiers = modifiers; + AreaComTypes = areaComTypes; + } + + protected static async Task<(Season, Dictionary, Dictionary, Dictionary)> LoadData(AppDbContext ctx, int year) { + var season = await ctx.FetchSeasons(year).SingleOrDefaultAsync() ?? throw new ArgumentException("Invalid season"); + var attributes = await ctx.FetchWineAttributes().ToDictionaryAsync(a => a.AttrId, a => a.Name); + var modifiers = await ctx.FetchModifiers(year).ToDictionaryAsync(m => m.ModId, m => (m.Abs, m.Rel)); + var areaComTypes = ctx.AreaCommitmentTypes.ToDictionary(v => v.VtrgId, v => (v.SortId, v.AttrId, v.Discriminator, v.MinKgPerHa, v.PenaltyAmount)); + return (season, attributes, modifiers, areaComTypes); + } + + public static async Task Create(int year) { using var ctx = new AppDbContext(); - Season = ctx.Seasons.Find(Year)!; - Attributes = ctx.WineAttributes.ToDictionary(a => a.AttrId, a => a.Name); - Modifiers = ctx.Modifiers.Where(m => m.Year == Year).ToDictionary(m => m.ModId, m => (m.Abs, m.Rel)); - AreaComTypes = ctx.AreaCommitmentTypes.ToDictionary(v => v.VtrgId, v => (v.SortId, v.AttrId, v.Discriminator, v.MinKgPerHa, v.PenaltyAmount)); + var (season, attributes, modifiers, areaComTypes) = await LoadData(ctx, year); + return new Billing(year, season, attributes, modifiers, areaComTypes); } public async Task FinishSeason() { diff --git a/Elwig/Helpers/Billing/BillingVariant.cs b/Elwig/Helpers/Billing/BillingVariant.cs index a6613c8..6c79fd4 100644 --- a/Elwig/Helpers/Billing/BillingVariant.cs +++ b/Elwig/Helpers/Billing/BillingVariant.cs @@ -10,17 +10,35 @@ namespace Elwig.Helpers.Billing { public class BillingVariant : Billing { protected readonly int AvNr; - protected readonly PaymentVar PaymentVariant; - protected readonly PaymentBillingData Data; + protected PaymentVar PaymentVariant; + protected PaymentBillingData Data; - public BillingVariant(int year, int avnr) : base(year) { + protected BillingVariant(int year, int avnr, Season season, + Dictionary attributes, + Dictionary modifiers, + Dictionary areaComTypes, + PaymentVar paymentVar, PaymentBillingData data) : + base(year, season, attributes, modifiers, areaComTypes) { AvNr = avnr; + PaymentVariant = paymentVar; + Data = data; + } + + protected static async Task<(PaymentVar, PaymentBillingData)> LoadData(AppDbContext ctx, int year, int avnr) { + var paymentVar = await ctx.PaymentVariants.Where(v => v.Year == year && v.AvNr == avnr).SingleAsync(); + var data = PaymentBillingData.FromJson(paymentVar.Data, await Utils.GetVaributes(ctx, year, onlyDelivered: false)); + return (paymentVar, data); + } + + public static async Task Create(int year, int avnr) { using var ctx = new AppDbContext(); - PaymentVariant = ctx.PaymentVariants.Where(v => v.Year == Year && v.AvNr == AvNr).Single(); - Data = PaymentBillingData.FromJson(PaymentVariant.Data, Utils.GetVaributes(ctx, Year, onlyDelivered: false)); + var (season, attributes, modifiers, areaComTypes) = await LoadData(ctx, year); + var (paymentVar, data) = await LoadData(ctx, year, avnr); + return new BillingVariant(year, avnr, season, attributes, modifiers, areaComTypes, paymentVar, data); } public async Task Calculate(bool strictPrices = true, bool? honorGebunden = null, bool? allowAttrsIntoLower = null, bool? avoidUnderDeliveries = null) { + if (PaymentVariant == null || Data == null) throw new Exception("Call Load before Calculate"); using var cnx = await AppDbContext.ConnectAsync(); using var tx = await cnx.BeginTransactionAsync(); await CalculateBuckets(honorGebunden, allowAttrsIntoLower, avoidUnderDeliveries, cnx); diff --git a/Elwig/Helpers/Billing/EditBillingData.cs b/Elwig/Helpers/Billing/EditBillingData.cs index 64498fd..288650e 100644 --- a/Elwig/Helpers/Billing/EditBillingData.cs +++ b/Elwig/Helpers/Billing/EditBillingData.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Text.Json.Nodes; +using System.Threading.Tasks; namespace Elwig.Helpers.Billing { public class EditBillingData : BillingData { @@ -70,14 +71,14 @@ namespace Elwig.Helpers.Billing { return (curves, dict3); } - private static List CreateGraphEntries( + private static async Task> CreateGraphEntries( AppDbContext ctx, int precision, Dictionary curves, Dictionary> entries ) { - var vars = ctx.WineVarieties.ToDictionary(v => v.SortId, v => v); - var attrs = ctx.WineAttributes.ToDictionary(a => a.AttrId, a => a); - var cults = ctx.WineCultivations.ToDictionary(c => c.CultId, c => c); + var vars = await ctx.FetchWineVarieties().ToDictionaryAsync(v => v.SortId, v => v); + var attrs = await ctx.FetchWineAttributes().ToDictionaryAsync(a => a.AttrId, a => a); + var cults = await ctx.FetchWineCultivations().ToDictionaryAsync(c => c.CultId, c => c); return entries .Select(e => new GraphEntry(e.Key, precision, curves[e.Key], e.Value .Select(s => new Varibute(s, vars, attrs, cults)) @@ -85,18 +86,18 @@ namespace Elwig.Helpers.Billing { .ToList(); } - public IEnumerable GetPaymentGraphEntries(AppDbContext ctx, Season season) { + public async Task> GetPaymentGraphEntries(AppDbContext ctx, Season season) { var root = GetPaymentEntry(); var (curves, entries) = GetGraphEntries(root); - return CreateGraphEntries(ctx, season.Precision, curves, entries).Where(e => e.Vaributes.Count > 0); + return (await CreateGraphEntries(ctx, season.Precision, curves, entries)).Where(e => e.Vaributes.Count > 0); } - public IEnumerable GetQualityGraphEntries(AppDbContext ctx, Season season, int idOffset = 0) { + public async Task> GetQualityGraphEntries(AppDbContext ctx, Season season, int idOffset = 0) { var root = GetQualityEntry(); if (root == null || root["WEI"] is not JsonNode qualityWei) return []; var (curves, entries) = GetGraphEntries(qualityWei); - var list = CreateGraphEntries(ctx, season.Precision, curves, entries).Where(e => e.Vaributes.Count > 0); + var list = (await CreateGraphEntries(ctx, season.Precision, curves, entries)).Where(e => e.Vaributes.Count > 0); foreach (var e in list) { e.Id += idOffset; e.Abgewertet = true; diff --git a/Elwig/Helpers/Export/ElwigData.cs b/Elwig/Helpers/Export/ElwigData.cs index 9a7191c..b3bc693 100644 --- a/Elwig/Helpers/Export/ElwigData.cs +++ b/Elwig/Helpers/Export/ElwigData.cs @@ -41,7 +41,7 @@ namespace Elwig.Helpers.Export { List currentWbGls; using (var ctx = new AppDbContext()) { - branches = await ctx.Branches.ToDictionaryAsync(b => b.ZwstId); + branches = await ctx.FetchBranches().ToDictionaryAsync(b => b.ZwstId); currentDids = await ctx.Deliveries .GroupBy(d => d.Year) .ToDictionaryAsync(g => g.Key, g => g.Max(d => d.DId)); diff --git a/Elwig/Helpers/Utils.cs b/Elwig/Helpers/Utils.cs index 681ec3b..53e29e2 100644 --- a/Elwig/Helpers/Utils.cs +++ b/Elwig/Helpers/Utils.cs @@ -413,8 +413,8 @@ namespace Elwig.Helpers { return output.OrderByDescending(l => l.Count()); } - public static List GetVaributes(AppDbContext ctx, int year, bool onlyDelivered = true) { - var varieties = ctx.WineVarieties.Select(v => new RawVaribute(v.SortId, "", null)).ToList(); + public static async Task> GetVaributes(AppDbContext ctx, int year, bool onlyDelivered = true) { + var varieties = await ctx.FetchWineVarieties().Select(v => new RawVaribute(v.SortId, "", null)).ToListAsync(); var delivered = ctx.DeliveryParts .Where(d => d.Year == year) .Select(d => new RawVaribute(d.SortId, d.AttrId ?? "", d.CultId ?? "")) @@ -423,13 +423,11 @@ namespace Elwig.Helpers { return [.. (onlyDelivered ? delivered : delivered.Union(varieties)).Order()]; } - public static List GetVaributeList(AppDbContext ctx, int year, bool onlyDelivered = true) { - var varieties = ctx.WineVarieties.ToDictionary(v => v.SortId, v => v); - var attributes = ctx.WineAttributes.ToDictionary(a => a.AttrId, a => a); - var cultivations = ctx.WineCultivations.ToDictionary(c => c.CultId, c => c); - return GetVaributes(ctx, year, onlyDelivered) - .Select(s => new Varibute(s, varieties, attributes, cultivations)) - .ToList(); + public static async Task> GetVaributeList(AppDbContext ctx, int year, bool onlyDelivered = true) { + var varieties = await ctx.FetchWineVarieties().ToDictionaryAsync(v => v.SortId, v => v); + var attributes = await ctx.FetchWineAttributes().ToDictionaryAsync(a => a.AttrId, a => a); + var cultivations = await ctx.FetchWineCultivations().ToDictionaryAsync(c => c.CultId, c => c); + return [.. (await GetVaributes(ctx, year, onlyDelivered)).Select(s => new Varibute(s, varieties, attributes, cultivations))]; } [LibraryImport("wininet.dll")] diff --git a/Elwig/Models/Dtos/CreditNoteDeliveryData.cs b/Elwig/Models/Dtos/CreditNoteDeliveryData.cs index 7ad0b3d..e044987 100644 --- a/Elwig/Models/Dtos/CreditNoteDeliveryData.cs +++ b/Elwig/Models/Dtos/CreditNoteDeliveryData.cs @@ -28,7 +28,7 @@ namespace Elwig.Models.Dtos { } public static async Task> ForPaymentVariant(DbSet table, DbSet paymentVariants, int year, int avnr) { - var variant = await paymentVariants.Include(v => v.Season.Modifiers).SingleAsync(v => v.Year == year && v.AvNr == avnr); + var variant = await paymentVariants.Include(v => v.Season.Modifiers).Where(v => v.Year == year && v.AvNr == avnr).SingleAsync(); BillingData? varData = null; try { varData = variant.Data != null ? BillingData.FromJson(variant.Data) : null; } catch { } return (await FromDbSet(table, year, avnr)) diff --git a/Elwig/Services/AreaComService.cs b/Elwig/Services/AreaComService.cs index 7fe2f67..da29570 100644 --- a/Elwig/Services/AreaComService.cs +++ b/Elwig/Services/AreaComService.cs @@ -56,9 +56,9 @@ namespace Elwig.Services { var filter = vm.TextFilter; if (filter.Count > 0) { - var var = await ctx.WineVarieties.ToDictionaryAsync(v => v.SortId, v => v); - var attr = await ctx.WineAttributes.ToDictionaryAsync(a => a.Name.ToLower().Split(" ")[0], a => a); - var attrId = await ctx.WineAttributes.ToDictionaryAsync(a => a.AttrId, a => a); + var var = await ctx.FetchWineVarieties().ToDictionaryAsync(v => v.SortId, v => v); + var attrId = await ctx.FetchWineAttributes().ToDictionaryAsync(a => a.AttrId, a => a); + var attr = attrId.Values.ToDictionary(a => a.Name.ToLower().Split(" ")[0], a => a); for (int i = 0; i < filter.Count; i++) { var e = filter[i]; diff --git a/Elwig/Services/DeliveryAncmtService.cs b/Elwig/Services/DeliveryAncmtService.cs index e9ada63..067cb26 100644 --- a/Elwig/Services/DeliveryAncmtService.cs +++ b/Elwig/Services/DeliveryAncmtService.cs @@ -65,11 +65,11 @@ namespace Elwig.Services { var filter = vm.TextFilter; if (filter.Count > 0) { - var var = await ctx.WineVarieties.ToDictionaryAsync(v => v.SortId, v => v); - var mgnr = await ctx.Members.ToDictionaryAsync(m => m.MgNr.ToString(), m => m); - var zwst = await ctx.Branches.ToDictionaryAsync(b => b.Name.ToLower().Split(' ')[0], b => b); - var attr = await ctx.WineAttributes.ToDictionaryAsync(a => a.Name.ToLower().Split(' ')[0], a => a); - var cult = await ctx.WineCultivations.ToDictionaryAsync(c => c.Name.ToLower().Split(' ')[0], c => c); + var var = await ctx.FetchWineVarieties().ToDictionaryAsync(v => v.SortId, v => v); + var mgnr = await ctx.FetchMembers(includeNotActive: true).ToDictionaryAsync(m => m.MgNr.ToString(), m => m); + var zwst = await ctx.FetchBranches().ToDictionaryAsync(b => b.Name.ToLower().Split(' ')[0], b => b); + var attr = await ctx.FetchWineAttributes().ToDictionaryAsync(a => a.Name.ToLower().Split(' ')[0], a => a); + var cult = await ctx.FetchWineCultivations().ToDictionaryAsync(c => c.Name.ToLower().Split(' ')[0], c => c); for (int i = 0; i < filter.Count; i++) { var e = filter[i]; diff --git a/Elwig/Services/DeliveryScheduleService.cs b/Elwig/Services/DeliveryScheduleService.cs index 969208b..68897df 100644 --- a/Elwig/Services/DeliveryScheduleService.cs +++ b/Elwig/Services/DeliveryScheduleService.cs @@ -60,8 +60,8 @@ namespace Elwig.Services { var filter = vm.TextFilter; if (filter.Count > 0) { - var var = await ctx.WineVarieties.ToDictionaryAsync(v => v.SortId, v => v); - var zwst = await ctx.Branches.ToDictionaryAsync(b => b.Name.ToLower().Split(" ")[0], b => b); + var var = await ctx.FetchWineVarieties().ToDictionaryAsync(v => v.SortId, v => v); + var zwst = await ctx.FetchBranches().ToDictionaryAsync(b => b.Name.ToLower().Split(" ")[0], b => b); for (int i = 0; i < filter.Count; i++) { var e = filter[i]; @@ -174,12 +174,12 @@ namespace Elwig.Services { ctx.Add(s); } - ctx.UpdateDeliveryScheduleWineVarieties(s, (await ctx.DeliveryScheduleWineVarieties + await ctx.UpdateDeliveryScheduleWineVarieties(s, (await ctx.DeliveryScheduleWineVarieties .Where(v => v.Year == s.Year && v.DsNr == s.DsNr) .Select(v => new { v.Variety, v.Priority }) .ToListAsync()) - .Select(v => (v.Variety, v.Priority)) - .ToList(), vm.MainVarieties.Select(v => (v, 1)).Union(vm.OtherVarieties.Select(v => (v, 2))).ToList()); + .Select(v => (v.Variety.SortId, v.Priority)) + .ToList(), vm.MainVarieties.Select(v => (v.SortId, 1)).Union(vm.OtherVarieties.Select(v => (v.SortId, 2))).ToList()); await ctx.SaveChangesAsync(); }); diff --git a/Elwig/Services/DeliveryService.cs b/Elwig/Services/DeliveryService.cs index 75ece62..27b161e 100644 --- a/Elwig/Services/DeliveryService.cs +++ b/Elwig/Services/DeliveryService.cs @@ -27,7 +27,7 @@ namespace Elwig.Services { public static async Task GetMemberAsync(int mgnr) { using var ctx = new AppDbContext(); - return await ctx.Members.FirstOrDefaultAsync(m => m.MgNr == mgnr); + return await ctx.FetchMembers(mgnr).SingleOrDefaultAsync(); } public static Member? GetMember(int mgnr) { @@ -126,12 +126,12 @@ namespace Elwig.Services { var filter = vm.TextFilter; if (filter.Count > 0) { - var var = await ctx.WineVarieties.ToDictionaryAsync(v => v.SortId, v => v); - var qual = await ctx.WineQualityLevels.Where(q => !q.IsPredicate).ToDictionaryAsync(q => q.QualId, q => q); - var mgnr = await ctx.Members.ToDictionaryAsync(m => m.MgNr.ToString(), m => m); - var zwst = await ctx.Branches.ToDictionaryAsync(b => b.Name.ToLower().Split(' ')[0], b => b); - var attr = await ctx.WineAttributes.ToDictionaryAsync(a => a.Name.ToLower().Split(' ')[0], a => a); - var cult = await ctx.WineCultivations.ToDictionaryAsync(c => c.Name.ToLower().Split(' ')[0], c => c); + var var = await ctx.FetchWineVarieties().ToDictionaryAsync(v => v.SortId, v => v); + var qual = await ctx.FetchWineQualityLevels(false).ToDictionaryAsync(q => q.QualId, q => q); + var mgnr = await ctx.FetchMembers(includeNotActive: true).ToDictionaryAsync(m => m.MgNr.ToString(), m => m); + var zwst = await ctx.FetchBranches().ToDictionaryAsync(b => b.Name.ToLower().Split(' ')[0], b => b); + var attr = await ctx.FetchWineAttributes().ToDictionaryAsync(a => a.Name.ToLower().Split(' ')[0], a => a); + var cult = await ctx.FetchWineCultivations().ToDictionaryAsync(c => c.Name.ToLower().Split(' ')[0], c => c); for (int i = 0; i < filter.Count; i++) { var e = filter[i]; @@ -546,14 +546,14 @@ namespace Elwig.Services { ctx.Add(p); } - ctx.UpdateDeliveryPartModifiers(p, await ctx.DeliveryPartModifiers + await ctx.UpdateDeliveryPartModifiers(p, await ctx.DeliveryPartModifiers .Where(m => m.Year == p.Year && m.DId == p.DId && m.DPNr == p.DPNr) - .Select(m => m.Modifier) - .ToListAsync(), vm.Modifiers); + .Select(m => m.ModId) + .ToListAsync(), vm.Modifiers.Select(m => m.ModId).ToList()); if (originalMgNr != null && originalMgNr.Value != d.MgNr) { // update origin (KgNr), if default is selected - var newKgNr = (await ctx.Members.FindAsync(d.MgNr))?.DefaultKgNr; + var newKgNr = (await ctx.FetchMembers(d.MgNr).SingleOrDefaultAsync())?.DefaultKgNr; await ctx.DeliveryParts .Where(p => p.Year == d.Year && p.DId == d.DId && p.DPNr != dpnr && p.KgNr == originalMemberKgNr) .ExecuteUpdateAsync(u => u.SetProperty(p => p.KgNr, newKgNr)); @@ -637,7 +637,7 @@ namespace Elwig.Services { Delivery n; using var ctx = new AppDbContext(); var anyLeft = false; - n = (await ctx.Deliveries.FirstAsync(d => d.LsNr == lsnr))!; + n = (await ctx.Deliveries.Where(d => d.LsNr == lsnr).FirstAsync())!; var d = await ctx.Deliveries .Where(d => d.Year == year && d.DId == did) .Include(d => d.Parts).ThenInclude(p => p.PartModifiers) @@ -951,7 +951,7 @@ namespace Elwig.Services { tblTotal.FullName = DeliveryDepreciationList.Name; tblTotal.Name = "Gesamt"; await ods.AddTable(tblTotal); - foreach (var branch in await ctx.Branches.OrderBy(b => b.Name).ToListAsync()) { + foreach (var branch in await ctx.FetchBranches().ToListAsync()) { var tbl = await DeliveryJournalData.FromQuery(query.Where(p => p.Delivery.ZwstId == branch.ZwstId), filterNames); tbl.FullName = DeliveryDepreciationList.Name; tbl.Name = branch.Name; @@ -1062,16 +1062,23 @@ namespace Elwig.Services { var gGrid = new List<(string?, string?, double, double, double)>(); var gText = "-"; - var weight = await deliveryParts.SumAsync(p => p.Weight); - wText = $"{weight:N0} kg"; - wGrid.Add(("Menge", null, weight, null, weight)); + var stat = (await deliveryParts.GroupBy(p => 0) + .Select(g => new { + Weight = g.Sum(p => p.Weight), + Min = g.Select(p => (double?)p.Kmw).DefaultIfEmpty().Min(), + Avg = g.Sum(p => p.Kmw * p.Weight) / g.Sum(p => p.Weight), + Max = g.Select(p => (double?)p.Kmw).DefaultIfEmpty().Max(), + }) + .ToListAsync()) + .DefaultIfEmpty(new { Weight = 0, Min = (double?)null, Avg = (double)0, Max = (double?)null }) + .Single(); - if (await deliveryParts.AnyAsync()) { - var kmwMin = await deliveryParts.MinAsync(p => p.Kmw); - var kmwAvg = Utils.AggregateDeliveryPartsKmw(deliveryParts); - var kmwMax = await deliveryParts.MaxAsync(p => p.Kmw); - gText = $"{kmwMin:N1}° / {kmwAvg:N1}° / {kmwMax:N1}°"; - gGrid.Add(("Gradation", null, kmwMin, kmwAvg, kmwMax)); + wText = $"{stat.Weight:N0} kg"; + wGrid.Add(("Menge", null, stat.Weight, null, stat.Weight)); + + if (stat.Min != null && stat.Max != null) { + gText = $"{stat.Min:N1}° / {stat.Avg:N1}° / {stat.Max:N1}°"; + gGrid.Add(("Gradation", null, stat.Min.Value, stat.Avg, stat.Max.Value)); var attrGroups = await deliveryParts .GroupBy(p => new { Attr = p.Attribute!.Name, Cult = p.Cultivation!.Name }) @@ -1122,9 +1129,9 @@ namespace Elwig.Services { foreach (var attrG in attrGroups) { var name = attrG.Attr == null && attrG.Cult == null ? null : attrG.Attr + (attrG.Attr != null && attrG.Cult != null ? " / " : "") + attrG.Cult; - wGrid.Add((name, null, attrG.Weight, attrG.Weight, weight)); + wGrid.Add((name, null, attrG.Weight, attrG.Weight, stat.Weight)); foreach (var g in groups.Where(g => g.Attr == attrG.Attr && g.Cult == attrG.Cult).OrderByDescending(g => g.Weight).ThenBy(g => g.SortId)) { - wGrid.Add((null, g.SortId, g.Weight, attrG.Weight, weight)); + wGrid.Add((null, g.SortId, g.Weight, attrG.Weight, stat.Weight)); } } foreach (var attrG in attrGroups) { @@ -1143,12 +1150,12 @@ namespace Elwig.Services { gText += $" [{name}]"; } if (sortGroups.Count > 1 && sortGroups.Count <= 4) { - wText += $" = {string.Join(" + ", sortGroups.Select(g => $"{g.Weight:N0} kg ({(double)g.Weight / weight:0%})" + (g.SortId == null ? "" : $" [{g.SortId}]")))}"; + wText += $" = {string.Join(" + ", sortGroups.Select(g => $"{g.Weight:N0} kg ({(double)g.Weight / stat.Weight:0%})" + (g.SortId == null ? "" : $" [{g.SortId}]")))}"; gText += $" = {string.Join(" + ", sortGroups.Select(g => $"{g.Min:N1}/{g.Avg:N1}/{g.Max:N1}" + (g.SortId == null ? "" : $" [{g.SortId}]")))}"; } } else if (attrGroups.Count <= 4) { - wText += $" = {string.Join(" + ", attrGroups.Select(g => $"{g.Weight:N0} kg ({(double)g.Weight / weight:0%})" + (g.Attr == null && g.Cult == null ? "" : $" [{g.Attr}{(g.Attr != null && g.Cult != null ? " / " : "")}{g.Cult}]")))}"; + wText += $" = {string.Join(" + ", attrGroups.Select(g => $"{g.Weight:N0} kg ({(double)g.Weight / stat.Weight:0%})" + (g.Attr == null && g.Cult == null ? "" : $" [{g.Attr}{(g.Attr != null && g.Cult != null ? " / " : "")}{g.Cult}]")))}"; gText += $" = {string.Join(" + ", attrGroups.Select(g => $"{g.Min:N1}/{g.Avg:N1}/{g.Max:N1}" + (g.Attr == null && g.Cult == null ? "" : $" [{g.Attr}{(g.Attr != null && g.Cult != null ? " / " : "")}{g.Cult}]")))}"; } } diff --git a/Elwig/Services/MemberService.cs b/Elwig/Services/MemberService.cs index a71f52d..9adde38 100644 --- a/Elwig/Services/MemberService.cs +++ b/Elwig/Services/MemberService.cs @@ -172,7 +172,7 @@ namespace Elwig.Services { var c = m.ActiveAreaCommitments(ctx, Utils.CurrentLastSeason); int maxKgPerHa = 10_000; try { - var s = await ctx.Seasons.FindAsync(await ctx.Seasons.MaxAsync(s => s.Year)); + var s = await ctx.FetchSeasons().FirstOrDefaultAsync(); if (s != null) maxKgPerHa = s.MaxKgPerHa; } catch { } var (text, gridData) = await AreaComService.GenerateToolTipData(c, maxKgPerHa); @@ -225,8 +225,8 @@ namespace Elwig.Services { var filter = vm.TextFilter; if (filter.Count > 0) { - var branches = await ctx.Branches.ToListAsync(); - var mgnr = await ctx.Members.ToDictionaryAsync(m => m.MgNr.ToString(), m => m); + var branches = await ctx.FetchBranches().ToListAsync(); + var mgnr = await ctx.FetchMembers(includeNotActive: true).ToDictionaryAsync(m => m.MgNr.ToString(), m => m); var kgs = await ctx.WbKgs.ToDictionaryAsync(k => k.AtKg.Name.ToLower(), k => k.AtKg); var areaComs = await ctx.AreaCommitmentTypes.ToDictionaryAsync(t => $"{t.SortId}{t.AttrId}", t => t); @@ -408,7 +408,7 @@ namespace Elwig.Services { Mouse.OverrideCursor = Cursors.Wait; await Task.Run(async () => { try { - var b = new Billing(year); + var b = await Billing.Create(year); await b.FinishSeason(); await b.CalculateBuckets(); App.HintContextChange(); @@ -708,7 +708,7 @@ namespace Elwig.Services { await Task.Run(async () => { using var ctx = new AppDbContext(); using var tx = await ctx.Database.BeginTransactionAsync(); - var l = (await ctx.Members.FindAsync(mgnr))!; + var l = await ctx.FetchMembers(mgnr).SingleAsync(); if (deletePaymentData) { await ctx.Credits.Where(c => c.MgNr == mgnr).ExecuteDeleteAsync(); } diff --git a/Elwig/Services/PaymentVariantService.cs b/Elwig/Services/PaymentVariantService.cs index 4e17014..13150c2 100644 --- a/Elwig/Services/PaymentVariantService.cs +++ b/Elwig/Services/PaymentVariantService.cs @@ -363,21 +363,21 @@ namespace Elwig.Services { public static async Task Calculate(int year, int avnr) { await Task.Run(async () => { - var b = new BillingVariant(year, avnr); + var b = await BillingVariant.Create(year, avnr); await b.Calculate(); }); } public static async Task Commit(int year, int avnr) { await Task.Run(async () => { - var b = new BillingVariant(year, avnr); + var b = await BillingVariant.Create(year, avnr); await b.Commit(); }); } public static async Task Revert(int year, int avnr) { await Task.Run(async () => { - var b = new BillingVariant(year, avnr); + var b = await BillingVariant.Create(year, avnr); await b.Revert(); }); } diff --git a/Elwig/Services/SyncService.cs b/Elwig/Services/SyncService.cs index 3eb76ec..4bd2854 100644 --- a/Elwig/Services/SyncService.cs +++ b/Elwig/Services/SyncService.cs @@ -258,7 +258,7 @@ namespace Elwig.Services { public static async Task ChangesAvailable(AppDbContext ctx, string url, string username, string password) { try { - return await ctx.Members.AnyAsync(ChangedMembers) || await ctx.AreaCommitmentContracts.AnyAsync(ChangedAreaComContracts) || await ctx.Deliveries.AnyAsync(ChangedDeliveries) || (Utils.HasInternetConnectivity() && (await GetFilesToImport(url, username, password)).Count > 0); + return await ctx.Members.Where(ChangedMembers).AnyAsync() || await ctx.AreaCommitmentContracts.Where(ChangedAreaComContracts).AnyAsync() || await ctx.Deliveries.Where(ChangedDeliveries).AnyAsync() || (Utils.HasInternetConnectivity() && (await GetFilesToImport(url, username, password)).Count > 0); } catch { return false; } diff --git a/Elwig/Windows/AreaComAdminWindow.xaml.cs b/Elwig/Windows/AreaComAdminWindow.xaml.cs index bbe50b9..a2b3f12 100644 --- a/Elwig/Windows/AreaComAdminWindow.xaml.cs +++ b/Elwig/Windows/AreaComAdminWindow.xaml.cs @@ -74,7 +74,7 @@ namespace Elwig.Windows { } var areaComCount = await areaComQuery.CountAsync(); - var season = await ctx.Seasons.FindAsync(await ctx.Seasons.MaxAsync(s => s.Year)); + var season = await ctx.FetchSeasons().FirstOrDefaultAsync(); var stat = await AreaComService.GenerateToolTipData(areaComQuery, season?.MaxKgPerHa ?? 10_000); return (filter, contracts, areaComs, areaComCount, stat); @@ -163,7 +163,7 @@ namespace Elwig.Windows { protected override async Task OnRenewContext(AppDbContext ctx) { await base.OnRenewContext(ctx); - if (await ctx.Members.FindAsync(ViewModel.FilterMember.MgNr) is not Member m) { + if (await ctx.FetchMembers(ViewModel.FilterMember.MgNr).SingleOrDefaultAsync() is not Member m) { Close(); return; } @@ -180,12 +180,8 @@ namespace Elwig.Windows { .Include(c => c.WineAttr) .OrderBy(v => v.VtrgId) .ToListAsync()); - ControlUtils.RenewItemsSource(MemberInput, await ctx.Members - .OrderBy(m => m.Name).ThenBy(m => m.GivenName).ThenBy(m => m.MgNr) - .ToListAsync()); - var cultList = await ctx.WineCultivations - .OrderBy(c => c.Name) - .Cast().ToListAsync(); + ControlUtils.RenewItemsSource(MemberInput, await ctx.FetchMembers(includeNotActive: true).ToListAsync()); + var cultList = await ctx.FetchWineCultivations().Cast().ToListAsync(); cultList.Insert(0, new NullItem()); ControlUtils.RenewItemsSource(WineCultivationInput, cultList, null, ControlUtils.RenewSourceDefault.First); await RefreshList(); diff --git a/Elwig/Windows/BaseDataWindow.xaml.Branch.cs b/Elwig/Windows/BaseDataWindow.xaml.Branch.cs index cb1ed3b..70f688f 100644 --- a/Elwig/Windows/BaseDataWindow.xaml.Branch.cs +++ b/Elwig/Windows/BaseDataWindow.xaml.Branch.cs @@ -19,10 +19,7 @@ namespace Elwig.Windows { private bool _branchUpdate = false; private async Task BranchesInitEditing(AppDbContext ctx) { - _branchList = new(await ctx.Branches - .OrderBy(b => b.Name) - .Include(b => b.PostalDest) - .ToListAsync()); + _branchList = new(await ctx.FetchBranches().ToListAsync()); _branches = _branchList.ToDictionary(b => b.ZwstId, b => (string?)b.ZwstId); _branchIds = _branchList.ToDictionary(b => b, b => b.ZwstId); ControlUtils.RenewItemsSource(BranchList, _branchList); @@ -30,10 +27,7 @@ namespace Elwig.Windows { } private async Task BranchesFinishEditing(AppDbContext ctx) { - ControlUtils.RenewItemsSource(BranchList, await ctx.Branches - .OrderBy(b => b.Name) - .Include(b => b.PostalDest) - .ToListAsync()); + ControlUtils.RenewItemsSource(BranchList, await ctx.FetchBranches().ToListAsync()); _branchList = null; _branches = null; _branchIds = null; @@ -47,9 +41,10 @@ namespace Elwig.Windows { if (!_branchChanged || _branchList == null || _branches == null || _branchIds == null) return; - foreach (var (zwstid, _) in _branches.Where(b => b.Value == null)) { - ctx.Remove(ctx.Branches.Find(zwstid)!); - } + var tx = await ctx.Database.BeginTransactionAsync(); + var deleteZwstIds = _branches.Where(b => b.Value == null).Select(b => b.Key).ToList(); + await ctx.Branches.Where(b => deleteZwstIds.Contains(b.ZwstId)).ExecuteDeleteAsync(); + foreach (var (branch, old) in _branchIds) { branch.ZwstId = old; } @@ -61,13 +56,13 @@ namespace Elwig.Windows { foreach (var (old, zwstid) in _branches.Where(b => b.Value != null)) { await ctx.Database.ExecuteSqlAsync($"UPDATE branch SET zwstid = {zwstid} WHERE zwstid = {old}"); } - await ctx.SaveChangesAsync(); foreach (var branch in _branchList.Where(b => !_branchIds.ContainsKey(b))) { if (branch.ZwstId == null) continue; ctx.Add(branch); } await ctx.SaveChangesAsync(); + await tx.CommitAsync(); } private void BranchList_SelectionChanged(object? sender, SelectionChangedEventArgs? evt) { diff --git a/Elwig/Windows/BaseDataWindow.xaml.Mod.cs b/Elwig/Windows/BaseDataWindow.xaml.Mod.cs index 321e117..431814e 100644 --- a/Elwig/Windows/BaseDataWindow.xaml.Mod.cs +++ b/Elwig/Windows/BaseDataWindow.xaml.Mod.cs @@ -22,10 +22,7 @@ namespace Elwig.Windows { private async Task ModifiersInitEditing(AppDbContext ctx) { SeasonList.IsEnabled = false; var year = (SeasonList.SelectedItem as Season)?.Year; - _modList = new(await ctx.Modifiers - .Where(m => m.Year == year) - .OrderBy(m => m.Ordering) - .ToListAsync()); + _modList = new(await ctx.FetchModifiers(year).ToListAsync()); _mods = _modList.ToDictionary(m => m.ModId, m => (string?)m.ModId); _modIds = _modList.ToDictionary(m => m, m => m.ModId); ControlUtils.RenewItemsSource(SeasonModifierList, _modList); @@ -34,10 +31,7 @@ namespace Elwig.Windows { private async Task ModifiersFinishEditing(AppDbContext ctx) { var year = (SeasonList.SelectedItem as Season)?.Year; - ControlUtils.RenewItemsSource(SeasonModifierList, await ctx.Modifiers - .Where(m => m.Year == year) - .OrderBy(m => m.Ordering) - .ToListAsync()); + ControlUtils.RenewItemsSource(SeasonModifierList, await ctx.FetchModifiers(year).ToListAsync()); _modList = null; _mods = null; _modIds = null; diff --git a/Elwig/Windows/BaseDataWindow.xaml.Season.cs b/Elwig/Windows/BaseDataWindow.xaml.Season.cs index 718a8b4..f326fe8 100644 --- a/Elwig/Windows/BaseDataWindow.xaml.Season.cs +++ b/Elwig/Windows/BaseDataWindow.xaml.Season.cs @@ -19,20 +19,14 @@ namespace Elwig.Windows { private async Task SeasonsInitEditing(AppDbContext ctx) { SeasonAddButton.IsEnabled = false; SeasonRemoveButton.IsEnabled = false; - ControlUtils.RenewItemsSource(SeasonList, await ctx.Seasons - .OrderByDescending(s => s.Year) - .Include(s => s.Modifiers) - .ToListAsync()); + ControlUtils.RenewItemsSource(SeasonList, await ctx.FetchSeasons(includeModifiers: true).ToListAsync()); SeasonList_SelectionChanged(null, null); } private async Task SeasonsFinishEditing(AppDbContext ctx) { SeasonAddButton.IsEnabled = true; SeasonRemoveButton.IsEnabled = true; - ControlUtils.RenewItemsSource(SeasonList, await ctx.Seasons - .OrderByDescending(s => s.Year) - .Include(s => s.Modifiers) - .ToListAsync()); + ControlUtils.RenewItemsSource(SeasonList, await ctx.FetchSeasons(includeModifiers: true).ToListAsync()); _seasonChanged = false; } diff --git a/Elwig/Windows/BaseDataWindow.xaml.WineAttr.cs b/Elwig/Windows/BaseDataWindow.xaml.WineAttr.cs index 0baa244..2937375 100644 --- a/Elwig/Windows/BaseDataWindow.xaml.WineAttr.cs +++ b/Elwig/Windows/BaseDataWindow.xaml.WineAttr.cs @@ -19,9 +19,7 @@ namespace Elwig.Windows { private bool _attrUpdate = false; private async Task WineAttributesInitEditing(AppDbContext ctx) { - _attrList = new(await ctx.WineAttributes - .OrderBy(a => a.Name) - .ToListAsync()); + _attrList = new(await ctx.FetchWineAttributes().ToListAsync()); _attrs = _attrList.ToDictionary(a => a.AttrId, a => (string?)a.AttrId); _attrIds = _attrList.ToDictionary(a => a, a => a.AttrId); ControlUtils.RenewItemsSource(WineAttributeList, _attrList); @@ -29,9 +27,7 @@ namespace Elwig.Windows { } private async Task WineAttributesFinishEditing(AppDbContext ctx) { - ControlUtils.RenewItemsSource(WineAttributeList, await ctx.WineAttributes - .OrderBy(a => a.Name) - .ToListAsync()); + ControlUtils.RenewItemsSource(WineAttributeList, await ctx.FetchWineAttributes().ToListAsync()); _attrList = null; _attrs = null; _attrIds = null; @@ -45,9 +41,9 @@ namespace Elwig.Windows { if (!_attrChanged || _attrList == null || _attrs == null || _attrIds == null) return; - foreach (var (attrid, _) in _attrs.Where(a => a.Value == null)) { - ctx.Remove(ctx.WineAttributes.Find(attrid)!); - } + using var tx = await ctx.Database.BeginTransactionAsync(); + var deleteAttrIds = _attrs.Where(a => a.Value == null).Select(a => a.Key).ToList(); + await ctx.WineAttributes.Where(a => deleteAttrIds.Contains(a.AttrId)).ExecuteDeleteAsync(); foreach (var (attr, old) in _attrIds) { attr.AttrId = old; } @@ -61,13 +57,13 @@ namespace Elwig.Windows { await ctx.Database.ExecuteSqlAsync($"UPDATE area_commitment_type SET vtrgid = (sortid || COALESCE(attrid, '') || COALESCE(disc, '')) WHERE attrid = {attrid}"); await ctx.Database.ExecuteSqlRawAsync($"UPDATE payment_variant SET data = REPLACE(REPLACE(data, '/{old}\"', '/{attrid}\"'), '/{old}-', '/{attrid}-')"); } - await ctx.SaveChangesAsync(); foreach (var attr in _attrList.Where(a => !_attrIds.ContainsKey(a))) { if (attr.AttrId == null) continue; ctx.Add(attr); } await ctx.SaveChangesAsync(); + await tx.CommitAsync(); } private void WineAttributeList_SelectionChanged(object? sender, SelectionChangedEventArgs? evt) { diff --git a/Elwig/Windows/BaseDataWindow.xaml.WineCult.cs b/Elwig/Windows/BaseDataWindow.xaml.WineCult.cs index 33d999e..54a4923 100644 --- a/Elwig/Windows/BaseDataWindow.xaml.WineCult.cs +++ b/Elwig/Windows/BaseDataWindow.xaml.WineCult.cs @@ -19,9 +19,7 @@ namespace Elwig.Windows { private bool _cultUpdate = false; private async Task WineCultivationsInitEditing(AppDbContext ctx) { - _cultList = new(await ctx.WineCultivations - .OrderBy(c => c.Name) - .ToListAsync()); + _cultList = new(await ctx.FetchWineCultivations().ToListAsync()); _cults = _cultList.ToDictionary(c => c.CultId, c => (string?)c.CultId); _cultIds = _cultList.ToDictionary(c => c, c => c.CultId); ControlUtils.RenewItemsSource(WineCultivationList, _cultList); @@ -29,9 +27,7 @@ namespace Elwig.Windows { } private async Task WineCultivationsFinishEditing(AppDbContext ctx) { - ControlUtils.RenewItemsSource(WineCultivationList, await ctx.WineCultivations - .OrderBy(c => c.Name) - .ToListAsync()); + ControlUtils.RenewItemsSource(WineCultivationList, await ctx.FetchWineCultivations().ToListAsync()); _cultList = null; _cults = null; _cultIds = null; @@ -45,9 +41,9 @@ namespace Elwig.Windows { if (!_cultChanged || _cultList == null || _cults == null || _cultIds == null) return; - foreach (var (cultid, _) in _cults.Where(c => c.Value == null)) { - ctx.Remove(ctx.WineCultivations.Find(cultid)!); - } + using var tx = await ctx.Database.BeginTransactionAsync(); + var deleteCultIds = _cults.Where(c => c.Value == null).Select(c => c.Key).ToList(); + await ctx.WineCultivations.Where(c => deleteCultIds.Contains(c.CultId)).ExecuteDeleteAsync(); foreach (var (cult, old) in _cultIds) { cult.CultId = old; } @@ -60,13 +56,13 @@ namespace Elwig.Windows { await ctx.Database.ExecuteSqlAsync($"UPDATE wine_cultivation SET cultid = {cultid} WHERE cultid = {old}"); await ctx.Database.ExecuteSqlRawAsync($"UPDATE payment_variant SET data = REPLACE(data, '-{old}\"', '-{cultid}\"')"); } - await ctx.SaveChangesAsync(); foreach (var cult in _cultList.Where(c => !_cultIds.ContainsKey(c))) { if (cult.CultId == null) continue; ctx.Add(cult); } await ctx.SaveChangesAsync(); + await tx.CommitAsync(); } private void WineCultivationList_SelectionChanged(object? sender, SelectionChangedEventArgs? evt) { diff --git a/Elwig/Windows/BaseDataWindow.xaml.cs b/Elwig/Windows/BaseDataWindow.xaml.cs index 679b35b..390be7d 100644 --- a/Elwig/Windows/BaseDataWindow.xaml.cs +++ b/Elwig/Windows/BaseDataWindow.xaml.cs @@ -159,35 +159,20 @@ namespace Elwig.Windows { protected override async Task OnRenewContext(AppDbContext ctx) { await base.OnRenewContext(ctx); - FillInputs(App.Client, await ctx.Seasons.FindAsync(Utils.CurrentLastSeason)); - ControlUtils.RenewItemsSource(SeasonList, await ctx.Seasons - .OrderByDescending(s => s.Year) - .Include(s => s.Modifiers) - .ToListAsync(), null, ControlUtils.RenewSourceDefault.First); + FillInputs(App.Client, await ctx.FetchSeasons(Utils.CurrentLastSeason).SingleOrDefaultAsync()); + ControlUtils.RenewItemsSource(SeasonList, await ctx.FetchSeasons(includeModifiers: true).ToListAsync(), null, ControlUtils.RenewSourceDefault.First); var year = (SeasonList.SelectedItem as Season)?.Year; - ControlUtils.RenewItemsSource(BranchList, await ctx.Branches - .OrderBy(b => b.Name) - .Include(b => b.PostalDest) - .ToListAsync(), null, ControlUtils.RenewSourceDefault.First); - ControlUtils.RenewItemsSource(WineAttributeList, await ctx.WineAttributes - .OrderBy(a => a.Name) - .ToListAsync(), null, ControlUtils.RenewSourceDefault.First); - ControlUtils.RenewItemsSource(AreaCommitmentTypeWineVariantInput, await ctx.WineVarieties - .OrderBy(s => s.Name) - .ToListAsync()); - var attrList = await ctx.WineAttributes.OrderBy(a => a.Name).Cast().ToListAsync(); + ControlUtils.RenewItemsSource(BranchList, await ctx.FetchBranches().ToListAsync(), null, ControlUtils.RenewSourceDefault.First); + ControlUtils.RenewItemsSource(WineAttributeList, await ctx.FetchWineAttributes().ToListAsync(), null, ControlUtils.RenewSourceDefault.First); + ControlUtils.RenewItemsSource(AreaCommitmentTypeWineVariantInput, await ctx.FetchWineVarieties().ToListAsync()); + var attrList = await ctx.FetchWineAttributes().Cast().ToListAsync(); attrList.Insert(0, new NullItem("")); ControlUtils.RenewItemsSource(AreaCommitmentTypeWineAttributeInput, attrList); ControlUtils.RenewItemsSource(AreaCommitmentTypeList, await ctx.AreaCommitmentTypes .OrderBy(t => t.VtrgId) .ToListAsync(), null, ControlUtils.RenewSourceDefault.First); - ControlUtils.RenewItemsSource(WineCultivationList, await ctx.WineCultivations - .OrderBy(c => c.Name) - .ToListAsync(), null, ControlUtils.RenewSourceDefault.First); - ControlUtils.RenewItemsSource(SeasonModifierList, await ctx.Modifiers - .Where(m => m.Year == year) - .OrderBy(m => m.Ordering) - .ToListAsync(), null, ControlUtils.RenewSourceDefault.First); + ControlUtils.RenewItemsSource(WineCultivationList, await ctx.FetchWineCultivations().ToListAsync(), null, ControlUtils.RenewSourceDefault.First); + ControlUtils.RenewItemsSource(SeasonModifierList, await ctx.FetchModifiers(year).ToListAsync(), null, ControlUtils.RenewSourceDefault.First); } protected override void UpdateButtons() { @@ -283,7 +268,7 @@ namespace Elwig.Windows { using var ctx = new AppDbContext(); ClearInputStates(); - FillInputs(App.Client, await ctx.Seasons.FindAsync(Utils.CurrentLastSeason)); + FillInputs(App.Client, await ctx.FetchSeasons(Utils.CurrentLastSeason).SingleOrDefaultAsync()); LockInputs(); } @@ -303,7 +288,7 @@ namespace Elwig.Windows { using var ctx = new AppDbContext(); ClearInputStates(); - FillInputs(App.Client, await ctx.Seasons.FindAsync(Utils.CurrentLastSeason)); + FillInputs(App.Client, await ctx.FetchSeasons(Utils.CurrentLastSeason).SingleOrDefaultAsync()); UpdateButtons(); } @@ -339,7 +324,7 @@ namespace Elwig.Windows { using (var ctx = new AppDbContext()) { ClearInputStates(); - FillInputs(App.Client, await ctx.Seasons.FindAsync(Utils.CurrentLastSeason)); + FillInputs(App.Client, await ctx.FetchSeasons(Utils.CurrentLastSeason).SingleOrDefaultAsync()); LockInputs(); } @@ -427,7 +412,7 @@ namespace Elwig.Windows { private async Task UpdateParameters(int year) { try { using var ctx = new AppDbContext(); - if (await ctx.Seasons.FindAsync(year) is not Season s) + if (await ctx.FetchSeasons(year).SingleOrDefaultAsync() is not Season s) return; s.Billing_AllowAttrsIntoLower = ParameterAllowAttrIntoLowerInput.IsChecked ?? false; diff --git a/Elwig/Windows/ChartWindow.xaml.cs b/Elwig/Windows/ChartWindow.xaml.cs index 2c3619d..98b852a 100644 --- a/Elwig/Windows/ChartWindow.xaml.cs +++ b/Elwig/Windows/ChartWindow.xaml.cs @@ -98,17 +98,17 @@ namespace Elwig.Windows { private async Task RefreshGraphList(AppDbContext ctx) { PaymentVar = await ctx.PaymentVariants.FindAsync(Year, AvNr) ?? throw new ArgumentException("PaymentVar not found"); - Season = await ctx.Seasons.FindAsync(Year) ?? throw new ArgumentException("Season not found"); + Season = await ctx.FetchSeasons(Year).SingleOrDefaultAsync() ?? throw new ArgumentException("Season not found"); CurrencySymbol = Season.Currency.Symbol ?? Season.Currency.Code; PriceInput.Unit = $"{CurrencySymbol}/kg"; GebundenFlatBonus.Unit = $"{CurrencySymbol}/kg"; try { - var data = EditBillingData.FromJson(PaymentVar.Data, Utils.GetVaributes(ctx, Year)); - var paymentEntries = data.GetPaymentGraphEntries(ctx, Season); + var data = EditBillingData.FromJson(PaymentVar.Data, await Utils.GetVaributes(ctx, Year)); + var paymentEntries = await data.GetPaymentGraphEntries(ctx, Season); GraphEntries = [ ..paymentEntries, - ..data.GetQualityGraphEntries(ctx, Season, paymentEntries.Any() ? paymentEntries.Max(e => e.Id) : 0) + ..await data.GetQualityGraphEntries(ctx, Season, paymentEntries.Any() ? paymentEntries.Max(e => e.Id) : 0) ]; } catch (KeyNotFoundException ex) { var key = ex.Message.Split('\'')[1].Split('\'')[0]; @@ -123,7 +123,7 @@ namespace Elwig.Windows { MessageBox.Show("Fehler beim Laden der Auszahlungsvariante:\n\n" + ex.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); } - Vaributes = Utils.GetVaributeList(ctx, Year); + Vaributes = await Utils.GetVaributeList(ctx, Year); GraphEntries.ForEach(e => { e.Vaributes.ForEach(v => { var found = Vaributes.Find(a => a.Variety?.SortId == v.Variety?.SortId && a.Attribute?.AttrId == v.Attribute?.AttrId && a.Cultivation?.CultId == v.Cultivation?.CultId); @@ -642,7 +642,7 @@ namespace Elwig.Windows { await Task.Run(async () => { using var ctx = new AppDbContext(); var origData = BillingData.FromJson(PaymentVar.Data); - var data = BillingData.FromGraphEntries(GraphEntries, origData, Utils.GetVaributes(ctx, Year), + var data = BillingData.FromGraphEntries(GraphEntries, origData, await Utils.GetVaributes(ctx, Year), AllVaributesAssigned, AllVaributesAssignedAbgew); PaymentVar.Data = data.ToJsonString(); @@ -660,7 +660,7 @@ namespace Elwig.Windows { try { await Task.Run(async () => { - var b = new BillingVariant(PaymentVar.Year, PaymentVar.AvNr); + var b = await BillingVariant.Create(PaymentVar.Year, PaymentVar.AvNr); await b.Calculate(false); }); } catch (KeyNotFoundException exc) { diff --git a/Elwig/Windows/DeliveryAdminWindow.xaml.cs b/Elwig/Windows/DeliveryAdminWindow.xaml.cs index f98379c..8f7aa4e 100644 --- a/Elwig/Windows/DeliveryAdminWindow.xaml.cs +++ b/Elwig/Windows/DeliveryAdminWindow.xaml.cs @@ -135,7 +135,7 @@ namespace Elwig.Windows { LockInputs(); if (ViewModel.IsReceipt) { NewDeliveryButton_Click(null, null); - if (await ctx.Seasons.FindAsync(Utils.CurrentYear) == null) { + if (await ctx.FetchSeasons(Utils.CurrentYear).SingleOrDefaultAsync() == null) { MessageBox.Show("Die Saison für das aktuelle Jahr wurde noch nicht erstellt. Neue Lieferungen können nicht abgespeichert werden.\n\n(Stammdaten -> Saisons -> Neu anlegen...)", "Saison noch nicht erstellt", MessageBoxButton.OK, MessageBoxImage.Warning); } @@ -430,7 +430,6 @@ namespace Elwig.Windows { var deliveries = await deliveryQuery .Include(d => d.Parts).ThenInclude(p => p.PartModifiers).ThenInclude(m => m.Modifier) .Include(d => d.Parts).ThenInclude(p => p.Variety) - .Include(d => d.Member.EmailAddresses) .IgnoreAutoIncludes() .AsSplitQuery() .ToListAsync(); @@ -497,7 +496,7 @@ namespace Elwig.Windows { int year = 0; Menu_Bki_SaveList.Items.Clear(); - foreach (var s in await ctx.Seasons.OrderByDescending(s => s.Year).IgnoreAutoIncludes().ToListAsync()) { + foreach (var s in await ctx.FetchSeasons().ToListAsync()) { if (s.Year > year) year = s.Year; var i = new MenuItem { Header = $"Saison {s.Year}", @@ -506,6 +505,9 @@ namespace Elwig.Windows { Menu_Bki_SaveList.Items.Add(i); } + var attributes = await ctx.FetchWineAttributes(!IsCreating).ToListAsync(); + var modifiers = await ctx.FetchModifiers(year, !IsCreating).ToListAsync(); + var font = new FontFamily("Segoe MDL2 Assets"); Menu_BulkAction_SetAttribute.Items.Clear(); var noAttr = new MenuItem { @@ -514,7 +516,7 @@ namespace Elwig.Windows { }; noAttr.Click += Menu_BulkAction_SetAttribute_Click; Menu_BulkAction_SetAttribute.Items.Add(noAttr); - foreach (var attr in await ctx.WineAttributes.OrderBy(a => a.AttrId).IgnoreAutoIncludes().ToListAsync()) { + foreach (var attr in attributes) { var i = new MenuItem { Header = attr.Name, }; @@ -524,7 +526,7 @@ namespace Elwig.Windows { Menu_BulkAction_AddModifier.Items.Clear(); Menu_BulkAction_RemoveModifier.Items.Clear(); - foreach (var mod in await ctx.Modifiers.Where(m => m.Year == year).OrderBy(m => m.ModId).IgnoreAutoIncludes().ToListAsync()) { + foreach (var mod in modifiers) { var i1 = new MenuItem { Header = mod.Name, }; @@ -538,27 +540,21 @@ namespace Elwig.Windows { } await RefreshList(); + var d = DeliveryList.SelectedItem as Delivery; - var y = d?.Year ?? ViewModel.FilterSeason; - ControlUtils.RenewItemsSource(MemberInput, await ctx.Members - .Where(m => m.IsActive || !IsCreating) - .OrderBy(m => m.Name) - .ThenBy(m => m.GivenName) - .ToListAsync()); - ControlUtils.RenewItemsSource(BranchInput, await ctx.Branches.OrderBy(b => b.Name).ToListAsync()); - ControlUtils.RenewItemsSource(WineVarietyInput, await ctx.WineVarieties.OrderBy(v => v.Name).ToListAsync()); - var attrList = await ctx.WineAttributes.Where(a => !IsCreating || a.IsActive).OrderBy(a => a.Name).Cast().ToListAsync(); + var y = d?.Year ?? ViewModel.FilterSeason ?? Utils.CurrentYear; + ControlUtils.RenewItemsSource(MemberInput, await ctx.FetchMembers(includeNotActive: !IsCreating, includeContactInfo: true).ToListAsync()); + ControlUtils.RenewItemsSource(BranchInput, await ctx.FetchBranches().ToListAsync()); + ControlUtils.RenewItemsSource(WineVarietyInput, await ctx.FetchWineVarieties().ToListAsync()); + var attrList = attributes.Cast().ToList(); attrList.Insert(0, new NullItem("")); ControlUtils.RenewItemsSource(AttributeInput, attrList, null, ControlUtils.RenewSourceDefault.First); - var cultList = await ctx.WineCultivations.OrderBy(a => a.Name).Cast().ToListAsync(); + var cultList = await ctx.FetchWineCultivations().Cast().ToListAsync(); cultList.Insert(0, new NullItem("")); ControlUtils.RenewItemsSource(CultivationInput, cultList, null, ControlUtils.RenewSourceDefault.First); - WineQualityLevels = await ctx.WineQualityLevels.ToListAsync(); + WineQualityLevels = await ctx.FetchWineQualityLevels().ToListAsync(); ControlUtils.RenewItemsSource(WineQualityLevelInput, WineQualityLevels); - ControlUtils.RenewItemsSource(ModifiersInput, await ctx.Modifiers - .Where(m => m.Year == y && (!IsCreating || m.IsActive)) - .OrderBy(m => m.Ordering) - .ToListAsync()); + ControlUtils.RenewItemsSource(ModifiersInput, modifiers); var origins = await ctx.WineOrigins.ToListAsync(); origins.ForEach(o => { origins.FirstOrDefault(p => p.HkId == o.ParentHkId)?.Children.Add(o); }); origins = [.. origins.OrderByDescending(o => o.SortKey).ThenBy(o => o.HkId)]; @@ -587,16 +583,10 @@ namespace Elwig.Windows { private async Task RefreshDeliveryParts() { using var ctx = new AppDbContext(); if (DeliveryList.SelectedItem is Delivery d) { - ControlUtils.RenewItemsSource(ModifiersInput, await ctx.Modifiers - .Where(m => m.Year == d.Year && (!IsCreating || m.IsActive)) - .OrderBy(m => m.Ordering) - .ToListAsync()); + ControlUtils.RenewItemsSource(ModifiersInput, await ctx.FetchModifiers(d.Year, !IsCreating).ToListAsync()); ControlUtils.RenewItemsSource(DeliveryPartList, d.Parts, DeliveryPartList_SelectionChanged, ControlUtils.RenewSourceDefault.First); } else { - ControlUtils.RenewItemsSource(ModifiersInput, await ctx.Modifiers - .Where(m => m.Year == ViewModel.FilterSeason && (!IsCreating || m.IsActive)) - .OrderBy(m => m.Ordering) - .ToListAsync()); + ControlUtils.RenewItemsSource(ModifiersInput, await ctx.FetchModifiers(ViewModel.FilterSeason, !IsCreating).ToListAsync()); DeliveryPartList.ItemsSource = null; } } @@ -726,7 +716,7 @@ namespace Elwig.Windows { Menu_DeliveryNote_Show.IsEnabled = !IsEditing && !IsCreating; Menu_DeliveryNote_SavePdf.IsEnabled = !IsEditing && !IsCreating; Menu_DeliveryNote_Print.IsEnabled = !IsEditing && !IsCreating; - Menu_DeliveryNote_Email.IsEnabled = !IsEditing && !IsCreating && App.Config.Smtp != null && d.Member.EmailAddresses.Count > 0; + Menu_DeliveryNote_Email.IsEnabled = !IsEditing && !IsCreating && App.Config.Smtp != null && ViewModel.Member?.EmailAddresses.Count > 0; Menu_Export_ExportSelected.IsEnabled = !IsEditing && !IsCreating; Menu_Export_UploadSelected.IsEnabled = !IsEditing && !IsCreating && App.Config.SyncUrl != null; } else { @@ -884,14 +874,10 @@ namespace Elwig.Windows { } using var ctx = new AppDbContext(); - var attrList = await ctx.WineAttributes.OrderBy(a => a.Name).Cast().ToListAsync(); + var attrList = await ctx.FetchWineAttributes().Cast().ToListAsync(); attrList.Insert(0, new NullItem("")); ControlUtils.RenewItemsSource(AttributeInput, attrList, null, ControlUtils.RenewSourceDefault.First); - ControlUtils.RenewItemsSource(MemberInput, await ctx.Members - .Where(m => m.IsActive || !ViewModel.IsReceipt) - .OrderBy(m => m.Name) - .ThenBy(m => m.GivenName) - .ToListAsync()); + ControlUtils.RenewItemsSource(MemberInput, await ctx.FetchMembers(includeNotActive: !ViewModel.IsReceipt, includeContactInfo: true).ToListAsync()); if (DeliveryList.SelectedItem is not Delivery d) { // switch away from creating mode IsCreating = false; @@ -923,18 +909,11 @@ namespace Elwig.Windows { ViewModel.FilterTodayOnly = true; ViewModel.SearchQuery = ""; using var ctx = new AppDbContext(); - var attrList = await ctx.WineAttributes.Where(a => a.IsActive).OrderBy(a => a.Name).Cast().ToListAsync(); + var attrList = await ctx.FetchWineAttributes(false).Cast().ToListAsync(); attrList.Insert(0, new NullItem("")); ControlUtils.RenewItemsSource(AttributeInput, attrList, null, ControlUtils.RenewSourceDefault.First); - ControlUtils.RenewItemsSource(ModifiersInput, await ctx.Modifiers - .Where(m => m.Year == ViewModel.FilterSeason && m.IsActive) - .OrderBy(m => m.Ordering) - .ToListAsync()); - ControlUtils.RenewItemsSource(MemberInput, await ctx.Members - .Where(m => m.IsActive || !ViewModel.IsReceipt) - .OrderBy(m => m.Name) - .ThenBy(m => m.GivenName) - .ToListAsync()); + ControlUtils.RenewItemsSource(ModifiersInput, await ctx.FetchModifiers(ViewModel.FilterSeason, false).ToListAsync()); + ControlUtils.RenewItemsSource(MemberInput, await ctx.FetchMembers(includeNotActive: !ViewModel.IsReceipt, includeContactInfo: true).ToListAsync()); IsCreating = true; DeliveryList.IsEnabled = false; DeliveryPartList.IsEnabled = false; diff --git a/Elwig/Windows/DeliveryAncmtAdminWindow.xaml.cs b/Elwig/Windows/DeliveryAncmtAdminWindow.xaml.cs index 70f1635..321f32e 100644 --- a/Elwig/Windows/DeliveryAncmtAdminWindow.xaml.cs +++ b/Elwig/Windows/DeliveryAncmtAdminWindow.xaml.cs @@ -181,13 +181,8 @@ namespace Elwig.Windows { protected override async Task OnRenewContext(AppDbContext ctx) { await base.OnRenewContext(ctx); - ControlUtils.RenewItemsSource(MemberInput, await ctx.Members - .Where(m => m.IsActive || !IsCreating) - .OrderBy(m => m.Name) - .ThenBy(m => m.GivenName) - .ThenBy(m => m.MgNr) - .ToListAsync()); - ControlUtils.RenewItemsSource(WineVarietyInput, await ctx.WineVarieties.OrderBy(v => v.Name).ToListAsync()); + ControlUtils.RenewItemsSource(MemberInput, await ctx.FetchMembers(includeNotActive: !IsCreating).ToListAsync()); + ControlUtils.RenewItemsSource(WineVarietyInput, await ctx.FetchWineVarieties().ToListAsync()); await RefreshDeliveryScheduleList(); await RefreshList(); @@ -276,12 +271,7 @@ namespace Elwig.Windows { ViewModel.SelectedDeliveryAncmt = null; using var ctx = new AppDbContext(); - ControlUtils.RenewItemsSource(MemberInput, await ctx.Members - .Where(m => m.IsActive || !IsCreating) - .OrderBy(m => m.Name) - .ThenBy(m => m.GivenName) - .ThenBy(m => m.MgNr) - .ToListAsync()); + ControlUtils.RenewItemsSource(MemberInput, await ctx.FetchMembers(includeNotActive: !IsCreating).ToListAsync()); HideNewEditDeleteButtons(); ShowSaveResetCancelButtons(); @@ -403,12 +393,7 @@ namespace Elwig.Windows { DeliveryAncmtList.IsEnabled = true; using var ctx = new AppDbContext(); - ControlUtils.RenewItemsSource(MemberInput, await ctx.Members - .Where(m => m.IsActive || !IsCreating) - .OrderBy(m => m.Name) - .ThenBy(m => m.GivenName) - .ThenBy(m => m.MgNr) - .ToListAsync()); + ControlUtils.RenewItemsSource(MemberInput, await ctx.FetchMembers(includeNotActive: !IsCreating).ToListAsync()); HideSaveResetCancelButtons(); ShowNewEditDeleteButtons(); diff --git a/Elwig/Windows/DeliveryScheduleAdminWindow.xaml.cs b/Elwig/Windows/DeliveryScheduleAdminWindow.xaml.cs index bfe299d..110d064 100644 --- a/Elwig/Windows/DeliveryScheduleAdminWindow.xaml.cs +++ b/Elwig/Windows/DeliveryScheduleAdminWindow.xaml.cs @@ -105,14 +105,14 @@ namespace Elwig.Windows { protected override async Task OnRenewContext(AppDbContext ctx) { await base.OnRenewContext(ctx); - ControlUtils.RenewItemsSource(BranchInput, await ctx.Branches.OrderBy(b => b.Name).ToListAsync()); - var varieties = await ctx.WineVarieties.OrderBy(v => v.Name).ToListAsync(); + ControlUtils.RenewItemsSource(BranchInput, await ctx.FetchBranches().ToListAsync()); + var varieties = await ctx.FetchWineVarieties().ToListAsync(); ControlUtils.RenewItemsSource(MainWineVarietiesInput, varieties); ControlUtils.RenewItemsSource(OtherWineVarietiesInput, varieties); - var attrList = await ctx.WineAttributes.OrderBy(a => a.Name).Cast().ToListAsync(); + var attrList = await ctx.FetchWineAttributes().Cast().ToListAsync(); attrList.Insert(0, new NullItem("- Keine Angabe -")); ControlUtils.RenewItemsSource(AttributeInput, attrList, null, ControlUtils.RenewSourceDefault.First); - var cultList = await ctx.WineCultivations.OrderBy(a => a.Name).Cast().ToListAsync(); + var cultList = await ctx.FetchWineCultivations().Cast().ToListAsync(); cultList.Insert(0, new NullItem("- Kein Angabe -")); ControlUtils.RenewItemsSource(CultivationInput, cultList, null, ControlUtils.RenewSourceDefault.First); diff --git a/Elwig/Windows/MailWindow.xaml.cs b/Elwig/Windows/MailWindow.xaml.cs index 91534ad..6e1cb58 100644 --- a/Elwig/Windows/MailWindow.xaml.cs +++ b/Elwig/Windows/MailWindow.xaml.cs @@ -107,7 +107,7 @@ namespace Elwig.Windows { public MailWindow(int? year = null) { InitializeComponent(); using (var ctx = new AppDbContext()) { - Year = year ?? ctx.Seasons.OrderBy(s => s.Year).LastOrDefault()?.Year ?? Utils.Today.Year; + Year = year ?? ctx.Seasons.OrderByDescending(s => s.Year).FirstOrDefault()?.Year ?? Utils.Today.Year; Title = $"Rundschreiben - Lese {Year} - Elwig"; } @@ -155,7 +155,7 @@ namespace Elwig.Windows { } protected override async Task OnRenewContext(AppDbContext ctx) { - var season = await ctx.Seasons.Include(s => s.PaymentVariants).SingleAsync(s => s.Year == Year); + var season = await ctx.Seasons.Include(s => s.PaymentVariants).Where(s => s.Year == Year).SingleAsync(); var l = new List { MemberDataSheet.Name }; @@ -165,10 +165,7 @@ namespace Elwig.Windows { } AvaiableDocumentsList.ItemsSource = l; - ControlUtils.RenewItemsSource(MemberBranchInput, await ctx.Branches - .Where(b => b.Members.Count != 0) - .OrderBy(b => b.Name) - .ToListAsync(), MemberInput_SelectionChanged); + ControlUtils.RenewItemsSource(MemberBranchInput, await ctx.FetchBranches(includeWithoutMembers: false).ToListAsync(), MemberInput_SelectionChanged); if (MemberBranchInput.SelectedItems.Count == 0) { MemberBranchInput.SelectionChanged -= MemberInput_SelectionChanged; MemberBranchInput.SelectAll(); @@ -368,7 +365,7 @@ namespace Elwig.Windows { 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)!; + var pv = await ctx.PaymentVariants.Where(v => v.Year == Year && v.Name == name).SingleAsync(); SelectedDocs.Add(new(DocType.CreditNote, s, (pv.Year, pv.AvNr))); RecipientsCreditMembersInput.IsChecked = true; } @@ -715,7 +712,7 @@ namespace Elwig.Windows { foreach (var doc in docs) { if (doc.Type == DocType.DeliveryConfirmation) { var year = (int)doc.Details!; - var b = new Billing(year); + var b = await Billing.Create(year); await b.FinishSeason(); await b.CalculateBuckets(); App.HintContextChange(); @@ -997,7 +994,7 @@ namespace Elwig.Windows { return; var name = s.Split(" – ")[^1]; using var ctx = new AppDbContext(); - var pv = ctx.PaymentVariants.Single(v => v.Year == Year && v.Name == name)!; + var pv = ctx.PaymentVariants.Where(v => v.Year == Year && v.Name == name).Single(); SelectedDocs.Add(new(DocType.CreditNote, s, (pv.Year, pv.AvNr))); SelectedDocumentsList.SelectedIndex = SelectedDocs.Count - 1; RecipientsCreditMembersInput.IsChecked = true; diff --git a/Elwig/Windows/MainWindow.xaml.cs b/Elwig/Windows/MainWindow.xaml.cs index 6d6cd3e..0cf7e89 100644 --- a/Elwig/Windows/MainWindow.xaml.cs +++ b/Elwig/Windows/MainWindow.xaml.cs @@ -404,7 +404,7 @@ namespace Elwig.Windows { private async void SeasonInput_TextChanged(object? sender, TextChangedEventArgs? evt) { using var ctx = new AppDbContext(); var year = SeasonInput.Value; - var s0 = await ctx.Seasons.FindAsync(year); + var s0 = await ctx.FetchSeasons(year).SingleOrDefaultAsync(); var valid = (s0 != null); DeliveryConfirmationButton.IsEnabled = valid; PaymentButton.IsEnabled = valid; @@ -468,7 +468,7 @@ namespace Elwig.Windows { Mouse.OverrideCursor = Cursors.Wait; await Task.Run(async () => { try { - var b = new Billing(year); + var b = await Billing.Create(year); await b.FinishSeason(); await b.CalculateBuckets(); App.HintContextChange(); @@ -501,7 +501,7 @@ namespace Elwig.Windows { Mouse.OverrideCursor = Cursors.Wait; await Task.Run(async () => { try { - var b = new Billing(year); + var b = await Billing.Create(year); await b.FinishSeason(); await b.CalculateBuckets(); App.HintContextChange(); @@ -510,7 +510,7 @@ namespace Elwig.Windows { using var ods = new OdsFile(d.FileName); var tblTotal = await WeightBreakdownData.ForSeason(ctx.WeightBreakDownRows, year); await ods.AddTable(tblTotal); - foreach (var branch in await ctx.Branches.OrderBy(b => b.Name).ToListAsync()) { + foreach (var branch in await ctx.FetchBranches().ToListAsync()) { var tbl = await WeightBreakdownData.ForSeason(ctx.WeightBreakDownRows, year, branch); await ods.AddTable(tbl); } @@ -536,7 +536,7 @@ namespace Elwig.Windows { Mouse.OverrideCursor = Cursors.Wait; await Task.Run(async () => { try { - var b = new Billing(year); + var b = await Billing.Create(year); await b.FinishSeason(); await b.CalculateBuckets(); App.HintContextChange(); @@ -567,7 +567,7 @@ namespace Elwig.Windows { Mouse.OverrideCursor = Cursors.Wait; await Task.Run(async () => { try { - var b = new Billing(year); + var b = await Billing.Create(year); await b.FinishSeason(); await b.CalculateBuckets(); App.HintContextChange(); diff --git a/Elwig/Windows/MemberAdminWindow.xaml.cs b/Elwig/Windows/MemberAdminWindow.xaml.cs index 9aef452..53e45dc 100644 --- a/Elwig/Windows/MemberAdminWindow.xaml.cs +++ b/Elwig/Windows/MemberAdminWindow.xaml.cs @@ -190,7 +190,7 @@ namespace Elwig.Windows { protected override async Task OnRenewContext(AppDbContext ctx) { await base.OnRenewContext(ctx); - ControlUtils.RenewItemsSource(BranchInput, await ctx.Branches.OrderBy(b => b.Name).ToListAsync()); + ControlUtils.RenewItemsSource(BranchInput, await ctx.FetchBranches().ToListAsync()); ControlUtils.RenewItemsSource(DefaultKgInput, await ctx.WbKgs.Select(k => k.AtKg).OrderBy(k => k.Name).ToListAsync()); var font = new System.Windows.Media.FontFamily("Segoe MDL2 Assets"); @@ -391,7 +391,7 @@ namespace Elwig.Windows { int areaComs = 0, deliveries = 0, credits = 0; using (var ctx = new AppDbContext()) { - var l = (await ctx.Members.FindAsync(m.MgNr))!; + var l = await ctx.FetchMembers(m.MgNr).SingleAsync(); areaComs = l.AreaCommitments.Count; deliveries = l.Deliveries.Count; credits = l.Credits.Count; @@ -796,7 +796,7 @@ namespace Elwig.Windows { if (areaComs.Count == 0) return; - var oldMember = (await ctx.Members.FindAsync(mgnr))!; + var oldMember = await ctx.FetchMembers(mgnr).SingleAsync(); var newName = $"{ViewModel.Name?.Replace('ß', 'ẞ').ToUpper()} " + $"{ViewModel.Prefix}{(!string.IsNullOrEmpty(ViewModel.Prefix) ? " " : "")}" + $"{ViewModel.GivenName}{(!string.IsNullOrEmpty(ViewModel.GivenName) ? " " : "")}" + diff --git a/Elwig/Windows/PaymentAdjustmentWindow.xaml.cs b/Elwig/Windows/PaymentAdjustmentWindow.xaml.cs index f7be1d6..dd00ef1 100644 --- a/Elwig/Windows/PaymentAdjustmentWindow.xaml.cs +++ b/Elwig/Windows/PaymentAdjustmentWindow.xaml.cs @@ -40,7 +40,7 @@ namespace Elwig.Windows { } protected override async Task OnRenewContext(AppDbContext ctx) { - var members = await ctx.Members + var members = await ctx.FetchMembers(includeNotActive: true) .Select(m => new { m.MgNr, m.Name, @@ -48,11 +48,8 @@ namespace Elwig.Windows { 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 season = await ctx.FetchSeasons(Year).SingleAsync(); var contracts = await ctx.AreaCommitmentTypes.ToDictionaryAsync(t => t.VtrgId, t => t); var tbl1 = await OverUnderDeliveryData.ForSeason(ctx.OverUnderDeliveryRows, Year); @@ -145,11 +142,7 @@ namespace Elwig.Windows { 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()); + ControlUtils.RenewItemsSource(MemberInput, await ctx.FetchMembers(includeNotActive: true).ToListAsync()); CustomAmountInput.Unit = sym; } @@ -170,7 +163,7 @@ namespace Elwig.Windows { await Task.Run(async () => { await App.Client.UpdateValues(); - var b = new Billing(Year); + var b = await Billing.Create(Year); await b.AutoAdjustBusinessShares(new DateOnly(Year, 11, 30), kg ?? default, bs ?? default, kgPerBs ?? default, percent / 100.0 ?? default, minBs ?? default); }); App.HintContextChange(); @@ -186,7 +179,7 @@ namespace Elwig.Windows { Mouse.OverrideCursor = Cursors.Wait; try { await Task.Run(async () => { - var b = new Billing(Year); + var b = await Billing.Create(Year); await b.UnAdjustBusinessShares(); }); App.HintContextChange(); diff --git a/Tests/UnitTests/DocumentTests/DeliveryConfirmationTest.cs b/Tests/UnitTests/DocumentTests/DeliveryConfirmationTest.cs index f87bb81..8989bb5 100644 --- a/Tests/UnitTests/DocumentTests/DeliveryConfirmationTest.cs +++ b/Tests/UnitTests/DocumentTests/DeliveryConfirmationTest.cs @@ -9,7 +9,7 @@ namespace Tests.UnitTests.DocumentTests { [Test] public async Task Test_01_SimpleDeliveryConfirmation() { using var ctx = new AppDbContext(); - var m = await ctx.Members.FindAsync(101); + var m = await ctx.FetchMembers(101).SingleAsync(); var data = await DeliveryConfirmationDeliveryData.ForMember(ctx.DeliveryParts, 2020, m!); using var doc = new DeliveryConfirmation(2020, m!, data); var text = await Utils.GeneratePdfText(doc); diff --git a/Tests/UnitTests/DocumentTests/LetterheadTest.cs b/Tests/UnitTests/DocumentTests/LetterheadTest.cs index e6aca72..0e995df 100644 --- a/Tests/UnitTests/DocumentTests/LetterheadTest.cs +++ b/Tests/UnitTests/DocumentTests/LetterheadTest.cs @@ -8,7 +8,7 @@ namespace Tests.UnitTests.DocumentTests { [Test] public async Task Test_01_SimpleLetterhead() { using var ctx = new AppDbContext(); - var m = await ctx.Members.FindAsync(104); + var m = await ctx.FetchMembers(104).SingleAsync(); using var doc = new Letterhead(m!); var text = await Utils.GeneratePdfText(doc); Assert.Multiple(() => { diff --git a/Tests/UnitTests/HelperTests/BillingTest.cs b/Tests/UnitTests/HelperTests/BillingTest.cs index f95d572..ad757e8 100644 --- a/Tests/UnitTests/HelperTests/BillingTest.cs +++ b/Tests/UnitTests/HelperTests/BillingTest.cs @@ -135,7 +135,7 @@ namespace Tests.UnitTests.HelperTests { Assert.That(delivery["GVK"], Is.EqualTo( 4_000)); }); - BillingVariant b = new(year, 1); + var b = await BillingVariant.Create(year, 1); await b.CalculateBuckets(false, false, false); var payment = await GetMemberPaymentBuckets(year, mgnr); Assert.Multiple(() => { @@ -179,7 +179,7 @@ namespace Tests.UnitTests.HelperTests { Assert.That(delivery["GVK"], Is.EqualTo( 4_000)); }); - BillingVariant b = new(year, 1); + var b = await BillingVariant.Create(year, 1); await b.CalculateBuckets(false, false, false, Connection); var payment = await GetMemberPaymentBuckets(year, mgnr); Assert.Multiple(() => { @@ -225,7 +225,7 @@ namespace Tests.UnitTests.HelperTests { Assert.That(delivery["GVK"], Is.EqualTo( 4_000)); }); - BillingVariant b = new(year, 1); + var b = await BillingVariant.Create(year, 1); await b.CalculateBuckets(true, false, false, Connection); var payment = await GetMemberPaymentBuckets(year, mgnr); Assert.Multiple(() => { diff --git a/Tests/UnitTests/HelperTests/EbicsTest.cs b/Tests/UnitTests/HelperTests/EbicsTest.cs index b825e84..87b96e3 100644 --- a/Tests/UnitTests/HelperTests/EbicsTest.cs +++ b/Tests/UnitTests/HelperTests/EbicsTest.cs @@ -33,7 +33,7 @@ namespace Tests.UnitTests.HelperTests { DateString = "2021-01-31", }; using var ctx = new AppDbContext(); - var members = ctx.Members.ToList(); + var members = await ctx.FetchMembers().ToListAsync(); Assert.That(members, Has.Count.GreaterThan(0)); using var exporter = new Ebics(v, FileName, version, mode); await exporter.ExportAsync(members.Select(m => new Transaction(m, 1234.56m, "EUR", m.MgNr % 100))); diff --git a/Tests/UnitTests/ServiceTests/DeliveryServiceTest.cs b/Tests/UnitTests/ServiceTests/DeliveryServiceTest.cs index a5504f2..d4bb7a0 100644 --- a/Tests/UnitTests/ServiceTests/DeliveryServiceTest.cs +++ b/Tests/UnitTests/ServiceTests/DeliveryServiceTest.cs @@ -10,19 +10,19 @@ namespace Tests.UnitTests.ServiceTests { private static async Task InitViewModel(DeliveryAdminViewModel vm) { using var ctx = new AppDbContext(); - vm.MemberSource = await ctx.Members.ToListAsync(); - vm.BranchSource = await ctx.Branches.ToListAsync(); - vm.WineVarSource = await ctx.WineVarieties.ToListAsync(); - List attrs = (await ctx.WineAttributes.ToListAsync()).Cast().ToList(); + vm.MemberSource = await ctx.FetchMembers(includeNotActive: true).ToListAsync(); + vm.BranchSource = await ctx.FetchBranches().ToListAsync(); + vm.WineVarSource = await ctx.FetchWineVarieties().ToListAsync(); + List attrs = await ctx.FetchWineAttributes().Cast().ToListAsync(); attrs.Insert(0, new NullItem()); vm.WineAttrSource = attrs; - List cults = (await ctx.WineCultivations.ToListAsync()).Cast().ToList(); + List cults = await ctx.FetchWineCultivations().Cast().ToListAsync(); cults.Insert(0, new NullItem()); vm.WineCultSource = cults; - vm.WineQualityLevelSource = await ctx.WineQualityLevels.ToListAsync(); + vm.WineQualityLevelSource = await ctx.FetchWineQualityLevels().ToListAsync(); vm.WineOriginSource = await ctx.WineOrigins.ToListAsync(); vm.WineKgSource = await ctx.Katastralgemeinden.ToListAsync(); - vm.ModifiersSource = await ctx.Modifiers.Where(m => m.Year == 2022).ToListAsync(); + vm.ModifiersSource = await ctx.FetchModifiers(2022).ToListAsync(); } private static async Task GetDelivery(string lsnr) { diff --git a/Tests/UnitTests/ServiceTests/MemberServiceTest.cs b/Tests/UnitTests/ServiceTests/MemberServiceTest.cs index 8a4dfd2..45929d5 100644 --- a/Tests/UnitTests/ServiceTests/MemberServiceTest.cs +++ b/Tests/UnitTests/ServiceTests/MemberServiceTest.cs @@ -10,7 +10,7 @@ namespace Tests.UnitTests.ServiceTests { private static async Task InitViewModel(MemberAdminViewModel vm) { using var ctx = new AppDbContext(); - vm.BranchSource = await ctx.Branches.ToListAsync(); + vm.BranchSource = await ctx.FetchBranches().ToListAsync(); vm.DefaultKgSource = await ctx.Katastralgemeinden.ToListAsync(); vm.OrtSource = await ctx.PlzDestinations.ToListAsync(); vm.BillingOrtSource = await ctx.PlzDestinations.ToListAsync(); @@ -31,18 +31,14 @@ namespace Tests.UnitTests.ServiceTests { Assert.That(vm.MgNr, Is.EqualTo(205)); using (var ctx = new AppDbContext()) { - Assert.That(await ctx.Members.FindAsync(205), Is.Null); + Assert.That(await ctx.FetchMembers(205, includeNotActive: true).SingleOrDefaultAsync(), Is.Null); } Assert.DoesNotThrowAsync(async () => await vm.UpdateMember(null)); Member m; using (var ctx = new AppDbContext()) { - m = await ctx.Members - .Where(m => m.MgNr == vm.MgNr) - .Include(m => m.EmailAddresses) - .Include(m => m.TelephoneNumbers) - .SingleAsync(); + m = await ctx.FetchMembers(vm.MgNr, includeNotActive: true, includeContactInfo: true).SingleAsync(); } Assert.That(m, Is.Not.Null); @@ -115,18 +111,14 @@ namespace Tests.UnitTests.ServiceTests { vm.IsFunktionär = true; using (var ctx = new AppDbContext()) { - Assert.That(await ctx.Members.FindAsync(999), Is.Null); + Assert.That(await ctx.FetchMembers(999, includeNotActive: true).SingleOrDefaultAsync(), Is.Null); } Assert.DoesNotThrowAsync(async () => await vm.UpdateMember(null)); Member m; using (var ctx = new AppDbContext()) { - m = await ctx.Members - .Where(m => m.MgNr == vm.MgNr) - .Include(m => m.EmailAddresses) - .Include(m => m.TelephoneNumbers) - .SingleAsync(); + m = await ctx.FetchMembers(vm.MgNr, includeNotActive: true, includeContactInfo: true).SingleAsync(); } Assert.That(m, Is.Not.Null); @@ -226,11 +218,7 @@ namespace Tests.UnitTests.ServiceTests { var vm = new MemberAdminViewModel(); await InitViewModel(vm); using (var ctx = new AppDbContext()) { - vm.FillInputs(await ctx.Members - .Where(m => m.MgNr == 202) - .Include(m => m.EmailAddresses) - .Include(m => m.TelephoneNumbers) - .SingleAsync()); + vm.FillInputs(await ctx.FetchMembers(202, includeNotActive: true, includeContactInfo: true).SingleAsync()); } Assert.That(vm.IsActive, Is.True); @@ -243,11 +231,7 @@ namespace Tests.UnitTests.ServiceTests { Member m; using (var ctx = new AppDbContext()) { - m = await ctx.Members - .Where(m => m.MgNr == 202) - .Include(m => m.EmailAddresses) - .Include(m => m.TelephoneNumbers) - .SingleAsync(); + m = await ctx.FetchMembers(202, includeNotActive: true, includeContactInfo: true).SingleAsync(); } Assert.That(m, Is.Not.Null); @@ -270,11 +254,7 @@ namespace Tests.UnitTests.ServiceTests { var vm = new MemberAdminViewModel(); await InitViewModel(vm); using (var ctx = new AppDbContext()) { - vm.FillInputs(await ctx.Members - .Where(m => m.MgNr == 203) - .Include(m => m.EmailAddresses) - .Include(m => m.TelephoneNumbers) - .SingleAsync()); + vm.FillInputs(await ctx.FetchMembers(203, includeNotActive: true, includeContactInfo: true).SingleAsync()); } Assert.Multiple(() => { @@ -288,11 +268,7 @@ namespace Tests.UnitTests.ServiceTests { Member m; using (var ctx = new AppDbContext()) { - m = await ctx.Members - .Where(m => m.MgNr == 210) - .Include(m => m.EmailAddresses) - .Include(m => m.TelephoneNumbers) - .SingleAsync(); + m = await ctx.FetchMembers(210, includeNotActive: true, includeContactInfo: true).SingleAsync(); } Assert.That(m, Is.Not.Null); @@ -310,27 +286,27 @@ namespace Tests.UnitTests.ServiceTests { [Test] public async Task TestDelete_01_NoReferences() { using (var ctx = new AppDbContext()) { - Assert.That(await ctx.Members.FindAsync(201), Is.Not.Null); + Assert.That(await ctx.FetchMembers(201, includeNotActive: true).SingleOrDefaultAsync(), Is.Not.Null); } Assert.DoesNotThrowAsync(async () => await MemberService.DeleteMember(201, false, false, false)); using (var ctx = new AppDbContext()) { - Assert.That(await ctx.Members.FindAsync(201), Is.Null); + Assert.That(await ctx.FetchMembers(201, includeNotActive: true).SingleOrDefaultAsync(), Is.Null); } } [Test] public async Task TestDelete_02_AllReferences() { using (var ctx = new AppDbContext()) { - Assert.That(await ctx.Members.FindAsync(204), Is.Not.Null); + Assert.That(await ctx.FetchMembers(204, includeNotActive: true).SingleOrDefaultAsync(), Is.Not.Null); } for (int i = 0; i < 7; i++) { Assert.ThrowsAsync(async () => await MemberService.DeleteMember(204, (i & 1) != 0, (i & 2) != 0, (i & 4) != 0)); using var ctx = new AppDbContext(); - Assert.That(await ctx.Members.FindAsync(204), Is.Not.Null); + Assert.That(await ctx.FetchMembers(204, includeNotActive: true).SingleOrDefaultAsync(), Is.Not.Null); } Assert.DoesNotThrowAsync(async () => await MemberService.DeleteMember(204, true, true, true)); using (var ctx = new AppDbContext()) { - Assert.That(await ctx.Members.FindAsync(204), Is.Null); + Assert.That(await ctx.FetchMembers(204, includeNotActive: true).SingleOrDefaultAsync(), Is.Null); } } }