Compare commits

..

23 Commits

Author SHA1 Message Date
95fabe3633 Bump version to 1.0.5.1
All checks were successful
Test / Run tests (push) Successful in 2m25s
Deploy / Build and Deploy (push) Successful in 2m14s
2026-04-20 19:23:01 +02:00
7861a15e2e Test: Update dependencies
All checks were successful
Test / Run tests (push) Successful in 2m20s
2026-04-20 15:12:29 +02:00
20fd5d5826 Elwig: Update dependencies 2026-04-20 15:12:29 +02:00
2b3c293730 Database: Adapt to changes for examples in WLNS 2026-04-20 15:12:22 +02:00
a852dbb242 PaymentVariantSummary: Fix price display when null 2026-04-20 15:05:09 +02:00
7edf395497 CreditNote: Fix padding for Rbl. 2026-04-20 14:21:13 +02:00
ea2b6db1fc Billing: Fix modifiers with absolute amounts 2026-04-20 14:20:43 +02:00
cf48f005e2 DeliveryAdminWindow: Fix missing LostFocus for gradation inputs
All checks were successful
Test / Run tests (push) Successful in 2m54s
2026-04-08 17:18:40 +02:00
4eac8cd629 DeliveryAdminWindow: Fix modifiers for bulk actions 2026-04-08 17:18:08 +02:00
360856585a Bump version to 1.0.5.0
All checks were successful
Test / Run tests (push) Successful in 1m54s
Deploy / Build and Deploy (push) Successful in 2m14s
2026-04-08 00:47:15 +02:00
cc6e31a006 Installer/Setup: Update to WiX 7 2026-04-08 00:31:00 +02:00
ce1a55df86 Tests: Update dependencies
All checks were successful
Test / Run tests (push) Successful in 2m1s
2026-04-07 23:57:52 +02:00
07d93dd384 Elwig: Update dependencies 2026-04-07 23:57:40 +02:00
f6e9d429d5 [#77] Export/ElwigData: Fix import of AreaComContracts
All checks were successful
Test / Run tests (push) Successful in 2m41s
2026-04-07 23:51:32 +02:00
7b78f9d6b9 [#79] Windows: Fix errors unconvered by E2E tests
All checks were successful
Test / Run tests (push) Successful in 2m12s
2026-04-07 12:34:38 +02:00
22fbb0772f MailWindow: Fix MessageBox and ProgressBar
All checks were successful
Test / Run tests (push) Successful in 2m11s
2026-04-07 12:16:50 +02:00
0a9c800116 BusinessDocument: Add DateFrom to be used for ShowDateAndLocation
All checks were successful
Test / Run tests (push) Successful in 2m0s
2026-04-07 12:06:06 +02:00
278d79429b [#79] DeliveryAdminWindow: Cache modifiers 2026-04-07 11:15:56 +02:00
e5e5e10cd7 ContextWindow: Add HasContextLoaded property 2026-04-07 11:15:34 +02:00
d051a2bfcf [#79] AppDbContext: Use compiled queries 2026-04-07 11:15:14 +02:00
9c39a2f820 [#79] Entities: Remove EF proxies 2026-04-07 11:14:20 +02:00
4460de9975 [#77] Entities: Add AreaComContract to group area commitments together 2026-04-07 11:13:54 +02:00
f96ebdcf60 DeliveryAdminWindow: Fix creation of new deliveries
All checks were successful
Test / Run tests (push) Successful in 2m2s
2026-04-02 20:58:01 +02:00
70 changed files with 635 additions and 668 deletions

View File

@@ -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

View File

@@ -2,6 +2,45 @@
Changelog
=========
[v1.0.5.1][v1.0.5.1] (2026-04-20) {#v1.0.5.1}
---------------------------------------------
### Behobene Fehler {#v1.0.5.1-bugfixes}
* Zu-/Abschläge mit absolutem Wert (z.B. `€/kg`) wurden bei der Auszahlung nie mit der Menge multipliziert. (ea2b6db1fc)
* Massenaktionen im Lieferungen-Fenster (`DeliveryAdminWindow`) haben für Zu-/Abschläge nicht funktioniert. (4eac8cd629, cf48f005e2)
### Sonstiges {#v1.0.5.1-misc}
* Behebung von Kleinigkeiten im Layout bei Dokumenten (`CreditNote`, `PaymentVariantSummary`). (7edf395497, a852dbb242)
* Zuordnung von zwei Gemeinden vom Weinbaugebiet Neusiedlersee (`WLNS`) zu Leithaberg (`WLLB`). (2b3c293730)
* Abhängigkeiten aktualisiert. (20fd5d5826, 7861a15e2e)
[v1.0.5.1]: https://git.necronda.net/winzer/elwig/releases/tag/v1.0.5.1
[v1.0.5.0][v1.0.5.0] (2026-04-08) {#v1.0.5.0}
---------------------------------------------
### Neue Funktionen {#v1.0.5.0-features}
* Flächenbindungen werden nun in _Verträgen_ zusammengefasst um bessere Übersicht und historische Nachvollziehbarkeit zu gewährleisten. ([#77][i77])
### Sonstiges {#v1.0.5.0-misc}
* Erhebliche Verbesserung der Leistung/Geschwindigkeit. ([#79][i79], e5e5e10cd7, 22fbb0772f)
* Am Stammdatenblatt (`MemberDataSheet`) wird nun als Datum das Datum der letzten Bearbeitung angegeben. (0a9c800116)
* Abhängigkeiten aktualisiert. (07d93dd384, ce1a55df86, cc6e31a006)
[v1.0.5.0]: https://git.necronda.net/winzer/elwig/releases/tag/v1.0.5.0
[i77]: https://git.necronda.net/winzer/elwig/issues/77
[i79]: https://git.necronda.net/winzer/elwig/issues/79
[v1.0.4.1][v1.0.4.1] (2026-03-27) {#v1.0.4.1}
---------------------------------------------

View File

@@ -105,9 +105,9 @@ namespace Elwig {
Dictionary<string, (string, string, int?, string?, string?, string?, string?, string?)> 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) {
@@ -201,6 +201,7 @@ namespace Elwig {
BranchName = entry.Item2;
BranchPlz = entry.Item3;
BranchLocation = entry.Item4?
.Split(",")[0]
.Split(" in ")[0]
.Split(" im ")[0]
.Split(" an ")[0]
@@ -221,7 +222,8 @@ namespace Elwig {
MainDispatcher.Invoke(() => {
foreach (Window w in CurrentApp.Windows) {
if (w is not ContextWindow c) continue;
MainDispatcher.BeginInvoke(c.HintContextChange);
MainDispatcher.Invoke(c.HintContextChange);
MainDispatcher.BeginInvoke(c.TryContextReload);
}
});
}

View File

@@ -44,15 +44,10 @@ 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)
.Include(d => d.Member)
.Include(d => d.Parts)
.ToListAsync());
if (DeliveryInput.SelectedItem == null)

View File

@@ -22,6 +22,7 @@ namespace Elwig.Documents {
public bool IncludeSender = false;
public bool UseBillingAddress = false;
public bool ShowDateAndLocation = false;
public DateOnly? DateFrom;
protected Table? Aside;
public string Address {
@@ -47,11 +48,12 @@ namespace Elwig.Documents {
return NewAsideCell(new KernedParagraph(text, 10), colspan, isName);
}
public BusinessDocument(string title, Member m, bool includeSender = false) :
public BusinessDocument(string title, Member m, DateOnly? dateFrom, bool includeSender = false) :
base(title) {
Member = m;
Location = App.BranchLocation;
IncludeSender = includeSender;
DateFrom = dateFrom;
}
protected override void BeforeRenderBody(iText.Layout.Document doc, PdfDocument pdf) {
@@ -105,7 +107,7 @@ namespace Elwig.Documents {
}
}
doc.Add(new KernedParagraph(ShowDateAndLocation ? $"{Location}, am {Date:dd.MM.yyyy}" : "", 12).SetTextAlignment(TextAlignment.RIGHT).SetVerticalAlignment(VerticalAlignment.MIDDLE).SetHeight(24).SetMargin(0));
doc.Add(new KernedParagraph(ShowDateAndLocation ? $"{Location}, am {DateFrom ?? Date:dd.MM.yyyy}" : "", 12).SetTextAlignment(TextAlignment.RIGHT).SetVerticalAlignment(VerticalAlignment.MIDDLE).SetHeight(24).SetMargin(0));
doc.Add(new KernedParagraph(Title, 12).SetFont(BF).SetMargins(0, 0, 12, 0));
}

View File

@@ -37,8 +37,8 @@ namespace Elwig.Documents {
private CreditNoteDeliveryData? _data;
private Dictionary<string, UnderDelivery>? _underDeliveries;
public CreditNote(PaymentMember p, BillingData? billingData = null, CreditNoteDeliveryData? data = null, Dictionary<string, UnderDelivery>? underDeliveries = null) :
base($"{Name} {(p.Credit != null ? $"Nr. {p.Credit.Year}/{p.Credit.TgNr:000}" : p.Member.FullName)} {p.Variant.Name}", p.Member) {
public CreditNote(PaymentMember p, DateOnly? dateFrom, BillingData? billingData = null, CreditNoteDeliveryData? data = null, Dictionary<string, UnderDelivery>? underDeliveries = null) :
base($"{Name} {(p.Credit != null ? $"Nr. {p.Credit.Year}/{p.Credit.TgNr:000}" : p.Member.FullName)} {p.Variant.Name}", p.Member, dateFrom) {
UseBillingAddress = true;
ShowDateAndLocation = true;
Payment = p;
@@ -58,12 +58,12 @@ namespace Elwig.Documents {
ConsiderCustomModifiers = billingData.ConsiderCustomModifiers;
}
public static async Task<CreditNote> Initialize(int year, int avnr, int mgnr, BillingData? billingData = null, CreditNoteDeliveryData? data = null, Dictionary<string, UnderDelivery>? underDeliveries = null) {
public static async Task<CreditNote> Initialize(int year, int avnr, int mgnr, DateOnly? dateFrom, BillingData? billingData = null, CreditNoteDeliveryData? data = null, Dictionary<string, UnderDelivery>? underDeliveries = null) {
using var ctx = new AppDbContext();
var p = await ctx.MemberPayments
.Where(p => p.Year == year && p.AvNr == avnr && p.MgNr == mgnr)
.SingleAsync();
return new CreditNote(p, billingData, data, underDeliveries);
return new CreditNote(p, dateFrom, billingData, data, underDeliveries);
}
protected override async Task LoadData(AppDbContext ctx) {
@@ -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)
@@ -321,7 +321,7 @@ namespace Elwig.Documents {
var totalMod = p.TotalModifiers ?? 0;
var pad = i == 0 ? 0.5f : 0;
sub.AddCell(NewTd(rebelMod == 0 ? "-" : (Utils.GetSign(rebelMod) + $"{Math.Abs(rebelMod):0.0##}"), 6, center: true)
.SetPaddingTopMM(pad))
.SetPaddingTopMM(pad).SetPaddingLeft(0).SetPaddingRight(0))
.AddCell(NewTd(totalMod == 0 ? "-" : Utils.GetSign(totalMod) + $"{Math.Abs(totalMod):N2}", center: totalMod == 0, right: true)
.SetPaddingTopMM(pad))
.AddCell(NewTd($"{p.Amount:N2}", right: true)

View File

@@ -24,8 +24,8 @@ namespace Elwig.Documents {
public Dictionary<string, MemberBucket> MemberBuckets = [];
public List<MemberStat> MemberStats = [];
public DeliveryConfirmation(int year, Member m, DeliveryConfirmationDeliveryData? data = null) :
base($"{Name} {year}", m) {
public DeliveryConfirmation(int year, Member m, DateOnly? dateFrom, DeliveryConfirmationDeliveryData? data = null) :
base($"{Name} {year}", m, dateFrom) {
_year = year;
ShowDateAndLocation = true;
UseBillingAddress = true;
@@ -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)

View File

@@ -29,14 +29,12 @@ namespace Elwig.Documents {
public int DisplayStats = App.Client.ModeDeliveryNoteStats;
public DeliveryNote(Delivery d) :
base($"{Name} Nr. {d.LsNr}", d.Member) {
base($"{Name} Nr. {d.LsNr}", d.Member, DateOnly.FromDateTime(d.ModifiedAt)) {
UseBillingAddress = true;
ShowDateAndLocation = true;
Delivery = d;
Text = App.Client.TextDeliveryNote;
DocumentId = d.LsNr;
Date = DateOnly.FromDateTime(d.ModifiedAt);
IsDoublePaged = true;
}
public static async Task<DeliveryNote> Initialize(int year, int did) {

View File

@@ -49,14 +49,12 @@ namespace Elwig.Documents {
public bool IsPreview = false;
private iText.Layout.Document? _doc;
public int CurrentNextSeason;
public string? DocumentId;
public string Title;
public string Author;
public DateOnly Date;
public Document(string title) {
CurrentNextSeason = Utils.CurrentNextSeason;
Title = title;
Author = App.Client.NameFull;
Date = DateOnly.FromDateTime(Utils.Today);

View File

@@ -6,7 +6,7 @@ using iText.Layout;
namespace Elwig.Documents {
public class Letterhead : BusinessDocument {
public Letterhead(Member m) :
base($"Briefkopf {m.FullName}", m, true) {
base($"Briefkopf {m.FullName}", m, null, includeSender: true) {
}
protected override void RenderBody(iText.Layout.Document doc, PdfDocument pdf) {

View File

@@ -23,18 +23,19 @@ namespace Elwig.Documents {
public List<AreaCom> ActiveAreaCommitments = [];
public MemberDataSheet(Member m) :
base($"{Name} {m.AdministrativeName}", m) {
base($"{Name} {m.AdministrativeName}", m, DateOnly.FromDateTime(m.ModifiedAt)) {
ShowDateAndLocation = true;
DocumentId = $"{Name} {m.MgNr}";
}
public static async Task<MemberDataSheet> 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)

View File

@@ -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) {
@@ -183,21 +183,21 @@ namespace Elwig.Documents {
.AddCell(NewTd(CurrencySymbol))
.AddCell(NewTd($"{Math.Abs(payed):N2}", right: true))
.AddCell(NewSectionTh("Preis (abgewertet):", borderTop: true, borderLeft: true))
.AddCell(NewTd((minWei != maxWei ? $"{minWei:N4}\u2013{maxWei:N4}" : $"{minWei:N4}") + $" {CurrencySymbol}/kg", colspan: 2, center: true, borderTop: true))
.AddCell(NewTd(minWei == null && maxWei == null ? "-" : (minWei != maxWei ? $"{minWei:N4}\u2013{maxWei:N4}" : $"{minWei:N4}") + $" {CurrencySymbol}/kg", colspan: 2, center: true, borderTop: true))
.AddCell(NewSectionTh("Nettosumme:", colspan: 2))
.AddCell(NewTd(borderTop: true))
.AddCell(NewTd(CurrencySymbol, borderTop: true))
.AddCell(NewTd($"{netSum:N2}", right: true, borderTop: true))
.AddCell(NewSectionTh("Preis (ungeb., nicht abgew.):", borderLeft: true))
.AddCell(NewTd((minPrice != maxPrice ? $"{minPrice:N4}{maxPrice:N4}" : $"{minPrice:N4}") + $" {CurrencySymbol}/kg", colspan: 2, center: true))
.AddCell(NewTd(minPrice == null && maxPrice == null ? "-" : (minPrice != maxPrice ? $"{minPrice:N4}{maxPrice:N4}" : $"{minPrice:N4}") + $" {CurrencySymbol}/kg", colspan: 2, center: true))
.AddCell(NewSectionTh("Mehrwertsteuer:", colspan: 2))
.AddCell(NewTd(Utils.GetSign(vat), right: true))
.AddCell(NewTd(CurrencySymbol))
.AddCell(NewTd($"{Math.Abs(vat):N2}", right: true))
.AddCell(NewSectionTh("Gebunden-Zuschlag:", borderLeft: true))
.AddCell(NewTd(minGeb != maxGeb ? $"{minGeb:N4}\u2013{maxGeb:N4} {CurrencySymbol}/kg" : minGeb == 0 ? "-" : $"{minGeb:N4} {CurrencySymbol}/kg", colspan: 2, center: true))
.AddCell(NewTd(minGeb == null && maxGeb == null ? "-" : minGeb != maxGeb ? $"{minGeb:N4}\u2013{maxGeb:N4} {CurrencySymbol}/kg" : minGeb == 0 ? "-" : $"{minGeb:N4} {CurrencySymbol}/kg", colspan: 2, center: true))
.AddCell(NewSectionTh("Bruttosumme:", colspan: 2))
.AddCell(NewTd(borderTop: true))

View File

@@ -9,7 +9,7 @@
<UseWindowsForms>true</UseWindowsForms>
<PreserveCompilationContext>true</PreserveCompilationContext>
<ApplicationIcon>Resources\Images\Elwig.ico</ApplicationIcon>
<Version>1.0.4.1</Version>
<Version>1.0.5.1</Version>
<SatelliteResourceLanguages>de-AT</SatelliteResourceLanguages>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<ApplicationManifest>app.manifest</ApplicationManifest>
@@ -23,21 +23,21 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="bblanchon.PDFium.Win32" Version="148.0.7749" />
<PackageReference Include="bblanchon.PDFium.Win32" Version="149.0.7802" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.2" />
<PackageReference Include="itext" Version="9.5.0" />
<PackageReference Include="itext.bouncy-castle-adapter" Version="9.5.0" />
<PackageReference Include="itext" Version="9.6.0" />
<PackageReference Include="itext.bouncy-castle-adapter" Version="9.6.0" />
<PackageReference Include="LinqKit" Version="1.3.11" />
<PackageReference Include="MailKit" Version="4.15.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.5" />
<PackageReference Include="Microsoft.Extensions.Configuration.Ini" Version="10.0.5" />
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.3856.49" />
<PackageReference Include="NJsonSchema" Version="11.5.2" />
<PackageReference Include="ScottPlot.WPF" Version="5.1.57" />
<PackageReference Include="MailKit" Version="4.16.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.6" />
<PackageReference Include="Microsoft.Extensions.Configuration.Ini" Version="10.0.6" />
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.3912.50" />
<PackageReference Include="NJsonSchema" Version="11.6.0" />
<PackageReference Include="ScottPlot.WPF" Version="5.1.58" />
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="3.0.2" />
<PackageReference Include="System.IO.Hashing" Version="10.0.5" />
<PackageReference Include="System.IO.Ports" Version="10.0.5" />
<PackageReference Include="System.Management" Version="10.0.5" />
<PackageReference Include="System.IO.Hashing" Version="10.0.6" />
<PackageReference Include="System.IO.Ports" Version="10.0.6" />
<PackageReference Include="System.Management" Version="10.0.6" />
</ItemGroup>
</Project>

View File

@@ -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<AppDbContext, string?, bool, IAsyncEnumerable<Branch>> _compiledQueryBranches =
EF.CompileAsyncQuery<AppDbContext, string?, bool, Branch>((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<AppDbContext, string?, IAsyncEnumerable<WineVar>> _compiledQueryWineVarieties =
EF.CompileAsyncQuery<AppDbContext, string?, WineVar>((ctx, sortid) => ctx.WineVarieties
.Where(v => sortid == null || v.SortId == sortid)
.OrderBy(v => v.Name));
private static readonly Func<AppDbContext, string?, bool, IAsyncEnumerable<WineAttr>> _compiledQueryWineAttributes =
EF.CompileAsyncQuery<AppDbContext, string?, bool, WineAttr>((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<AppDbContext, string?, IAsyncEnumerable<WineCult>> _compiledQueryWineCultivations =
EF.CompileAsyncQuery<AppDbContext, string?, WineCult>((ctx, cultid) => ctx.WineCultivations
.Where(c => cultid == null || c.CultId == cultid)
.OrderBy(v => v.Name));
private static readonly Func<AppDbContext, bool, IAsyncEnumerable<WineQualLevel>> _compiledQueryWineQualityLevels =
EF.CompileAsyncQuery<AppDbContext, bool, WineQualLevel>((ctx, includePredicate) => ctx.WineQualityLevels
.Where(l => includePredicate || !l.IsPredicate)
.OrderBy(l => l.MinKmw));
private static readonly Func<AppDbContext, int?, bool, IAsyncEnumerable<Modifier>> _compiledQueryModifiers =
EF.CompileAsyncQuery<AppDbContext, int?, bool, Modifier>((ctx, year, incudeNotActive) => ctx.Modifiers
.Where(m => (year == null || m.Year == year) && (incudeNotActive || m.IsActive))
.OrderBy(m => m.Year).ThenBy(m => m.Ordering).ThenBy(m => m.Name));
private static readonly Func<AppDbContext, int?, bool, IAsyncEnumerable<Member>> _compiledQueryMembers =
EF.CompileAsyncQuery<AppDbContext, int?, bool, Member>((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<AppDbContext, int?, bool, IAsyncEnumerable<Member>> _compiledQueryMembersContactInfo =
EF.CompileAsyncQuery<AppDbContext, int?, bool, Member>((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<AppDbContext, int?, IAsyncEnumerable<AreaCom>> _compiledQueryAreaCommitments =
EF.CompileAsyncQuery<AppDbContext, int?, AreaCom>((ctx, fbnr) => ctx.AreaCommitments
.Where(c => fbnr == null || c.FbNr == fbnr)
.OrderBy(c => c.FbNr).ThenBy(c => c.RevNr));
private static readonly Func<AppDbContext, int?, IAsyncEnumerable<Season>> _compiledQuerySeasons =
EF.CompileAsyncQuery<AppDbContext, int?, Season>((ctx, year) => ctx.Seasons
.Where(s => year == null || s.Year == year)
.OrderByDescending(s => s.Year));
private static readonly Func<AppDbContext, int?, IAsyncEnumerable<Season>> _compiledQuerySeasonsModifiers =
EF.CompileAsyncQuery<AppDbContext, int?, Season>((ctx, year) => ctx.Seasons
.Where(s => year == null || s.Year == year)
.Include(s => s.Modifiers)
.OrderByDescending(s => s.Year));
private readonly Dictionary<int, Dictionary<int, Dictionary<string, AreaComBucket>>> _memberAreaCommitmentBuckets = [];
private readonly Dictionary<int, Dictionary<int, Dictionary<string, int>>> _memberDeliveryBuckets = [];
private readonly Dictionary<int, Dictionary<int, Dictionary<string, int>>> _memberDeliveryBucketsStrict = [];
@@ -162,6 +229,10 @@ namespace Elwig.Helpers {
modelBuilder.Entity<PaymentMember>().Navigation(c => c.Credit).AutoInclude();
modelBuilder.Entity<PaymentMember>().Navigation(c => c.Member).AutoInclude();
modelBuilder.Entity<PaymentMember>().Navigation(c => c.Variant).AutoInclude();
modelBuilder.Entity<DeliveryAncmt>().Navigation(a => a.Member).AutoInclude();
modelBuilder.Entity<DeliveryAncmt>().Navigation(a => a.Schedule).AutoInclude();
modelBuilder.Entity<DeliveryAncmt>().Navigation(a => a.Variety).AutoInclude();
modelBuilder.Entity<DeliverySchedule>().Navigation(s => s.Branch).AutoInclude();
}
public override void Dispose() {
@@ -179,23 +250,23 @@ namespace Elwig.Helpers {
}
public async Task<bool> MgNrExists(int mgnr) {
return await Members.FindAsync(mgnr) != null;
return await _compiledQueryMembers.Invoke(this, mgnr, true).AnyAsync();
}
public async Task<bool> FbNrExists(int fbnr) {
return await AreaCommitmentContracts.FindAsync(fbnr) != null;
return await _compiledQueryAreaCommitments.Invoke(this, fbnr).AnyAsync();
}
public async Task<bool> SortIdExists(string sortId) {
return await WineVarieties.FindAsync(sortId) != null;
return await _compiledQueryWineVarieties.Invoke(this, sortId).AnyAsync();
}
public async Task<bool> AttrIdExists(string attrId) {
return await WineAttributes.FindAsync(attrId) != null;
return await _compiledQueryWineAttributes.Invoke(this, attrId, true).AnyAsync();
}
public async Task<bool> CultIdExists(string cultId) {
return await WineCultivations.FindAsync(cultId) != null;
return await _compiledQueryWineCultivations.Invoke(this, cultId).AnyAsync();
}
public async Task<int> NextMgNr() {
@@ -213,88 +284,107 @@ namespace Elwig.Helpers {
}
public async Task<int> 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<int> 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<int> 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<int> 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<int> 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<int> 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<int> 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<Modifier> oldModifiers, IEnumerable<Modifier> newModifiers) {
foreach (var m in Modifiers.Where(m => m.Year == part.Year)) {
public IAsyncEnumerable<Branch> FetchBranches(string? zwstid = null, bool includeWithoutMembers = true) {
return _compiledQueryBranches.Invoke(this, zwstid, includeWithoutMembers);
}
public IAsyncEnumerable<WineVar> FetchWineVarieties() {
return _compiledQueryWineVarieties.Invoke(this, null);
}
public IAsyncEnumerable<WineAttr> FetchWineAttributes(bool incudeNotActive = true) {
return _compiledQueryWineAttributes.Invoke(this, null, incudeNotActive);
}
public IAsyncEnumerable<WineCult> FetchWineCultivations() {
return _compiledQueryWineCultivations.Invoke(this, null);
}
public IAsyncEnumerable<WineQualLevel> FetchWineQualityLevels(bool includePredicate = true) {
return _compiledQueryWineQualityLevels.Invoke(this, includePredicate);
}
public IAsyncEnumerable<Modifier> FetchModifiers(int? year, bool incudeNotActive = true) {
return _compiledQueryModifiers.Invoke(this, year, incudeNotActive);
}
public IAsyncEnumerable<Member> 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<Season> 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<string> oldModIds, IEnumerable<string> 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) {

View File

@@ -9,7 +9,7 @@ namespace Elwig.Helpers {
public static class AppDbUpdater {
// Don't forget to update value in Tests/fetch-resources.bat!
public static readonly int RequiredSchemaVersion = 38;
public static readonly int RequiredSchemaVersion = 39;
private static int VersionOffset = 0;

View File

@@ -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<string, (decimal?, decimal?)> Modifiers;
protected readonly Dictionary<string, (string, string?, string?, int?, decimal?)> AreaComTypes;
public Billing(int year) {
protected Billing(int year, Season season,
Dictionary<string, string> attributes,
Dictionary<string, (decimal?, decimal?)> modifiers,
Dictionary<string, (string, string?, string?, int?, decimal?)> areaComTypes
) {
Year = year;
Season = season;
Attributes = attributes;
Modifiers = modifiers;
AreaComTypes = areaComTypes;
}
protected static async Task<(Season, Dictionary<string, string>, Dictionary<string, (decimal?, decimal?)>, Dictionary<string, (string, string?, string?, int?, decimal?)>)> 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<Billing> 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).Include(m => m.Season).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() {

View File

@@ -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<string, string> attributes,
Dictionary<string, (decimal?, decimal?)> modifiers,
Dictionary<string, (string, string?, string?, int?, decimal?)> 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<BillingVariant> Create(int year, int avnr) {
using var ctx = new AppDbContext();
PaymentVariant = ctx.PaymentVariants.Include(v => v.Season).Where(v => v.Year == Year && v.AvNr == AvNr).Single() ?? throw new ArgumentException("PaymentVar not found");
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);
@@ -214,7 +232,7 @@ namespace Elwig.Helpers.Billing {
SET mod_rel = mod_rel + excluded.mod_rel;
INSERT INTO payment_delivery_part (year, did, dpnr, avnr, net_amount, mod_abs, mod_rel)
SELECT d.year, d.did, d.dpnr, {AvNr}, 0, COALESCE(m.abs, 0), COALESCE(m.rel, 0)
SELECT d.year, d.did, d.dpnr, {AvNr}, 0, COALESCE(m.abs, 0) * d.weight, COALESCE(m.rel, 0)
FROM delivery_part d
LEFT JOIN delivery_part_modifier p ON (p.year, p.did, p.dpnr) = (d.year, d.did, d.dpnr)
LEFT JOIN modifier m ON (m.year, m.modid) = (d.year, p.modid)

View File

@@ -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<GraphEntry> CreateGraphEntries(
private static async Task<List<GraphEntry>> CreateGraphEntries(
AppDbContext ctx, int precision,
Dictionary<int, Curve> curves,
Dictionary<int, List<RawVaribute>> 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<GraphEntry> GetPaymentGraphEntries(AppDbContext ctx, Season season) {
public async Task<IEnumerable<GraphEntry>> 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<GraphEntry> GetQualityGraphEntries(AppDbContext ctx, Season season, int idOffset = 0) {
public async Task<IEnumerable<GraphEntry>> 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;

View File

@@ -41,7 +41,7 @@ namespace Elwig.Helpers.Export {
List<WbGl> 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));
@@ -224,7 +224,7 @@ namespace Elwig.Helpers.Export {
}
var importedMembers = new List<(string FileName, string ZwstId, string Device, int New, int Overwritten, int NotImported, string? Filters)>();
var importedAreaComs = new List<(string FileName, string ZwstId, string Device, int Imported, int NotImported, string? Filters)>();
var importedAreaComs = new List<(string FileName, string ZwstId, string Device, int New, int Overwritten, int NotImported, string? Filters)>();
var importedDeliveries = new List<(string FileName, string ZwstId, string Device, int New, int Overwritten, int NotImported, string? Filters)>();
foreach (var ((members, billingAddresses, telephoneNumbers, emailAddresses, areaCommitments, contracts, riede, wbKgs, wbGls, deliveries, deliveryParts, modifiers, timestamps), meta) in data.Zip(metaData)) {
@@ -308,9 +308,9 @@ namespace Elwig.Helpers.Export {
}
if (importDuplicateMembers) {
ctx.RemoveRange(ctx.BillingAddresses.Where(a => duplicateMgNrs.Contains(a.MgNr)));
ctx.RemoveRange(ctx.MemberTelephoneNrs.Where(n => duplicateMgNrs.Contains(n.MgNr)));
ctx.RemoveRange(ctx.MemberEmailAddrs.Where(a => duplicateMgNrs.Contains(a.MgNr)));
ctx.RemoveRange(ctx.BillingAddresses.IgnoreAutoIncludes().Where(a => duplicateMgNrs.Contains(a.MgNr)));
ctx.RemoveRange(ctx.MemberTelephoneNrs.IgnoreAutoIncludes().Where(n => duplicateMgNrs.Contains(n.MgNr)));
ctx.RemoveRange(ctx.MemberEmailAddrs.IgnoreAutoIncludes().Where(a => duplicateMgNrs.Contains(a.MgNr)));
ctx.UpdateRange(members.Where(m => duplicateMgNrs.Contains(m.MgNr)));
ctx.AddRange(billingAddresses.Where(a => duplicateMgNrs.Contains(a.MgNr)));
ctx.AddRange(telephoneNumbers.Where(n => duplicateMgNrs.Contains(n.MgNr)));
@@ -329,7 +329,7 @@ namespace Elwig.Helpers.Export {
}
if (importDuplicateContracts) {
ctx.RemoveRange(ctx.AreaCommitments.Where(c => duplicateFbNrs.Contains(c.FbNr)));
ctx.RemoveRange(ctx.AreaCommitments.IgnoreAutoIncludes().Where(c => duplicateFbNrs.Contains(c.FbNr)));
ctx.UpdateRange(contracts.Where(c => duplicateFbNrs.Contains(c.FbNr)));
ctx.AddRange(areaCommitments.Where(c => duplicateFbNrs.Contains(c.FbNr)));
}
@@ -339,8 +339,9 @@ namespace Elwig.Helpers.Export {
}
if (contracts.Count > 0) {
ctx.AddRange(riede);
var imported = contracts.Where(c => (importNewContracts && !duplicateFbNrs.Contains(c.FbNr)) || (importDuplicateContracts && duplicateFbNrs.Contains(c.FbNr))).ToList();
importedAreaComs.Add((meta.FileName, meta.ZwstId, meta.Device, imported.Count, areaCommitments.Count - imported.Count, meta.AreaComFilters));
var n = importNewContracts ? contracts.Count - duplicateFbNrs.Count : 0;
var o = importDuplicateContracts ? duplicateFbNrs.Count : 0;
importedAreaComs.Add((meta.FileName, meta.ZwstId, meta.Device, n, o, contracts.Count - n - o, meta.AreaComFilters));
}
if (allowedDuplicateLsNrs.Count > 0) {
@@ -349,9 +350,10 @@ namespace Elwig.Helpers.Export {
.Select(d => (d.Year, d.DId))
.ToList();
ctx.RemoveRange(ctx.DeliveryParts
.IgnoreAutoIncludes()
.Where(p => allowedDuplicateLsNrs.Contains(p.Delivery.LsNr))
.SelectMany(p => p.PartModifiers));
ctx.RemoveRange(ctx.DeliveryParts.Where(p => allowedDuplicateLsNrs.Contains(p.Delivery.LsNr)));
ctx.RemoveRange(ctx.DeliveryParts.IgnoreAutoIncludes().Where(p => allowedDuplicateLsNrs.Contains(p.Delivery.LsNr)));
ctx.UpdateRange(deliveries.Where(d => dids.Contains((d.Year, d.DId))));
ctx.AddRange(deliveryParts.Where(p => dids.Contains((p.Year, p.DId))));
ctx.AddRange(modifiers.Where(m => dids.Contains((m.Year, m.DId))));
@@ -363,9 +365,10 @@ namespace Elwig.Helpers.Export {
.Select(d => (d.Year, d.DId))
.ToList();
ctx.RemoveRange(ctx.DeliveryParts
.IgnoreAutoIncludes()
.Where(p => l.Contains(p.Delivery.LsNr))
.SelectMany(p => p.PartModifiers));
ctx.RemoveRange(ctx.DeliveryParts.Where(p => l.Contains(p.Delivery.LsNr)));
ctx.RemoveRange(ctx.DeliveryParts.IgnoreAutoIncludes().Where(p => l.Contains(p.Delivery.LsNr)));
ctx.UpdateRange(deliveries.Where(d => dids.Contains((d.Year, d.DId))));
ctx.AddRange(deliveryParts.Where(p => dids.Contains((p.Year, p.DId))));
ctx.AddRange(modifiers.Where(m => dids.Contains((m.Year, m.DId))));
@@ -418,10 +421,10 @@ namespace Elwig.Helpers.Export {
$" ({d.New} neu, {d.Overwritten} überschrieben, {d.NotImported} nicht importiert)\n" +
$" Zweigstelle: {branches[d.ZwstId].Name} (Gerät {d.Device})\n" +
$" Filter: {d.Filters}"),
$"Flächenbindungen: {importedAreaComs.Sum(d => d.Imported)}",
$"Flächenbindungen: {importedAreaComs.Sum(d => d.New + d.Overwritten)}",
..importedAreaComs.Select(d =>
$" {d.FileName} ({d.Imported})\n" +
$" ({d.Imported} importiert, {d.NotImported} nicht importiert)\n" +
$" {d.FileName} ({d.New + d.Overwritten})\n" +
$" ({d.New} importiert, {d.Overwritten} überschreiben, {d.NotImported} nicht importiert)\n" +
$" Zweigstelle: {branches[d.ZwstId].Name} (Gerät {d.Device})\n" +
$" Filter: {d.Filters}"),
$"Lieferungen: {importedDeliveries.Sum(d => d.New + d.Overwritten)}",
@@ -860,7 +863,7 @@ namespace Elwig.Helpers.Export {
["ried"] = p.Rd?.Name,
["net_weight"] = p.IsNetWeight,
["manual_weighing"] = p.IsManualWeighing,
["modids"] = new JsonArray(p.Modifiers.Select(m => (JsonNode)m.ModId).ToArray()),
["modids"] = new JsonArray(p.PartModifiers.Select(m => (JsonNode)m.ModId).ToArray()),
["comment"] = p.Comment,
["created_at"] = $"{p.CreatedAt:yyyy-MM-ddTHH:mm:ssK}",
["modified_at"] = $"{p.ModifiedAt:yyyy-MM-ddTHH:mm:ssK}",

View File

@@ -413,8 +413,8 @@ namespace Elwig.Helpers {
return output.OrderByDescending(l => l.Count());
}
public static List<RawVaribute> GetVaributes(AppDbContext ctx, int year, bool onlyDelivered = true) {
var varieties = ctx.WineVarieties.Select(v => new RawVaribute(v.SortId, "", null)).ToList();
public static async Task<List<RawVaribute>> 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<Varibute> 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<List<Varibute>> 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")]

View File

@@ -28,7 +28,7 @@ namespace Elwig.Models.Dtos {
}
public static async Task<IDictionary<int, CreditNoteDeliveryData>> ForPaymentVariant(DbSet<CreditNoteDeliveryRowSingle> table, DbSet<PaymentVar> 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))

View File

@@ -28,12 +28,7 @@ namespace Elwig.Models.Dtos {
}
public static async Task<DeliveryAncmtListData> FromQuery(IQueryable<DeliveryAncmt> query, List<string> filterNames) {
return new((await query
.Include(a => a.Schedule.Branch)
.Include(a => a.Member)
.Include(a => a.Variety)
.AsSplitQuery()
.ToListAsync()).Select(d => new DeliveryAncmtListRow(d)), filterNames);
return new((await query.ToListAsync()).Select(d => new DeliveryAncmtListRow(d)), filterNames);
}
}

View File

@@ -52,12 +52,8 @@ namespace Elwig.Models.Dtos {
if (mgnr != null) q = q.Where(p => p.Delivery.MgNr == mgnr);
await q
.Include(p => p.Delivery)
.Include(p => p.Variety)
.Include(p => p.Attribute)
.Include(p => p.Quality)
.Include(p => p.Buckets)
.Include(p => p.PartModifiers)
.ThenInclude(m => m.Modifier)
.Include(p => p.PartModifiers).ThenInclude(m => m.Modifier)
.LoadAsync();
return await table.FromSqlRaw($"""
SELECT p.*

View File

@@ -40,12 +40,7 @@ namespace Elwig.Models.Dtos {
.Include(p => p.Delivery.Member.Branch)
.Include(p => p.Delivery.Branch)
.Include(p => p.PartModifiers).ThenInclude(m => m.Modifier)
.Include(p => p.Variety)
.Include(p => p.Attribute)
.Include(p => p.Cultivation)
.Include(p => p.Origin)
.Include(p => p.Quality)
.AsSplitQuery()
.ToListAsync()).Select(d => new DeliveryJournalRow(d)), filterNames);
}
}

View File

@@ -49,13 +49,9 @@ namespace Elwig.Models.Dtos {
public static async Task<MemberListData> FromQuery(IQueryable<Member> query, List<string> filterNames, IEnumerable<string> filterAreaCom) {
var areaComs = await query.Include(m => m.AreaCommitments).ToDictionaryAsync(m => m.MgNr, m => Utils.ActiveAreaCommitments(m.AreaCommitments));
return new((await query
.Include(m => m.DefaultWbKg!.AtKg)
.Include(m => m.Branch)
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.BillingAddress!.PostalDest.AtPlz!.Ort)
.Include(m => m.TelephoneNumbers)
.Include(m => m.EmailAddresses)
.AsSplitQuery()
.ToListAsync()).Select(m => new MemberListRow(m,
areaComs[m.MgNr].Sum(c => c.Area),
areaComs[m.MgNr].Where(c => filterAreaCom.Contains(c.VtrgId)).GroupBy(c => c.VtrgId).ToDictionary(g => g.Key, g => g.Sum(c => c.Area)))),

View File

@@ -106,7 +106,10 @@ namespace Elwig.Models.Entities {
[InverseProperty(nameof(DeliveryPart.Delivery))]
public virtual ICollection<DeliveryPart> Parts { get; private set; } = null!;
[NotMapped]
public IEnumerable<DeliveryPart> FilteredParts { get; set; } = [];
public IEnumerable<DeliveryPart> FilteredParts => PartFilter == null ? Parts : Parts.Where(p => PartFilter(p));
[NotMapped]
public Predicate<DeliveryPart>? PartFilter { get; set; }
public int Weight => Parts.Sum(p => p.Weight);
public int FilteredWeight => FilteredParts.Sum(p => p.Weight);

View File

@@ -27,7 +27,9 @@ namespace Elwig.Models.Entities {
public virtual ICollection<WbGem> Gems { get; private set; } = null!;
[InverseProperty(nameof(Parent))]
public virtual ICollection<WineOrigin> Children { get; private set; } = null!;
public virtual ICollection<WineOrigin> RealChildren { get; private set; } = null!;
[NotMapped]
public List<WineOrigin> Children { get; private set; } = [];
public int Level => (Parent?.Level + 1) ?? 0;

View File

@@ -153,6 +153,27 @@ BEGIN
UPDATE area_commitment_contract SET mtime = UNIXEPOCH() WHERE fbnr = OLD.fbnr;
END;
CREATE TRIGGER t_area_commitment_i_mtime_member
AFTER INSERT ON area_commitment FOR EACH ROW
WHEN (SELECT value FROM client_parameter WHERE param = 'ENABLE_TIME_TRIGGERS') = 1
BEGIN
UPDATE member SET mtime = UNIXEPOCH() WHERE mgnr = NEW.mgnr;
END;
CREATE TRIGGER t_area_commitment_u_mtime_member
AFTER UPDATE ON area_commitment FOR EACH ROW
WHEN (SELECT value FROM client_parameter WHERE param = 'ENABLE_TIME_TRIGGERS') = 1
BEGIN
UPDATE member SET mtime = UNIXEPOCH() WHERE mgnr = NEW.mgnr OR mgnr = OLD.mgnr;
END;
CREATE TRIGGER t_area_commitment_d_mtime_member
AFTER DELETE ON area_commitment FOR EACH ROW
WHEN (SELECT value FROM client_parameter WHERE param = 'ENABLE_TIME_TRIGGERS') = 1
BEGIN
UPDATE member SET mtime = UNIXEPOCH() WHERE mgnr = OLD.mgnr;
END;
-- fix user fiddling - set actual year_from
UPDATE area_commitment AS b
SET fbnr = a.fbnr, revnr = b.fbnr, year_from = a.year_to + 1

View File

@@ -0,0 +1,8 @@
-- schema version 38 to 39
PRAGMA writable_schema = ON;
UPDATE sqlite_schema SET sql = REPLACE(sql, '{2,}', '{2,64}')
WHERE type = 'table' AND name = 'member_email_address';
PRAGMA writable_schema = OFF;
UPDATE wb_gem SET hkid = 'WLLB' WHERE gkz IN (10710, 10723);

View File

@@ -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];

View File

@@ -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];

View File

@@ -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();
});

View File

@@ -27,10 +27,7 @@ namespace Elwig.Services {
public static async Task<Member?> GetMemberAsync(int mgnr) {
using var ctx = new AppDbContext();
return await ctx.Members
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.DefaultWbKg!.AtKg)
.FirstOrDefaultAsync(m => m.MgNr == mgnr);
return await ctx.FetchMembers(mgnr).SingleOrDefaultAsync();
}
public static Member? GetMember(int mgnr) {
@@ -71,7 +68,7 @@ namespace Elwig.Services {
vm.IsNetWeight = p.IsNetWeight;
vm.Modifiers.Clear();
foreach (var m in p.Modifiers) {
foreach (var m in p.PartModifiers) {
vm.Modifiers.Add((Modifier)ControlUtils.GetItemFromSourceWithPk(vm.ModifiersSource, m.Year, m.ModId)!);
}
@@ -129,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];
@@ -549,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));
@@ -640,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)
@@ -812,9 +809,6 @@ namespace Elwig.Services {
.Select(p => p.Delivery)
.Distinct()
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers)
.Include(d => d.Parts).ThenInclude(p => p.Rd)
.Include(d => d.Parts).ThenInclude(p => p.Kg!.Gl)
.AsSplitQuery()
.ToListAsync();
var wbKgs = list
.SelectMany(d => d.Parts)
@@ -957,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;
@@ -1068,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 })
@@ -1128,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) {
@@ -1149,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}]")))}";
}
}

View File

@@ -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,12 +408,12 @@ 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();
using var doc = new DeliveryConfirmation(year, m);
using var doc = new DeliveryConfirmation(year, m, null);
await Utils.ExportDocument(doc, mode, emailData: (m, $"{DeliveryConfirmation.Name} {year}", $"Im Anhang finden Sie die Anlieferungsbestätigung {year}"));
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
@@ -426,7 +426,7 @@ namespace Elwig.Services {
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
using var doc = await CreditNote.Initialize(year, avnr, m.MgNr);
using var doc = await CreditNote.Initialize(year, avnr, m.MgNr, null);
await Utils.ExportDocument(doc, mode, emailData: (m, $"{CreditNote.Name} {doc.Payment.Variant.Name}", $"Im Anhang finden Sie die Traubengutschrift {doc.Payment.Variant.Name}"));
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
@@ -509,10 +509,8 @@ namespace Elwig.Services {
try {
var members = await query
.OrderBy(m => m.MgNr)
.Include(m => m.BillingAddress)
.Include(m => m.TelephoneNumbers)
.Include(m => m.EmailAddresses)
.AsSplitQuery()
.ToListAsync();
using var exporter = new VCard(d.FileName);
await exporter.ExportAsync(members);
@@ -537,17 +535,12 @@ namespace Elwig.Services {
try {
var members = await query
.OrderBy(m => m.MgNr)
.Include(m => m.BillingAddress)
.Include(m => m.TelephoneNumbers)
.Include(m => m.EmailAddresses)
.Include(m => m.DefaultWbKg!.Gl)
.AsSplitQuery()
.ToListAsync();
var areaComs = await query
.SelectMany(m => m.AreaCommitments)
.Select(c => c.Contract).Distinct()
.Include(c => c.Rd)
.Include(c => c.Kg.Gl)
.Include(c => c.Revisions)
.ToListAsync();
var wbKgs = members
@@ -715,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();
}

View File

@@ -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();
});
}

View File

@@ -25,18 +25,13 @@ namespace Elwig.Services {
var path = Path.Combine(App.TempPath, filename);
var members = await query
.OrderBy(m => m.MgNr)
.Include(m => m.BillingAddress)
.Include(m => m.TelephoneNumbers)
.Include(m => m.EmailAddresses)
.Include(m => m.DefaultWbKg!.Gl)
.AsSplitQuery()
.ToListAsync();
var areaComs = await query
.SelectMany(m => m.AreaCommitments)
.Select(c => c.Contract).Distinct()
.OrderBy(c => c.FbNr)
.Include(c => c.Rd)
.Include(c => c.Kg.Gl)
.Include(c => c.Revisions)
.ToListAsync();
var wbKgs = members
@@ -73,10 +68,7 @@ namespace Elwig.Services {
var list = await query
.Select(p => p.Delivery)
.Distinct()
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers).ThenInclude(m => m.Modifier)
.Include(d => d.Parts).ThenInclude(p => p.Rd)
.Include(d => d.Parts).ThenInclude(p => p.Kg!.Gl)
.AsSplitQuery()
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers)
.ToListAsync();
var wbKgs = list
.SelectMany(d => d.Parts)
@@ -114,27 +106,19 @@ namespace Elwig.Services {
using (var ctx = new AppDbContext()) {
members = await ctx.Members
.Where(ChangedMembers)
.Include(m => m.BillingAddress)
.Include(m => m.TelephoneNumbers)
.Include(m => m.EmailAddresses)
.Include(m => m.DefaultWbKg!.Gl)
.OrderBy(m => m.MgNr)
.AsSplitQuery()
.ToListAsync();
areaComs = await ctx.AreaCommitmentContracts
.Where(ChangedAreaComContracts)
.Include(c => c.Rd)
.Include(c => c.Kg.Gl)
.Include(c => c.Revisions)
.OrderBy(c => c.FbNr)
.ToListAsync();
deliveries = await ctx.Deliveries
.Where(ChangedDeliveries)
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers).ThenInclude(m => m.Modifier)
.Include(d => d.Parts).ThenInclude(p => p.Rd)
.Include(d => d.Parts).ThenInclude(p => p.Kg).ThenInclude(k => k!.Gl)
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers)
.OrderBy(d => d.DateString).ThenBy(d => d.TimeString).ThenBy(d => d.LsNr)
.AsSplitQuery()
.ToListAsync();
}
var wbKgs = members
@@ -179,11 +163,8 @@ namespace Elwig.Services {
using var ctx = new AppDbContext();
var deliveries = await ctx.Deliveries
.Where(d => d.Year == year && d.ZwstId == App.ZwstId)
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers).ThenInclude(m => m.Modifier)
.Include(d => d.Parts).ThenInclude(p => p.Rd)
.Include(d => d.Parts).ThenInclude(p => p.Kg).ThenInclude(k => k!.Gl)
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers)
.OrderBy(d => d.DateString).ThenBy(d => d.TimeString).ThenBy(d => d.LsNr)
.AsSplitQuery()
.ToListAsync();
var wbKgs = deliveries
.SelectMany(d => d.Parts)
@@ -277,7 +258,7 @@ namespace Elwig.Services {
public static async Task<bool> 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;
}

View File

@@ -104,6 +104,7 @@ namespace Elwig.Windows {
cb.SelectionChanged += ComboBox_SelectionChanged;
foreach (var lb in ListBoxInputs)
lb.SelectionChanged += ComboBox_SelectionChanged;
LockInputs();
}
private void OnClosing(object? sender, CancelEventArgs evt) {
@@ -349,7 +350,6 @@ namespace Elwig.Windows {
using var ctx = new AppDbContext();
list = await ctx.PlzDestinations
.Where(p => p.Plz == plz)
.Include(p => p.Ort)
.ToListAsync();
}

View File

@@ -39,10 +39,6 @@ namespace Elwig.Windows {
ViewModel.FilterSeason = Utils.CurrentYear;
}
protected override async Task OnInit(AppDbContext ctx) {
LockInputs();
}
private void FocusSearchInput(object sender, RoutedEventArgs evt) {
if (!IsEditing && !IsCreating) {
SearchInput.Focus();
@@ -59,20 +55,9 @@ namespace Elwig.Windows {
using var ctx = new AppDbContext();
var (_, contractQuery, areaComQuery, filter) = await vm.GetFilters(ctx);
var contracts = await contractQuery
.Include(c => c.Kg.AtKg)
.Include(c => c.Rd!.Kg.AtKg)
.Include(c => c.Revisions).ThenInclude(a => a.WineCult)
.Include(c => c.Revisions).ThenInclude(a => a.AreaComType.WineAttr)
.Include(c => c.Revisions).ThenInclude(a => a.AreaComType.WineVar)
.Include(c => c.Revisions).ThenInclude(a => a.Member)
.ToListAsync();
var areaComs = await areaComQuery
.Include(c => c.Contract.Kg.AtKg)
.Include(c => c.Contract.Rd!.Kg.AtKg)
.Include(a => a.WineCult)
.Include(a => a.AreaComType.WineAttr)
.Include(a => a.AreaComType.WineVar)
.ToListAsync();
var areaComs = await areaComQuery.ToListAsync();
if (filter.Count > 0 && contracts.Count > 0) {
var dict = contracts.AsParallel()
@@ -85,7 +70,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);
@@ -174,7 +159,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;
}
@@ -191,12 +176,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<object>().ToListAsync();
ControlUtils.RenewItemsSource(MemberInput, await ctx.FetchMembers(includeNotActive: true).ToListAsync());
var cultList = await ctx.FetchWineCultivations().Cast<object>().ToListAsync();
cultList.Insert(0, new NullItem());
ControlUtils.RenewItemsSource(WineCultivationInput, cultList, null, ControlUtils.RenewSourceDefault.First);
await RefreshList();
@@ -466,17 +447,19 @@ namespace Elwig.Windows {
}
private async void ActiveAreaCommitmentInput_Changed(object sender, RoutedEventArgs evt) {
if (!HasContextLoaded) return;
await RefreshList();
}
private async void SearchInput_TextChanged(object sender, RoutedEventArgs evt) {
if (!HasContextLoaded) return;
var binding = ((TextBox)sender).GetBindingExpression(TextBox.TextProperty);
binding?.UpdateSource();
await RefreshList(true);
}
private async void SeasonInput_TextChanged(object sender, TextChangedEventArgs evt) {
if (ViewModel.FilterSeason == null) return;
if (!HasContextLoaded || ViewModel.FilterSeason == null) return;
await RefreshList();
}

View File

@@ -21,8 +21,6 @@ namespace Elwig.Windows {
private async Task AreaCommitmentTypesInitEditing(AppDbContext ctx) {
_actList = new(await ctx.AreaCommitmentTypes
.OrderBy(v => v.VtrgId)
.Include(t => t.WineVar)
.Include(t => t.WineAttr)
.ToListAsync());
_acts = _actList.ToDictionary(v => v.VtrgId, v => (string?)v.VtrgId);
_actIds = _actList.ToDictionary(v => v, v => v.VtrgId);

View File

@@ -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!.AtPlz)
.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!.AtPlz)
.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) {

View File

@@ -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 ?? 0).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 ?? 0).ToListAsync());
_modList = null;
_mods = null;
_modIds = null;

View File

@@ -19,22 +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)
.Include(s => s.Currency)
.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)
.Include(s => s.Currency)
.ToListAsync());
ControlUtils.RenewItemsSource(SeasonList, await ctx.FetchSeasons(includeModifiers: true).ToListAsync());
_seasonChanged = false;
}

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -153,44 +153,22 @@ namespace Elwig.Windows {
ParameterExportEbicsAddress.IsEnabled = true;
}
protected override async Task OnInit(AppDbContext ctx) {
LockInputs();
}
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)
.Include(s => s.Currency)
.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!.AtPlz)
.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<object>().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<object>().ToListAsync();
attrList.Insert(0, new NullItem(""));
ControlUtils.RenewItemsSource(AreaCommitmentTypeWineAttributeInput, attrList);
ControlUtils.RenewItemsSource(AreaCommitmentTypeList, await ctx.AreaCommitmentTypes
.OrderBy(t => t.VtrgId)
.Include(t => t.WineVar)
.Include(t => t.WineAttr)
.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 ?? 0).ToListAsync(), null, ControlUtils.RenewSourceDefault.First);
}
protected override void UpdateButtons() {
@@ -286,7 +264,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();
}
@@ -306,7 +284,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();
}
@@ -342,7 +320,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();
}
@@ -430,7 +408,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;

View File

@@ -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) {

View File

@@ -18,6 +18,8 @@ namespace Elwig.Windows {
}
}
protected bool HasContextLoaded { get; private set; }
private bool _renewPending = false;
private readonly RoutedCommand CtrlR = new("CtrlR", typeof(ContextWindow), [new KeyGesture(Key.R, ModifierKeys.Control)]);
@@ -30,11 +32,19 @@ namespace Elwig.Windows {
}
public async void ForceContextReload(object sender, EventArgs evt) {
await HintContextChange();
await ForceContextReload();
}
public async Task HintContextChange() {
public async Task ForceContextReload() {
HintContextChange();
await TryContextReload();
}
public void HintContextChange() {
_renewPending = true;
}
public async Task TryContextReload() {
if (LockContext) return;
await EnsureContextRenewed();
}
@@ -43,15 +53,16 @@ namespace Elwig.Windows {
Mouse.OverrideCursor = Cursors.AppStarting;
using var ctx = new AppDbContext();
await OnRenewContext(ctx);
HasContextLoaded = true;
await OnInit(ctx);
Mouse.OverrideCursor = null;
}
protected async Task EnsureContextRenewed() {
if (!_renewPending) return;
_renewPending = false;
using var ctx = new AppDbContext();
await OnRenewContext(ctx);
_renewPending = false;
}
virtual protected async Task OnInit(AppDbContext ctx) { }

View File

@@ -529,12 +529,12 @@
</Grid.ColumnDefinitions>
<Label Content="Gradation:" Margin="10,10,10,10"/>
<ctrl:UnitTextBox x:Name="GradationOeInput" Unit="°Oe" Text="{Binding GradationOeString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
TextChanged="GradationOeInput_TextChanged" KeyUp="Input_KeyUp"
TextChanged="GradationOeInput_TextChanged" LostFocus="GradationOeInput_LostFocus" KeyUp="Input_KeyUp"
Grid.Column="1" Width="54" Margin="0,10,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<Label Content="=" Margin="60,10,10,10" Grid.Column="1"/>
<ctrl:UnitTextBox x:Name="GradationKmwInput" Unit="°KMW" Text="{Binding GradationKmwString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
TextChanged="GradationKmwInput_TextChanged" KeyUp="Input_KeyUp"
TextChanged="GradationKmwInput_TextChanged" LostFocus="GradationKmwInput_LostFocus" KeyUp="Input_KeyUp"
Grid.Column="1" Width="68" Margin="78,10,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<Label Content="Qualitätsstufe:" Margin="10,40,10,10"/>

View File

@@ -37,6 +37,7 @@ namespace Elwig.Windows {
private readonly Button[] WeighingButtons;
private List<WineQualLevel> WineQualityLevels = [];
private Dictionary<int, List<Modifier>> Modifiers = [];
public DeliveryAdminWindow(bool receipt = false) {
InitializeComponent();
@@ -122,7 +123,8 @@ namespace Elwig.Windows {
Menu_Export_UploadSeason.IsEnabled = App.Config.SyncUrl != null;
}
public DeliveryAdminWindow(int mgnr) : this() {
public DeliveryAdminWindow(int mgnr) :
this() {
ViewModel.FilterMember = DeliveryService.GetMember(mgnr) ?? throw new ArgumentException("MgNr argument has invalid value");
ViewModel.Title = $"Lieferungen - {ViewModel.FilterMember.AdministrativeName} - Elwig";
ViewModel.EnableAllSeasons = true;
@@ -132,10 +134,9 @@ namespace Elwig.Windows {
await base.OnInit(ctx);
OnSecondPassed(null, null);
SecondsTimer.Start();
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);
}
@@ -428,7 +429,10 @@ namespace Elwig.Windows {
using var ctx = new AppDbContext();
var (_, deliveryQuery, deliveryPartsQuery, predicate, filter) = await vm.GetFilters(ctx);
var deliveries = await deliveryQuery
.Include(d => d.Member.EmailAddresses)
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers).ThenInclude(m => m.Modifier)
.Include(d => d.Parts).ThenInclude(p => p.Variety)
.IgnoreAutoIncludes()
.AsSplitQuery()
.ToListAsync();
deliveries.Reverse();
@@ -443,11 +447,7 @@ namespace Elwig.Windows {
.Select(a => a.Key)];
}
var filteredParts = await deliveryPartsQuery
.Include(p => p.PartModifiers).ThenInclude(p => p.Modifier)
.GroupBy(p => new { p.Year, p.DId })
.ToDictionaryAsync(g => (g.Key.Year, g.Key.DId), g => g.ToList());
deliveries.ForEach(d => { d.FilteredParts = filteredParts.GetValueOrDefault((d.Year, d.DId)) ?? []; });
deliveries.ForEach(d => { d.PartFilter = predicate; });
var deliveryPartsNum = await deliveryPartsQuery.CountAsync();
var varieties = await deliveryPartsQuery.Select(d => d.SortId).Distinct().ToListAsync();
@@ -497,7 +497,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 +506,9 @@ namespace Elwig.Windows {
Menu_Bki_SaveList.Items.Add(i);
}
var attributes = await ctx.FetchWineAttributes(!IsCreating).ToListAsync();
Modifiers = await ctx.FetchModifiers(null).GroupBy(m => m.Year).ToDictionaryAsync(g => g.Key, g => g.ToList());
var font = new FontFamily("Segoe MDL2 Assets");
Menu_BulkAction_SetAttribute.Items.Clear();
var noAttr = new MenuItem {
@@ -514,7 +517,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 +527,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.GetValueOrDefault(ViewModel.SelectedDelivery?.Year ?? year, [])) {
var i1 = new MenuItem {
Header = mod.Name,
};
@@ -538,44 +541,34 @@ 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)
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.DefaultWbKg!.AtKg)
.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<object>().ToListAsync();
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<object>().ToList();
attrList.Insert(0, new NullItem(""));
ControlUtils.RenewItemsSource(AttributeInput, attrList, null, ControlUtils.RenewSourceDefault.First);
var cultList = await ctx.WineCultivations.OrderBy(a => a.Name).Cast<object>().ToListAsync();
var cultList = await ctx.FetchWineCultivations().Cast<object>().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)
.Include(m => m.Season.Currency)
.ToListAsync());
ControlUtils.RenewItemsSource(WineOriginInput, (await ctx.WineOrigins.Include(o => o.Parent).Include(o => o.Children).ToListAsync()).OrderByDescending(o => o.SortKey).ThenBy(o => o.HkId));
ControlUtils.RenewItemsSource(ModifiersInput, Modifiers.GetValueOrDefault(year, []).Where(m => m.IsActive || !IsCreating).ToList());
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)];
ControlUtils.RenewItemsSource(WineOriginInput, origins);
var kgList = (await ctx.Katastralgemeinden
.Where(k => k.WbKg != null)
.Include(k => k.WbKg)
.Include(k => k.Gem.WbGem)
.OrderBy(k => k.Name)
.AsSplitQuery()
.ToListAsync()).Cast<object>().ToList();
kgList.Insert(0, new NullItem());
ControlUtils.RenewItemsSource(WineKgInput, kgList);
UpdateRdInput();
if (IsCreating) await UpdateLsNr();
await RefreshDeliveryParts();
RefreshInputs();
}
@@ -587,22 +580,11 @@ 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(DeliveryPartList, await ctx.DeliveryParts
.Where(p => p.Year == d.Year && p.DId == d.DId)
.OrderBy(p => p.DPNr)
.Include(p => p.PartModifiers)
.ToListAsync(), DeliveryPartList_SelectionChanged, ControlUtils.RenewSourceDefault.First);
ControlUtils.RenewItemsSource(ModifiersInput, Modifiers.GetValueOrDefault(d.Year, []).Where(m => m.IsActive || !IsCreating).ToList());
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, Modifiers.GetValueOrDefault(ViewModel.FilterSeason ?? 0, []).Where(m => m.IsActive || !IsCreating).ToList());
DeliveryPartList.ItemsSource = null;
}
}
@@ -694,17 +676,19 @@ namespace Elwig.Windows {
}
private async void SearchInput_TextChanged(object sender, RoutedEventArgs evt) {
if (!HasContextLoaded) return;
await RefreshList(true);
}
private async void SeasonInput_TextChanged(object sender, TextChangedEventArgs evt) {
if (ViewModel.FilterSeason == null || TodayOnlyInput == null || AllSeasonsInput == null) return;
if (!HasContextLoaded || ViewModel.FilterSeason == null || TodayOnlyInput == null || AllSeasonsInput == null) return;
TodayOnlyInput.IsChecked = false;
AllSeasonsInput.IsChecked = false;
await RefreshList();
}
private async void TodayOnlyInput_Changed(object sender, RoutedEventArgs evt) {
if (!HasContextLoaded) return;
if (TodayOnlyInput.IsChecked == true && AllSeasonsInput.IsChecked == false) {
ViewModel.FilterSeason = Utils.Today.Year;
ViewModel.FilterTodayOnly = true;
@@ -713,6 +697,7 @@ namespace Elwig.Windows {
}
private async void AllSeasonsInput_Changed(object sender, RoutedEventArgs evt) {
if (!HasContextLoaded) return;
if (AllSeasonsInput.IsChecked == true) {
SeasonInput.IsEnabled = false;
ViewModel.FilterSeason = null;
@@ -732,7 +717,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 {
@@ -825,11 +810,12 @@ namespace Elwig.Windows {
}
EmptyScale();
await EnsureContextRenewed();
Mouse.OverrideCursor = null;
ControlUtils.SelectItem(DeliveryList, p?.Delivery);
ControlUtils.SelectItemWithPk(DeliveryList, p?.Year, p?.DId);
DeliveryPartList.SelectedItem = null;
DeliveryPartList.ScrollIntoView(DeliveryPartList.ItemsSource.Cast<object>().Last());
DeliveryPartList.ScrollIntoView(DeliveryPartList.ItemsSource.Cast<object>().LastOrDefault());
InitialInputs();
}
@@ -862,26 +848,22 @@ namespace Elwig.Windows {
}
EmptyScale();
await EnsureContextRenewed();
if (p?.Delivery != null) {
try {
using var doc = await DeliveryNote.Initialize(p.Year, p.DId);
using (var ctx = new AppDbContext()) {
await doc.Generate(ctx);
}
if (App.Config.Debug) {
doc.Show();
} else {
await doc.Print(2);
}
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
Utils.RunBackground("Lieferschein drucken", async () => {
using var doc = await DeliveryNote.Initialize(p.Year, p.DId);
using (var ctx = new AppDbContext()) {
await doc.Generate(ctx);
}
if (App.Config.Debug) {
doc.Show();
} else {
await doc.Print(2);
}
});
await EnsureContextRenewed();
Mouse.OverrideCursor = null;
DeliveryList.SelectedItem = null;
await EnsureContextRenewed();
InitInputs();
}
@@ -893,16 +875,10 @@ namespace Elwig.Windows {
}
using var ctx = new AppDbContext();
var attrList = await ctx.WineAttributes.OrderBy(a => a.Name).Cast<object>().ToListAsync();
var attrList = await ctx.FetchWineAttributes().Cast<object>().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)
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.DefaultWbKg!.AtKg)
.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;
@@ -934,21 +910,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<object>().ToListAsync();
var attrList = await ctx.FetchWineAttributes(false).Cast<object>().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)
.Include(m => m.Season.Currency)
.ToListAsync());
ControlUtils.RenewItemsSource(MemberInput, await ctx.Members
.Where(m => m.IsActive || !ViewModel.IsReceipt)
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.DefaultWbKg!.AtKg)
.OrderBy(m => m.Name)
.ThenBy(m => m.GivenName)
.ToListAsync());
ControlUtils.RenewItemsSource(ModifiersInput, Modifiers.GetValueOrDefault(ViewModel.FilterSeason ?? 0, []).Where(m => m.IsActive).ToList());
ControlUtils.RenewItemsSource(MemberInput, await ctx.FetchMembers(includeNotActive: !ViewModel.IsReceipt, includeContactInfo: true).ToListAsync());
IsCreating = true;
DeliveryList.IsEnabled = false;
DeliveryPartList.IsEnabled = false;

View File

@@ -39,10 +39,6 @@ namespace Elwig.Windows {
ViewModel.FilterOnlyUpcoming = true;
}
protected override async Task OnInit(AppDbContext ctx) {
LockInputs();
}
private void Input_KeyUp(object sender, KeyEventArgs evt) {
if (sender is not Control ctrl) return;
if (evt.Key != Key.Enter) return;
@@ -85,7 +81,6 @@ namespace Elwig.Windows {
using var ctx = new AppDbContext();
var list = await ctx.DeliverySchedules
.Where(s => s.Year == ViewModel.FilterSeason)
.Include(s => s.Branch)
.OrderBy(s => s.DateString)
.ThenBy(s => s.Branch.Name)
.ThenBy(s => s.Description)
@@ -110,12 +105,7 @@ namespace Elwig.Windows {
var (filter, deliveryAncmts, stat) = await Task.Run(async () => {
using var ctx = new AppDbContext();
var (_, deliveryAncmtQuery, filter) = await vm.GetFilters(ctx);
var deliveryAncmts = await deliveryAncmtQuery
.Include(a => a.Member.BillingAddress)
.Include(a => a.Schedule)
.Include(a => a.Variety)
.AsSplitQuery()
.ToListAsync();
var deliveryAncmts = await deliveryAncmtQuery.ToListAsync();
if (filter.Count > 0 && deliveryAncmts.Count > 0) {
var dict = deliveryAncmts.AsParallel()
@@ -187,15 +177,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)
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.DefaultWbKg!.AtKg)
.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();
@@ -206,6 +189,7 @@ namespace Elwig.Windows {
}
private async void DeliveryScheduleList_SelectionChanged(object sender, RoutedEventArgs evt) {
if (!HasContextLoaded) return;
await RefreshList();
if (DeliveryScheduleList.SelectedItem is DeliverySchedule s) {
Menu_DeliveryAncmtList_SaveSelected.IsEnabled = !IsEditing && !IsCreating;
@@ -227,11 +211,13 @@ namespace Elwig.Windows {
}
private async void OnlyUpcomingInput_Changed(object sender, RoutedEventArgs evt) {
if (!HasContextLoaded) return;
await RefreshDeliveryScheduleList();
await RefreshList(true);
}
private async void FromAllSchedulesInput_Changed(object sender, RoutedEventArgs evt) {
if (!HasContextLoaded) return;
if (ViewModel.FilterFromAllSchedules) {
DeliveryScheduleList.SelectedItem = null;
} else if (DeliveryScheduleList.SelectedItem == null) {
@@ -241,11 +227,12 @@ namespace Elwig.Windows {
}
private async void SearchInput_TextChanged(object sender, TextChangedEventArgs evt) {
if (!HasContextLoaded) return;
await RefreshList(true);
}
private async void SeasonInput_TextChanged(object sender, TextChangedEventArgs evt) {
if (ViewModel.FilterSeason == null) return;
if (!HasContextLoaded || ViewModel.FilterSeason == null) return;
ViewModel.FilterOnlyUpcoming = false;
await RefreshDeliveryScheduleList();
await RefreshList();
@@ -284,14 +271,7 @@ namespace Elwig.Windows {
ViewModel.SelectedDeliveryAncmt = null;
using var ctx = new AppDbContext();
ControlUtils.RenewItemsSource(MemberInput, await ctx.Members
.Where(m => m.IsActive || !IsCreating)
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.DefaultWbKg!.AtKg)
.OrderBy(m => m.Name)
.ThenBy(m => m.GivenName)
.ThenBy(m => m.MgNr)
.ToListAsync());
ControlUtils.RenewItemsSource(MemberInput, await ctx.FetchMembers(includeNotActive: !IsCreating).ToListAsync());
HideNewEditDeleteButtons();
ShowSaveResetCancelButtons();
@@ -413,14 +393,7 @@ namespace Elwig.Windows {
DeliveryAncmtList.IsEnabled = true;
using var ctx = new AppDbContext();
ControlUtils.RenewItemsSource(MemberInput, await ctx.Members
.Where(m => m.IsActive || !IsCreating)
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.DefaultWbKg!.AtKg)
.OrderBy(m => m.Name)
.ThenBy(m => m.GivenName)
.ThenBy(m => m.MgNr)
.ToListAsync());
ControlUtils.RenewItemsSource(MemberInput, await ctx.FetchMembers(includeNotActive: !IsCreating).ToListAsync());
HideSaveResetCancelButtons();
ShowNewEditDeleteButtons();

View File

@@ -33,10 +33,6 @@ namespace Elwig.Windows {
ViewModel.FilterOnlyUpcoming = true;
}
protected override async Task OnInit(AppDbContext ctx) {
LockInputs();
}
private async Task RefreshList(bool updateSort = false) {
var vm = ViewModel;
var cursor = Mouse.OverrideCursor != null;
@@ -47,8 +43,6 @@ namespace Elwig.Windows {
var (_, deliveryScheduleQuery, filter) = await vm.GetFilters(ctx);
var deliverySchedules = await deliveryScheduleQuery
.Include(s => s.Varieties)
.Include(s => s.Branch)
.AsSplitQuery()
.ToListAsync();
if (filter.Count > 0 && deliverySchedules.Count > 0) {
@@ -107,14 +101,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<object>().ToListAsync();
var attrList = await ctx.FetchWineAttributes().Cast<object>().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<object>().ToListAsync();
var cultList = await ctx.FetchWineCultivations().Cast<object>().ToListAsync();
cultList.Insert(0, new NullItem("- Kein Angabe -"));
ControlUtils.RenewItemsSource(CultivationInput, cultList, null, ControlUtils.RenewSourceDefault.First);
@@ -126,15 +120,17 @@ namespace Elwig.Windows {
}
private async void OnlyUpcomingInput_Changed(object sender, RoutedEventArgs evt) {
if (!HasContextLoaded) return;
await RefreshList();
}
private async void SearchInput_TextChanged(object sender, TextChangedEventArgs evt) {
if (!HasContextLoaded) return;
await RefreshList(true);
}
private async void SeasonInput_TextChanged(object sender, TextChangedEventArgs evt) {
if (ViewModel.FilterSeason == null) return;
if (!HasContextLoaded || ViewModel.FilterSeason == null) return;
ViewModel.FilterOnlyUpcoming = false;
await RefreshList();
}

View File

@@ -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).SingleOrDefaultAsync();
var l = new List<string> {
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();
@@ -207,13 +204,8 @@ namespace Elwig.Windows {
.OrderBy(m => m.Name)
.ThenBy(m => m.GivenName)
.Include(m => m.Branch)
.Include(m => m.DefaultWbKg!.AtKg)
.Include(m => m.EmailAddresses)
.Include(m => m.TelephoneNumbers)
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.PostalDest.AtPlz!.Country)
.Include(m => m.BillingAddress!.PostalDest.AtPlz!.Ort)
.Include(m => m.BillingAddress!.PostalDest.AtPlz!.Country)
.ToListAsync(), MemberInput_SelectionChanged);
if (MemberCustomInput.SelectedItems.Count == 0) {
MemberCustomInput.SelectionChanged -= MemberInput_SelectionChanged;
@@ -373,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;
}
@@ -492,13 +484,8 @@ namespace Elwig.Windows {
}
Recipients = await query
.Include(m => m.Branch)
.Include(m => m.DefaultWbKg!.AtKg)
.Include(m => m.EmailAddresses)
.Include(m => m.TelephoneNumbers)
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.PostalDest.AtPlz!.Country)
.Include(m => m.BillingAddress!.PostalDest.AtPlz!.Ort)
.Include(m => m.BillingAddress!.PostalDest.AtPlz!.Country)
.ToListAsync();
}
UpdatePostalEmailRecipients();
@@ -703,7 +690,7 @@ namespace Elwig.Windows {
PrintButton.IsEnabled = PrintDocument != null && !hasPreviewDocs;
EmailButton.IsEnabled = EmailDocuments != null && !hasPreviewDocs && App.Config.Smtp != null;
} catch (Exception exc) {
MessageBox.Show(exc.ToString(), "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
} finally {
UnlockInputs();
GenerateButton.IsEnabled = true;
@@ -725,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();
@@ -755,6 +742,9 @@ namespace Elwig.Windows {
Member = m,
Docs = docs.SelectMany<SelectedDoc, GeneratedDoc>(doc => {
try {
App.MainDispatcher.Invoke(() => {
ProgressBar.Value = offset + 100.0 * i / 2 / totalNum;
});
if (doc.Type == DocType.Custom) {
return [new GeneratedDoc((string)doc.Details!)];
} else if (doc.Type == DocType.MemberDataSheet) {
@@ -769,14 +759,14 @@ namespace Elwig.Windows {
} else {
return [];
}
return [new GeneratedDoc(new DeliveryConfirmation(year, m, data) { Date = postalDate })];
return [new GeneratedDoc(new DeliveryConfirmation(year, m, postalDate, data) { Date = postalDate })];
} else if (doc.Type == DocType.CreditNote) {
var details = ((int, int))doc.Details!;
var year = details.Item1;
var avnr = details.Item2;
var data = cnData[(year, avnr)];
try {
return [new GeneratedDoc(new CreditNote(data.Item2[m.MgNr], data.Item3, data.Item1[m.MgNr]) { Date = postalDate })];
return [new GeneratedDoc(new CreditNote(data.Item2[m.MgNr], postalDate, data.Item3, data.Item1[m.MgNr]) { Date = postalDate })];
} catch (Exception) {
return [];
}
@@ -1007,7 +997,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;

View File

@@ -41,6 +41,7 @@ namespace Elwig.Windows {
}
protected override async Task OnInit(AppDbContext ctx) {
await base.OnInit(ctx);
if (Utils.HasInternetConnectivity()) {
CheckSync(200);
}
@@ -404,7 +405,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 +469,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 +502,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 +511,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 +537,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 +568,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();

View File

@@ -83,11 +83,8 @@ namespace Elwig.Windows {
Menu_Export_UploadFilters.IsEnabled = App.Config.SyncUrl != null;
Menu_Export_UploadAll.IsEnabled = App.Config.SyncUrl != null;
ViewModel.ShowOnlyActiveMembers = true;
}
protected override async Task OnInit(AppDbContext ctx) {
UpdateContactInfoVisibility();
LockInputs();
}
public void FocusMember(int mgnr) {
@@ -121,14 +118,9 @@ namespace Elwig.Windows {
using var ctx = new AppDbContext();
var (_, memberQuery, filter) = await vm.GetFilters(ctx);
var members = await memberQuery
.Include(m => m.Branch)
.Include(m => m.DefaultWbKg!.AtKg)
.Include(m => m.EmailAddresses)
.Include(m => m.TelephoneNumbers)
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.PostalDest.AtPlz!.Country)
.Include(m => m.BillingAddress!.PostalDest.AtPlz!.Ort)
.Include(m => m.BillingAddress!.PostalDest.AtPlz!.Country)
.AsSplitQuery()
.ToListAsync();
if (filter.Count > 0 && members.Count > 0) {
@@ -195,7 +187,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");
@@ -339,7 +331,7 @@ namespace Elwig.Windows {
}
private async void ActiveMemberInput_Changed(object sender, RoutedEventArgs evt) {
if (!IsInitialized) return;
if (!HasContextLoaded) return;
await RefreshList();
}
@@ -396,10 +388,9 @@ namespace Elwig.Windows {
int areaComs = 0, deliveries = 0, credits = 0;
using (var ctx = new AppDbContext()) {
var l = (await ctx.Members.FindAsync(m.MgNr))!;
areaComs = l.AreaCommitments.Count;
deliveries = l.Deliveries.Count;
credits = l.Credits.Count;
areaComs = await ctx.AreaCommitments.Where(c => c.MgNr == m.MgNr).CountAsync();
deliveries = await ctx.Deliveries.Where(d => d.MgNr == m.MgNr).CountAsync();
credits = await ctx.Credits.Where(c => c.MgNr == m.MgNr).CountAsync();
}
var d = new DeleteMemberDialog(m.MgNr, m.AdministrativeName, areaComs, deliveries, credits);
if (d.ShowDialog() == true) {
@@ -496,6 +487,7 @@ namespace Elwig.Windows {
}
private async void SearchInput_TextChanged(object sender, RoutedEventArgs evt) {
if (!HasContextLoaded) return;
await RefreshList(true);
}
@@ -801,7 +793,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) ? " " : "")}" +

View File

@@ -21,12 +21,11 @@ namespace Elwig.Windows {
}
protected override async Task OnRenewContext(AppDbContext ctx) {
var origins = (await ctx.WineOrigins
.Include("Gems.AtGem.Kgs.WbKg.Gl")
.AsSplitQuery()
.ToListAsync())
.OrderByDescending(o => o.SortKey)
.ThenBy(o => o.HkId);
var origins = await ctx.WineOrigins
.Include(o => o.Gems).ThenInclude(g => g.AtGem.Kgs).ThenInclude(k => k.WbKg!.Gl)
.ToListAsync();
origins.ForEach(o => { origins.FirstOrDefault(p => p.HkId == o.ParentHkId)?.Children.Add(o); });
origins = [.. origins.OrderByDescending(o => o.SortKey).ThenBy(o => o.HkId)];
ControlUtils.RenewItemsSource(WineOrigins, origins, WineOrigins_SelectionChanged);
if (WineOrigins.SelectedItem == null) {
var hkid = await ctx.WbKgs
@@ -39,8 +38,7 @@ namespace Elwig.Windows {
}
var gls = await ctx.WbGls
.OrderBy(g => g.GlNr)
.Include("Kgs.Rds")
.AsSplitQuery()
.Include(g => g.Kgs).ThenInclude(k => k.Rds)
.ToListAsync();
ControlUtils.RenewItemsSource(WbGls, gls, WbGls_SelectionChanged, ControlUtils.RenewSourceDefault.First);
UpdateWbGems();
@@ -214,7 +212,7 @@ namespace Elwig.Windows {
App.HintContextChange();
ControlUtils.SelectItemWithPk(WbKgs, k.KgNr);
} catch (Exception exc) {
await HintContextChange();
await ForceContextReload();
var str = "Der Eintrag konnte nicht aus der Datenbank gelöscht werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Katastralgemeinde deaktivieren", MessageBoxButton.OK, MessageBoxImage.Error);

View File

@@ -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();

View File

@@ -48,7 +48,6 @@ namespace Elwig.Windows {
ControlUtils.RenewItemsSource(PaymentVariantList, await ctx.PaymentVariants
.Where(v => v.Year == Year)
.OrderBy(v => v.AvNr)
.Include(v => v.Season.Currency)
.ToListAsync());
if (PaymentVariantList.SelectedItem == null && PaymentVariantList.Items.Count > 0) {
PaymentVariantList.SelectedIndex = PaymentVariantList.Items.Count - 1;
@@ -256,13 +255,13 @@ namespace Elwig.Windows {
await ViewModel.UpdatePaymentVariant(v.Year, v.AvNr);
App.HintContextChange();
} catch (Exception exc) {
await HintContextChange();
await ForceContextReload();
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Auszahlungsvariante aktualisieren", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = null;
await HintContextChange();
await EnsureContextRenewed();
CommentInput_TextChanged(null, null);
DateInput_TextChanged(null, null);
TransferDateInput_TextChanged(null, null);

View File

@@ -1,4 +1,4 @@
<Project Sdk="WixToolset.Sdk/6">
<Project Sdk="WixToolset.Sdk/7">
<PropertyGroup>
<HarvestFileSuppressUniqueIds>false</HarvestFileSuppressUniqueIds>
<HarvestFileGenerateGuidsNow>true</HarvestFileGenerateGuidsNow>
@@ -11,6 +11,7 @@
<BuildProjectReferences>False</BuildProjectReferences>
<OutputName>Elwig</OutputName>
<Cultures>de-AT</Cultures>
<AcceptEula>wix7</AcceptEula>
</PropertyGroup>
<UsingTask TaskName="GetFileVersion" TaskFactory="RoslynCodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll">
<ParameterGroup>

View File

@@ -13,7 +13,7 @@ About
**Product:** Elwig
**Description:** Electronic Management for Vintners' Cooperatives
**Type:** ERP system
**Version:** 1.0.4.1 ([Changelog](./CHANGELOG.md))
**Version:** 1.0.5.1 ([Changelog](./CHANGELOG.md))
**License:** [GNU General Public License 3.0 (GPLv3)](./LICENSE)
**Website:** https://elwig.at/
**Source code:** https://git.necronda.net/winzer/elwig
@@ -33,7 +33,7 @@ Packaging: [WiX Toolset](https://www.firegiant.com/wixtoolset/)
**Produkt:** Elwig
**Beschreibung:** Elektronische Winzergenossenschaftsverwaltung
**Typ:** Warenwirtschaftssystem (ERP-System)
**Version:** 1.0.4.1 ([Änderungsprotokoll](./CHANGELOG.md))
**Version:** 1.0.5.1 ([Änderungsprotokoll](./CHANGELOG.md))
**Lizenz:** [GNU General Public License 3.0 (GPLv3)](./LICENSE)
**Website:** https://elwig.at/
**Quellcode:** https://git.necronda.net/winzer/elwig

View File

@@ -1,8 +1,9 @@
<Project Sdk="WixToolset.Sdk/6">
<Project Sdk="WixToolset.Sdk/7">
<PropertyGroup>
<OutputType>Bundle</OutputType>
<OutputName>Elwig</OutputName>
<Cultures>de-AT</Cultures>
<AcceptEula>wix7</AcceptEula>
</PropertyGroup>
<Target Name="CustomBeforeBuild" BeforeTargets="BeforeBuild">
<Exec Command="curl --fail -s -L &quot;https://go.microsoft.com/fwlink/p/?LinkId=2124703&quot; -z &quot;$(ProjectDir)\Files\MicrosoftEdgeWebview2Setup.exe&quot; -o &quot;$(ProjectDir)\Files\MicrosoftEdgeWebview2Setup.exe&quot;" />
@@ -13,7 +14,7 @@
</Target>
<ItemGroup>
<ProjectReference Include="..\Installer\Installer.wixproj" />
<PackageReference Include="WixToolset.Bal.wixext" Version="6.0.2" />
<PackageReference Include="WixToolset.Util.wixext" Version="6.0.2" />
<PackageReference Include="WixToolset.Bal.wixext" Version="7.0.0" />
<PackageReference Include="WixToolset.Util.wixext" Version="7.0.0" />
</ItemGroup>
</Project>

View File

@@ -80,6 +80,7 @@ namespace Tests.E2ETests {
Window.FindElement(By.WpfId("SaveButton")).Click();
Thread.Sleep(500);
Window.FindElement(By.WpfId("SearchInput")).SendKeys("9999");
Thread.Sleep(500);
var memberListRow = Window.FindElement(By.WpfId("MemberList")).FindElement(By.ClassName("DataGridRow"));

View File

@@ -19,7 +19,7 @@
</Target>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.3.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.4.0" />
<PackageReference Include="Appium.WebDriver" Version="4.4.5" />
<PackageReference Include="NReco.PdfRenderer" Version="1.6.0" />
<PackageReference Include="NUnit" Version="4.5.1" />
@@ -28,7 +28,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="8.0.1">
<PackageReference Include="coverlet.collector" Version="10.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

@@ -6,7 +6,7 @@ namespace Tests.UnitTests.DocumentTests {
[Test]
public async Task Test_01_VirtualCreditNote() {
using var doc = await CreditNote.Initialize(2020, 1, 101);
using var doc = await CreditNote.Initialize(2020, 1, 101, null);
var text = await Utils.GeneratePdfText(doc);
Assert.Multiple(() => {
Assert.That(text, Contains.Substring("""

View File

@@ -9,9 +9,9 @@ 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);
using var doc = new DeliveryConfirmation(2020, m!, null, data);
var text = await Utils.GeneratePdfText(doc);
Assert.Multiple(() => {
Assert.That(text, Contains.Substring("""

View File

@@ -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(() => {

View File

@@ -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(() => {

View File

@@ -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)));

View File

@@ -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<object> attrs = (await ctx.WineAttributes.ToListAsync()).Cast<object>().ToList();
vm.MemberSource = await ctx.FetchMembers(includeNotActive: true).ToListAsync();
vm.BranchSource = await ctx.FetchBranches().ToListAsync();
vm.WineVarSource = await ctx.FetchWineVarieties().ToListAsync();
List<object> attrs = await ctx.FetchWineAttributes().Cast<object>().ToListAsync();
attrs.Insert(0, new NullItem());
vm.WineAttrSource = attrs;
List<object> cults = (await ctx.WineCultivations.ToListAsync()).Cast<object>().ToList();
List<object> cults = await ctx.FetchWineCultivations().Cast<object>().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<Delivery?> GetDelivery(string lsnr) {
@@ -32,7 +32,6 @@ namespace Tests.UnitTests.ServiceTests {
.Include(d => d.Parts)
.ThenInclude(p => p.PartModifiers)
.ThenInclude(m => m.Modifier)
.AsSplitQuery()
.FirstOrDefaultAsync();
}

View File

@@ -10,10 +10,10 @@ 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.Include(p => p.Ort).ToListAsync();
vm.BillingOrtSource = await ctx.PlzDestinations.Include(p => p.Ort).ToListAsync();
vm.OrtSource = await ctx.PlzDestinations.ToListAsync();
vm.BillingOrtSource = await ctx.PlzDestinations.ToListAsync();
}
[Test]
@@ -31,22 +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;
Member m;
using (var ctx = new AppDbContext()) {
m = await ctx.Members
.Where(m => m.MgNr == vm.MgNr)
.Include(m => m.BillingAddress!.PostalDest.AtPlz!.Ort)
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.DefaultWbKg!.AtKg)
.Include(m => m.EmailAddresses)
.Include(m => m.TelephoneNumbers)
.AsSplitQuery()
.FirstOrDefaultAsync();
m = await ctx.FetchMembers(vm.MgNr, includeNotActive: true, includeContactInfo: true).SingleAsync();
}
Assert.That(m, Is.Not.Null);
@@ -119,22 +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;
Member m;
using (var ctx = new AppDbContext()) {
m = await ctx.Members
.Where(m => m.MgNr == vm.MgNr)
.Include(m => m.BillingAddress!.PostalDest.AtPlz!.Ort)
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.DefaultWbKg!.AtKg)
.Include(m => m.EmailAddresses)
.Include(m => m.TelephoneNumbers)
.AsSplitQuery()
.FirstOrDefaultAsync();
m = await ctx.FetchMembers(vm.MgNr, includeNotActive: true, includeContactInfo: true).SingleAsync();
}
Assert.That(m, Is.Not.Null);
@@ -234,15 +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.BillingAddress!.PostalDest.AtPlz!.Ort)
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.DefaultWbKg!.AtKg)
.Include(m => m.EmailAddresses)
.Include(m => m.TelephoneNumbers)
.AsSplitQuery()
.FirstAsync());
vm.FillInputs(await ctx.FetchMembers(202, includeNotActive: true, includeContactInfo: true).SingleAsync());
}
Assert.That(vm.IsActive, Is.True);
@@ -253,17 +229,9 @@ namespace Tests.UnitTests.ServiceTests {
Assert.DoesNotThrowAsync(async () => await vm.UpdateMember(202));
Member? m;
Member m;
using (var ctx = new AppDbContext()) {
m = await ctx.Members
.Where(m => m.MgNr == 202)
.Include(m => m.BillingAddress!.PostalDest.AtPlz!.Ort)
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.DefaultWbKg!.AtKg)
.Include(m => m.EmailAddresses)
.Include(m => m.TelephoneNumbers)
.AsSplitQuery()
.FirstOrDefaultAsync();
m = await ctx.FetchMembers(202, includeNotActive: true, includeContactInfo: true).SingleAsync();
}
Assert.That(m, Is.Not.Null);
@@ -286,15 +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.BillingAddress!.PostalDest.AtPlz!.Ort)
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.DefaultWbKg!.AtKg)
.Include(m => m.EmailAddresses)
.Include(m => m.TelephoneNumbers)
.AsSplitQuery()
.FirstAsync());
vm.FillInputs(await ctx.FetchMembers(203, includeNotActive: true, includeContactInfo: true).SingleAsync());
}
Assert.Multiple(() => {
@@ -306,17 +266,9 @@ namespace Tests.UnitTests.ServiceTests {
vm.MgNr = 210;
Assert.DoesNotThrowAsync(async () => await vm.UpdateMember(203));
Member? m;
Member m;
using (var ctx = new AppDbContext()) {
m = await ctx.Members
.Where(m => m.MgNr == 210)
.Include(m => m.BillingAddress!.PostalDest.AtPlz!.Ort)
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.DefaultWbKg!.AtKg)
.Include(m => m.EmailAddresses)
.Include(m => m.TelephoneNumbers)
.AsSplitQuery()
.FirstOrDefaultAsync();
m = await ctx.FetchMembers(210, includeNotActive: true, includeContactInfo: true).SingleAsync();
}
Assert.That(m, Is.Not.Null);
@@ -334,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<DbUpdateException>(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);
}
}
}

View File

@@ -1 +1 @@
curl --fail -s -L "https://elwig.at/files/create.sql?v=38" -u "elwig:ganzGeheim123!" -o "Resources\Sql\Create.sql"
curl --fail -s -L "https://elwig.at/files/create.sql?v=39" -u "elwig:ganzGeheim123!" -o "Resources\Sql\Create.sql"