Compare commits

...

15 Commits

Author SHA1 Message Date
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
e593175e72 ContextWindow: Use Task.Run to load data outside main thread
All checks were successful
Test / Run tests (push) Successful in 2m29s
2026-04-02 14:18:06 +02:00
95 changed files with 2039 additions and 1301 deletions

View File

@@ -23,6 +23,16 @@ jobs:
echo "No files with BOM found" echo "No files with BOM found"
exit 0 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 - name: Setup MSBuild
uses: microsoft/setup-msbuild@v1.1 uses: microsoft/setup-msbuild@v1.1
- name: Setup NuGet - name: Setup NuGet

View File

@@ -2,6 +2,26 @@
Changelog Changelog
========= =========
[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. (e5e5e10cd7)
* 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} [v1.0.4.1][v1.0.4.1] (2026-03-27) {#v1.0.4.1}
--------------------------------------------- ---------------------------------------------

View File

@@ -6,6 +6,7 @@ using Elwig.Helpers.Printing;
using Elwig.Helpers.Weighing; using Elwig.Helpers.Weighing;
using Elwig.Models.Entities; using Elwig.Models.Entities;
using Elwig.Windows; using Elwig.Windows;
using Microsoft.EntityFrameworkCore;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data; using System.Data;
@@ -104,7 +105,9 @@ namespace Elwig {
Dictionary<string, (string, string, int?, string?, string?, string?, string?, string?)> branches = []; Dictionary<string, (string, string, int?, string?, string?, string?, string?, string?)> branches = [];
using (var ctx = new AppDbContext()) { using (var ctx = new AppDbContext()) {
branches = ctx.Branches.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 { try {
Client = new(ctx); Client = new(ctx);
} catch (Exception e) { } catch (Exception e) {
@@ -218,7 +221,8 @@ namespace Elwig {
MainDispatcher.Invoke(() => { MainDispatcher.Invoke(() => {
foreach (Window w in CurrentApp.Windows) { foreach (Window w in CurrentApp.Windows) {
if (w is not ContextWindow c) continue; if (w is not ContextWindow c) continue;
MainDispatcher.BeginInvoke(c.HintContextChange); MainDispatcher.Invoke(c.HintContextChange);
MainDispatcher.BeginInvoke(c.TryContextReload);
} }
}); });
} }

View File

@@ -41,13 +41,21 @@ namespace Elwig.Controls {
incButton!.Click += IncrementButton_Click; incButton!.Click += IncrementButton_Click;
decButton!.Click += DecrementButton_Click; decButton!.Click += DecrementButton_Click;
base.OnApplyTemplate(); base.OnApplyTemplate();
UpdateButtons();
}
private void UpdateButtons() {
var incButton = GetTemplateChild("IncrementButton") as RepeatButton;
var decButton = GetTemplateChild("DecrementButton") as RepeatButton;
incButton?.IsEnabled = Maximum == null || Value < Maximum;
decButton?.IsEnabled = Minimum == null || Value > Minimum;
} }
private void IntegerUpDown_TextChanged(object sender, TextChangedEventArgs evt) { private void IntegerUpDown_TextChanged(object sender, TextChangedEventArgs evt) {
var idx = CaretIndex; var idx = CaretIndex;
Text = new string(Text.Where(char.IsAsciiDigit).Take(4).ToArray()); Text = new string([.. Text.Where(char.IsAsciiDigit).Take(4)]);
CaretIndex = idx; CaretIndex = idx;
evt.Handled = !(Value >= Minimum && Value <= Maximum); evt.Handled = !((!Minimum.HasValue || Value >= Minimum) && (!Maximum.HasValue || Value <= Maximum));
if (idx >= 4) { if (idx >= 4) {
if (Value < Minimum) { if (Value < Minimum) {
Value = Minimum; Value = Minimum;
@@ -56,6 +64,7 @@ namespace Elwig.Controls {
} }
CaretIndex = 4; CaretIndex = 4;
} }
UpdateButtons();
} }
private void IntegerUpDown_LostFocus(object sender, RoutedEventArgs evt) { private void IntegerUpDown_LostFocus(object sender, RoutedEventArgs evt) {

View File

@@ -1,4 +1,5 @@
using Elwig.Helpers; using Elwig.Helpers;
using System;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
@@ -12,23 +13,27 @@ namespace Elwig.Dialogs {
public string OrigYearTo { get; set; } public string OrigYearTo { get; set; }
public string Area { get; set; } public string Area { get; set; }
public AreaComModifyDialog(int? yearFrom, int? yearTo, int area, bool delete) { public AreaComModifyDialog(int? yearFrom, int? yearTo, int area, bool delete, bool forceRetroactive = false) {
Area = $"{area:N0}"; Area = $"{area:N0}";
OrigYearFrom = $"{yearFrom}"; OrigYearFrom = $"{yearFrom}";
OrigYearTo = $"{yearTo}"; OrigYearTo = $"{yearTo}";
InitializeComponent(); InitializeComponent();
Title = delete ? "Flächenbindung löschen" : "Flächenbindung bearbeiten"; Title = delete ? "Flächenbindung löschen" : "Flächenbindung bearbeiten";
RetroactiveInput.Content = delete ? "Rückwirkend löschen" : "Rückwirkend bearbeiten"; RetroactiveInput.Content = delete ? "Rückwirkend löschen" : "Rückwirkend bearbeiten";
forceRetroactive = forceRetroactive || yearFrom.HasValue && yearTo.HasValue && yearFrom.Value == yearTo.Value;
RetroactiveInput.IsEnabled = !forceRetroactive;
if (delete) { if (delete) {
QuestionBlock1.Visibility = Visibility.Hidden; QuestionBlock1.Visibility = Visibility.Hidden;
QuestionBlock2.Visibility = Visibility.Visible; QuestionBlock2.Visibility = Visibility.Visible;
DescBlock1.Visibility = Visibility.Hidden; DescBlock1.Visibility = Visibility.Hidden;
DescBlock2.Visibility = Visibility.Visible; DescBlock2.Visibility = Visibility.Visible;
} }
if ((yearTo.HasValue && yearTo < Utils.CurrentNextSeason) || (yearFrom.HasValue && yearFrom >= Utils.CurrentNextSeason)) { SeasonInput.Minimum = yearFrom.HasValue ? yearFrom + 1 : null;
SeasonInput.Maximum = yearTo.HasValue ? yearTo : null;
if (forceRetroactive || (yearTo.HasValue && yearTo < Utils.CurrentYear) || (yearFrom.HasValue && yearFrom >= Utils.CurrentYear)) {
RetroactiveInput.IsChecked = true; RetroactiveInput.IsChecked = true;
} else { } else {
SeasonInput.Text = $"{Utils.CurrentNextSeason}"; SeasonInput.Text = $"{Utils.CurrentYear}";
} }
} }
@@ -48,7 +53,7 @@ namespace Elwig.Dialogs {
DescBlock2.Visibility = Visibility.Hidden; DescBlock2.Visibility = Visibility.Hidden;
} else { } else {
SeasonInput.IsEnabled = true; SeasonInput.IsEnabled = true;
SeasonInput.Text = $"{Utils.CurrentNextSeason}"; SeasonInput.Text = $"{Math.Max(SeasonInput.Minimum ?? Utils.CurrentYear, Utils.CurrentYear)}";
DescBlock1.Visibility = QuestionBlock1.Visibility; DescBlock1.Visibility = QuestionBlock1.Visibility;
DescBlock2.Visibility = QuestionBlock2.Visibility; DescBlock2.Visibility = QuestionBlock2.Visibility;
} }

View File

@@ -8,7 +8,7 @@
ResizeMode="NoResize" ShowInTaskbar="False" Topmost="True" ResizeMode="NoResize" ShowInTaskbar="False" Topmost="True"
WindowStartupLocation="CenterOwner" WindowStartupLocation="CenterOwner"
DataContext="{Binding RelativeSource={RelativeSource Self}}" DataContext="{Binding RelativeSource={RelativeSource Self}}"
Title="Flächenbindungen übertragen" Height="260" Width="450"> Title="Flächenbindungen übertragen" Height="240" Width="450">
<Window.Resources> <Window.Resources>
<Style TargetType="Label"> <Style TargetType="Label">
<Setter Property="HorizontalAlignment" Value="Left"/> <Setter Property="HorizontalAlignment" Value="Left"/>
@@ -48,12 +48,8 @@
Minimum="1900" Maximum="9999" Minimum="1900" Maximum="9999"
HorizontalAlignment="Center" VerticalAlignment="Top" HorizontalAlignment="Center" VerticalAlignment="Top"
TextChanged="SeasonInput_TextChanged"/> TextChanged="SeasonInput_TextChanged"/>
<CheckBox x:Name="CopyYearToInput" Content="Beginn der Laufzeit von Vorgänger übernehmen" Margin="0,80,0,0"
HorizontalAlignment="Center" VerticalAlignment="Top"
Checked="CopyYearToInput_Changed" Unchecked="CopyYearToInput_Changed"
IsChecked="{Binding MaintainYearFrom}"/>
<TextBlock x:Name="DescBlock1" Margin="0,105,0,0" TextAlignment="Center" <TextBlock x:Name="DescBlock1" Margin="0,90,0,0" TextAlignment="Center"
HorizontalAlignment="Center" VerticalAlignment="Top"> HorizontalAlignment="Center" VerticalAlignment="Top">
Die Flächenbindungen beim <Bold>Vorgänger</Bold> sind bis inkl. Saison <Bold><Run x:Name="CancelSeason1"/></Bold> gültig,<LineBreak/> Die Flächenbindungen beim <Bold>Vorgänger</Bold> sind bis inkl. Saison <Bold><Run x:Name="CancelSeason1"/></Bold> gültig,<LineBreak/>
und werden beim <Bold>Nachfolger</Bold> ab <Run x:Name="DescBlock1Season" Text="inkl. Saison "/><Bold><Run x:Name="TransferSeason"/></Bold> übernommen. und werden beim <Bold>Nachfolger</Bold> ab <Run x:Name="DescBlock1Season" Text="inkl. Saison "/><Bold><Run x:Name="TransferSeason"/></Bold> übernommen.

View File

@@ -5,51 +5,51 @@ using System.Windows.Controls;
namespace Elwig.Dialogs { namespace Elwig.Dialogs {
public partial class AreaComTransferDialog : Window { public partial class AreaComTransferDialog : Window {
public int CancelSeason { get; set; } public int CancelSeason => SuccessorSeason - 1;
public int SuccessorSeason => CancelSeason + 1; public int SuccessorSeason { get; set; }
public bool MaintainYearFrom { get; set; }
public string AreaComNum { get; set; } public string AreaComNum { get; set; }
public string Area { get; set; } public string Area { get; set; }
public AreaComTransferDialog(string name, int areaComNum, int area) { public AreaComTransferDialog(string name, int areaComNum, int area) {
CancelSeason = Utils.FollowingSeason - 1; SuccessorSeason = Utils.FollowingSeason;
AreaComNum = $"{areaComNum:N0}"; AreaComNum = $"{areaComNum:N0}";
Area = $"{area:N0}"; Area = $"{area:N0}";
InitializeComponent(); InitializeComponent();
SeasonInput.Text = $"{CancelSeason}"; SeasonInput.Text = $"{SuccessorSeason}";
SeasonInput.Minimum = Utils.CurrentLastSeason;
Title = $"Aktive Flächenbindungen kündigen - {name}"; Title = $"Aktive Flächenbindungen kündigen - {name}";
QuestionBlock1.Visibility = Visibility.Hidden; QuestionBlock1.Visibility = Visibility.Hidden;
QuestionBlock2.Visibility = Visibility.Visible; QuestionBlock2.Visibility = Visibility.Visible;
DescBlock1.Visibility = Visibility.Hidden; DescBlock1.Visibility = Visibility.Hidden;
DescBlock2.Visibility = Visibility.Visible; DescBlock2.Visibility = Visibility.Visible;
CopyYearToInput.Visibility = Visibility.Hidden;
Height = 240; Height = 240;
SeasonInput.Margin = new(0, 40, 0, 0); SeasonInput.Margin = new(0, 40, 0, 0);
SeasonLabel.Margin = new(0, 40, 100, 0); SeasonLabel.Margin = new(0, 40, 100, 0);
} }
public AreaComTransferDialog(string name, string successorName, int areaComNum, int area) { public AreaComTransferDialog(string name, string successorName, int areaComNum, int area) {
CancelSeason = Utils.FollowingSeason - 1; SuccessorSeason = Utils.FollowingSeason;
AreaComNum = $"{areaComNum:N0}"; AreaComNum = $"{areaComNum:N0}";
Area = $"{area:N0}"; Area = $"{area:N0}";
InitializeComponent(); InitializeComponent();
SeasonInput.Text = $"{CancelSeason}"; SeasonInput.Text = $"{SuccessorSeason}";
SeasonInput.Minimum = Utils.CurrentLastSeason;
Title = $"Aktive Flächenbindungen übertragen - {name} - {successorName}"; Title = $"Aktive Flächenbindungen übertragen - {name} - {successorName}";
InfoBlock.Visibility = Visibility.Hidden; InfoBlock.Visibility = Visibility.Hidden;
} }
private void SeasonInput_TextChanged(object sender, TextChangedEventArgs evt) { private void SeasonInput_TextChanged(object sender, TextChangedEventArgs evt) {
CancelSeason = (int)SeasonInput.Value!; SuccessorSeason = (int)SeasonInput.Value!;
CancelSeason1.Text = $"{CancelSeason}"; CancelSeason1.Text = $"{CancelSeason}";
CancelSeason2.Text = $"{CancelSeason}"; CancelSeason2.Text = $"{CancelSeason}";
TransferSeason.Text = MaintainYearFrom ? "" : $"{SuccessorSeason}"; TransferSeason.Text = $"{SuccessorSeason}";
DescBlock1Season.Text = MaintainYearFrom ? "dem originalen Beginn der FB" : "inkl. Saison "; DescBlock1Season.Text = "inkl. Saison ";
} }
private void CopyYearToInput_Changed(object sender, RoutedEventArgs evt) { private void CopyYearToInput_Changed(object sender, RoutedEventArgs evt) {
TransferSeason.Text = MaintainYearFrom ? "" : $"{SuccessorSeason}"; TransferSeason.Text = $"{SuccessorSeason}";
DescBlock1Season.Text = MaintainYearFrom ? "dem originalen Beginn der FB" : "inkl. Saison "; DescBlock1Season.Text = "inkl. Saison ";
} }
private void ConfirmButton_Click(object sender, RoutedEventArgs evt) { private void ConfirmButton_Click(object sender, RoutedEventArgs evt) {

View File

@@ -44,15 +44,10 @@ namespace Elwig.Dialogs {
} }
protected override async Task OnRenewContext(AppDbContext ctx) { protected override async Task OnRenewContext(AppDbContext ctx) {
ControlUtils.RenewItemsSource(MemberInput, await ctx.Members ControlUtils.RenewItemsSource(MemberInput, await ctx.FetchMembers().ToListAsync());
.Where(m => m.IsActive)
.OrderBy(m => m.Name)
.ThenBy(m => m.GivenName)
.ToListAsync());
ControlUtils.RenewItemsSource(DeliveryInput, await ctx.Deliveries ControlUtils.RenewItemsSource(DeliveryInput, await ctx.Deliveries
.Where(d => d.DateString == $"{_delivery.Date:yyyy-MM-dd}" && d.ZwstId == _delivery.ZwstId) .Where(d => d.DateString == $"{_delivery.Date:yyyy-MM-dd}" && d.ZwstId == _delivery.ZwstId)
.OrderBy(d => d.LsNr) .OrderBy(d => d.LsNr)
.Include(d => d.Member)
.Include(d => d.Parts) .Include(d => d.Parts)
.ToListAsync()); .ToListAsync());
if (DeliveryInput.SelectedItem == null) if (DeliveryInput.SelectedItem == null)

View File

@@ -22,6 +22,7 @@ namespace Elwig.Documents {
public bool IncludeSender = false; public bool IncludeSender = false;
public bool UseBillingAddress = false; public bool UseBillingAddress = false;
public bool ShowDateAndLocation = false; public bool ShowDateAndLocation = false;
public DateOnly? DateFrom;
protected Table? Aside; protected Table? Aside;
public string Address { public string Address {
@@ -47,11 +48,12 @@ namespace Elwig.Documents {
return NewAsideCell(new KernedParagraph(text, 10), colspan, isName); 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) { base(title) {
Member = m; Member = m;
Location = App.BranchLocation; Location = App.BranchLocation;
IncludeSender = includeSender; IncludeSender = includeSender;
DateFrom = dateFrom;
} }
protected override void BeforeRenderBody(iText.Layout.Document doc, PdfDocument pdf) { 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)); doc.Add(new KernedParagraph(Title, 12).SetFont(BF).SetMargins(0, 0, 12, 0));
} }
@@ -261,7 +263,7 @@ namespace Elwig.Documents {
} }
protected Table NewBucketTable( protected Table NewBucketTable(
Season season, Dictionary<string, MemberBucket> buckets, Season season, Dictionary<string, MemberBucket> buckets, int deliveredWeight,
bool includeDelivery = true, bool includePayment = false, bool includeDelivery = true, bool includePayment = false,
bool isTiny = false, IEnumerable<string>? filter = null bool isTiny = false, IEnumerable<string>? filter = null
) { ) {
@@ -315,10 +317,8 @@ namespace Elwig.Documents {
.OrderBy(b => b.Value.Name); .OrderBy(b => b.Value.Name);
tbl.AddCell(NewBucketTh("Gesamtlieferung lt. gez. GA", isTiny: isTiny)); tbl.AddCell(NewBucketTh("Gesamtlieferung lt. gez. GA", isTiny: isTiny));
tbl.AddCells(FormatRow(Member.BusinessShares * season.MinKgPerBusinessShare, tbl.AddCells(FormatRow(Member.BusinessShares * season.MinKgPerBusinessShare, Member.BusinessShares * season.MaxKgPerBusinessShare,
Member.BusinessShares * season.MaxKgPerBusinessShare, deliveredWeight, isGa: true, showPayment: includePayment, showArea: !includeDelivery, isTiny: isTiny));
season.Deliveries.Where(d => d.MgNr == Member.MgNr).Sum(d => d.Weight),
isGa: true, showPayment: includePayment, showArea: !includeDelivery, isTiny: isTiny));
if (fbs.Any()) { if (fbs.Any()) {
tbl.AddCell(NewBucketSubHdr("Flächenbindungen" + (vtr.Any() ? " (inkl. Verträge)" : "") + ":", includePayment ? 8 : 7, isTiny: isTiny)); tbl.AddCell(NewBucketSubHdr("Flächenbindungen" + (vtr.Any() ? " (inkl. Verträge)" : "") + ":", includePayment ? 8 : 7, isTiny: isTiny));

View File

@@ -1,55 +1,82 @@
using Elwig.Helpers; using Elwig.Helpers;
using Elwig.Helpers.Billing;
using Elwig.Models.Dtos; using Elwig.Models.Dtos;
using Elwig.Models.Entities; using Elwig.Models.Entities;
using iText.Kernel.Pdf; using iText.Kernel.Pdf;
using iText.Layout.Borders; using iText.Layout.Borders;
using iText.Layout.Element; using iText.Layout.Element;
using iText.Layout.Properties; using iText.Layout.Properties;
using Microsoft.EntityFrameworkCore;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
namespace Elwig.Documents { namespace Elwig.Documents {
public class CreditNote : BusinessDocument { public class CreditNote : BusinessDocument {
public new static string Name => "Traubengutschrift"; public new static string Name => "Traubengutschrift";
public PaymentMember? Payment; public PaymentMember Payment;
public Credit? Credit; public Credit? Credit;
public CreditNoteDeliveryData Data;
public string? Text; public string? Text;
public string CurrencySymbol; public string CurrencySymbol;
public int Precision; public int Precision;
public string MemberModifier; public string? MemberModifier;
public List<(string Name, int Kg, decimal Amount)>? MemberUnderDeliveries; public List<(string Name, int Kg, decimal Amount)>? MemberUnderDeliveries;
public decimal MemberTotalUnderDelivery; public decimal MemberTotalUnderDelivery;
public int MemberAutoBusinessShares; public int MemberAutoBusinessShares;
public decimal MemberAutoBusinessSharesAmount; public decimal MemberAutoBusinessSharesAmount;
public PaymentCustom? CustomPayment; public PaymentCustom? CustomPayment;
public CreditNote( protected bool ConsiderContractPenalties;
AppDbContext ctx, protected bool ConsiderTotalPenalty;
PaymentMember p, protected bool ConsiderAutoBusinessShares;
CreditNoteDeliveryData data, protected bool ConsiderCustomModifiers;
bool considerContractPenalties,
bool considerTotalPenalty, private CreditNoteDeliveryData? _data;
bool considerAutoBusinessShares, private Dictionary<string, UnderDelivery>? _underDeliveries;
bool considerCustomModifiers,
Dictionary<string, UnderDelivery>? underDeliveries = null 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) {
base($"{Name} {(p.Credit != null ? $"Nr. {p.Credit.Year}/{p.Credit.TgNr:000}" : p.Member.FullName)} {p.Variant.Name}", p.Member) {
UseBillingAddress = true; UseBillingAddress = true;
ShowDateAndLocation = true; ShowDateAndLocation = true;
Data = data;
Payment = p; Payment = p;
Credit = p.Credit; Credit = p.Credit;
IsPreview = Payment == null || Credit == null; Text = App.Client.TextCreditNote;
var season = p.Variant.Season; DocumentId = $"Tr.-Gutschr. " + (Credit != null ? $"{Credit.Year}/{Credit.TgNr:000}" : Payment.MgNr);
if (considerCustomModifiers) { IsPreview = Credit == null;
CustomPayment = ctx.CustomPayments.Find(p.Year, p.MgNr); _data = data;
_underDeliveries = underDeliveries;
CurrencySymbol = Payment.Variant.Season.Currency.Symbol ?? Payment.Variant.Season.Currency.Code;
Precision = Payment.Variant.Season.Precision;
billingData ??= BillingData.FromJson(Payment.Variant.Data);
ConsiderContractPenalties = billingData.ConsiderContractPenalties;
ConsiderTotalPenalty = billingData.ConsiderTotalPenalty;
ConsiderAutoBusinessShares = billingData.ConsiderAutoBusinessShares;
ConsiderCustomModifiers = billingData.ConsiderCustomModifiers;
} }
var mod = App.Client.IsMatzen ? ctx.Modifiers.Where(m => m.Year == season.Year && m.Name.StartsWith("Treue")).FirstOrDefault() : 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, dateFrom, billingData, data, underDeliveries);
}
protected override async Task LoadData(AppDbContext ctx) {
await base.LoadData(ctx);
var season = Payment.Variant.Season;
if (ConsiderCustomModifiers) {
CustomPayment = await ctx.CustomPayments.FindAsync(Payment.Year, Payment.MgNr);
}
_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.FetchModifiers(season.Year).Where(m => m.Name.StartsWith("Treue")).FirstOrDefaultAsync() : null;
if (CustomPayment?.ModComment != null) { if (CustomPayment?.ModComment != null) {
MemberModifier = CustomPayment.ModComment; MemberModifier = CustomPayment.ModComment;
} else if (mod != null) { } else if (mod != null) {
@@ -57,32 +84,28 @@ namespace Elwig.Documents {
} else { } else {
MemberModifier = "Sonstige Zu-/Abschläge"; MemberModifier = "Sonstige Zu-/Abschläge";
} }
Text = App.Client.TextCreditNote;
DocumentId = $"Tr.-Gutschr. " + (p.Credit != null ? $"{p.Credit.Year}/{p.Credit.TgNr:000}" : p.MgNr);
CurrencySymbol = season.Currency.Symbol ?? season.Currency.Code;
Precision = season.Precision;
if (considerTotalPenalty) { if (ConsiderTotalPenalty) {
var total = data.Rows.SelectMany(r => r.Buckets).Sum(b => b.Value); var total = _data.Rows.SelectMany(r => r.Buckets).Sum(b => b.Value);
var totalUnderDelivery = total - p.Member.BusinessShares * season.MinKgPerBusinessShare; var totalUnderDelivery = total - Member.BusinessShares * season.MinKgPerBusinessShare;
MemberTotalUnderDelivery = totalUnderDelivery < 0 ? totalUnderDelivery * (season.PenaltyPerKg ?? 0) - (season.PenaltyAmount ?? 0) - (season.PenaltyPerBsAmount * Math.Floor(-(decimal)totalUnderDelivery / season.MinKgPerBusinessShare) ?? 0) : 0; MemberTotalUnderDelivery = totalUnderDelivery < 0 ? totalUnderDelivery * (season.PenaltyPerKg ?? 0) - (season.PenaltyAmount ?? 0) - (season.PenaltyPerBsAmount * Math.Floor(-(decimal)totalUnderDelivery / season.MinKgPerBusinessShare) ?? 0) : 0;
if (total == 0) if (total == 0)
MemberTotalUnderDelivery -= (season.PenaltyNone ?? 0) + (season.PenaltyPerBsNone * p.Member.BusinessShares ?? 0); MemberTotalUnderDelivery -= (season.PenaltyNone ?? 0) + (season.PenaltyPerBsNone * Member.BusinessShares ?? 0);
} }
if (considerAutoBusinessShares) { if (ConsiderAutoBusinessShares) {
var fromDate = $"{season.Year}-01-01"; var fromDate = $"{season.Year}-01-01";
var toDate = $"{season.Year}-12-31"; var toDate = $"{season.Year}-12-31";
MemberAutoBusinessShares = ctx.MemberHistory MemberAutoBusinessShares = await ctx.MemberHistory
.Where(h => h.MgNr == p.Member.MgNr && h.Type == "auto") .Where(h => h.MgNr == Member.MgNr && h.Type == "auto")
.Where(h => h.DateString.CompareTo(fromDate) >= 0 && h.DateString.CompareTo(toDate) <= 0) .Where(h => h.DateString.CompareTo(fromDate) >= 0 && h.DateString.CompareTo(toDate) <= 0)
.Sum(h => h.BusinessShares); .SumAsync(h => h.BusinessShares);
MemberAutoBusinessSharesAmount = MemberAutoBusinessShares * (-season.BusinessShareValue ?? 0); MemberAutoBusinessSharesAmount = MemberAutoBusinessShares * (-season.BusinessShareValue ?? 0);
} }
if (considerContractPenalties) { if (ConsiderContractPenalties) {
var varieties = ctx.WineVarieties.ToDictionary(v => v.SortId, v => v); var varieties = await ctx.FetchWineVarieties().ToDictionaryAsync(v => v.SortId, v => v);
var attributes = ctx.WineAttributes.ToDictionary(a => a.AttrId, a => a); var attributes = await ctx.FetchWineAttributes().ToDictionaryAsync(a => a.AttrId, a => a);
var comTypes = ctx.AreaCommitmentTypes.ToDictionary(t => t.VtrgId, t => t); var comTypes = await ctx.AreaCommitmentTypes.ToDictionaryAsync(t => t.VtrgId, t => t);
MemberUnderDeliveries = underDeliveries? MemberUnderDeliveries = _underDeliveries?
.OrderBy(u => u.Key) .OrderBy(u => u.Key)
.Select(u => ( .Select(u => (
varieties[u.Key[..2]].Name + (u.Key.Length > 2 ? " " + attributes[u.Key[2..]].Name : ""), varieties[u.Key[..2]].Name + (u.Key.Length > 2 ? " " + attributes[u.Key[2..]].Name : ""),
@@ -104,8 +127,9 @@ namespace Elwig.Documents {
} }
protected override void RenderBody(iText.Layout.Document doc, PdfDocument pdf) { protected override void RenderBody(iText.Layout.Document doc, PdfDocument pdf) {
if (_data == null) throw new Exception("Call LoadData before RenderBody");
base.RenderBody(doc, pdf); base.RenderBody(doc, pdf);
doc.Add(NewCreditTable(Data)); doc.Add(NewCreditTable(_data));
var div = new Table(ColsMM(60, 105)) var div = new Table(ColsMM(60, 105))
.SetWidth(UnitValue.CreatePercentValue(100)).SetFixedLayout() .SetWidth(UnitValue.CreatePercentValue(100)).SetFixedLayout()
@@ -131,7 +155,7 @@ namespace Elwig.Documents {
.SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE) .SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE)
.SetKeepTogether(true); .SetKeepTogether(true);
var sum = Data.Rows.Sum(p => p.Amount); var sum = _data.Rows.Sum(p => p.Amount);
if (Payment == null) { if (Payment == null) {
tbl1.AddCells(FormatRow("Gesamt", sum, bold: true, noTopBorder: true)); tbl1.AddCells(FormatRow("Gesamt", sum, bold: true, noTopBorder: true));
} else { } else {
@@ -139,7 +163,7 @@ namespace Elwig.Documents {
if (Payment.NetAmount != Payment.Amount) { if (Payment.NetAmount != Payment.Amount) {
tbl1.AddCells(FormatRow("Zwischensumme", Payment.NetAmount, noTopBorder: noBorder)); tbl1.AddCells(FormatRow("Zwischensumme", Payment.NetAmount, noTopBorder: noBorder));
noBorder = false; noBorder = false;
tbl1.AddCells(FormatRow(MemberModifier, Payment.Amount - Payment.NetAmount, add: true)); tbl1.AddCells(FormatRow(MemberModifier ?? "", Payment.Amount - Payment.NetAmount, add: true));
} }
if (Credit == null) { if (Credit == null) {
tbl1.AddCells(FormatRow("Gesamtbetrag", Payment.Amount, bold: true, noTopBorder: noBorder)); tbl1.AddCells(FormatRow("Gesamtbetrag", Payment.Amount, bold: true, noTopBorder: noBorder));

View File

@@ -5,33 +5,48 @@ using iText.Kernel.Pdf;
using iText.Layout.Borders; using iText.Layout.Borders;
using iText.Layout.Element; using iText.Layout.Element;
using iText.Layout.Properties; using iText.Layout.Properties;
using Microsoft.EntityFrameworkCore;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
namespace Elwig.Documents { namespace Elwig.Documents {
public class DeliveryConfirmation : BusinessDocument { public class DeliveryConfirmation : BusinessDocument {
public new static string Name => "Anlieferungsbestätigung"; public new static string Name => "Anlieferungsbestätigung";
public Season Season; private readonly int _year;
public DeliveryConfirmationDeliveryData Data; public Season? Season;
public int MemberDeliveredWeight;
public DeliveryConfirmationDeliveryData? Data;
public string? Text = App.Client.TextDeliveryConfirmation; public string? Text = App.Client.TextDeliveryConfirmation;
public Dictionary<string, MemberBucket> MemberBuckets; public Dictionary<string, MemberBucket> MemberBuckets = [];
public List<MemberStat> MemberStats; public List<MemberStat> MemberStats = [];
public DeliveryConfirmation(AppDbContext ctx, int year, Member m, DeliveryConfirmationDeliveryData data) : public DeliveryConfirmation(int year, Member m, DateOnly? dateFrom, DeliveryConfirmationDeliveryData? data = null) :
base($"{Name} {year}", m) { base($"{Name} {year}", m, dateFrom) {
Season = ctx.Seasons.Find(year) ?? throw new ArgumentException("invalid season"); _year = year;
ShowDateAndLocation = true; ShowDateAndLocation = true;
UseBillingAddress = true; UseBillingAddress = true;
DocumentId = $"Anl.-Best. {Season.Year}/{m.MgNr}"; DocumentId = $"Anl.-Best. {_year}/{m.MgNr}";
Data = data; Data = data;
MemberBuckets = ctx.GetMemberBuckets(Season.Year, m.MgNr).GetAwaiter().GetResult(); }
MemberStats = AppDbContext.GetMemberStats(Season.Year, m.MgNr).GetAwaiter().GetResult();
protected override async Task LoadData(AppDbContext ctx) {
await base.LoadData(ctx);
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)
.SumAsync(p => p.Weight);
MemberBuckets = await ctx.GetMemberBuckets(Season.Year, Member.MgNr);
MemberStats = await AppDbContext.GetMemberStats(Season.Year, Member.MgNr);
Data ??= await DeliveryConfirmationDeliveryData.ForMember(ctx.DeliveryParts, Season.Year, Member);
} }
protected override void BeforeRenderBody(iText.Layout.Document doc, PdfDocument pdf) { protected override void BeforeRenderBody(iText.Layout.Document doc, PdfDocument pdf) {
if (Data == null) throw new Exception("Call LoadData before BeforeRenderBody");
base.BeforeRenderBody(doc, pdf); base.BeforeRenderBody(doc, pdf);
var firstDay = Data.Rows.MinBy(r => r.Date)?.Date; var firstDay = Data.Rows.MinBy(r => r.Date)?.Date;
var lastDay = Data.Rows.MaxBy(r => r.Date)?.Date; var lastDay = Data.Rows.MaxBy(r => r.Date)?.Date;
@@ -42,12 +57,13 @@ namespace Elwig.Documents {
} }
protected override void RenderBody(iText.Layout.Document doc, PdfDocument pdf) { protected override void RenderBody(iText.Layout.Document doc, PdfDocument pdf) {
if (Season == null || Data == null) throw new Exception("Call LoadData before RenderBody");
base.RenderBody(doc, pdf); base.RenderBody(doc, pdf);
doc.Add(NewDeliveryListTable(Data)); doc.Add(NewDeliveryListTable(Data));
doc.Add(NewWeightsTable(MemberStats) doc.Add(NewWeightsTable(MemberStats)
.SetMarginTopMM(10).SetKeepTogether(true)); .SetMarginTopMM(10).SetKeepTogether(true));
doc.Add(NewBucketTable(Season, MemberBuckets, includePayment: true) doc.Add(NewBucketTable(Season, MemberBuckets, MemberDeliveredWeight, includePayment: true)
.SetMarginTopMM(10).SetKeepTogether(true)); .SetMarginTopMM(10).SetKeepTogether(true));
if (Text != null) { if (Text != null) {

View File

@@ -5,10 +5,12 @@ using iText.Layout.Borders;
using iText.Layout.Element; using iText.Layout.Element;
using iText.Layout.Layout; using iText.Layout.Layout;
using iText.Layout.Properties; using iText.Layout.Properties;
using Microsoft.EntityFrameworkCore;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace Elwig.Documents { namespace Elwig.Documents {
public class DeliveryNote : BusinessDocument { public class DeliveryNote : BusinessDocument {
@@ -17,7 +19,8 @@ namespace Elwig.Documents {
public Delivery Delivery; public Delivery Delivery;
public string? Text; public string? Text;
public Dictionary<string, MemberBucket> MemberBuckets; public int MemberDeliveredWeight;
public Dictionary<string, MemberBucket> MemberBuckets = [];
// 0 - none // 0 - none
// 1 - GA only // 1 - GA only
@@ -25,16 +28,41 @@ namespace Elwig.Documents {
// 3 - full // 3 - full
public int DisplayStats = App.Client.ModeDeliveryNoteStats; public int DisplayStats = App.Client.ModeDeliveryNoteStats;
public DeliveryNote(Delivery d, AppDbContext? ctx = null) : public DeliveryNote(Delivery d) :
base($"{Name} Nr. {d.LsNr}", d.Member) { base($"{Name} Nr. {d.LsNr}", d.Member, DateOnly.FromDateTime(d.ModifiedAt)) {
UseBillingAddress = true; UseBillingAddress = true;
ShowDateAndLocation = true; ShowDateAndLocation = true;
Delivery = d; Delivery = d;
Text = App.Client.TextDeliveryNote; Text = App.Client.TextDeliveryNote;
DocumentId = d.LsNr; DocumentId = d.LsNr;
Date = DateOnly.FromDateTime(d.ModifiedAt); }
IsDoublePaged = true;
MemberBuckets = ctx?.GetMemberBuckets(d.Year, d.Member.MgNr).GetAwaiter().GetResult() ?? []; public static async Task<DeliveryNote> Initialize(int year, int did) {
using var ctx = new AppDbContext();
await ctx.WineOrigins.LoadAsync();
var d = await ctx.Deliveries
.Where(d => d.Year == year && d.DId == did)
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers)
.SingleAsync();
return new DeliveryNote(d);
}
public static async Task<DeliveryNote> Initialize(string lsnr) {
using var ctx = new AppDbContext();
await ctx.WineOrigins.LoadAsync();
var d = await ctx.Deliveries
.Where(d => d.LsNr == lsnr)
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers)
.SingleAsync();
return new DeliveryNote(d);
}
protected override async Task LoadData(AppDbContext ctx) {
await base.LoadData(ctx);
MemberDeliveredWeight = await ctx.DeliveryParts
.Where(d => d.Year == Delivery.Year && d.Delivery.MgNr == Member.MgNr)
.SumAsync(p => p.Weight);
MemberBuckets = await ctx.GetMemberBuckets(Delivery.Year, Member.MgNr) ?? [];
} }
protected override void BeforeRenderBody(iText.Layout.Document doc, PdfDocument pdf) { protected override void BeforeRenderBody(iText.Layout.Document doc, PdfDocument pdf) {
@@ -53,7 +81,7 @@ namespace Elwig.Documents {
doc.Add(new KernedParagraph($"Anmerkung zur Lieferung: {Delivery.Comment}", 10).SetMarginsMM(5, 0, 0, 0)); doc.Add(new KernedParagraph($"Anmerkung zur Lieferung: {Delivery.Comment}", 10).SetMarginsMM(5, 0, 0, 0));
} }
if (DisplayStats > 0) { if (DisplayStats > 0) {
doc.Add(NewBucketTable(Delivery.Season, MemberBuckets, isTiny: true, doc.Add(NewBucketTable(Delivery.Season, MemberBuckets, MemberDeliveredWeight, isTiny: true,
filter: DisplayStats > 2 ? null : DisplayStats == 1 ? [] : Delivery.Parts.Select(p => p.SortId).Distinct().ToList()) filter: DisplayStats > 2 ? null : DisplayStats == 1 ? [] : Delivery.Parts.Select(p => p.SortId).Distinct().ToList())
.SetKeepTogether(true) .SetKeepTogether(true)
.SetMarginsMM(5, 0, 0, 0)); .SetMarginsMM(5, 0, 0, 0));

View File

@@ -49,14 +49,12 @@ namespace Elwig.Documents {
public bool IsPreview = false; public bool IsPreview = false;
private iText.Layout.Document? _doc; private iText.Layout.Document? _doc;
public int CurrentNextSeason;
public string? DocumentId; public string? DocumentId;
public string Title; public string Title;
public string Author; public string Author;
public DateOnly Date; public DateOnly Date;
public Document(string title) { public Document(string title) {
CurrentNextSeason = Utils.CurrentNextSeason;
Title = title; Title = title;
Author = App.Client.NameFull; Author = App.Client.NameFull;
Date = DateOnly.FromDateTime(Utils.Today); Date = DateOnly.FromDateTime(Utils.Today);
@@ -128,6 +126,8 @@ namespace Elwig.Documents {
} }
} }
protected virtual async Task LoadData(AppDbContext ctx) { }
protected virtual void BeforeRenderBody(iText.Layout.Document doc, PdfDocument pdf) { } protected virtual void BeforeRenderBody(iText.Layout.Document doc, PdfDocument pdf) { }
protected virtual void RenderBody(iText.Layout.Document doc, PdfDocument pdf) { } protected virtual void RenderBody(iText.Layout.Document doc, PdfDocument pdf) { }
@@ -136,7 +136,7 @@ namespace Elwig.Documents {
return new KernedParagraph(App.Client.NameFull, 10); return new KernedParagraph(App.Client.NameFull, 10);
} }
public async Task Generate(CancellationToken? cancelToken = null, IProgress<double>? progress = null) { public async Task Generate(AppDbContext ctx, CancellationToken? cancelToken = null, IProgress<double>? progress = null) {
if (_pdfFile != null) if (_pdfFile != null)
return; return;
progress?.Report(0.0); progress?.Report(0.0);
@@ -181,6 +181,7 @@ namespace Elwig.Documents {
merger.Merge(src, 1, src.GetNumberOfPages()); merger.Merge(src, 1, src.GetNumberOfPages());
p += src.GetNumberOfPages(); p += src.GetNumberOfPages();
} else { } else {
await doc.LoadData(ctx);
int pageNum = doc.Render(tmpPdf.FilePath); int pageNum = doc.Render(tmpPdf.FilePath);
if (IsDoublePaged && doc is Letterhead) { if (IsDoublePaged && doc is Letterhead) {
using var reader = new PdfReader(tmpPdf.FilePath); using var reader = new PdfReader(tmpPdf.FilePath);
@@ -233,6 +234,7 @@ namespace Elwig.Documents {
throw new OperationCanceledException("Dokumentenerzeugung abgebrochen!"); throw new OperationCanceledException("Dokumentenerzeugung abgebrochen!");
var pdf = new TempFile("pdf"); var pdf = new TempFile("pdf");
try { try {
await LoadData(ctx);
TotalPages = Render(pdf.FilePath); TotalPages = Render(pdf.FilePath);
} catch { } catch {
pdf.Dispose(); pdf.Dispose();

View File

@@ -6,7 +6,7 @@ using iText.Layout;
namespace Elwig.Documents { namespace Elwig.Documents {
public class Letterhead : BusinessDocument { public class Letterhead : BusinessDocument {
public Letterhead(Member m) : 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) { protected override void RenderBody(iText.Layout.Document doc, PdfDocument pdf) {

View File

@@ -5,31 +5,52 @@ using iText.Kernel.Pdf;
using iText.Layout.Borders; using iText.Layout.Borders;
using iText.Layout.Element; using iText.Layout.Element;
using iText.Layout.Properties; using iText.Layout.Properties;
using Microsoft.EntityFrameworkCore;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace Elwig.Documents { namespace Elwig.Documents {
public class MemberDataSheet : BusinessDocument { public class MemberDataSheet : BusinessDocument {
public new static string Name => "Stammdatenblatt"; public new static string Name => "Stammdatenblatt";
public Season Season; public Season? Season;
public Dictionary<string, MemberBucket> MemberBuckets; public int MemberDeliveredWeight;
public List<AreaCom> ActiveAreaCommitments; public Dictionary<string, MemberBucket> MemberBuckets = [];
public List<AreaCom> ActiveAreaCommitments = [];
public MemberDataSheet(Member m, AppDbContext ctx) : base($"{Name} {m.AdministrativeName}", m) { public MemberDataSheet(Member m) :
base($"{Name} {m.AdministrativeName}", m, DateOnly.FromDateTime(m.ModifiedAt)) {
ShowDateAndLocation = true;
DocumentId = $"{Name} {m.MgNr}"; DocumentId = $"{Name} {m.MgNr}";
Season = ctx.Seasons.ToList().MaxBy(s => s.Year) ?? throw new ArgumentException("invalid season"); }
MemberBuckets = ctx.GetMemberBuckets(Utils.CurrentYear, m.MgNr).GetAwaiter().GetResult();
ActiveAreaCommitments = [.. m.ActiveAreaCommitments(ctx)]; public static async Task<MemberDataSheet> Initialize(int mgnr) {
using var ctx = new AppDbContext();
return new MemberDataSheet(await ctx.FetchMembers(mgnr, true, true).SingleAsync());
}
protected override async Task LoadData(AppDbContext ctx) {
await base.LoadData(ctx);
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)
.ToListAsync();
MemberDeliveredWeight = await ctx.Deliveries
.Where(d => d.Year == Season.Year && d.MgNr == Member.MgNr)
.SelectMany(d => d.Parts)
.SumAsync(p => p.Weight);
} }
protected override void RenderBody(iText.Layout.Document doc, PdfDocument pdf) { protected override void RenderBody(iText.Layout.Document doc, PdfDocument pdf) {
if (Season == null) throw new Exception("Call LoadData before RenderBody");
base.RenderBody(doc, pdf); base.RenderBody(doc, pdf);
doc.Add(NewMemberData().SetMarginBottomMM(5)); doc.Add(NewMemberData(Season).SetMarginBottomMM(5));
doc.Add(NewBucketTable(Season, MemberBuckets, includeDelivery: false)); doc.Add(NewBucketTable(Season, MemberBuckets, MemberDeliveredWeight, includeDelivery: false));
if (ActiveAreaCommitments.Count != 0) { if (ActiveAreaCommitments.Count != 0) {
bool firstOnPage = false; bool firstOnPage = false;
if (pdf.GetNumberOfPages() == 1) { if (pdf.GetNumberOfPages() == 1) {
@@ -37,7 +58,7 @@ namespace Elwig.Documents {
firstOnPage = true; firstOnPage = true;
} }
doc.Add(new KernedParagraph(12).Add(Bold($"Flächenbindungen per {Date:dd.MM.yyyy}")).SetMargins(firstOnPage ? 0 : 24, 0, 12, 0)); doc.Add(new KernedParagraph(12).Add(Bold($"Flächenbindungen per {Date:dd.MM.yyyy}")).SetMargins(firstOnPage ? 0 : 24, 0, 12, 0));
doc.Add(NewAreaComTable()); doc.Add(NewAreaComTable(ActiveAreaCommitments));
} }
} }
@@ -51,7 +72,7 @@ namespace Elwig.Documents {
.SetPaddingRightMM(0); .SetPaddingRightMM(0);
} }
protected Table NewMemberData() { protected Table NewMemberData(Season season) {
var tbl = new Table(ColsMM(30.0, 51.5, 20.0, 12.0, 18.0, 31.5)) var tbl = new Table(ColsMM(30.0, 51.5, 20.0, 12.0, 18.0, 31.5))
.SetWidth(UnitValue.CreatePercentValue(100)).SetFixedLayout() .SetWidth(UnitValue.CreatePercentValue(100)).SetFixedLayout()
.SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE) .SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE)
@@ -116,7 +137,7 @@ namespace Elwig.Documents {
.AddCell(NewDataTh("UID:", colspan: 2)).AddCell(NewTd(Member.UstIdNr, colspan: 2)) .AddCell(NewDataTh("UID:", colspan: 2)).AddCell(NewTd(Member.UstIdNr, colspan: 2))
.AddCell(NewDataTh("Stammgemeinde:")).AddCell(NewTd(Member.DefaultKg?.Name)) .AddCell(NewDataTh("Stammgemeinde:")).AddCell(NewTd(Member.DefaultKg?.Name))
.AddCell(NewDataTh("Buchführend:", colspan: 2)).AddCell(NewTd(new KernedParagraph(Member.IsBuchführend ? "Ja " : "Nein ", 10) .AddCell(NewDataTh("Buchführend:", colspan: 2)).AddCell(NewTd(new KernedParagraph(Member.IsBuchführend ? "Ja " : "Nein ", 10)
.Add(Normal($"({(Member.IsBuchführend ? Season.VatNormal : Season.VatFlatrate) * 100:N0}% USt.)", 8)), colspan: 2)) .Add(Normal($"({(Member.IsBuchführend ? season.VatNormal : season.VatFlatrate) * 100:N0}% USt.)", 8)), colspan: 2))
.AddCell(NewDataTh("(Katastralgemeinde mit dem größten Anteil an Weinbauflächen)", 8, colspan: 2)) .AddCell(NewDataTh("(Katastralgemeinde mit dem größten Anteil an Weinbauflächen)", 8, colspan: 2))
.AddCell(NewDataTh("Bio:", colspan: 2)).AddCell(NewTd(Member.IsOrganic ? "Ja" : "Nein", colspan: 2)) .AddCell(NewDataTh("Bio:", colspan: 2)).AddCell(NewTd(Member.IsOrganic ? "Ja" : "Nein", colspan: 2))
.AddCell(NewDataHdr("Genossenschaft", colspan: 6)) .AddCell(NewDataHdr("Genossenschaft", colspan: 6))
@@ -133,10 +154,10 @@ namespace Elwig.Documents {
return tbl; return tbl;
} }
protected Table NewAreaComTable() { protected Table NewAreaComTable(IEnumerable<AreaCom> activeAreaComs) {
var areaComs = ActiveAreaCommitments.GroupBy(a => a.AreaComType).Select(group => new { var areaComs = activeAreaComs.GroupBy(a => a.AreaComType).Select(group => new {
Type = group.Key, Type = group.Key,
AreaComs = group.OrderBy(c => c.Kg.AtKg.Name).ToList(), AreaComs = group.OrderBy(c => c.Contract.Kg.AtKg.Name).ToList(),
Size = group.Sum(c => c.Area) Size = group.Sum(c => c.Area)
}).OrderByDescending(a => a.Size).ToList(); }).OrderByDescending(a => a.Size).ToList();
@@ -164,18 +185,19 @@ namespace Elwig.Documents {
.SetBorderTop(contractType.Type.DisplayName != lastContract && lastContract != "" ? new SolidBorder(BorderThickness) : Border.NO_BORDER)); .SetBorderTop(contractType.Type.DisplayName != lastContract && lastContract != "" ? new SolidBorder(BorderThickness) : Border.NO_BORDER));
foreach (var areaCom in contractType.AreaComs) { foreach (var areaCom in contractType.AreaComs) {
tbl.AddCell(NewTd(new KernedParagraph(10).Add(Normal($"{areaCom.Kg.AtKg.Name} ")).Add(Normal($"({areaCom.Kg.AtKg.KgNr:00000})", 8)))) var c = areaCom.Contract;
.AddCell(NewTd(areaCom.Rd?.Name)) tbl.AddCell(NewTd(new KernedParagraph(10).Add(Normal($"{c.Kg.AtKg.Name} ")).Add(Normal($"({c.Kg.AtKg.KgNr:00000})", 8))))
.AddCell(NewTd(c.Rd?.Name))
.AddCell(NewTd(Regex.Replace(areaCom.GstNr.Replace(",", ", ").Replace("-", "\u2013"), @"\s+", " "), 10)) .AddCell(NewTd(Regex.Replace(areaCom.GstNr.Replace(",", ", ").Replace("-", "\u2013"), @"\s+", " "), 10))
.AddCell(NewTd($"{areaCom.Area:N0}", right: true)) .AddCell(NewTd($"{areaCom.Area:N0}", right: true))
.AddCell(NewTd(areaCom.WineCult?.Name, center: true)) .AddCell(NewTd(areaCom.WineCult?.Name, center: true))
.AddCell(NewTd(areaCom.YearTo == null ? (areaCom.YearFrom == null ? "unbefristet" : $"ab {areaCom.YearFrom}") : (areaCom.YearFrom == null ? $"bis {areaCom.YearTo}" : $"{areaCom.YearFrom}{areaCom.YearTo}"), center: true)); .AddCell(NewTd(c.YearTo == null ? (c.YearFrom == null ? "unbefristet" : $"ab {c.YearFrom}") : (c.YearFrom == null ? $"bis {c.YearTo}" : $"{c.YearFrom}{c.YearTo}"), center: true));
lastContract = contractType.Type.DisplayName; lastContract = contractType.Type.DisplayName;
} }
} }
tbl.AddCell(NewTd("Gesamt:", 12, colspan: 2, bold: true, borderTop: true).SetPaddingsMM(1, 1, 1, 1)); tbl.AddCell(NewTd("Gesamt:", 12, colspan: 2, bold: true, borderTop: true).SetPaddingsMM(1, 1, 1, 1));
tbl.AddCell(NewTd($"{ActiveAreaCommitments.Sum(a => a.Area):N0}", 12, colspan: 2, right: true, bold: true, borderTop: true).SetPaddingsMM(1, 1, 1, 1)); tbl.AddCell(NewTd($"{activeAreaComs.Sum(a => a.Area):N0}", 12, colspan: 2, right: true, bold: true, borderTop: true).SetPaddingsMM(1, 1, 1, 1));
tbl.AddCell(NewTd(colspan: 2, borderTop: true).SetPaddingsMM(1, 1, 1, 1)); tbl.AddCell(NewTd(colspan: 2, borderTop: true).SetPaddingsMM(1, 1, 1, 1));
return tbl; return tbl;

View File

@@ -7,40 +7,60 @@ using iText.Kernel.Pdf;
using iText.Layout.Borders; using iText.Layout.Borders;
using iText.Layout.Element; using iText.Layout.Element;
using iText.Layout.Properties; using iText.Layout.Properties;
using Microsoft.EntityFrameworkCore;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
namespace Elwig.Documents { namespace Elwig.Documents {
public class PaymentVariantSummary : Document { public class PaymentVariantSummary : Document {
public new static string Name => "Auszahlungsvariante"; public new static string Name => "Auszahlungsvariante";
public PaymentVariantSummaryData Data; public PaymentVariantSummaryData? Data;
public PaymentVar Variant; public PaymentVar Variant;
public BillingData BillingData; public BillingData BillingData;
public string CurrencySymbol; public string CurrencySymbol;
public int MemberNum; public int MemberNum;
public int DeliveryNum; public int DeliveryNum;
public int DeliveryPartNum; public int DeliveryPartNum;
public List<ModifierStat> ModifierStat; public List<ModifierStat>? ModifierStat;
public Dictionary<string, Modifier> Modifiers; public Dictionary<string, Modifier>? Modifiers;
public PaymentVariantSummary(PaymentVar v, PaymentVariantSummaryData data) : private List<Credit> _credits = [];
private List<PaymentDeliveryPart> _parts = [];
public PaymentVariantSummary(PaymentVar v, PaymentVariantSummaryData? data = null) :
base($"{Name} {v.Year} - {v.Name}") { base($"{Name} {v.Year} - {v.Name}") {
Variant = v; Variant = v;
BillingData = BillingData.FromJson(v.Data); BillingData = BillingData.FromJson(v.Data);
Data = data; Data = data;
CurrencySymbol = v.Season.Currency.Symbol ?? v.Season.Currency.Code; CurrencySymbol = v.Season.Currency.Symbol ?? v.Season.Currency.Code;
MemberNum = v.Credits.Count; }
public static async Task<PaymentVariantSummary> Initialize(int year, int avnr, PaymentVariantSummaryData? data = null) {
using var ctx = new AppDbContext();
var v = await ctx.PaymentVariants
.Where(v => v.Year == year && v.AvNr == avnr)
.SingleAsync();
return new PaymentVariantSummary(v, data);
}
protected override async Task LoadData(AppDbContext ctx) {
_credits = await ctx.Credits.Where(c => c.Year == Variant.Year && c.AvNr == Variant.AvNr).ToListAsync();
_parts = await ctx.PaymentDeliveryParts.Where(p => p.Year == Variant.Year && p.AvNr == Variant.AvNr).ToListAsync();
MemberNum = _credits.Count;
IsPreview = MemberNum == 0; IsPreview = MemberNum == 0;
DeliveryNum = v.DeliveryPartPayments.DistinctBy(p => p.DeliveryPart.Delivery).Count(); DeliveryNum = await ctx.Deliveries.Where(d => d.Year == Variant.Year).CountAsync();
DeliveryPartNum = v.DeliveryPartPayments.Count; DeliveryPartNum = await ctx.DeliveryParts.Where(d => d.Year == Variant.Year).CountAsync();
ModifierStat = AppDbContext.GetModifierStats(v.Year, v.AvNr).GetAwaiter().GetResult(); Data ??= await PaymentVariantSummaryData.ForPaymentVariant(Variant, ctx.PaymentVariantSummaryRows);
Modifiers = v.Season.Modifiers.ToDictionary(m => m.ModId); ModifierStat = await AppDbContext.GetModifierStats(Variant.Year, Variant.AvNr);
Modifiers = await ctx.FetchModifiers(Variant.Year).ToDictionaryAsync(m => m.ModId);
} }
protected override void RenderBody(iText.Layout.Document doc, PdfDocument pdf) { protected override void RenderBody(iText.Layout.Document doc, PdfDocument pdf) {
if (Data == null || Modifiers == null || ModifierStat == null) throw new Exception("Call LoadData before RenderBody");
base.RenderBody(doc, pdf); base.RenderBody(doc, pdf);
doc.Add(new KernedParagraph($"{Name} Lese {Variant.Year}", 24) doc.Add(new KernedParagraph($"{Name} Lese {Variant.Year}", 24)
.SetTextAlignment(TextAlignment.CENTER).SetFont(BF) .SetTextAlignment(TextAlignment.CENTER).SetFont(BF)
@@ -48,10 +68,10 @@ namespace Elwig.Documents {
doc.Add(new KernedParagraph(Variant.Name, 14) doc.Add(new KernedParagraph(Variant.Name, 14)
.SetTextAlignment(TextAlignment.CENTER).SetFont(BF) .SetTextAlignment(TextAlignment.CENTER).SetFont(BF)
.SetMarginsMM(0, 0, 10, 0)); .SetMarginsMM(0, 0, 10, 0));
doc.Add(NewVariantStatTable().SetMarginBottomMM(10)); doc.Add(NewVariantStatTable(Data).SetMarginBottomMM(10));
doc.Add(NewModifierStatTable()); doc.Add(NewModifierStatTable(Modifiers, ModifierStat));
doc.Add(new AreaBreak(AreaBreakType.NEXT_PAGE)); doc.Add(new AreaBreak(AreaBreakType.NEXT_PAGE));
doc.Add(NewPriceTable()); doc.Add(NewPriceTable(Data));
} }
protected Cell NewSectionHdr(string text, int colspan = 1, bool borderLeft = false) { protected Cell NewSectionHdr(string text, int colspan = 1, bool borderLeft = false) {
@@ -67,33 +87,33 @@ namespace Elwig.Documents {
.SetBorderLeft(borderLeft ? new SolidBorder(BorderThickness) : Border.NO_BORDER); .SetBorderLeft(borderLeft ? new SolidBorder(BorderThickness) : Border.NO_BORDER);
} }
protected Table NewVariantStatTable() { protected Table NewVariantStatTable(PaymentVariantSummaryData data) {
var tbl = new Table(ColsMM(20, 30, 4.5, 4.5, 23.5, 47.5, 15, 20)) var tbl = new Table(ColsMM(20, 30, 4.5, 4.5, 23.5, 47.5, 15, 20))
.SetWidth(UnitValue.CreatePercentValue(100)).SetFixedLayout() .SetWidth(UnitValue.CreatePercentValue(100)).SetFixedLayout()
.SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE) .SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE)
.SetBorder(new SolidBorder(BorderThickness)); .SetBorder(new SolidBorder(BorderThickness));
//var sum1 = Variant.DeliveryPartPayments.Sum(p => p.NetAmount); //var sum1 = _parts.Sum(p => p.NetAmount);
//var sum2 = Variant.Credits.Sum(p => p.); //Variant.MemberPayments.Sum(p => p.Amount); //var sum2 = _credits.Sum(p => p.); //Variant.MemberPayments.Sum(p => p.Amount);
var deliveryModifiers = Variant.DeliveryPartPayments.Sum(p => p.Amount - p.NetAmount); var deliveryModifiers = _parts.Sum(p => p.Amount - p.NetAmount);
var memberModifiers = Variant.Credits.Sum(c => c.Payment.Amount - c.Payment.NetAmount); var memberModifiers = _credits.Sum(c => c.Payment.Amount - c.Payment.NetAmount);
var sum2 = Variant.Credits.Sum(p => p.NetAmount); var sum2 = _credits.Sum(p => p.NetAmount);
var sum1 = sum2 - deliveryModifiers - memberModifiers; var sum1 = sum2 - deliveryModifiers - memberModifiers;
var payed = -Variant.Credits.Sum(p => p.PrevNetAmount ?? 0m); var payed = -_credits.Sum(p => p.PrevNetAmount ?? 0m);
var netSum = Variant.Credits.Sum(p => p.NetAmount) - Variant.Credits.Sum(p => p.PrevNetAmount ?? 0m); var netSum = _credits.Sum(p => p.NetAmount) - _credits.Sum(p => p.PrevNetAmount ?? 0m);
var vat = Variant.Credits.Sum(p => p.VatAmount); var vat = _credits.Sum(p => p.VatAmount);
var grossSum = Variant.Credits.Sum(p => p.GrossAmount); var grossSum = _credits.Sum(p => p.GrossAmount);
var totalMods = Variant.Credits.Sum(p => p.Modifiers ?? 0m); var totalMods = _credits.Sum(p => p.Modifiers ?? 0m);
var considered = -Variant.Credits.Sum(p => p.PrevModifiers ?? 0m); var considered = -_credits.Sum(p => p.PrevModifiers ?? 0m);
var totalSum = Variant.Credits.Sum(p => p.Amount); var totalSum = _credits.Sum(p => p.Amount);
var weiRows = Data.Rows.Where(r => r.QualityLevel == "Wein"); var weiRows = data.Rows.Where(r => r.QualityLevel == "Wein");
var minWei = weiRows.Min(r => r.Ungeb.MinPrice); var minWei = weiRows.Min(r => r.Ungeb.MinPrice);
var maxWei = weiRows.Max(r => r.Ungeb.MaxPrice); var maxWei = weiRows.Max(r => r.Ungeb.MaxPrice);
var quwRows = Data.Rows.Where(r => r.QualityLevel != "Wein"); var quwRows = data.Rows.Where(r => r.QualityLevel != "Wein");
var minPrice = quwRows.Min(r => r.Ungeb.MinPrice); var minPrice = quwRows.Min(r => r.Ungeb.MinPrice);
var maxPrice = quwRows.Max(r => r.Ungeb.MaxPrice); var maxPrice = quwRows.Max(r => r.Ungeb.MaxPrice);
var gebRows = Data.Rows var gebRows = data.Rows
.Where(r => r.Geb.MaxPrice != null && r.Ungeb.MinPrice != null) .Where(r => r.Geb.MaxPrice != null && r.Ungeb.MinPrice != null)
.Select(r => r.Geb.MaxPrice - r.Ungeb.MinPrice); .Select(r => r.Geb.MaxPrice - r.Ungeb.MinPrice);
var minGeb = gebRows.Min(); var minGeb = gebRows.Min();
@@ -191,26 +211,26 @@ namespace Elwig.Documents {
.AddCell(NewTd(CurrencySymbol)) .AddCell(NewTd(CurrencySymbol))
.AddCell(NewTd($"{Math.Abs(totalMods):N2}", right: true)) .AddCell(NewTd($"{Math.Abs(totalMods):N2}", right: true))
.AddCell(NewSectionTh("Menge (ungebunden):", borderLeft: true, borderTop: true)) .AddCell(NewSectionTh("Menge (ungebunden):", borderLeft: true, borderTop: true))
.AddCell(NewTd($"{Data.Rows.Sum(r => r.Ungeb.Weight):N0} kg", colspan: 2, right: true, borderTop: true)) .AddCell(NewTd($"{data.Rows.Sum(r => r.Ungeb.Weight):N0} kg", colspan: 2, right: true, borderTop: true))
.AddCell(NewSectionTh("Bereits berücksichtigte Abzüge:", colspan: 2)) .AddCell(NewSectionTh("Bereits berücksichtigte Abzüge:", colspan: 2))
.AddCell(NewTd(Utils.GetSign(considered))) .AddCell(NewTd(Utils.GetSign(considered)))
.AddCell(NewTd(CurrencySymbol)) .AddCell(NewTd(CurrencySymbol))
.AddCell(NewTd($"{Math.Abs(considered):N2}", right: true)) .AddCell(NewTd($"{Math.Abs(considered):N2}", right: true))
.AddCell(NewSectionTh("Menge (gebunden):", borderLeft: true)) .AddCell(NewSectionTh("Menge (gebunden):", borderLeft: true))
.AddCell(NewTd($"{Data.Rows.Sum(r => r.Geb.Weight + r.LowGeb.Weight):N0} kg", colspan: 2, right: true)) .AddCell(NewTd($"{data.Rows.Sum(r => r.Geb.Weight + r.LowGeb.Weight):N0} kg", colspan: 2, right: true))
.AddCell(NewSectionTh("Auszahlungsbetrag:", colspan: 2)) .AddCell(NewSectionTh("Auszahlungsbetrag:", colspan: 2))
.AddCell(NewTd(borderTop: true)) .AddCell(NewTd(borderTop: true))
.AddCell(NewTd(CurrencySymbol, borderTop: true)) .AddCell(NewTd(CurrencySymbol, borderTop: true))
.AddCell(NewTd($"{totalSum:N2}", right: true, borderTop: true)) .AddCell(NewTd($"{totalSum:N2}", right: true, borderTop: true))
.AddCell(NewSectionTh("Gesamtmenge:", borderLeft: true)) .AddCell(NewSectionTh("Gesamtmenge:", borderLeft: true))
.AddCell(NewTd($"{Data.Rows.Sum(r => r.Ungeb.Weight + r.LowGeb.Weight + r.Geb.Weight):N0} kg", colspan: 2, right: true, borderTop: true)); .AddCell(NewTd($"{data.Rows.Sum(r => r.Ungeb.Weight + r.LowGeb.Weight + r.Geb.Weight):N0} kg", colspan: 2, right: true, borderTop: true));
return tbl; return tbl;
} }
protected Table NewModifierStatTable() { protected Table NewModifierStatTable(Dictionary<string, Modifier> modifiers, IEnumerable<ModifierStat> modStat) {
var tbl = new Table(ColsMM(35, 30, 25, 25, 25, 25)) var tbl = new Table(ColsMM(35, 30, 25, 25, 25, 25))
.SetWidth(UnitValue.CreatePercentValue(100)).SetFixedLayout() .SetWidth(UnitValue.CreatePercentValue(100)).SetFixedLayout()
.SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE) .SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE)
@@ -228,8 +248,8 @@ namespace Elwig.Documents {
.AddCell(NewTh($"[{CurrencySymbol}]")) .AddCell(NewTh($"[{CurrencySymbol}]"))
.AddCell(NewTh($"[{CurrencySymbol}]")); .AddCell(NewTh($"[{CurrencySymbol}]"));
foreach (var m in ModifierStat) { foreach (var m in modStat) {
var mod = Modifiers[m.ModId]; var mod = modifiers[m.ModId];
tbl.AddCell(NewTd(mod.Name, italic: true)) tbl.AddCell(NewTd(mod.Name, italic: true))
.AddCell(NewTd(mod.ValueStr, right: true)) .AddCell(NewTd(mod.ValueStr, right: true))
.AddCell(NewTd($"{m.Count:N0}", right: true)) .AddCell(NewTd($"{m.Count:N0}", right: true))
@@ -241,7 +261,7 @@ namespace Elwig.Documents {
return tbl; return tbl;
} }
protected Table NewPriceTable() { protected Table NewPriceTable(PaymentVariantSummaryData data) {
var tbl = new Table(ColsMM(25, 19, 18, 15, 18, 15, 18, 15, 22)) var tbl = new Table(ColsMM(25, 19, 18, 15, 18, 15, 18, 15, 22))
.SetWidth(UnitValue.CreatePercentValue(100)).SetFixedLayout() .SetWidth(UnitValue.CreatePercentValue(100)).SetFixedLayout()
.SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE); .SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE);
@@ -262,10 +282,10 @@ namespace Elwig.Documents {
.AddHeaderCell(NewTh($"[{CurrencySymbol}]")); .AddHeaderCell(NewTh($"[{CurrencySymbol}]"));
string? lastHdr = null; string? lastHdr = null;
foreach (var row in Data.Rows) { foreach (var row in data.Rows) {
var hdr = $"{row.Variety}{(row.Attribute != null ? " / " : "")}{row.Attribute}{(row.Cultivation != null ? " / " : "")}{row.Cultivation}"; var hdr = $"{row.Variety}{(row.Attribute != null ? " / " : "")}{row.Attribute}{(row.Cultivation != null ? " / " : "")}{row.Cultivation}";
if (lastHdr != hdr) { if (lastHdr != hdr) {
var rows = Data.Rows var rows = data.Rows
.Where(r => r.Variety == row.Variety && r.Attribute == row.Attribute && r.Cultivation == row.Cultivation) .Where(r => r.Variety == row.Variety && r.Attribute == row.Attribute && r.Cultivation == row.Cultivation)
.ToList(); .ToList();
var border = lastHdr != null; var border = lastHdr != null;

View File

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

View File

@@ -1,16 +1,19 @@
using Microsoft.EntityFrameworkCore;
using Elwig.Models.Entities;
using System.Linq;
using System.Threading.Tasks;
using System.IO;
using System;
using System.Windows;
using Microsoft.Extensions.Logging;
using Microsoft.Data.Sqlite;
using System.Text.RegularExpressions;
using System.Collections.Generic;
using Elwig.Models.Dtos; using Elwig.Models.Dtos;
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; using System.Data;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media.Converters;
namespace Elwig.Helpers { namespace Elwig.Helpers {
@@ -48,6 +51,7 @@ namespace Elwig.Helpers {
public DbSet<MemberTelNr> MemberTelephoneNrs { get; private set; } public DbSet<MemberTelNr> MemberTelephoneNrs { get; private set; }
public DbSet<MemberEmailAddr> MemberEmailAddrs { get; private set; } public DbSet<MemberEmailAddr> MemberEmailAddrs { get; private set; }
public DbSet<MemberHistory> MemberHistory { get; private set; } public DbSet<MemberHistory> MemberHistory { get; private set; }
public DbSet<AreaComContract> AreaCommitmentContracts { get; private set; }
public DbSet<AreaCom> AreaCommitments { get; private set; } public DbSet<AreaCom> AreaCommitments { get; private set; }
public DbSet<Season> Seasons { get; private set; } public DbSet<Season> Seasons { get; private set; }
public DbSet<DeliverySchedule> DeliverySchedules { get; private set; } public DbSet<DeliverySchedule> DeliverySchedules { get; private set; }
@@ -81,6 +85,70 @@ namespace Elwig.Helpers {
public static string? ConnectionStringOverride { get; set; } = null; 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"; 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, AreaComBucket>>> _memberAreaCommitmentBuckets = [];
private readonly Dictionary<int, Dictionary<int, Dictionary<string, int>>> _memberDeliveryBuckets = []; private readonly Dictionary<int, Dictionary<int, Dictionary<string, int>>> _memberDeliveryBuckets = [];
private readonly Dictionary<int, Dictionary<int, Dictionary<string, int>>> _memberDeliveryBucketsStrict = []; private readonly Dictionary<int, Dictionary<int, Dictionary<string, int>>> _memberDeliveryBucketsStrict = [];
@@ -118,11 +186,55 @@ namespace Elwig.Helpers {
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
optionsBuilder.UseSqlite(ConnectionString); optionsBuilder.UseSqlite(ConnectionString);
optionsBuilder.UseLazyLoadingProxies();
optionsBuilder.LogTo(Log, LogLevel.Information); optionsBuilder.LogTo(Log, LogLevel.Information);
base.OnConfiguring(optionsBuilder); base.OnConfiguring(optionsBuilder);
} }
protected override void OnModelCreating(ModelBuilder modelBuilder) {
modelBuilder.Entity<WbKg>().Navigation(k => k.AtKg).AutoInclude();
modelBuilder.Entity<WbKg>().Navigation(k => k.Gl).AutoInclude();
modelBuilder.Entity<AT_Kg>().Navigation(k => k.Gem).AutoInclude();
modelBuilder.Entity<PostalDest>().Navigation(p => p.Country).AutoInclude();
modelBuilder.Entity<PostalDest>().Navigation(p => p.AtPlz).AutoInclude();
modelBuilder.Entity<AT_PlzDest>().Navigation(p => p.AtPlz).AutoInclude();
modelBuilder.Entity<AT_PlzDest>().Navigation(p => p.Ort).AutoInclude();
modelBuilder.Entity<Member>().Navigation(m => m.DefaultWbKg).AutoInclude();
modelBuilder.Entity<Member>().Navigation(m => m.Country).AutoInclude();
modelBuilder.Entity<Member>().Navigation(m => m.PostalDest).AutoInclude();
modelBuilder.Entity<Member>().Navigation(m => m.BillingAddress).AutoInclude();
modelBuilder.Entity<BillingAddr>().Navigation(a => a.Country).AutoInclude();
modelBuilder.Entity<BillingAddr>().Navigation(a => a.PostalDest).AutoInclude();
modelBuilder.Entity<Modifier>().Navigation(m => m.Season).AutoInclude();
modelBuilder.Entity<Season>().Navigation(s => s.Currency).AutoInclude();
modelBuilder.Entity<PaymentVar>().Navigation(v => v.Season).AutoInclude();
modelBuilder.Entity<PaymentDeliveryPart>().Navigation(p => p.Variant).AutoInclude();
modelBuilder.Entity<Credit>().Navigation(c => c.Payment).AutoInclude();
modelBuilder.Entity<Delivery>().Navigation(d => d.Member).AutoInclude();
modelBuilder.Entity<Delivery>().Navigation(d => d.Season).AutoInclude();
modelBuilder.Entity<Delivery>().Navigation(d => d.Branch).AutoInclude();
modelBuilder.Entity<DeliveryPart>().Navigation(p => p.Quality).AutoInclude();
modelBuilder.Entity<DeliveryPart>().Navigation(p => p.Variety).AutoInclude();
modelBuilder.Entity<DeliveryPart>().Navigation(p => p.Attribute).AutoInclude();
modelBuilder.Entity<DeliveryPart>().Navigation(p => p.Cultivation).AutoInclude();
modelBuilder.Entity<DeliveryPart>().Navigation(p => p.Kg).AutoInclude();
modelBuilder.Entity<DeliveryPart>().Navigation(p => p.Rd).AutoInclude();
modelBuilder.Entity<DeliveryPartModifier>().Navigation(m => m.Modifier).AutoInclude();
modelBuilder.Entity<AreaComContract>().Navigation(c => c.Kg).AutoInclude();
modelBuilder.Entity<AreaComContract>().Navigation(c => c.Rd).AutoInclude();
modelBuilder.Entity<AreaCom>().Navigation(c => c.Contract).AutoInclude();
modelBuilder.Entity<AreaCom>().Navigation(c => c.WineCult).AutoInclude();
modelBuilder.Entity<AreaCom>().Navigation(c => c.AreaComType).AutoInclude();
modelBuilder.Entity<AreaComType>().Navigation(c => c.WineVar).AutoInclude();
modelBuilder.Entity<AreaComType>().Navigation(c => c.WineAttr).AutoInclude();
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() { public override void Dispose() {
base.Dispose(); base.Dispose();
LogFile?.Dispose(); LogFile?.Dispose();
@@ -138,23 +250,23 @@ namespace Elwig.Helpers {
} }
public async Task<bool> MgNrExists(int mgnr) { 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) { public async Task<bool> FbNrExists(int fbnr) {
return await AreaCommitments.FindAsync(fbnr) != null; return await _compiledQueryAreaCommitments.Invoke(this, fbnr).AnyAsync();
} }
public async Task<bool> SortIdExists(string sortId) { 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) { 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) { 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() { public async Task<int> NextMgNr() {
@@ -166,87 +278,113 @@ namespace Elwig.Helpers {
public async Task<int> NextFbNr() { public async Task<int> NextFbNr() {
int c = 0; int c = 0;
(await AreaCommitments.OrderBy(ac => ac.FbNr).Select(ac => ac.FbNr).ToListAsync()) (await AreaCommitmentContracts.OrderBy(ac => ac.FbNr).Select(ac => ac.FbNr).ToListAsync())
.ForEach(a => { if (a <= c + 10000) c = a; }); .ForEach(a => { if (a <= c + 10000) c = a; });
return c + 1; return c + 1;
} }
public async Task<int> NextRevNr(int fbnr) {
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) { public async Task<int> NextLNr(DateOnly date, string zwstid) {
var dateStr = date.ToString("yyyy-MM-dd"); var dateStr = date.ToString("yyyy-MM-dd");
int c = 0; return (await Deliveries.Where(d => d.DateString == dateStr && d.ZwstId == zwstid).Select(d => (int?)d.LNr).MaxAsync() ?? 0) + 1;
(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;
} }
public async Task<int> NextDId(int year) { public async Task<int> NextDId(int year) {
int c = 0; return (await Deliveries.Where(d => d.Year == year).Select(d => (int?)d.DId).MaxAsync() ?? 0) + 1;
(await Deliveries.Where(d => d.Year == year).Select(d => d.DId).ToListAsync())
.ForEach(a => { if (a <= c + 100) c = a; });
return c + 1;
} }
public async Task<int> NextDPNr(int year, int did) { public async Task<int> NextDPNr(int year, int did) {
int c = 0; return (await DeliveryParts.Where(p => p.Year == year && p.DId == did).Select(p => (int?)p.DPNr).MaxAsync() ?? 0) + 1;
(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;
} }
public async Task<int> NextRdNr(int kgnr) { public async Task<int> NextRdNr(int kgnr) {
int c = 0; return (await WbRde.Where(r => r.KgNr == kgnr).Select(r => (int?)r.RdNr).MaxAsync() ?? 0) + 1;
(await WbRde.Where(r => r.KgNr == kgnr).Select(r => r.RdNr).ToListAsync())
.ForEach(a => { if (a <= c + 100) c = a; });
return c + 1;
} }
public async Task<int> NextAvNr(int year) { public async Task<int> NextAvNr(int year) {
int c = 0; return (await PaymentVariants.Where(v => v.Year == year).Select(v => (int?)v.AvNr).MaxAsync() ?? 0) + 1;
(await PaymentVariants.Where(v => v.Year == year).Select(v => v.AvNr).ToListAsync())
.ForEach(a => { if (a <= c + 100) c = a; });
return c + 1;
} }
public async Task<int> NextDsNr(int year) { public async Task<int> NextDsNr(int year) {
int c = 0; return (await DeliverySchedules.Where(s => s.Year == year).Select(v => (int?)v.DsNr).MaxAsync() ?? 0) + 1;
(await DeliverySchedules.Where(s => s.Year == year).Select(s => s.DsNr).ToListAsync())
.ForEach(a => { if (a <= c + 100) c = a; });
return c + 1;
} }
public void UpdateDeliveryPartModifiers(DeliveryPart part, IEnumerable<Modifier> oldModifiers, IEnumerable<Modifier> newModifiers) { public IAsyncEnumerable<Branch> FetchBranches(string? zwstid = null, bool includeWithoutMembers = true) {
foreach (var m in Modifiers.Where(m => m.Year == part.Year)) { 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 { var mod = new DeliveryPartModifier {
Year = part.Year, Year = part.Year,
DId = part.DId, DId = part.DId,
DPNr = part.DPNr, DPNr = part.DPNr,
ModId = m.ModId, ModId = m.ModId,
}; };
var old = oldModifiers.Where(pa => pa.ModId == m.ModId).FirstOrDefault(); var old = oldModIds.Contains(m.ModId);
if (newModifiers.Any(md => md.ModId == m.ModId)) { if (newModIds.Contains(m.ModId)) {
if (old == null) { if (!old) {
Add(mod); Add(mod);
} else { } else {
Update(mod); Update(mod);
} }
} else { } else {
if (old != null) { if (old) {
Remove(mod); Remove(mod);
} }
} }
} }
} }
public void UpdateDeliveryScheduleWineVarieties(DeliverySchedule schedule, IEnumerable<(WineVar, int)> oldVarieties, IEnumerable<(WineVar, int)> newVarieties) { public async Task UpdateDeliveryScheduleWineVarieties(DeliverySchedule schedule, IEnumerable<(string, int)> oldVarieties, IEnumerable<(string, int)> newVarieties) {
foreach (var v in WineVarieties) { foreach (var v in await FetchWineVarieties().ToArrayAsync()) {
var e = new DeliveryScheduleWineVar { var e = new DeliveryScheduleWineVar {
Year = schedule.Year, Year = schedule.Year,
DsNr = schedule.DsNr, DsNr = schedule.DsNr,
SortId = v.SortId, SortId = v.SortId,
Priority = 1, Priority = 1,
}; };
var o = oldVarieties.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.SortId == 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) { if (n != -1) {
e.Priority = n; e.Priority = n;
if (o == -1) { if (o == -1) {
@@ -391,10 +529,12 @@ namespace Elwig.Helpers {
var paymentBuckets = await GetMemberPaymentBuckets(year, mgnr, cnx); var paymentBuckets = await GetMemberPaymentBuckets(year, mgnr, cnx);
if (ownCnx) await cnx.DisposeAsync(); if (ownCnx) await cnx.DisposeAsync();
var varieties = await WineVarieties.ToDictionaryAsync(v => v.SortId);
var attributes = await WineAttributes.ToDictionaryAsync(a => a.AttrId);
var buckets = new Dictionary<string, MemberBucket>(); var buckets = new Dictionary<string, MemberBucket>();
foreach (var id in rightsAndObligations.Keys.Union(deliveryBuckets.Keys).Union(paymentBuckets.Keys)) { foreach (var id in rightsAndObligations.Keys.Union(deliveryBuckets.Keys).Union(paymentBuckets.Keys)) {
var variety = await WineVarieties.FindAsync(id[..2]); var variety = varieties.GetValueOrDefault(id[..2]);
var attribute = await WineAttributes.FindAsync(id[2..]); var attribute = attributes.GetValueOrDefault(id[2..]);
var name = (variety?.Name ?? "") + (id[2..] == "_" ? " (kein Qual.Wein)" : attribute != null ? $" ({attribute})" : ""); var name = (variety?.Name ?? "") + (id[2..] == "_" ? " (kein Qual.Wein)" : attribute != null ? $" ({attribute})" : "");
buckets[id] = new( buckets[id] = new(
name, name,

View File

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

View File

@@ -1,6 +1,5 @@
using Elwig.Models.Entities; using Elwig.Models.Entities;
using Microsoft.Data.Sqlite; using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
@@ -16,13 +15,30 @@ namespace Elwig.Helpers.Billing {
protected readonly Dictionary<string, (decimal?, decimal?)> Modifiers; protected readonly Dictionary<string, (decimal?, decimal?)> Modifiers;
protected readonly Dictionary<string, (string, string?, string?, int?, decimal?)> AreaComTypes; 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; 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(); using var ctx = new AppDbContext();
Season = ctx.Seasons.Find(Year)!; var (season, attributes, modifiers, areaComTypes) = await LoadData(ctx, year);
Attributes = ctx.WineAttributes.ToDictionary(a => a.AttrId, a => a.Name); return new Billing(year, season, attributes, modifiers, areaComTypes);
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));
} }
public async Task FinishSeason() { public async Task FinishSeason() {

View File

@@ -10,17 +10,35 @@ namespace Elwig.Helpers.Billing {
public class BillingVariant : Billing { public class BillingVariant : Billing {
protected readonly int AvNr; protected readonly int AvNr;
protected readonly PaymentVar PaymentVariant; protected PaymentVar PaymentVariant;
protected readonly PaymentBillingData Data; 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; 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(); 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"); var (season, attributes, modifiers, areaComTypes) = await LoadData(ctx, year);
Data = PaymentBillingData.FromJson(PaymentVariant.Data, Utils.GetVaributes(ctx, Year, onlyDelivered: false)); 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) { 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 cnx = await AppDbContext.ConnectAsync();
using var tx = await cnx.BeginTransactionAsync(); using var tx = await cnx.BeginTransactionAsync();
await CalculateBuckets(honorGebunden, allowAttrsIntoLower, avoidUnderDeliveries, cnx); await CalculateBuckets(honorGebunden, allowAttrsIntoLower, avoidUnderDeliveries, cnx);

View File

@@ -3,6 +3,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text.Json.Nodes; using System.Text.Json.Nodes;
using System.Threading.Tasks;
namespace Elwig.Helpers.Billing { namespace Elwig.Helpers.Billing {
public class EditBillingData : BillingData { public class EditBillingData : BillingData {
@@ -70,14 +71,14 @@ namespace Elwig.Helpers.Billing {
return (curves, dict3); return (curves, dict3);
} }
private static List<GraphEntry> CreateGraphEntries( private static async Task<List<GraphEntry>> CreateGraphEntries(
AppDbContext ctx, int precision, AppDbContext ctx, int precision,
Dictionary<int, Curve> curves, Dictionary<int, Curve> curves,
Dictionary<int, List<RawVaribute>> entries Dictionary<int, List<RawVaribute>> entries
) { ) {
var vars = ctx.WineVarieties.ToDictionary(v => v.SortId, v => v); var vars = await ctx.FetchWineVarieties().ToDictionaryAsync(v => v.SortId, v => v);
var attrs = ctx.WineAttributes.ToDictionary(a => a.AttrId, a => a); var attrs = await ctx.FetchWineAttributes().ToDictionaryAsync(a => a.AttrId, a => a);
var cults = ctx.WineCultivations.ToDictionary(c => c.CultId, c => c); var cults = await ctx.FetchWineCultivations().ToDictionaryAsync(c => c.CultId, c => c);
return entries return entries
.Select(e => new GraphEntry(e.Key, precision, curves[e.Key], e.Value .Select(e => new GraphEntry(e.Key, precision, curves[e.Key], e.Value
.Select(s => new Varibute(s, vars, attrs, cults)) .Select(s => new Varibute(s, vars, attrs, cults))
@@ -85,18 +86,18 @@ namespace Elwig.Helpers.Billing {
.ToList(); .ToList();
} }
public IEnumerable<GraphEntry> GetPaymentGraphEntries(AppDbContext ctx, Season season) { public async Task<IEnumerable<GraphEntry>> GetPaymentGraphEntries(AppDbContext ctx, Season season) {
var root = GetPaymentEntry(); var root = GetPaymentEntry();
var (curves, entries) = GetGraphEntries(root); 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(); var root = GetQualityEntry();
if (root == null || root["WEI"] is not JsonNode qualityWei) if (root == null || root["WEI"] is not JsonNode qualityWei)
return []; return [];
var (curves, entries) = GetGraphEntries(qualityWei); 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) { foreach (var e in list) {
e.Id += idOffset; e.Id += idOffset;
e.Abgewertet = true; e.Abgewertet = true;

View File

@@ -41,7 +41,7 @@ namespace Elwig.Helpers.Export {
List<WbGl> currentWbGls; List<WbGl> currentWbGls;
using (var ctx = new AppDbContext()) { 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 currentDids = await ctx.Deliveries
.GroupBy(d => d.Year) .GroupBy(d => d.Year)
.ToDictionaryAsync(g => g.Key, g => g.Max(d => d.DId)); .ToDictionaryAsync(g => g.Key, g => g.Max(d => d.DId));
@@ -60,13 +60,14 @@ namespace Elwig.Helpers.Export {
List<MemberTelNr> TelephoneNumbers, List<MemberTelNr> TelephoneNumbers,
List<MemberEmailAddr> EmailAddresses, List<MemberEmailAddr> EmailAddresses,
List<AreaCom> AreaCommitments, List<AreaCom> AreaCommitments,
List<AreaComContract> Contracts,
List<WbRd> Riede, List<WbRd> Riede,
List<WbKg> WbKgs, List<WbKg> WbKgs,
List<WbGl> WbGls, List<WbGl> WbGls,
List<Delivery> Deliveries, List<Delivery> Deliveries,
List<DeliveryPart> DeliveryParts, List<DeliveryPart> DeliveryParts,
List<DeliveryPartModifier> Modifiers, List<DeliveryPartModifier> Modifiers,
Dictionary<string, List<(int Id1, int Id2, DateTime CreatedAt, DateTime ModifiedAt)>> Timestamps)>(); Dictionary<string, List<(int Id1, int Id2, int Id3, DateTime CreatedAt, DateTime ModifiedAt)>> Timestamps)>();
var metaData = new List<(string FileName, string ZwstId, string Device, var metaData = new List<(string FileName, string ZwstId, string Device,
int? MemberNum, string? MemberFilters, int? MemberNum, string? MemberFilters,
@@ -75,10 +76,12 @@ namespace Elwig.Helpers.Export {
foreach (var filename in filenames) { foreach (var filename in filenames) {
try { try {
data.Add(new([], [], [], [], [], [], [], new([], [], [], [], new() { data.Add(new([], [], [], [], [], [], [], new([], [], [], [], [], new() {
["member"] = [], ["member"] = [],
["area_commitment_contract"] = [],
["area_commitment"] = [], ["area_commitment"] = [],
["delivery"] = [], ["delivery"] = [],
["delivery_part"] = [],
}))); })));
var r = data[^1]; var r = data[^1];
@@ -86,9 +89,11 @@ namespace Elwig.Helpers.Export {
using var zip = ZipFile.Open(filename, ZipArchiveMode.Read); using var zip = ZipFile.Open(filename, ZipArchiveMode.Read);
await zip.CheckIntegrity(); await zip.CheckIntegrity();
string[] acceptableVersions = ["1", "2"];
var version = zip.GetEntry("version"); var version = zip.GetEntry("version");
using (var reader = new StreamReader(version!.Open(), Utils.UTF8)) { using (var reader = new StreamReader(version!.Open(), Utils.UTF8)) {
if (await reader.ReadToEndAsync() != "elwig:1") var v = await reader.ReadToEndAsync();
if (!v.StartsWith("elwig:") || !acceptableVersions.Contains(v[6..]))
throw new FileFormatException($"Ungültige Elwig-Export-Datei ({filename})"); throw new FileFormatException($"Ungültige Elwig-Export-Datei ({filename})");
} }
@@ -96,8 +101,8 @@ namespace Elwig.Helpers.Export {
var meta = await JsonNode.ParseAsync(metaJson!.Open()); var meta = await JsonNode.ParseAsync(metaJson!.Open());
var memberCount = meta!["members"]?["count"]?.AsValue().GetValue<int>(); var memberCount = meta!["members"]?["count"]?.AsValue().GetValue<int>();
var memberFilters = meta!["members"]?["filters"]?.AsArray().Select(f => f!.AsValue().GetValue<string>()).ToArray(); var memberFilters = meta!["members"]?["filters"]?.AsArray().Select(f => f!.AsValue().GetValue<string>()).ToArray();
var areaComCount = meta!["area_commitments"]?["count"]?.AsValue().GetValue<int>(); var areaComCount = meta!["area_commitment_contracts"]?["count"]?.AsValue().GetValue<int>();
var areaComFilters = meta!["area_commitments"]?["filters"]?.AsArray().Select(f => f!.AsValue().GetValue<string>()).ToArray(); var areaComFilters = meta!["area_commitment_contracts"]?["filters"]?.AsArray().Select(f => f!.AsValue().GetValue<string>()).ToArray();
var deliveryCount = meta!["deliveries"]?["count"]?.AsValue().GetValue<int>(); var deliveryCount = meta!["deliveries"]?["count"]?.AsValue().GetValue<int>();
var deliveryFilters = meta!["deliveries"]?["filters"]?.AsArray().Select(f => f!.AsValue().GetValue<string>()).ToArray(); var deliveryFilters = meta!["deliveries"]?["filters"]?.AsArray().Select(f => f!.AsValue().GetValue<string>()).ToArray();
metaData.Add((Path.GetFileName(filename), metaData.Add((Path.GetFileName(filename),
@@ -133,23 +138,48 @@ namespace Elwig.Helpers.Export {
r.TelephoneNumbers.AddRange(telNrs); r.TelephoneNumbers.AddRange(telNrs);
r.EmailAddresses.AddRange(emailAddrs); r.EmailAddresses.AddRange(emailAddrs);
if (timestamps.HasValue) if (timestamps.HasValue)
r.Timestamps["member"].Add((m.MgNr, 0, timestamps.Value.CreatedAt, timestamps.Value.ModifiedAt)); r.Timestamps["member"].Add((m.MgNr, 0, 0, timestamps.Value.CreatedAt, timestamps.Value.ModifiedAt));
} }
} }
// legacy area commitments
var areaComsJson = zip.GetEntry("area_commitments.json"); var areaComsJson = zip.GetEntry("area_commitments.json");
if (areaComsJson != null) { if (areaComsJson != null) {
using var reader = new StreamReader(areaComsJson.Open(), Utils.UTF8); using var reader = new StreamReader(areaComsJson.Open(), Utils.UTF8);
string? line; string? line;
while ((line = await reader.ReadLineAsync()) != null) { while ((line = await reader.ReadLineAsync()) != null) {
var obj = JsonNode.Parse(line)!.AsObject(); var obj = JsonNode.Parse(line)!.AsObject();
var (areaCom, wbrd, timestamps) = obj.ToAreaCom(currentWbRde); var (contract, areaCom, wbrd, timestamps) = obj.ToAreaCom(currentWbRde);
r.Contracts.Add(contract);
r.AreaCommitments.Add(areaCom); r.AreaCommitments.Add(areaCom);
if (wbrd != null) { if (wbrd != null) {
r.Riede.Add(wbrd); r.Riede.Add(wbrd);
} }
if (timestamps.HasValue) {
r.Timestamps["area_commitment_contract"].Add((contract.FbNr, 0, 0, timestamps.Value.CreatedAt, timestamps.Value.ModifiedAt));
r.Timestamps["area_commitment"].Add((areaCom.FbNr, areaCom.RevNr, 0, timestamps.Value.CreatedAt, timestamps.Value.ModifiedAt));
}
}
}
var contractsJson = zip.GetEntry("area_commitment_contracts.json");
if (contractsJson != null) {
using var reader = new StreamReader(contractsJson.Open(), Utils.UTF8);
string? line;
while ((line = await reader.ReadLineAsync()) != null) {
var obj = JsonNode.Parse(line)!.AsObject();
var (contract, areaComs, wbrd, timestamps) = obj.ToAreaComContract(currentWbRde);
r.Contracts.Add(contract);
r.AreaCommitments.AddRange(areaComs.Select(v => v.Item1));
if (wbrd != null) {
r.Riede.Add(wbrd);
}
if (timestamps.HasValue) if (timestamps.HasValue)
r.Timestamps["area_commitment"].Add((areaCom.FbNr, 0, timestamps.Value.CreatedAt, timestamps.Value.ModifiedAt)); r.Timestamps["area_commitment_contract"].Add((contract.FbNr, 0, 0, timestamps.Value.CreatedAt, timestamps.Value.ModifiedAt));
foreach (var (areaCom, ts) in areaComs) {
if (!ts.HasValue) continue;
r.Timestamps["area_commitment"].Add((areaCom.FbNr, areaCom.RevNr, 0, ts.Value.CreatedAt, ts.Value.ModifiedAt));
}
} }
} }
@@ -161,11 +191,15 @@ namespace Elwig.Helpers.Export {
var obj = JsonNode.Parse(line)!.AsObject(); var obj = JsonNode.Parse(line)!.AsObject();
var (d, parts, mods, rde, timestamps) = obj.ToDelivery(currentLsNrs, currentDids, kgs, currentWbRde); var (d, parts, mods, rde, timestamps) = obj.ToDelivery(currentLsNrs, currentDids, kgs, currentWbRde);
r.Deliveries.Add(d); r.Deliveries.Add(d);
r.DeliveryParts.AddRange(parts); r.DeliveryParts.AddRange(parts.Select(p => p.Item1));
r.Modifiers.AddRange(mods); r.Modifiers.AddRange(mods);
r.Riede.AddRange(rde); r.Riede.AddRange(rde);
if (timestamps.HasValue) if (timestamps.HasValue)
r.Timestamps["delivery"].Add((d.Year, d.DId, timestamps.Value.CreatedAt, timestamps.Value.ModifiedAt)); r.Timestamps["delivery"].Add((d.Year, d.DId, 0, timestamps.Value.CreatedAt, timestamps.Value.ModifiedAt));
foreach (var (part, ts) in parts) {
if (!ts.HasValue) continue;
r.Timestamps["area_commitment"].Add((part.Year, part.DId, part.DPNr, ts.Value.CreatedAt, ts.Value.ModifiedAt));
}
} }
} }
} catch (Exception exc) when ( } catch (Exception exc) when (
@@ -189,11 +223,11 @@ namespace Elwig.Helpers.Export {
} }
} }
var importedMembers = new List<(string FileName, string ZwstId, string Device, int New, int Overwritten, int NotImported, string Filters)>(); 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)>(); 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, riede, wbKgs, wbGls, deliveries, deliveryParts, modifiers, timestamps), meta) in data.Zip(metaData)) { foreach (var ((members, billingAddresses, telephoneNumbers, emailAddresses, areaCommitments, contracts, riede, wbKgs, wbGls, deliveries, deliveryParts, modifiers, timestamps), meta) in data.Zip(metaData)) {
var branch = branches[meta.ZwstId]; var branch = branches[meta.ZwstId];
var device = meta.Device; var device = meta.Device;
@@ -220,11 +254,20 @@ namespace Elwig.Helpers.Export {
if (duplicateMgNrs.Count > 0) if (duplicateMgNrs.Count > 0)
importDuplicateMembers = ImportQuestion(branch.Name, device, "Mitglieder", true, duplicateMgNrs.Count); importDuplicateMembers = ImportQuestion(branch.Name, device, "Mitglieder", true, duplicateMgNrs.Count);
var fbnrs = areaCommitments.Select(c => c.FbNr).ToList(); var fbnrs = contracts.Select(c => c.FbNr).ToList();
var duplicateFbNrs = await ctx.AreaCommitments var duplicateFbNrs = await ctx.AreaCommitmentContracts
.Where(c => fbnrs.Contains(c.FbNr)) .Where(c => fbnrs.Contains(c.FbNr))
.Select(c => c.FbNr) .Select(c => c.FbNr)
.ToListAsync(); .ToListAsync();
bool importNewContracts = false, importDuplicateContracts = false;
if (mode == ImportMode.Interactively) {
if (fbnrs.Count - duplicateFbNrs.Count > 0)
importNewContracts = ImportQuestion(branch.Name, device, "Flächenbindungsverträge", false, fbnrs.Count - duplicateFbNrs.Count);
} else {
importNewContracts = true;
}
if (duplicateFbNrs.Count > 0)
importDuplicateContracts = ImportQuestion(branch.Name, device, "Flächenbindungsverträge", true, duplicateFbNrs.Count);
var lsnrs = deliveries.Select(d => d.LsNr).ToList(); var lsnrs = deliveries.Select(d => d.LsNr).ToList();
var duplicateLsNrs = await ctx.Deliveries var duplicateLsNrs = await ctx.Deliveries
@@ -258,40 +301,47 @@ namespace Elwig.Helpers.Export {
importDuplicateDeliveries = ImportQuestion(branch.Name, device, "Lieferungen", true, duplicateLsNrs.Count); importDuplicateDeliveries = ImportQuestion(branch.Name, device, "Lieferungen", true, duplicateLsNrs.Count);
} }
if (importDuplicateMembers || importNewMembers || importDuplicateDeliveries || importNewDeliveries) { if (importDuplicateMembers || importNewMembers || importDuplicateContracts || importNewContracts || importDuplicateDeliveries || importNewDeliveries) {
ctx.AddRange(wbGls); ctx.AddRange(wbGls);
ctx.UpdateRange(wbKgs.Where(k => duplicateKgNrs.Contains(k.KgNr))); ctx.UpdateRange(wbKgs.Where(k => duplicateKgNrs.Contains(k.KgNr)));
ctx.AddRange(wbKgs.Where(k => !duplicateKgNrs.Contains(k.KgNr))); ctx.AddRange(wbKgs.Where(k => !duplicateKgNrs.Contains(k.KgNr)));
} }
if (importDuplicateMembers) { if (importDuplicateMembers) {
ctx.RemoveRange(ctx.BillingAddresses.Where(a => duplicateMgNrs.Contains(a.MgNr))); ctx.RemoveRange(ctx.BillingAddresses.IgnoreAutoIncludes().Where(a => duplicateMgNrs.Contains(a.MgNr)));
ctx.RemoveRange(ctx.MemberTelephoneNrs.Where(n => duplicateMgNrs.Contains(n.MgNr))); ctx.RemoveRange(ctx.MemberTelephoneNrs.IgnoreAutoIncludes().Where(n => duplicateMgNrs.Contains(n.MgNr)));
ctx.RemoveRange(ctx.MemberEmailAddrs.Where(a => duplicateMgNrs.Contains(a.MgNr))); ctx.RemoveRange(ctx.MemberEmailAddrs.IgnoreAutoIncludes().Where(a => duplicateMgNrs.Contains(a.MgNr)));
ctx.UpdateRange(members.Where(m => duplicateMgNrs.Contains(m.MgNr))); ctx.UpdateRange(members.Where(m => duplicateMgNrs.Contains(m.MgNr)));
ctx.AddRange(billingAddresses.Where(a => duplicateMgNrs.Contains(a.MgNr))); ctx.AddRange(billingAddresses.Where(a => duplicateMgNrs.Contains(a.MgNr)));
ctx.AddRange(telephoneNumbers.Where(n => duplicateMgNrs.Contains(n.MgNr))); ctx.AddRange(telephoneNumbers.Where(n => duplicateMgNrs.Contains(n.MgNr)));
ctx.AddRange(emailAddresses.Where(a => duplicateMgNrs.Contains(a.MgNr))); ctx.AddRange(emailAddresses.Where(a => duplicateMgNrs.Contains(a.MgNr)));
ctx.UpdateRange(areaCommitments.Where(c => duplicateMgNrs.Contains(c.MgNr) && duplicateFbNrs.Contains(c.FbNr)));
ctx.AddRange(areaCommitments.Where(c => duplicateMgNrs.Contains(c.MgNr) && !duplicateFbNrs.Contains(c.FbNr)));
} }
if (importNewMembers) { if (importNewMembers) {
ctx.AddRange(members.Where(m => !duplicateMgNrs.Contains(m.MgNr))); ctx.AddRange(members.Where(m => !duplicateMgNrs.Contains(m.MgNr)));
ctx.AddRange(billingAddresses.Where(a => !duplicateMgNrs.Contains(a.MgNr))); ctx.AddRange(billingAddresses.Where(a => !duplicateMgNrs.Contains(a.MgNr)));
ctx.AddRange(telephoneNumbers.Where(n => !duplicateMgNrs.Contains(n.MgNr))); ctx.AddRange(telephoneNumbers.Where(n => !duplicateMgNrs.Contains(n.MgNr)));
ctx.AddRange(emailAddresses.Where(a => !duplicateMgNrs.Contains(a.MgNr))); ctx.AddRange(emailAddresses.Where(a => !duplicateMgNrs.Contains(a.MgNr)));
ctx.UpdateRange(areaCommitments.Where(c => !duplicateMgNrs.Contains(c.MgNr) && duplicateFbNrs.Contains(c.FbNr)));
ctx.AddRange(areaCommitments.Where(c => !duplicateMgNrs.Contains(c.MgNr) && !duplicateFbNrs.Contains(c.FbNr)));
} }
if (members.Count > 0) { if (members.Count > 0) {
var n = importNewMembers ? members.Count - duplicateMgNrs.Count : 0; var n = importNewMembers ? members.Count - duplicateMgNrs.Count : 0;
var o = importDuplicateMembers ? duplicateMgNrs.Count : 0; var o = importDuplicateMembers ? duplicateMgNrs.Count : 0;
importedMembers.Add((meta.FileName, meta.ZwstId, meta.Device, n, o, members.Count - n - o, meta.MemberFilters)); importedMembers.Add((meta.FileName, meta.ZwstId, meta.Device, n, o, members.Count - n - o, meta.MemberFilters));
} }
if (areaCommitments.Count > 0) {
if (importDuplicateContracts) {
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)));
}
if (importNewContracts) {
ctx.AddRange(contracts.Where(c => !duplicateFbNrs.Contains(c.FbNr)));
ctx.AddRange(areaCommitments.Where(c => !duplicateFbNrs.Contains(c.FbNr)));
}
if (contracts.Count > 0) {
ctx.AddRange(riede); ctx.AddRange(riede);
var imported = areaCommitments.Where(c => (importNewMembers && !duplicateMgNrs.Contains(c.MgNr)) || (importDuplicateMembers && duplicateMgNrs.Contains(c.MgNr))).ToList(); var n = importNewContracts ? contracts.Count - duplicateFbNrs.Count : 0;
importedAreaComs.Add((meta.FileName, meta.ZwstId, meta.Device, imported.Count, areaCommitments.Count - imported.Count, meta.AreaComFilters)); 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) { if (allowedDuplicateLsNrs.Count > 0) {
@@ -300,9 +350,10 @@ namespace Elwig.Helpers.Export {
.Select(d => (d.Year, d.DId)) .Select(d => (d.Year, d.DId))
.ToList(); .ToList();
ctx.RemoveRange(ctx.DeliveryParts ctx.RemoveRange(ctx.DeliveryParts
.IgnoreAutoIncludes()
.Where(p => allowedDuplicateLsNrs.Contains(p.Delivery.LsNr)) .Where(p => allowedDuplicateLsNrs.Contains(p.Delivery.LsNr))
.SelectMany(p => p.PartModifiers)); .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.UpdateRange(deliveries.Where(d => dids.Contains((d.Year, d.DId))));
ctx.AddRange(deliveryParts.Where(p => dids.Contains((p.Year, p.DId)))); ctx.AddRange(deliveryParts.Where(p => dids.Contains((p.Year, p.DId))));
ctx.AddRange(modifiers.Where(m => dids.Contains((m.Year, m.DId)))); ctx.AddRange(modifiers.Where(m => dids.Contains((m.Year, m.DId))));
@@ -314,9 +365,10 @@ namespace Elwig.Helpers.Export {
.Select(d => (d.Year, d.DId)) .Select(d => (d.Year, d.DId))
.ToList(); .ToList();
ctx.RemoveRange(ctx.DeliveryParts ctx.RemoveRange(ctx.DeliveryParts
.IgnoreAutoIncludes()
.Where(p => l.Contains(p.Delivery.LsNr)) .Where(p => l.Contains(p.Delivery.LsNr))
.SelectMany(p => p.PartModifiers)); .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.UpdateRange(deliveries.Where(d => dids.Contains((d.Year, d.DId))));
ctx.AddRange(deliveryParts.Where(p => dids.Contains((p.Year, p.DId)))); ctx.AddRange(deliveryParts.Where(p => dids.Contains((p.Year, p.DId))));
ctx.AddRange(modifiers.Where(m => dids.Contains((m.Year, m.DId)))); ctx.AddRange(modifiers.Where(m => dids.Contains((m.Year, m.DId))));
@@ -335,15 +387,17 @@ namespace Elwig.Helpers.Export {
await ctx.SaveChangesAsync(); await ctx.SaveChangesAsync();
var primaryKeys = new Dictionary<string, string>() { var primaryKeys = new Dictionary<string, string>() {
["member"] = "mgnr, 0", ["member"] = "mgnr, 0, 0",
["area_commitment"] = "fbnr, 0", ["area_commitment_contract"] = "fbnr, 0, 0",
["delivery"] = "year, did", ["area_commitment"] = "fbnr, revnr, 0",
["delivery"] = "year, did, 0",
["delivery_part"] = "year, did, dpnr",
}; };
var updateStmts = timestamps var updateStmts = timestamps
.SelectMany(e => e.Value.Select(m => $"UPDATE {e.Key} " + .SelectMany(e => e.Value.Select(m => $"UPDATE {e.Key} " +
$"SET ctime = {((DateTimeOffset)m.CreatedAt.ToUniversalTime()).ToUnixTimeSeconds()}, " + $"SET ctime = {((DateTimeOffset)m.CreatedAt.ToUniversalTime()).ToUnixTimeSeconds()}, " +
$"mtime = {((DateTimeOffset)m.ModifiedAt.ToUniversalTime()).ToUnixTimeSeconds()} " + $"mtime = {((DateTimeOffset)m.ModifiedAt.ToUniversalTime()).ToUnixTimeSeconds()} " +
$"WHERE ({primaryKeys[e.Key]}) = ({m.Id1}, {m.Id2});")); $"WHERE ({primaryKeys[e.Key]}) = ({m.Id1}, {m.Id2}, {m.Id3});"));
using var cnx = AppDbContext.Connect(); using var cnx = AppDbContext.Connect();
await cnx.ExecuteBatch($""" await cnx.ExecuteBatch($"""
BEGIN; BEGIN;
@@ -367,10 +421,10 @@ namespace Elwig.Helpers.Export {
$" ({d.New} neu, {d.Overwritten} überschrieben, {d.NotImported} nicht importiert)\n" + $" ({d.New} neu, {d.Overwritten} überschrieben, {d.NotImported} nicht importiert)\n" +
$" Zweigstelle: {branches[d.ZwstId].Name} (Gerät {d.Device})\n" + $" Zweigstelle: {branches[d.ZwstId].Name} (Gerät {d.Device})\n" +
$" Filter: {d.Filters}"), $" Filter: {d.Filters}"),
$"Flächenbindungen: {importedAreaComs.Sum(d => d.Imported)}", $"Flächenbindungen: {importedAreaComs.Sum(d => d.New + d.Overwritten)}",
..importedAreaComs.Select(d => ..importedAreaComs.Select(d =>
$" {d.FileName} ({d.Imported})\n" + $" {d.FileName} ({d.New + d.Overwritten})\n" +
$" ({d.Imported} importiert, {d.NotImported} nicht importiert)\n" + $" ({d.New} importiert, {d.Overwritten} überschreiben, {d.NotImported} nicht importiert)\n" +
$" Zweigstelle: {branches[d.ZwstId].Name} (Gerät {d.Device})\n" + $" Zweigstelle: {branches[d.ZwstId].Name} (Gerät {d.Device})\n" +
$" Filter: {d.Filters}"), $" Filter: {d.Filters}"),
$"Lieferungen: {importedDeliveries.Sum(d => d.New + d.Overwritten)}", $"Lieferungen: {importedDeliveries.Sum(d => d.New + d.Overwritten)}",
@@ -407,7 +461,7 @@ namespace Elwig.Helpers.Export {
}.Export(filename); }.Export(filename);
} }
public static Task Export(string filename, IEnumerable<Member> members, IEnumerable<AreaCom> areaComs, IEnumerable<WbKg> wbKgs, IEnumerable<string> filters) { public static Task Export(string filename, IEnumerable<Member> members, IEnumerable<AreaComContract> areaComs, IEnumerable<WbKg> wbKgs, IEnumerable<string> filters) {
return new ElwigExport { return new ElwigExport {
Members = (members, filters), Members = (members, filters),
AreaComs = (areaComs, ["von exportierten Mitgliedern"]), AreaComs = (areaComs, ["von exportierten Mitgliedern"]),
@@ -425,7 +479,7 @@ namespace Elwig.Helpers.Export {
public class ElwigExport { public class ElwigExport {
public (IEnumerable<WbKg> WbKgs, IEnumerable<string> Filters)? WbKgs { get; set; } public (IEnumerable<WbKg> WbKgs, IEnumerable<string> Filters)? WbKgs { get; set; }
public (IEnumerable<Member> Members, IEnumerable<string> Filters)? Members { get; set; } public (IEnumerable<Member> Members, IEnumerable<string> Filters)? Members { get; set; }
public (IEnumerable<AreaCom> AreaComs, IEnumerable<string> Filters)? AreaComs { get; set; } public (IEnumerable<AreaComContract> AreaComs, IEnumerable<string> Filters)? AreaComs { get; set; }
public (IEnumerable<Delivery> Deliveries, IEnumerable<string> Filters)? Deliveries { get; set; } public (IEnumerable<Delivery> Deliveries, IEnumerable<string> Filters)? Deliveries { get; set; }
public async Task Export(string filename) { public async Task Export(string filename) {
@@ -434,7 +488,7 @@ namespace Elwig.Helpers.Export {
var version = zip.CreateEntry("version", CompressionLevel.NoCompression); var version = zip.CreateEntry("version", CompressionLevel.NoCompression);
using (var writer = new StreamWriter(version.Open(), Utils.UTF8)) { using (var writer = new StreamWriter(version.Open(), Utils.UTF8)) {
await writer.WriteAsync("elwig:1"); await writer.WriteAsync("elwig:2");
} }
var meta = zip.CreateEntry("meta.json", CompressionLevel.NoCompression); var meta = zip.CreateEntry("meta.json", CompressionLevel.NoCompression);
@@ -456,8 +510,9 @@ namespace Elwig.Helpers.Export {
["filters"] = new JsonArray(Members.Value.Filters.Select(f => (JsonNode)f).ToArray()), ["filters"] = new JsonArray(Members.Value.Filters.Select(f => (JsonNode)f).ToArray()),
}; };
if (AreaComs != null) if (AreaComs != null)
obj["area_commitments"] = new JsonObject { obj["area_commitment_contracts"] = new JsonObject {
["count"] = AreaComs.Value.AreaComs.Count(), ["count"] = AreaComs.Value.AreaComs.Count(),
["revisions"] = AreaComs.Value.AreaComs.Sum(c => c.Revisions.Count),
["filters"] = new JsonArray(AreaComs.Value.Filters.Select(f => (JsonNode)f).ToArray()), ["filters"] = new JsonArray(AreaComs.Value.Filters.Select(f => (JsonNode)f).ToArray()),
}; };
if (Deliveries != null) if (Deliveries != null)
@@ -485,7 +540,7 @@ namespace Elwig.Helpers.Export {
} }
} }
if (AreaComs != null) { if (AreaComs != null) {
var json = zip.CreateEntry("area_commitments.json", CompressionLevel.SmallestSize); var json = zip.CreateEntry("area_commitment_contracts.json", CompressionLevel.SmallestSize);
using var writer = new StreamWriter(json.Open(), Utils.UTF8); using var writer = new StreamWriter(json.Open(), Utils.UTF8);
foreach (var c in AreaComs.Value.AreaComs) { foreach (var c in AreaComs.Value.AreaComs) {
await writer.WriteLineAsync(c.ToJson().ToJsonString(Utils.JsonOpts)); await writer.WriteLineAsync(c.ToJson().ToJsonString(Utils.JsonOpts));
@@ -639,42 +694,102 @@ namespace Elwig.Helpers.Export {
CountryNum = a["country"]!.AsValue().GetValue<int>(), CountryNum = a["country"]!.AsValue().GetValue<int>(),
PostalDestId = a["postal_dest"]!.AsValue().GetValue<string>(), PostalDestId = a["postal_dest"]!.AsValue().GetValue<string>(),
Address = a["address"]!.AsValue().GetValue<string>(), Address = a["address"]!.AsValue().GetValue<string>(),
} : null, json["telephone_numbers"]!.AsArray().Select(n => n!.AsObject()).Select((n, i) => new MemberTelNr { } : null, [.. json["telephone_numbers"]!.AsArray().Select(n => n!.AsObject()).Select((n, i) => new MemberTelNr {
MgNr = mgnr, MgNr = mgnr,
Nr = i + 1, Nr = i + 1,
Type = n["type"]!.AsValue().GetValue<string>(), Type = n["type"]!.AsValue().GetValue<string>(),
Number = n["number"]!.AsValue().GetValue<string>(), Number = n["number"]!.AsValue().GetValue<string>(),
Comment = n["comment"]?.AsValue().GetValue<string>(), Comment = n["comment"]?.AsValue().GetValue<string>(),
}).ToList(), json["email_addresses"]!.AsArray().Select(a => a!.AsObject()).Select((a, i) => new MemberEmailAddr { })], [.. json["email_addresses"]!.AsArray().Select(a => a!.AsObject()).Select((a, i) => new MemberEmailAddr {
MgNr = mgnr, MgNr = mgnr,
Nr = i + 1, Nr = i + 1,
Address = a["address"]!.AsValue().GetValue<string>(), Address = a["address"]!.AsValue().GetValue<string>(),
Comment = a["comment"]?.AsValue().GetValue<string>(), Comment = a["comment"]?.AsValue().GetValue<string>(),
}).ToList(), })],
createdAt == null || modifiedAt == null ? null : createdAt == null || modifiedAt == null ? null :
(DateTime.ParseExact(createdAt, "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None), (DateTime.ParseExact(createdAt, "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None),
DateTime.ParseExact(modifiedAt, "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None))); DateTime.ParseExact(modifiedAt, "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None)));
} }
public static JsonObject ToJson(this AreaCom c) { public static JsonObject ToJson(this AreaComContract c) {
return new JsonObject { return new JsonObject {
["fbnr"] = c.FbNr, ["fbnr"] = c.FbNr,
["mgnr"] = c.MgNr,
["vtrgid"] = c.VtrgId,
["cultid"] = c.CultId,
["area"] = c.Area,
["kgnr"] = c.KgNr, ["kgnr"] = c.KgNr,
["gstnr"] = c.GstNr,
["ried"] = c.Rd?.Name, ["ried"] = c.Rd?.Name,
["year_from"] = c.YearFrom, ["revisions"] = new JsonArray(c.Revisions.OrderBy(r => r.RevNr).Select(r => r.ToJson()).ToArray()),
["year_to"] = c.YearTo,
["comment"] = c.Comment, ["comment"] = c.Comment,
["created_at"] = $"{c.CreatedAt:yyyy-MM-ddTHH:mm:ssK}", ["created_at"] = $"{c.CreatedAt:yyyy-MM-ddTHH:mm:ssK}",
["modified_at"] = $"{c.ModifiedAt:yyyy-MM-ddTHH:mm:ssK}", ["modified_at"] = $"{c.ModifiedAt:yyyy-MM-ddTHH:mm:ssK}",
}; };
} }
public static (AreaCom, WbRd?, (DateTime CreatedAt, DateTime ModifiedAt)?) ToAreaCom(this JsonNode json, Dictionary<int, List<WbRd>> riede) { private static JsonObject ToJson(this AreaCom c) {
return new JsonObject {
["revnr"] = c.RevNr,
["mgnr"] = c.MgNr,
["vtrgid"] = c.VtrgId,
["cultid"] = c.CultId,
["area"] = c.Area,
["gstnr"] = c.GstNr,
["year_from"] = c.YearFrom,
["year_to"] = c.YearTo,
["created_at"] = $"{c.CreatedAt:yyyy-MM-ddTHH:mm:ssK}",
["modified_at"] = $"{c.ModifiedAt:yyyy-MM-ddTHH:mm:ssK}",
};
}
public static (AreaComContract, List<(AreaCom, (DateTime CreatedAt, DateTime ModifiedAt)?)>, WbRd?, (DateTime CreatedAt, DateTime ModifiedAt)?) ToAreaComContract(this JsonNode json, Dictionary<int, List<WbRd>> riede) {
var kgnr = json["kgnr"]!.AsValue().GetValue<int>();
var ried = json["ried"]?.AsValue().GetValue<string>();
var fbnr = json["fbnr"]!.AsValue()!.GetValue<int>();
WbRd? rd = null;
bool newRd = false;
if (ried != null) {
var rde = riede.GetValueOrDefault(kgnr, []);
rd = rde.FirstOrDefault(r => r.Name == ried);
if (rd == null) {
newRd = true;
rd = new WbRd {
KgNr = kgnr,
RdNr = (rde.Count == 0 ? 1 : rde.Max(r => r.RdNr)) + 1,
Name = ried,
};
rde.Add(rd);
riede[rd.KgNr] = rde;
}
}
var createdAt = json["created_at"]?.AsValue().GetValue<string>();
var modifiedAt = json["modified_at"]?.AsValue().GetValue<string>();
return (new AreaComContract {
FbNr = fbnr,
KgNr = kgnr,
RdNr = rd?.RdNr ?? json["rdnr"]?.AsValue().GetValue<int>(),
Comment = json["comment"]?.AsValue().GetValue<string>(),
ImportedAt = DateTime.Now,
}, [.. json["revisions"]!.AsArray().Select(r => r!.AsObject()).Select<JsonObject, (AreaCom, (DateTime, DateTime)?)>(r => {
var createdAt = json["created_at"]?.AsValue().GetValue<string>();
var modifiedAt = json["modified_at"]?.AsValue().GetValue<string>();
return (new AreaCom {
FbNr = fbnr,
RevNr = r["revnr"]!.AsValue().GetValue<int>(),
MgNr = r["mgnr"]!.AsValue().GetValue<int>(),
VtrgId = r["vtrgid"]!.AsValue().GetValue<string>(),
CultId = r["cultid"]?.AsValue().GetValue<string>(),
Area = r["area"]!.AsValue().GetValue<int>(),
GstNr = r["gstnr"]?.AsValue().GetValue<string>() ?? "-",
YearFrom = r["year_from"]?.AsValue().GetValue<int>(),
YearTo = r["year_to"]?.AsValue().GetValue<int>(),
ImportedAt = DateTime.Now,
}, createdAt == null || modifiedAt == null ? null :
(DateTime.ParseExact(createdAt, "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None),
DateTime.ParseExact(modifiedAt, "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None)));
})], newRd ? rd : null,
createdAt == null || modifiedAt == null ? null :
(DateTime.ParseExact(createdAt, "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None),
DateTime.ParseExact(modifiedAt, "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None)));
}
public static (AreaComContract, AreaCom, WbRd?, (DateTime CreatedAt, DateTime ModifiedAt)?) ToAreaCom(this JsonNode json, Dictionary<int, List<WbRd>> riede) {
var kgnr = json["kgnr"]!.AsValue().GetValue<int>(); var kgnr = json["kgnr"]!.AsValue().GetValue<int>();
var ried = json["ried"]?.AsValue().GetValue<string>(); var ried = json["ried"]?.AsValue().GetValue<string>();
WbRd? rd = null; WbRd? rd = null;
@@ -695,18 +810,22 @@ namespace Elwig.Helpers.Export {
} }
var createdAt = json["created_at"]?.AsValue().GetValue<string>(); var createdAt = json["created_at"]?.AsValue().GetValue<string>();
var modifiedAt = json["modified_at"]?.AsValue().GetValue<string>(); var modifiedAt = json["modified_at"]?.AsValue().GetValue<string>();
return (new AreaCom { return (new AreaComContract {
FbNr = json["fbnr"]!.AsValue().GetValue<int>(), FbNr = json["fbnr"]!.AsValue().GetValue<int>(),
KgNr = kgnr,
RdNr = rd?.RdNr ?? json["rdnr"]?.AsValue().GetValue<int>(),
Comment = json["comment"]?.AsValue().GetValue<string>(),
ImportedAt = DateTime.Now,
}, new AreaCom {
FbNr = json["fbnr"]!.AsValue().GetValue<int>(),
RevNr = 1,
MgNr = json["mgnr"]!.AsValue().GetValue<int>(), MgNr = json["mgnr"]!.AsValue().GetValue<int>(),
VtrgId = json["vtrgid"]!.AsValue().GetValue<string>(), VtrgId = json["vtrgid"]!.AsValue().GetValue<string>(),
CultId = json["cultid"]?.AsValue().GetValue<string>(), CultId = json["cultid"]?.AsValue().GetValue<string>(),
Area = json["area"]!.AsValue().GetValue<int>(), Area = json["area"]!.AsValue().GetValue<int>(),
KgNr = kgnr,
GstNr = json["gstnr"]?.AsValue().GetValue<string>() ?? "-", GstNr = json["gstnr"]?.AsValue().GetValue<string>() ?? "-",
RdNr = rd?.RdNr ?? json["rdnr"]?.AsValue().GetValue<int>(),
YearFrom = json["year_from"]?.AsValue().GetValue<int>(), YearFrom = json["year_from"]?.AsValue().GetValue<int>(),
YearTo = json["year_to"]?.AsValue().GetValue<int>(), YearTo = json["year_to"]?.AsValue().GetValue<int>(),
Comment = json["comment"]?.AsValue().GetValue<string>(),
ImportedAt = DateTime.Now, ImportedAt = DateTime.Now,
}, newRd ? rd : null, }, newRd ? rd : null,
createdAt == null || modifiedAt == null ? null : createdAt == null || modifiedAt == null ? null :
@@ -723,7 +842,14 @@ namespace Elwig.Helpers.Export {
["lnr"] = d.LNr, ["lnr"] = d.LNr,
["time"] = d.Time != null ? $"{d.Time:HH:mm:ss}" : null, ["time"] = d.Time != null ? $"{d.Time:HH:mm:ss}" : null,
["mgnr"] = d.MgNr, ["mgnr"] = d.MgNr,
["parts"] = new JsonArray(d.Parts.OrderBy(p => p.DPNr).Select(p => { ["parts"] = new JsonArray(d.Parts.OrderBy(p => p.DPNr).Select(p => p.ToJson()).ToArray()),
["comment"] = d.Comment,
["created_at"] = $"{d.CreatedAt:yyyy-MM-ddTHH:mm:ssK}",
["modified_at"] = $"{d.ModifiedAt:yyyy-MM-ddTHH:mm:ssK}",
};
}
private static JsonObject ToJson(this DeliveryPart p) {
var obj = new JsonObject { var obj = new JsonObject {
["dpnr"] = p.DPNr, ["dpnr"] = p.DPNr,
["sortid"] = p.SortId, ["sortid"] = p.SortId,
@@ -737,7 +863,7 @@ namespace Elwig.Helpers.Export {
["ried"] = p.Rd?.Name, ["ried"] = p.Rd?.Name,
["net_weight"] = p.IsNetWeight, ["net_weight"] = p.IsNetWeight,
["manual_weighing"] = p.IsManualWeighing, ["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, ["comment"] = p.Comment,
["created_at"] = $"{p.CreatedAt:yyyy-MM-ddTHH:mm:ssK}", ["created_at"] = $"{p.CreatedAt:yyyy-MM-ddTHH:mm:ssK}",
["modified_at"] = $"{p.ModifiedAt:yyyy-MM-ddTHH:mm:ssK}", ["modified_at"] = $"{p.ModifiedAt:yyyy-MM-ddTHH:mm:ssK}",
@@ -752,14 +878,9 @@ namespace Elwig.Helpers.Export {
if (p.WeighingData != null) obj["weighing_data"] = JsonNode.Parse(p.WeighingData); if (p.WeighingData != null) obj["weighing_data"] = JsonNode.Parse(p.WeighingData);
if (p.WeighingReason != null) obj["weighing_reason"] = p.WeighingReason; if (p.WeighingReason != null) obj["weighing_reason"] = p.WeighingReason;
return obj; return obj;
}).ToArray()),
["comment"] = d.Comment,
["created_at"] = $"{d.CreatedAt:yyyy-MM-ddTHH:mm:ssK}",
["modified_at"] = $"{d.ModifiedAt:yyyy-MM-ddTHH:mm:ssK}",
};
} }
public static (Delivery, List<DeliveryPart>, List<DeliveryPartModifier>, List<WbRd>, (DateTime CreatedAt, DateTime ModifiedAt)?) ToDelivery(this JsonNode json, Dictionary<string, int> currentLsNrs, Dictionary<int, int> currentDids, Dictionary<int, AT_Kg> kgs, Dictionary<int, List<WbRd>> riede) { public static (Delivery, List<(DeliveryPart, (DateTime CreatedAt, DateTime ModifiedAt)?)>, List<DeliveryPartModifier>, List<WbRd>, (DateTime CreatedAt, DateTime ModifiedAt)?) ToDelivery(this JsonNode json, Dictionary<string, int> currentLsNrs, Dictionary<int, int> currentDids, Dictionary<int, AT_Kg> kgs, Dictionary<int, List<WbRd>> riede) {
var year = json["year"]!.AsValue().GetValue<int>(); var year = json["year"]!.AsValue().GetValue<int>();
var lsnr = json["lsnr"]!.AsValue().GetValue<string>(); var lsnr = json["lsnr"]!.AsValue().GetValue<string>();
var did = currentLsNrs.GetValueOrDefault(lsnr, -1); var did = currentLsNrs.GetValueOrDefault(lsnr, -1);
@@ -782,7 +903,7 @@ namespace Elwig.Helpers.Export {
MgNr = json["mgnr"]!.AsValue().GetValue<int>(), MgNr = json["mgnr"]!.AsValue().GetValue<int>(),
Comment = json["comment"]?.AsValue().GetValue<string>(), Comment = json["comment"]?.AsValue().GetValue<string>(),
ImportedAt = DateTime.Now, ImportedAt = DateTime.Now,
}, json["parts"]!.AsArray().Select(p => p!.AsObject()).Select(p => { }, [.. json["parts"]!.AsArray().Select(p => p!.AsObject()).Select<JsonObject, (DeliveryPart, (DateTime, DateTime)?)>(p => {
var kgnr = p["kgnr"]?.AsValue().GetValue<int>(); var kgnr = p["kgnr"]?.AsValue().GetValue<int>();
var ried = p["ried"]?.AsValue().GetValue<string>(); var ried = p["ried"]?.AsValue().GetValue<string>();
WbRd? rd = null; WbRd? rd = null;
@@ -800,7 +921,9 @@ namespace Elwig.Helpers.Export {
wbRde.Add(rd); wbRde.Add(rd);
} }
} }
return new DeliveryPart { var createdAt = p["created_at"]?.AsValue().GetValue<string>();
var modifiedAt = p["modified_at"]?.AsValue().GetValue<string>();
return (new DeliveryPart {
Year = year, Year = year,
DId = did, DId = did,
DPNr = p["dpnr"]!.AsValue().GetValue<int>(), DPNr = p["dpnr"]!.AsValue().GetValue<int>(),
@@ -825,13 +948,15 @@ namespace Elwig.Helpers.Export {
ScaleId = p["scale_id"]?.AsValue().GetValue<string>(), ScaleId = p["scale_id"]?.AsValue().GetValue<string>(),
WeighingData = p["weighing_data"]?.AsObject().ToJsonString(Utils.JsonOpts), WeighingData = p["weighing_data"]?.AsObject().ToJsonString(Utils.JsonOpts),
WeighingReason = p["weighing_reason"]?.AsValue().GetValue<string>(), WeighingReason = p["weighing_reason"]?.AsValue().GetValue<string>(),
}; }, createdAt == null || modifiedAt == null ? null :
}).ToList(), json["parts"]!.AsArray().SelectMany(p => p!["modids"]!.AsArray().Select(m => new DeliveryPartModifier { (DateTime.ParseExact(createdAt, "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None),
DateTime.ParseExact(modifiedAt, "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None)));
})], [.. json["parts"]!.AsArray().SelectMany(p => p!["modids"]!.AsArray().Select(m => new DeliveryPartModifier {
Year = year, Year = year,
DId = did, DId = did,
DPNr = p["dpnr"]!.AsValue().GetValue<int>(), DPNr = p["dpnr"]!.AsValue().GetValue<int>(),
ModId = m!.AsValue().GetValue<string>(), ModId = m!.AsValue().GetValue<string>(),
})).ToList(), }))],
wbRde, wbRde,
createdAt == null || modifiedAt == null ? null : createdAt == null || modifiedAt == null ? null :
(DateTime.ParseExact(createdAt, "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None), (DateTime.ParseExact(createdAt, "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None),

View File

@@ -413,8 +413,8 @@ namespace Elwig.Helpers {
return output.OrderByDescending(l => l.Count()); return output.OrderByDescending(l => l.Count());
} }
public static List<RawVaribute> GetVaributes(AppDbContext ctx, int year, bool onlyDelivered = true) { public static async Task<List<RawVaribute>> GetVaributes(AppDbContext ctx, int year, bool onlyDelivered = true) {
var varieties = ctx.WineVarieties.Select(v => new RawVaribute(v.SortId, "", null)).ToList(); var varieties = await ctx.FetchWineVarieties().Select(v => new RawVaribute(v.SortId, "", null)).ToListAsync();
var delivered = ctx.DeliveryParts var delivered = ctx.DeliveryParts
.Where(d => d.Year == year) .Where(d => d.Year == year)
.Select(d => new RawVaribute(d.SortId, d.AttrId ?? "", d.CultId ?? "")) .Select(d => new RawVaribute(d.SortId, d.AttrId ?? "", d.CultId ?? ""))
@@ -423,13 +423,11 @@ namespace Elwig.Helpers {
return [.. (onlyDelivered ? delivered : delivered.Union(varieties)).Order()]; return [.. (onlyDelivered ? delivered : delivered.Union(varieties)).Order()];
} }
public static List<Varibute> GetVaributeList(AppDbContext ctx, int year, bool onlyDelivered = true) { public static async Task<List<Varibute>> GetVaributeList(AppDbContext ctx, int year, bool onlyDelivered = true) {
var varieties = ctx.WineVarieties.ToDictionary(v => v.SortId, v => v); var varieties = await ctx.FetchWineVarieties().ToDictionaryAsync(v => v.SortId, v => v);
var attributes = ctx.WineAttributes.ToDictionary(a => a.AttrId, a => a); var attributes = await ctx.FetchWineAttributes().ToDictionaryAsync(a => a.AttrId, a => a);
var cultivations = ctx.WineCultivations.ToDictionary(c => c.CultId, c => c); var cultivations = await ctx.FetchWineCultivations().ToDictionaryAsync(c => c.CultId, c => c);
return GetVaributes(ctx, year, onlyDelivered) return [.. (await GetVaributes(ctx, year, onlyDelivered)).Select(s => new Varibute(s, varieties, attributes, cultivations))];
.Select(s => new Varibute(s, varieties, attributes, cultivations))
.ToList();
} }
[LibraryImport("wininet.dll")] [LibraryImport("wininet.dll")]
@@ -557,7 +555,9 @@ namespace Elwig.Helpers {
"Vorläufiges Dokument", MessageBoxButton.OK, MessageBoxImage.Error); "Vorläufiges Dokument", MessageBoxButton.OK, MessageBoxImage.Error);
return; return;
} }
await doc.Generate(); using (var ctx = new AppDbContext()) {
await doc.Generate(ctx);
}
await doc.Print(); await doc.Print();
} else if (mode == ExportMode.Email && emailData is (Member, string, string) e) { } else if (mode == ExportMode.Email && emailData is (Member, string, string) e) {
if (doc.IsPreview) { if (doc.IsPreview) {
@@ -565,7 +565,9 @@ namespace Elwig.Helpers {
"Vorläufiges Dokument", MessageBoxButton.OK, MessageBoxImage.Error); "Vorläufiges Dokument", MessageBoxButton.OK, MessageBoxImage.Error);
return; return;
} }
await doc.Generate(); using (var ctx = new AppDbContext()) {
await doc.Generate(ctx);
}
var success = await SendEmail(e.Member, e.Subject, e.Text, [doc]); var success = await SendEmail(e.Member, e.Subject, e.Text, [doc]);
if (success) if (success)
MessageBox.Show("Die E-Mail wurde erfolgreich verschickt!\n\nEs kann einige Minuten dauern, bis die E-Mail im Posteingang des Empfängers aufscheint.", "E-Mail verschickt", MessageBox.Show("Die E-Mail wurde erfolgreich verschickt!\n\nEs kann einige Minuten dauern, bis die E-Mail im Posteingang des Empfängers aufscheint.", "E-Mail verschickt",
@@ -582,12 +584,16 @@ namespace Elwig.Helpers {
Title = $"{doc.Title} speichern unter - Elwig" Title = $"{doc.Title} speichern unter - Elwig"
}; };
if (d.ShowDialog() == true) { if (d.ShowDialog() == true) {
await doc.Generate(); using (var ctx = new AppDbContext()) {
await doc.Generate(ctx);
}
doc.SaveTo(d.FileName); doc.SaveTo(d.FileName);
Process.Start("explorer.exe", d.FileName); Process.Start("explorer.exe", d.FileName);
} }
} else { } else {
await doc.Generate(); using (var ctx = new AppDbContext()) {
await doc.Generate(ctx);
}
doc.Show(); doc.Show();
} }
} }

View File

@@ -580,7 +580,7 @@ namespace Elwig.Helpers {
} }
} }
public static ValidationResult CheckFbNr(TextBox input, bool required, AreaCom? c) { public static ValidationResult CheckFbNr(TextBox input, bool required, AreaComContract? c) {
var res = CheckInteger(input, required); var res = CheckInteger(input, required);
if (!res.IsValid) { if (!res.IsValid) {
return res; return res;

View File

@@ -28,9 +28,9 @@ namespace Elwig.Models.Dtos {
} }
public static async Task<IDictionary<int, CreditNoteDeliveryData>> ForPaymentVariant(DbSet<CreditNoteDeliveryRowSingle> table, DbSet<PaymentVar> paymentVariants, int year, int avnr) { public static async Task<IDictionary<int, CreditNoteDeliveryData>> ForPaymentVariant(DbSet<CreditNoteDeliveryRowSingle> table, DbSet<PaymentVar> paymentVariants, int year, int avnr) {
var variant = await paymentVariants.FindAsync(year, avnr); var variant = await paymentVariants.Include(v => v.Season.Modifiers).Where(v => v.Year == year && v.AvNr == avnr).SingleAsync();
BillingData? varData = null; BillingData? varData = null;
try { varData = variant != null ? BillingData.FromJson(variant.Data) : null; } catch { } try { varData = variant.Data != null ? BillingData.FromJson(variant.Data) : null; } catch { }
return (await FromDbSet(table, year, avnr)) return (await FromDbSet(table, year, avnr))
.GroupBy( .GroupBy(
r => new { r.Year, r.AvNr, r.MgNr, r.TgNr, r.DId, r.DPNr }, r => new { r.Year, r.AvNr, r.MgNr, r.TgNr, r.DId, r.DPNr },

View File

@@ -28,12 +28,7 @@ namespace Elwig.Models.Dtos {
} }
public static async Task<DeliveryAncmtListData> FromQuery(IQueryable<DeliveryAncmt> query, List<string> filterNames) { public static async Task<DeliveryAncmtListData> FromQuery(IQueryable<DeliveryAncmt> query, List<string> filterNames) {
return new((await query return new((await query.ToListAsync()).Select(d => new DeliveryAncmtListRow(d)), filterNames);
.Include(a => a.Schedule.Branch)
.Include(a => a.Member)
.Include(a => a.Variety)
.AsSplitQuery()
.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); if (mgnr != null) q = q.Where(p => p.Delivery.MgNr == mgnr);
await q await q
.Include(p => p.Delivery) .Include(p => p.Delivery)
.Include(p => p.Variety)
.Include(p => p.Attribute)
.Include(p => p.Quality)
.Include(p => p.Buckets) .Include(p => p.Buckets)
.Include(p => p.PartModifiers) .Include(p => p.PartModifiers).ThenInclude(m => m.Modifier)
.ThenInclude(m => m.Modifier)
.LoadAsync(); .LoadAsync();
return await table.FromSqlRaw($""" return await table.FromSqlRaw($"""
SELECT p.* SELECT p.*
@@ -65,7 +61,7 @@ namespace Elwig.Models.Dtos {
JOIN delivery_part p ON (p.year, p.did, p.dpnr) = (v.year, v.did, v.dpnr) JOIN delivery_part p ON (p.year, p.did, p.dpnr) = (v.year, v.did, v.dpnr)
WHERE (p.year = {y} OR {y} IS NULL) AND (v.mgnr = {m} OR {m} IS NULL) WHERE (p.year = {y} OR {y} IS NULL) AND (v.mgnr = {m} OR {m} IS NULL)
ORDER BY p.year, v.mgnr, v.sortid, v.abgewertet ASC, v.attribute_prio DESC, COALESCE(v.attrid, '~'), v.kmw DESC, v.lsnr, v.dpnr ORDER BY p.year, v.mgnr, v.sortid, v.abgewertet ASC, v.attribute_prio DESC, COALESCE(v.attrid, '~'), v.kmw DESC, v.lsnr, v.dpnr
""").ToListAsync(); """).IgnoreAutoIncludes().ToListAsync();
} }
} }

View File

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

View File

@@ -47,15 +47,11 @@ namespace Elwig.Models.Dtos {
} }
public static async Task<MemberListData> FromQuery(IQueryable<Member> query, List<string> filterNames, IEnumerable<string> filterAreaCom) { public static async Task<MemberListData> FromQuery(IQueryable<Member> query, List<string> filterNames, IEnumerable<string> filterAreaCom) {
var areaComs = await query.ToDictionaryAsync(m => m.MgNr, m => Utils.ActiveAreaCommitments(m.AreaCommitments)); var areaComs = await query.Include(m => m.AreaCommitments).ToDictionaryAsync(m => m.MgNr, m => Utils.ActiveAreaCommitments(m.AreaCommitments));
return new((await query return new((await query
.Include(m => m.DefaultWbKg!.AtKg)
.Include(m => m.Branch) .Include(m => m.Branch)
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.BillingAddress!.PostalDest.AtPlz!.Ort)
.Include(m => m.TelephoneNumbers) .Include(m => m.TelephoneNumbers)
.Include(m => m.EmailAddresses) .Include(m => m.EmailAddresses)
.AsSplitQuery()
.ToListAsync()).Select(m => new MemberListRow(m, .ToListAsync()).Select(m => new MemberListRow(m,
areaComs[m.MgNr].Sum(c => c.Area), 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)))), 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

@@ -1,15 +1,16 @@
using Elwig.Helpers;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using System; using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
namespace Elwig.Models.Entities { namespace Elwig.Models.Entities {
[Table("area_commitment"), PrimaryKey("FbNr")] [Table("area_commitment"), PrimaryKey("FbNr", "RevNr")]
public class AreaCom { public class AreaCom {
[Column("fbnr")] [Column("fbnr")]
public int FbNr { get; set; } public int FbNr { get; set; }
[Column("revnr")]
public int RevNr { get; set; }
[Column("mgnr")] [Column("mgnr")]
public int MgNr { get; set; } public int MgNr { get; set; }
@@ -22,24 +23,15 @@ namespace Elwig.Models.Entities {
[Column("area")] [Column("area")]
public int Area { get; set; } public int Area { get; set; }
[Column("kgnr")]
public int KgNr { get; set; }
[Column("gstnr")] [Column("gstnr")]
public required string GstNr { get; set; } public required string GstNr { get; set; }
[Column("rdnr")]
public int? RdNr { get; set; }
[Column("year_from")] [Column("year_from")]
public int? YearFrom { get; set; } public int? YearFrom { get; set; }
[Column("year_to")] [Column("year_to")]
public int? YearTo { get; set; } public int? YearTo { get; set; }
[Column("comment")]
public string? Comment { get; set; }
[Column("ctime"), DatabaseGenerated(DatabaseGeneratedOption.Computed)] [Column("ctime"), DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public long CTime { get; set; } public long CTime { get; set; }
[NotMapped] [NotMapped]
@@ -72,6 +64,9 @@ namespace Elwig.Models.Entities {
set => ITime = value == null ? null : ((DateTimeOffset)value.Value.ToUniversalTime()).ToUnixTimeSeconds(); set => ITime = value == null ? null : ((DateTimeOffset)value.Value.ToUniversalTime()).ToUnixTimeSeconds();
} }
[ForeignKey("FbNr")]
public virtual AreaComContract Contract { get; private set; } = null!;
[ForeignKey("MgNr")] [ForeignKey("MgNr")]
public virtual Member Member { get; private set; } = null!; public virtual Member Member { get; private set; } = null!;
@@ -80,17 +75,5 @@ namespace Elwig.Models.Entities {
[ForeignKey("CultId")] [ForeignKey("CultId")]
public virtual WineCult? WineCult { get; private set; } public virtual WineCult? WineCult { get; private set; }
[ForeignKey("KgNr")]
public virtual WbKg Kg { get; private set; } = null!;
[ForeignKey("KgNr, RdNr")]
public virtual WbRd? Rd { get; private set; }
public int SearchScore(IEnumerable<string> keywords) {
return Utils.GetSearchScore([
WineCult?.Name, Kg.AtKg.Name, Rd?.Name, GstNr, Comment,
], keywords);
}
} }
} }

View File

@@ -0,0 +1,78 @@
using Elwig.Helpers;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
namespace Elwig.Models.Entities {
[Table("area_commitment_contract"), PrimaryKey("FbNr")]
public class AreaComContract {
[Column("fbnr")]
public int FbNr { get; set; }
[Column("kgnr")]
public int KgNr { get; set; }
[Column("rdnr")]
public int? RdNr { get; set; }
[Column("comment")]
public string? Comment { get; set; }
[Column("ctime"), DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public long CTime { get; set; }
[NotMapped]
public DateTime CreatedAt {
get => DateTimeOffset.FromUnixTimeSeconds(CTime).LocalDateTime;
set => CTime = ((DateTimeOffset)value.ToUniversalTime()).ToUnixTimeSeconds();
}
[Column("mtime"), DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public long MTime { get; set; }
[NotMapped]
public DateTime ModifiedAt {
get => DateTimeOffset.FromUnixTimeSeconds(MTime).LocalDateTime;
set => MTime = ((DateTimeOffset)value.ToUniversalTime()).ToUnixTimeSeconds();
}
[Column("xtime")]
public long? XTime { get; set; }
[NotMapped]
public DateTime? ExportedAt {
get => XTime == null ? null : DateTimeOffset.FromUnixTimeSeconds(XTime.Value).LocalDateTime;
set => XTime = value == null ? null : ((DateTimeOffset)value.Value.ToUniversalTime()).ToUnixTimeSeconds();
}
[Column("itime")]
public long? ITime { get; set; }
[NotMapped]
public DateTime? ImportedAt {
get => ITime == null ? null : DateTimeOffset.FromUnixTimeSeconds(ITime.Value).LocalDateTime;
set => ITime = value == null ? null : ((DateTimeOffset)value.Value.ToUniversalTime()).ToUnixTimeSeconds();
}
[ForeignKey("KgNr")]
public virtual WbKg Kg { get; private set; } = null!;
[ForeignKey("KgNr, RdNr")]
public virtual WbRd? Rd { get; private set; }
[InverseProperty(nameof(AreaCom.Contract))]
public virtual ICollection<AreaCom> Revisions { get; private set; } = null!;
[NotMapped]
public AreaCom? Latest => Revisions.OrderBy(r => r.RevNr).LastOrDefault();
[NotMapped]
public int? YearFrom => Revisions.Any(r => r.YearFrom == null) ? null : Revisions.Min(r => r.YearFrom);
[NotMapped]
public int? YearTo => Revisions.Any(r => r.YearTo == null) ? null : Revisions.Max(r => r.YearTo);
public int SearchScore(IEnumerable<string> keywords) {
return Utils.GetSearchScore([
..Revisions.Select(r => r.WineCult?.Name), Kg.AtKg.Name, Rd?.Name, ..Revisions.Select(r => r.GstNr), Comment,
], keywords);
}
}
}

View File

@@ -111,16 +111,16 @@ namespace Elwig.Models.Entities {
[NotMapped] [NotMapped]
public Predicate<DeliveryPart>? PartFilter { get; set; } public Predicate<DeliveryPart>? PartFilter { get; set; }
public int Weight => Parts.Select(p => p.Weight).Sum(); public int Weight => Parts.Sum(p => p.Weight);
public int FilteredWeight => FilteredParts.Select(p => p.Weight).Sum(); public int FilteredWeight => FilteredParts.Sum(p => p.Weight);
public IEnumerable<RawVaribute> Vaributes => Parts public IEnumerable<RawVaribute> Vaributes => Parts
.GroupBy(p => (p.SortId, p.AttrId, p.CultId)) .GroupBy(p => (p.SortId, p.AttrId, p.CultId))
.OrderByDescending(g => g.Select(p => p.Weight).Sum()) .OrderByDescending(g => g.Sum(p => p.Weight))
.Select(g => new RawVaribute(g.Key.SortId, g.Key.AttrId, g.Key.CultId)); .Select(g => new RawVaribute(g.Key.SortId, g.Key.AttrId, g.Key.CultId));
public IEnumerable<RawVaribute> FilteredVaributes => FilteredParts public IEnumerable<RawVaribute> FilteredVaributes => FilteredParts
.GroupBy(p => (p.SortId, p.AttrId, p.CultId)) .GroupBy(p => (p.SortId, p.AttrId, p.CultId))
.OrderByDescending(g => g.Select(p => p.Weight).Sum()) .OrderByDescending(g => g.Sum(p => p.Weight))
.Select(g => new RawVaribute(g.Key.SortId, g.Key.AttrId, g.Key.CultId)); .Select(g => new RawVaribute(g.Key.SortId, g.Key.AttrId, g.Key.CultId));
public string VaributeString => string.Join(", ", Vaributes); public string VaributeString => string.Join(", ", Vaributes);
public string FilteredVaributeString => string.Join(", ", FilteredVaributes); public string FilteredVaributeString => string.Join(", ", FilteredVaributes);
@@ -153,7 +153,7 @@ namespace Elwig.Models.Entities {
Member.Name, Member.MiddleName, Member.GivenName, Member.BillingAddress?.FullName, Member.Name, Member.MiddleName, Member.GivenName, Member.BillingAddress?.FullName,
Comment Comment
}.ToList(); }.ToList();
list.AddRange(Parts.Select(p => p.Comment).Distinct()); list.AddRange(FilteredParts.Select(p => p.Comment).Distinct());
return Utils.GetSearchScore(list, keywords); return Utils.GetSearchScore(list, keywords);
} }
} }

View File

@@ -27,13 +27,15 @@ namespace Elwig.Models.Entities {
public virtual ICollection<WbGem> Gems { get; private set; } = null!; public virtual ICollection<WbGem> Gems { get; private set; } = null!;
[InverseProperty(nameof(Parent))] [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; public int Level => (Parent?.Level + 1) ?? 0;
public string HkIdLevel => $"{new string(' ', Level * 2)}{HkId}"; public string HkIdLevel => $"{new string(' ', Level * 2)}{HkId}";
public int TotalChildNum => 1 + Children.Select(c => c.TotalChildNum).Sum(); public int TotalChildNum => 1 + Children.Sum(c => c.TotalChildNum);
private int SortKey1 => (Parent?.SortKey1 ?? 0) | (TotalChildNum << ((3 - Level) * 8)); private int SortKey1 => (Parent?.SortKey1 ?? 0) | (TotalChildNum << ((3 - Level) * 8));
public int SortKey => SortKey1 | ((Level < 3) ? (-1 >>> (Level * 8 + 8)) : 0); public int SortKey => SortKey1 | ((Level < 3) ? (-1 >>> (Level * 8 + 8)) : 0);

View File

@@ -0,0 +1,239 @@
-- schema version 37 to 38
UPDATE client_parameter SET value = '0' WHERE param = 'ENABLE_TIME_TRIGGERS';
DROP TRIGGER t_area_commitment_i_ctime;
DROP TRIGGER t_area_commitment_u_ctime;
DROP TRIGGER t_area_commitment_i_mtime;
DROP TRIGGER t_area_commitment_u_mtime;
CREATE TABLE area_commitment_contract (
fbnr INTEGER NOT NULL,
kgnr INTEGER NOT NULL,
rdnr INTEGER,
comment TEXT DEFAULT NULL,
ctime INTEGER NOT NULL DEFAULT (UNIXEPOCH()),
mtime INTEGER NOT NULL DEFAULT (UNIXEPOCH()),
xtime INTEGER DEFAULT NULL,
itime INTEGER DEFAULT NULL,
CONSTRAINT area_commitment_contract PRIMARY KEY (fbnr),
CONSTRAINT fk_area_commitment_contract_wb_kg FOREIGN KEY (kgnr) REFERENCES wb_kg (kgnr)
ON UPDATE CASCADE
ON DELETE RESTRICT,
CONSTRAINT fk_area_commitment_contract_wb_rd FOREIGN KEY (kgnr, rdnr) REFERENCES wb_rd (kgnr, rdnr)
ON UPDATE CASCADE
ON DELETE RESTRICT
) STRICT;
CREATE TABLE area_commitment_new (
fbnr INTEGER NOT NULL,
revnr INTEGER NOT NULL,
mgnr INTEGER NOT NULL,
vtrgid TEXT NOT NULL,
cultid TEXT DEFAULT NULL,
area INTEGER NOT NULL,
gstnr TEXT NOT NULL,
year_from INTEGER CHECK (year_from >= 1000 AND year_from <= 9999) DEFAULT NULL,
year_to INTEGER CHECK (year_to >= 1000 AND year_to <= 9999) DEFAULT NULL,
ctime INTEGER NOT NULL DEFAULT (UNIXEPOCH()),
mtime INTEGER NOT NULL DEFAULT (UNIXEPOCH()),
xtime INTEGER DEFAULT NULL,
itime INTEGER DEFAULT NULL,
CONSTRAINT pk_area_commitment PRIMARY KEY (fbnr, revnr),
CONSTRAINT fk_area_commitment_area_commitment_contract FOREIGN KEY (fbnr) REFERENCES area_commitment_contract (fbnr)
ON UPDATE CASCADE
ON DELETE CASCADE,
CONSTRAINT fk_area_commitment_member FOREIGN KEY (mgnr) REFERENCES member (mgnr)
ON UPDATE CASCADE
ON DELETE RESTRICT,
CONSTRAINT fk_area_commitment_area_commitment_type FOREIGN KEY (vtrgid) REFERENCES area_commitment_type (vtrgid)
ON UPDATE CASCADE
ON DELETE RESTRICT,
CONSTRAINT fk_area_commitment_wine_cultivation FOREIGN KEY (cultid) REFERENCES wine_cultivation (cultid)
ON UPDATE CASCADE
ON DELETE RESTRICT
) STRICT;
INSERT INTO area_commitment_contract (fbnr, kgnr, rdnr, comment, ctime, mtime, xtime, itime)
SELECT fbnr, kgnr, rdnr, comment, ctime, mtime, xtime, itime
FROM area_commitment;
INSERT INTO area_commitment_new (fbnr, revnr, mgnr, vtrgid, cultid, area, gstnr, year_from, year_to, ctime, mtime, xtime, itime)
SELECT fbnr, 1, mgnr, vtrgid, cultid, area, gstnr, year_from, year_to, ctime, mtime, xtime, itime
FROM area_commitment;
PRAGMA foreign_keys = OFF;
PRAGMA writable_schema = ON;
DROP TABLE area_commitment;
ALTER TABLE area_commitment_new RENAME TO area_commitment;
PRAGMA writable_schema = OFF;
PRAGMA foreign_keys = ON;
CREATE TRIGGER t_area_commitment_contract_i_ctime
AFTER INSERT ON area_commitment_contract FOR EACH ROW
WHEN (SELECT value FROM client_parameter WHERE param = 'ENABLE_TIME_TRIGGERS') = 1 AND NEW.ctime != UNIXEPOCH()
BEGIN
UPDATE area_commitment_contract SET ctime = UNIXEPOCH() WHERE fbnr = NEW.fbnr;
END;
CREATE TRIGGER t_area_commitment_contract_u_ctime
BEFORE UPDATE ON area_commitment_contract FOR EACH ROW
WHEN (SELECT value FROM client_parameter WHERE param = 'ENABLE_TIME_TRIGGERS') = 1 AND OLD.ctime != NEW.ctime
BEGIN
SELECT RAISE(ABORT, 'It is not allowed to change ctime');
END;
CREATE TRIGGER t_area_commitment_contract_i_mtime
AFTER INSERT ON area_commitment_contract FOR EACH ROW
WHEN (SELECT value FROM client_parameter WHERE param = 'ENABLE_TIME_TRIGGERS') = 1 AND NEW.mtime != UNIXEPOCH()
BEGIN
UPDATE area_commitment_contract SET mtime = UNIXEPOCH() WHERE fbnr = NEW.fbnr;
END;
CREATE TRIGGER t_area_commitment_contract_u_mtime
AFTER UPDATE ON area_commitment_contract FOR EACH ROW
WHEN (SELECT value FROM client_parameter WHERE param = 'ENABLE_TIME_TRIGGERS') = 1 AND NEW.mtime != UNIXEPOCH()
BEGIN
UPDATE area_commitment_contract SET mtime = UNIXEPOCH() WHERE fbnr = NEW.fbnr;
END;
CREATE TRIGGER t_area_commitment_i_ctime
AFTER INSERT ON area_commitment FOR EACH ROW
WHEN (SELECT value FROM client_parameter WHERE param = 'ENABLE_TIME_TRIGGERS') = 1 AND NEW.ctime != UNIXEPOCH()
BEGIN
UPDATE area_commitment SET ctime = UNIXEPOCH() WHERE (fbnr, revnr) = (NEW.fbnr, NEW.revnr);
END;
CREATE TRIGGER t_area_commitment_u_ctime
BEFORE UPDATE ON area_commitment FOR EACH ROW
WHEN (SELECT value FROM client_parameter WHERE param = 'ENABLE_TIME_TRIGGERS') = 1 AND OLD.ctime != NEW.ctime
BEGIN
SELECT RAISE(ABORT, 'It is not allowed to change ctime');
END;
CREATE TRIGGER t_area_commitment_i_mtime
AFTER INSERT ON area_commitment FOR EACH ROW
WHEN (SELECT value FROM client_parameter WHERE param = 'ENABLE_TIME_TRIGGERS') = 1 AND NEW.mtime != UNIXEPOCH()
BEGIN
UPDATE area_commitment SET mtime = UNIXEPOCH() WHERE (fbnr, revnr) = (NEW.fbnr, NEW.revnr);
END;
CREATE TRIGGER t_area_commitment_u_mtime
AFTER UPDATE ON area_commitment FOR EACH ROW
WHEN (SELECT value FROM client_parameter WHERE param = 'ENABLE_TIME_TRIGGERS') = 1 AND NEW.mtime != UNIXEPOCH()
BEGIN
UPDATE area_commitment SET mtime = UNIXEPOCH() WHERE (fbnr, revnr) = (NEW.fbnr, NEW.revnr);
END;
CREATE TRIGGER t_area_commitment_i_mtime_contract
AFTER INSERT ON area_commitment FOR EACH ROW
WHEN (SELECT value FROM client_parameter WHERE param = 'ENABLE_TIME_TRIGGERS') = 1
BEGIN
UPDATE area_commitment_contract SET mtime = UNIXEPOCH() WHERE fbnr = NEW.fbnr;
END;
CREATE TRIGGER t_area_commitment_u_mtime_contract
AFTER UPDATE ON area_commitment FOR EACH ROW
WHEN (SELECT value FROM client_parameter WHERE param = 'ENABLE_TIME_TRIGGERS') = 1
BEGIN
UPDATE area_commitment_contract SET mtime = UNIXEPOCH() WHERE fbnr = NEW.fbnr OR fbnr = OLD.fbnr;
END;
CREATE TRIGGER t_area_commitment_d_mtime_contract
AFTER DELETE ON area_commitment FOR EACH ROW
WHEN (SELECT value FROM client_parameter WHERE param = 'ENABLE_TIME_TRIGGERS') = 1
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
FROM area_commitment AS a
WHERE a.fbnr < b.fbnr
AND COALESCE(a.year_from <= a.year_to, TRUE)
AND COALESCE(b.year_from <= b.year_to, TRUE)
AND SUBSTR(a.vtrgid, 0, 2) = SUBSTR(b.vtrgid, 0, 2)
AND (SELECT c.kgnr = d.kgnr AND COALESCE(c.rdnr = d.rdnr, TRUE) FROM area_commitment_contract c, area_commitment_contract d WHERE c.fbnr = a.fbnr AND d.fbnr = b.fbnr)
AND ((IIF(INSTR(a.gstnr, b.gstnr) > 0, 1, 0) + IIF(INSTR(b.gstnr, a.gstnr) > 0, 1, 0) + IIF(a.area = b.area, 2, 0) + (a.mgnr = b.mgnr)) > 1)
AND ((a.year_from = b.year_from AND b.year_to IS NULL AND a.year_to IS NOT NULL));
-- simple
UPDATE area_commitment AS b
SET fbnr = a.fbnr, revnr = b.fbnr
FROM area_commitment AS a
WHERE a.fbnr < b.fbnr
AND COALESCE(a.year_from <= a.year_to, TRUE)
AND COALESCE(b.year_from <= b.year_to, TRUE)
AND SUBSTR(a.vtrgid, 0, 2) = SUBSTR(b.vtrgid, 0, 2)
AND (SELECT c.kgnr = d.kgnr AND COALESCE(c.rdnr = d.rdnr, TRUE) FROM area_commitment_contract c, area_commitment_contract d WHERE c.fbnr = a.fbnr AND d.fbnr = b.fbnr)
AND (a.gstnr = b.gstnr OR a.gstnr IN ('offen', '', '-')) AND a.area = b.area
AND a.year_to + 1 = b.year_from;
-- copy comments
UPDATE area_commitment_contract AS b
SET comment = IIF(b.comment IS NULL, a.comment, CONCAT(b.comment, '; ', a.comment))
FROM area_commitment_contract AS a
WHERE a.comment IS NOT NULL AND a.fbnr IN (SELECT revnr FROM area_commitment WHERE revnr > 1 AND fbnr = b.fbnr);
-- fix revnr
UPDATE area_commitment AS b
SET revnr = a.revnr + 1
FROM area_commitment AS a
WHERE a.fbnr = b.fbnr AND a.revnr < b.revnr;
UPDATE area_commitment AS b
SET revnr = a.revnr + 1
FROM area_commitment AS a
WHERE a.fbnr = b.fbnr AND a.revnr < b.revnr;
UPDATE area_commitment AS b
SET revnr = a.revnr + 1
FROM area_commitment AS a
WHERE a.fbnr = b.fbnr AND a.revnr < b.revnr;
-- fix year_from
UPDATE area_commitment AS b
SET year_from = a.year_to + 1
FROM area_commitment AS a
WHERE a.fbnr = b.fbnr AND a.revnr = b.revnr - 1
AND a.year_to = b.year_from;
UPDATE area_commitment AS b
SET year_from = a.year_to + 1
FROM area_commitment AS a
WHERE a.fbnr = b.fbnr AND a.revnr = b.revnr - 1
AND a.year_to = b.year_from;
-- delete unreferenced contracts
DELETE FROM area_commitment_contract
WHERE fbnr IN (SELECT c.fbnr FROM area_commitment_contract c
LEFT JOIN area_commitment a ON a.fbnr = c.fbnr
WHERE a.fbnr IS NULL);
UPDATE client_parameter SET value = '1' WHERE param = 'ENABLE_TIME_TRIGGERS';

View File

@@ -20,41 +20,45 @@ namespace Elwig.Services {
} }
public static void ClearInputs(this AreaComAdminViewModel vm) { public static void ClearInputs(this AreaComAdminViewModel vm) {
vm.Period = null;
}
public static void FillInputs(this AreaComAdminViewModel vm, AreaComContract c) {
vm.FbNr = c.FbNr;
vm.Period = c.YearTo == null ? $"ab {c.YearFrom}" : $"{c.YearFrom}\u2013{c.YearTo}";
vm.Comment = c.Comment;
vm.Kg = ControlUtils.GetItemFromSourceWithPk(vm.KgSource, c.KgNr) as AT_Kg;
vm.Rd = ControlUtils.GetItemFromSourceWithPk(vm.RdSource, c.KgNr, c.RdNr) as WbRd;
} }
public static void FillInputs(this AreaComAdminViewModel vm, AreaCom a) { public static void FillInputs(this AreaComAdminViewModel vm, AreaCom a) {
vm.FbNr = a.FbNr;
vm.MgNr = a.MgNr; vm.MgNr = a.MgNr;
vm.YearFrom = a.YearFrom; vm.YearFrom = a.YearFrom;
vm.YearTo = a.YearTo; vm.YearTo = a.YearTo;
vm.AreaComType = ControlUtils.GetItemFromSourceWithPk(vm.AreaComTypeSource, a.VtrgId) as AreaComType; vm.AreaComType = ControlUtils.GetItemFromSourceWithPk(vm.AreaComTypeSource, a.VtrgId) as AreaComType;
vm.WineCult = ControlUtils.GetItemFromSourceWithPk(vm.WineCultSource, a.CultId) as WineCult; vm.WineCult = ControlUtils.GetItemFromSourceWithPk(vm.WineCultSource, a.CultId) as WineCult;
vm.Comment = a.Comment;
vm.Kg = ControlUtils.GetItemFromSourceWithPk(vm.KgSource, a.KgNr) as AT_Kg;
vm.Rd = ControlUtils.GetItemFromSourceWithPk(vm.RdSource, a.KgNr, a.RdNr) as WbRd;
vm.GstNr = a.GstNr; vm.GstNr = a.GstNr;
vm.Area = a.Area; vm.Area = a.Area;
} }
public static async Task<(List<string>, IQueryable<AreaCom>, List<string>)> GetFilters(this AreaComAdminViewModel vm, AppDbContext ctx) { public static async Task<(List<string>, IQueryable<AreaComContract>, IQueryable<AreaCom>, List<string>)> GetFilters(this AreaComAdminViewModel vm, AppDbContext ctx) {
List<string> filterNames = []; List<string> filterNames = [];
IQueryable<AreaCom> areaComQuery = ctx.AreaCommitments.Where(a => a.MgNr == vm.FilterMember.MgNr).OrderBy(a => a.FbNr); IQueryable<AreaCom> areaComQuery = ctx.AreaCommitments.Where(a => a.MgNr == vm.FilterMember.MgNr).OrderBy(a => a.FbNr);
if (vm.ShowOnlyActiveAreaComs) { if (vm.FilterSeason is int season) {
areaComQuery = Utils.ActiveAreaCommitments(areaComQuery, Utils.CurrentLastSeason); areaComQuery = Utils.ActiveAreaCommitments(areaComQuery, season);
filterNames.Add($"laufend {Utils.CurrentLastSeason}"); filterNames.Add($"laufend {season}");
} }
var filterVar = new List<string>(); var filterVar = new List<string>();
var filterNotVar = new List<string>(); var filterNotVar = new List<string>();
var filterAttr = new List<string>(); var filterAttr = new List<string>();
var filterNotAttr = new List<string>(); var filterNotAttr = new List<string>();
var filterSeasons = new List<int>();
var filter = vm.TextFilter; var filter = vm.TextFilter;
if (filter.Count > 0) { if (filter.Count > 0) {
var var = await ctx.WineVarieties.ToDictionaryAsync(v => v.SortId, v => v); var var = await ctx.FetchWineVarieties().ToDictionaryAsync(v => v.SortId, v => v);
var attr = await ctx.WineAttributes.ToDictionaryAsync(a => a.Name.ToLower().Split(" ")[0], a => a); var attrId = await ctx.FetchWineAttributes().ToDictionaryAsync(a => a.AttrId, a => a);
var attrId = await ctx.WineAttributes.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++) { for (int i = 0; i < filter.Count; i++) {
var e = filter[i]; var e = filter[i];
@@ -88,10 +92,6 @@ namespace Elwig.Services {
filter.RemoveAt(i--); filter.RemoveAt(i--);
filterNames.Add($"ohne {var[e[1..3].ToUpper()].Name}"); filterNames.Add($"ohne {var[e[1..3].ToUpper()].Name}");
filterNames.Add($"ohne Attribut {attrId[e[3..].ToUpper()].Name}"); filterNames.Add($"ohne Attribut {attrId[e[3..].ToUpper()].Name}");
} else if (e.Length == 4 && int.TryParse(e, out var year)) {
filterSeasons.Add(year);
filter.RemoveAt(i--);
filterNames.Add($"laufend {e}");
} }
} }
@@ -99,38 +99,50 @@ namespace Elwig.Services {
if (filterNotVar.Count > 0) areaComQuery = areaComQuery.Where(a => !filterNotVar.Contains(a.AreaComType.WineVar.SortId)); if (filterNotVar.Count > 0) areaComQuery = areaComQuery.Where(a => !filterNotVar.Contains(a.AreaComType.WineVar.SortId));
if (filterAttr.Count > 0) areaComQuery = areaComQuery.Where(a => a.AreaComType.WineAttr!.AttrId != null && filterAttr.Contains(a.AreaComType.WineAttr.AttrId)); if (filterAttr.Count > 0) areaComQuery = areaComQuery.Where(a => a.AreaComType.WineAttr!.AttrId != null && filterAttr.Contains(a.AreaComType.WineAttr.AttrId));
if (filterNotAttr.Count > 0) areaComQuery = areaComQuery.Where(a => a.AreaComType.WineAttr!.AttrId == null || !filterNotAttr.Contains(a.AreaComType.WineAttr.AttrId)); if (filterNotAttr.Count > 0) areaComQuery = areaComQuery.Where(a => a.AreaComType.WineAttr!.AttrId == null || !filterNotAttr.Contains(a.AreaComType.WineAttr.AttrId));
foreach (var year in filterSeasons) areaComQuery = Utils.ActiveAreaCommitments(areaComQuery, year);
} }
return (filterNames, areaComQuery, filter); IQueryable<AreaComContract> contracts = areaComQuery
.Select(c => c.Contract).Distinct()
.OrderBy(c => c.FbNr);
return (filterNames, contracts, areaComQuery, filter);
} }
public static async Task<int> UpdateAreaCommitment(this AreaComAdminViewModel vm, int? oldFbNr) { public static async Task<(int FbNr, int RevNr)> UpdateAreaCommitment(this AreaComAdminViewModel vm, int? oldFbNr, int? revNr) {
int newFbNr = vm.FbNr!.Value; int newFbNr = vm.FbNr!.Value;
return await Task.Run(async () => { return await Task.Run(async () => {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
var c = new AreaComContract {
FbNr = oldFbNr ?? newFbNr,
Comment = string.IsNullOrEmpty(vm.Comment) ? null : vm.Comment,
KgNr = vm.Kg!.KgNr,
RdNr = vm.Rd?.RdNr,
};
var a = new AreaCom { var a = new AreaCom {
FbNr = oldFbNr ?? newFbNr, FbNr = oldFbNr ?? newFbNr,
RevNr = revNr ?? await ctx.NextRevNr(oldFbNr ?? newFbNr),
MgNr = vm.MgNr!.Value, MgNr = vm.MgNr!.Value,
YearFrom = vm.YearFrom, YearFrom = vm.YearFrom,
YearTo = vm.YearTo, YearTo = vm.YearTo,
VtrgId = vm.AreaComType!.VtrgId, VtrgId = vm.AreaComType!.VtrgId,
CultId = vm.WineCult?.CultId, CultId = vm.WineCult?.CultId,
Comment = string.IsNullOrEmpty(vm.Comment) ? null : vm.Comment,
KgNr = vm.Kg!.KgNr,
RdNr = vm.Rd?.RdNr,
GstNr = vm.GstNr?.Trim() ?? "-", GstNr = vm.GstNr?.Trim() ?? "-",
Area = vm.Area!.Value, Area = vm.Area!.Value,
}; };
if (vm.Rd?.RdNr == 0) { if (vm.Rd?.RdNr == 0) {
vm.Rd.RdNr = await ctx.NextRdNr(a.KgNr); vm.Rd.RdNr = await ctx.NextRdNr(c.KgNr);
a.RdNr = vm.Rd.RdNr; c.RdNr = vm.Rd.RdNr;
ctx.Add(vm.Rd); ctx.Add(vm.Rd);
} }
if (oldFbNr != null) { if (oldFbNr != null) {
ctx.Update(c);
} else {
ctx.Add(c);
}
if (revNr != null) {
ctx.Update(a); ctx.Update(a);
} else { } else {
ctx.Add(a); ctx.Add(a);
@@ -139,10 +151,10 @@ namespace Elwig.Services {
await ctx.SaveChangesAsync(); await ctx.SaveChangesAsync();
if (newFbNr != a.FbNr) { if (newFbNr != a.FbNr) {
await ctx.Database.ExecuteSqlAsync($"UPDATE area_commitment SET fbnr = {newFbNr} WHERE fbnr = {oldFbNr}"); await ctx.Database.ExecuteSqlAsync($"UPDATE area_commitment_contract SET fbnr = {newFbNr} WHERE fbnr = {oldFbNr}");
} }
return newFbNr; return (newFbNr, a.RevNr);
}); });
} }
@@ -256,7 +268,16 @@ namespace Elwig.Services {
public static async Task DeleteAreaCom(int fbnr) { public static async Task DeleteAreaCom(int fbnr) {
await Task.Run(async () => { await Task.Run(async () => {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
var l = (await ctx.AreaCommitments.FindAsync(fbnr))!; var l = (await ctx.AreaCommitmentContracts.FindAsync(fbnr))!;
ctx.Remove(l);
await ctx.SaveChangesAsync();
});
}
public static async Task DeleteAreaComRevision(int fbnr, int revnr) {
await Task.Run(async () => {
using var ctx = new AppDbContext();
var l = (await ctx.AreaCommitments.FindAsync(fbnr, revnr))!;
ctx.Remove(l); ctx.Remove(l);
await ctx.SaveChangesAsync(); await ctx.SaveChangesAsync();
}); });

View File

@@ -65,11 +65,11 @@ namespace Elwig.Services {
var filter = vm.TextFilter; var filter = vm.TextFilter;
if (filter.Count > 0) { if (filter.Count > 0) {
var var = await ctx.WineVarieties.ToDictionaryAsync(v => v.SortId, v => v); var var = await ctx.FetchWineVarieties().ToDictionaryAsync(v => v.SortId, v => v);
var mgnr = await ctx.Members.ToDictionaryAsync(m => m.MgNr.ToString(), m => m); var mgnr = await ctx.FetchMembers(includeNotActive: true).ToDictionaryAsync(m => m.MgNr.ToString(), m => m);
var zwst = await ctx.Branches.ToDictionaryAsync(b => b.Name.ToLower().Split(' ')[0], b => b); var zwst = await ctx.FetchBranches().ToDictionaryAsync(b => b.Name.ToLower().Split(' ')[0], b => b);
var attr = await ctx.WineAttributes.ToDictionaryAsync(a => a.Name.ToLower().Split(' ')[0], a => a); var attr = await ctx.FetchWineAttributes().ToDictionaryAsync(a => a.Name.ToLower().Split(' ')[0], a => a);
var cult = await ctx.WineCultivations.ToDictionaryAsync(c => c.Name.ToLower().Split(' ')[0], c => c); var cult = await ctx.FetchWineCultivations().ToDictionaryAsync(c => c.Name.ToLower().Split(' ')[0], c => c);
for (int i = 0; i < filter.Count; i++) { for (int i = 0; i < filter.Count; i++) {
var e = filter[i]; var e = filter[i];
@@ -318,18 +318,13 @@ namespace Elwig.Services {
AddToolTipCell(grid, $"{weight * 100.0 / total2:N1} %", row, 4, 1, bold, true); AddToolTipCell(grid, $"{weight * 100.0 / total2:N1} %", row, 4, 1, bold, true);
} }
public static async Task<(string, Grid)> GenerateToolTip(IQueryable<DeliveryAncmt> deliveryAncmts) { public static async Task<(string Text, (string?, string?, int, int?, int)[] Grid)> GenerateToolTipData(IQueryable<DeliveryAncmt> deliveryAncmts) {
var grid = new Grid(); var grid = new List<(string?, string?, int, int?, int)>();
grid.ColumnDefinitions.Add(new() { Width = new(10) });
grid.ColumnDefinitions.Add(new() { Width = new(60) });
grid.ColumnDefinitions.Add(new() { Width = new(80) });
grid.ColumnDefinitions.Add(new() { Width = new(50) });
grid.ColumnDefinitions.Add(new() { Width = new(50) });
var text = "-"; var text = "-";
var weight = await deliveryAncmts.SumAsync(p => p.Weight); var weight = await deliveryAncmts.SumAsync(p => p.Weight);
text = $"{weight:N0} kg"; text = $"{weight:N0} kg";
AddToolTipRow(grid, 0, "Menge", null, weight, null, weight); grid.Add(("Menge", null, weight, null, weight));
if (await deliveryAncmts.AnyAsync()) { if (await deliveryAncmts.AnyAsync()) {
var attrGroups = await deliveryAncmts var attrGroups = await deliveryAncmts
@@ -370,13 +365,11 @@ namespace Elwig.Services {
.ThenBy(g => g.SortId) .ThenBy(g => g.SortId)
.ToListAsync(); .ToListAsync();
int rowNum = 1;
foreach (var attrG in attrGroups) { foreach (var attrG in attrGroups) {
rowNum++;
var name = attrG.Attr == null && attrG.Cult == null ? null : attrG.Attr + (attrG.Attr != null && attrG.Cult != null ? " / " : "") + attrG.Cult; var name = attrG.Attr == null && attrG.Cult == null ? null : attrG.Attr + (attrG.Attr != null && attrG.Cult != null ? " / " : "") + attrG.Cult;
AddToolTipRow(grid, rowNum++, name, null, attrG.Weight, attrG.Weight, weight); grid.Add((name, null, attrG.Weight, attrG.Weight, weight));
foreach (var g in groups.Where(g => g.Attr == attrG.Attr && g.Cult == attrG.Cult).OrderByDescending(g => g.Weight).ThenBy(g => g.SortId)) { foreach (var g in groups.Where(g => g.Attr == attrG.Attr && g.Cult == attrG.Cult).OrderByDescending(g => g.Weight).ThenBy(g => g.SortId)) {
AddToolTipRow(grid, rowNum++, null, g.SortId, g.Weight, attrG.Weight, weight); grid.Add((null, g.SortId, g.Weight, attrG.Weight, weight));
} }
} }
@@ -395,7 +388,22 @@ namespace Elwig.Services {
} }
} }
return (text, grid); return (text, grid.ToArray());
}
public static Grid GenerateToolTip((string?, string?, int, int?, int)[] data) {
var grid = new Grid();
grid.ColumnDefinitions.Add(new() { Width = new(10) });
grid.ColumnDefinitions.Add(new() { Width = new(60) });
grid.ColumnDefinitions.Add(new() { Width = new(80) });
grid.ColumnDefinitions.Add(new() { Width = new(50) });
grid.ColumnDefinitions.Add(new() { Width = new(50) });
int rowNum = 0;
foreach (var row in data) {
if (rowNum != 0 && row.Item2 == null) rowNum++;
AddToolTipRow(grid, rowNum++, row.Item1, row.Item2, row.Item3, row.Item4, row.Item5);
}
return grid;
} }
} }
} }

View File

@@ -60,8 +60,8 @@ namespace Elwig.Services {
var filter = vm.TextFilter; var filter = vm.TextFilter;
if (filter.Count > 0) { if (filter.Count > 0) {
var var = await ctx.WineVarieties.ToDictionaryAsync(v => v.SortId, v => v); var var = await ctx.FetchWineVarieties().ToDictionaryAsync(v => v.SortId, v => v);
var zwst = await ctx.Branches.ToDictionaryAsync(b => b.Name.ToLower().Split(" ")[0], b => b); var zwst = await ctx.FetchBranches().ToDictionaryAsync(b => b.Name.ToLower().Split(" ")[0], b => b);
for (int i = 0; i < filter.Count; i++) { for (int i = 0; i < filter.Count; i++) {
var e = filter[i]; var e = filter[i];
@@ -174,12 +174,12 @@ namespace Elwig.Services {
ctx.Add(s); 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) .Where(v => v.Year == s.Year && v.DsNr == s.DsNr)
.Select(v => new { v.Variety, v.Priority }) .Select(v => new { v.Variety, v.Priority })
.ToListAsync()) .ToListAsync())
.Select(v => (v.Variety, v.Priority)) .Select(v => (v.Variety.SortId, v.Priority))
.ToList(), vm.MainVarieties.Select(v => (v, 1)).Union(vm.OtherVarieties.Select(v => (v, 2))).ToList()); .ToList(), vm.MainVarieties.Select(v => (v.SortId, 1)).Union(vm.OtherVarieties.Select(v => (v.SortId, 2))).ToList());
await ctx.SaveChangesAsync(); await ctx.SaveChangesAsync();
}); });

View File

@@ -27,10 +27,7 @@ namespace Elwig.Services {
public static async Task<Member?> GetMemberAsync(int mgnr) { public static async Task<Member?> GetMemberAsync(int mgnr) {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
return await ctx.Members return await ctx.FetchMembers(mgnr).SingleOrDefaultAsync();
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.DefaultWbKg!.AtKg)
.FirstOrDefaultAsync(m => m.MgNr == mgnr);
} }
public static Member? GetMember(int mgnr) { public static Member? GetMember(int mgnr) {
@@ -71,7 +68,7 @@ namespace Elwig.Services {
vm.IsNetWeight = p.IsNetWeight; vm.IsNetWeight = p.IsNetWeight;
vm.Modifiers.Clear(); 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)!); vm.Modifiers.Add((Modifier)ControlUtils.GetItemFromSourceWithPk(vm.ModifiersSource, m.Year, m.ModId)!);
} }
@@ -129,12 +126,12 @@ namespace Elwig.Services {
var filter = vm.TextFilter; var filter = vm.TextFilter;
if (filter.Count > 0) { if (filter.Count > 0) {
var var = await ctx.WineVarieties.ToDictionaryAsync(v => v.SortId, v => v); var var = await ctx.FetchWineVarieties().ToDictionaryAsync(v => v.SortId, v => v);
var qual = await ctx.WineQualityLevels.Where(q => !q.IsPredicate).ToDictionaryAsync(q => q.QualId, q => q); var qual = await ctx.FetchWineQualityLevels(false).ToDictionaryAsync(q => q.QualId, q => q);
var mgnr = await ctx.Members.ToDictionaryAsync(m => m.MgNr.ToString(), m => m); var mgnr = await ctx.FetchMembers(includeNotActive: true).ToDictionaryAsync(m => m.MgNr.ToString(), m => m);
var zwst = await ctx.Branches.ToDictionaryAsync(b => b.Name.ToLower().Split(' ')[0], b => b); var zwst = await ctx.FetchBranches().ToDictionaryAsync(b => b.Name.ToLower().Split(' ')[0], b => b);
var attr = await ctx.WineAttributes.ToDictionaryAsync(a => a.Name.ToLower().Split(' ')[0], a => a); var attr = await ctx.FetchWineAttributes().ToDictionaryAsync(a => a.Name.ToLower().Split(' ')[0], a => a);
var cult = await ctx.WineCultivations.ToDictionaryAsync(c => c.Name.ToLower().Split(' ')[0], c => c); var cult = await ctx.FetchWineCultivations().ToDictionaryAsync(c => c.Name.ToLower().Split(' ')[0], c => c);
for (int i = 0; i < filter.Count; i++) { for (int i = 0; i < filter.Count; i++) {
var e = filter[i]; var e = filter[i];
@@ -472,6 +469,7 @@ namespace Elwig.Services {
DeliveryPart p; DeliveryPart p;
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
using var tx = await ctx.Database.BeginTransactionAsync();
int year = oldYear ?? Utils.CurrentYear; int year = oldYear ?? Utils.CurrentYear;
int did = oldDid ?? await ctx.NextDId(year); int did = oldDid ?? await ctx.NextDId(year);
int dpnr = oldDpnr ?? await ctx.NextDPNr(year, did); int dpnr = oldDpnr ?? await ctx.NextDPNr(year, did);
@@ -548,21 +546,21 @@ namespace Elwig.Services {
ctx.Add(p); 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) .Where(m => m.Year == p.Year && m.DId == p.DId && m.DPNr == p.DPNr)
.Select(m => m.Modifier) .Select(m => m.ModId)
.ToListAsync(), vm.Modifiers); .ToListAsync(), vm.Modifiers.Select(m => m.ModId).ToList());
if (originalMgNr != null && originalMgNr.Value != d.MgNr) { if (originalMgNr != null && originalMgNr.Value != d.MgNr) {
// update origin (KgNr), if default is selected // 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;
foreach (var part in d.Parts.Where(part => part.DPNr != dpnr && part.KgNr == originalMemberKgNr)) { await ctx.DeliveryParts
part.KgNr = newKgNr; .Where(p => p.Year == d.Year && p.DId == d.DId && p.DPNr != dpnr && p.KgNr == originalMemberKgNr)
ctx.Update(part); .ExecuteUpdateAsync(u => u.SetProperty(p => p.KgNr, newKgNr));
}
} }
await ctx.SaveChangesAsync(); await ctx.SaveChangesAsync();
await tx.CommitAsync();
return p; return p;
}); });
@@ -574,7 +572,10 @@ namespace Elwig.Services {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
bool anyLeft = false; bool anyLeft = false;
var d = (await ctx.Deliveries.FindAsync(year, did))!; var d = await ctx.Deliveries
.Where(d => d.Year == year && d.DId == did)
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers)
.SingleAsync();
var lnr = await ctx.NextLNr(d.Date, d.ZwstId); var lnr = await ctx.NextLNr(d.Date, d.ZwstId);
n = new Delivery { n = new Delivery {
Year = year, Year = year,
@@ -601,7 +602,11 @@ namespace Elwig.Services {
anyLeft = true; anyLeft = true;
p.Weight -= w; p.Weight -= w;
ctx.Update(p); ctx.Update(p);
var s = ctx.CreateProxy<DeliveryPart>(); var s = new DeliveryPart {
SortId = null!,
QualId = null!,
HkId = null!,
};
var values = ctx.Entry(p).CurrentValues; var values = ctx.Entry(p).CurrentValues;
ctx.Entry(s).CurrentValues.SetValues(values); ctx.Entry(s).CurrentValues.SetValues(values);
s.Year = n.Year; s.Year = n.Year;
@@ -632,8 +637,11 @@ namespace Elwig.Services {
Delivery n; Delivery n;
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
var anyLeft = false; 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.FindAsync(year, did))!; var d = await ctx.Deliveries
.Where(d => d.Year == year && d.DId == did)
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers)
.SingleAsync();
var dpnr = await ctx.NextDPNr(n.Year, n.DId); var dpnr = await ctx.NextDPNr(n.Year, n.DId);
foreach (var (p, w) in d.Parts.ToList().Zip(weights)) { foreach (var (p, w) in d.Parts.ToList().Zip(weights)) {
if (w <= 0) { if (w <= 0) {
@@ -645,7 +653,11 @@ namespace Elwig.Services {
anyLeft = true; anyLeft = true;
p.Weight -= w; p.Weight -= w;
ctx.Update(p); ctx.Update(p);
var s = ctx.CreateProxy<DeliveryPart>(); var s = new DeliveryPart {
SortId = null!,
QualId = null!,
HkId = null!,
};
var values = ctx.Entry(p).CurrentValues; var values = ctx.Entry(p).CurrentValues;
ctx.Entry(s).CurrentValues.SetValues(values); ctx.Entry(s).CurrentValues.SetValues(values);
s.Year = n.Year; s.Year = n.Year;
@@ -674,7 +686,10 @@ namespace Elwig.Services {
public static async Task DepreciateDelivery(int year, int did, int[] weights) { public static async Task DepreciateDelivery(int year, int did, int[] weights) {
await Task.Run(async () => { await Task.Run(async () => {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
var d = (await ctx.Deliveries.FindAsync(year, did))!; var d = await ctx.Deliveries
.Where(d => d.Year == year && d.DId == did)
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers)
.SingleAsync();
var dpnr = await ctx.NextDPNr(year, did); var dpnr = await ctx.NextDPNr(year, did);
foreach (var (p, w) in d.Parts.ToList().Zip(weights)) { foreach (var (p, w) in d.Parts.ToList().Zip(weights)) {
if (w <= 0) { if (w <= 0) {
@@ -686,7 +701,11 @@ namespace Elwig.Services {
} else { } else {
p.Weight -= w; p.Weight -= w;
ctx.Update(p); ctx.Update(p);
var n = ctx.CreateProxy<DeliveryPart>(); var n = new DeliveryPart {
SortId = null!,
QualId = null!,
HkId = null!,
};
var values = ctx.Entry(p).CurrentValues; var values = ctx.Entry(p).CurrentValues;
ctx.Entry(n).CurrentValues.SetValues(values); ctx.Entry(n).CurrentValues.SetValues(values);
n.DPNr = dpnr++; n.DPNr = dpnr++;
@@ -711,10 +730,8 @@ namespace Elwig.Services {
Mouse.OverrideCursor = Cursors.Wait; Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => { await Task.Run(async () => {
try { try {
using var ctx = new AppDbContext(); using var doc = await DeliveryNote.Initialize(year, did);
var d = (await ctx.Deliveries.FindAsync(year, did))!; await Utils.ExportDocument(doc, mode, doc.Delivery.LsNr, (doc.Member, $"{DeliveryNote.Name} Nr. {doc.Delivery.LsNr}", $"Im Anhang finden Sie den {DeliveryNote.Name} Nr. {doc.Delivery.LsNr}"));
using var doc = new DeliveryNote(d, ctx);
await Utils.ExportDocument(doc, mode, d.LsNr, (d.Member, $"{DeliveryNote.Name} Nr. {d.LsNr}", $"Im Anhang finden Sie den {DeliveryNote.Name} Nr. {d.LsNr}"));
} catch (Exception exc) { } catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
} }
@@ -792,9 +809,6 @@ namespace Elwig.Services {
.Select(p => p.Delivery) .Select(p => p.Delivery)
.Distinct() .Distinct()
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers) .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(); .ToListAsync();
var wbKgs = list var wbKgs = list
.SelectMany(d => d.Parts) .SelectMany(d => d.Parts)
@@ -937,7 +951,7 @@ namespace Elwig.Services {
tblTotal.FullName = DeliveryDepreciationList.Name; tblTotal.FullName = DeliveryDepreciationList.Name;
tblTotal.Name = "Gesamt"; tblTotal.Name = "Gesamt";
await ods.AddTable(tblTotal); 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); var tbl = await DeliveryJournalData.FromQuery(query.Where(p => p.Delivery.ZwstId == branch.ZwstId), filterNames);
tbl.FullName = DeliveryDepreciationList.Name; tbl.FullName = DeliveryDepreciationList.Name;
tbl.Name = branch.Name; tbl.Name = branch.Name;
@@ -1048,16 +1062,23 @@ namespace Elwig.Services {
var gGrid = new List<(string?, string?, double, double, double)>(); var gGrid = new List<(string?, string?, double, double, double)>();
var gText = "-"; var gText = "-";
var weight = await deliveryParts.SumAsync(p => p.Weight); var stat = (await deliveryParts.GroupBy(p => 0)
wText = $"{weight:N0} kg"; .Select(g => new {
wGrid.Add(("Menge", null, weight, null, weight)); 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()) { wText = $"{stat.Weight:N0} kg";
var kmwMin = await deliveryParts.MinAsync(p => p.Kmw); wGrid.Add(("Menge", null, stat.Weight, null, stat.Weight));
var kmwAvg = Utils.AggregateDeliveryPartsKmw(deliveryParts);
var kmwMax = await deliveryParts.MaxAsync(p => p.Kmw); if (stat.Min != null && stat.Max != null) {
gText = $"{kmwMin:N1}° / {kmwAvg:N1}° / {kmwMax:N1}°"; gText = $"{stat.Min:N1}° / {stat.Avg:N1}° / {stat.Max:N1}°";
gGrid.Add(("Gradation", null, kmwMin, kmwAvg, kmwMax)); gGrid.Add(("Gradation", null, stat.Min.Value, stat.Avg, stat.Max.Value));
var attrGroups = await deliveryParts var attrGroups = await deliveryParts
.GroupBy(p => new { Attr = p.Attribute!.Name, Cult = p.Cultivation!.Name }) .GroupBy(p => new { Attr = p.Attribute!.Name, Cult = p.Cultivation!.Name })
@@ -1108,9 +1129,9 @@ namespace Elwig.Services {
foreach (var attrG in attrGroups) { foreach (var attrG in attrGroups) {
var name = attrG.Attr == null && attrG.Cult == null ? null : attrG.Attr + (attrG.Attr != null && attrG.Cult != null ? " / " : "") + attrG.Cult; 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)) { 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) { foreach (var attrG in attrGroups) {
@@ -1129,12 +1150,12 @@ namespace Elwig.Services {
gText += $" [{name}]"; gText += $" [{name}]";
} }
if (sortGroups.Count > 1 && sortGroups.Count <= 4) { 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}]")))}"; 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) { } 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}]")))}"; 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); var c = m.ActiveAreaCommitments(ctx, Utils.CurrentLastSeason);
int maxKgPerHa = 10_000; int maxKgPerHa = 10_000;
try { 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; if (s != null) maxKgPerHa = s.MaxKgPerHa;
} catch { } } catch { }
var (text, gridData) = await AreaComService.GenerateToolTipData(c, maxKgPerHa); var (text, gridData) = await AreaComService.GenerateToolTipData(c, maxKgPerHa);
@@ -225,8 +225,8 @@ namespace Elwig.Services {
var filter = vm.TextFilter; var filter = vm.TextFilter;
if (filter.Count > 0) { if (filter.Count > 0) {
var branches = await ctx.Branches.ToListAsync(); var branches = await ctx.FetchBranches().ToListAsync();
var mgnr = await ctx.Members.ToDictionaryAsync(m => m.MgNr.ToString(), m => m); 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 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); var areaComs = await ctx.AreaCommitmentTypes.ToDictionaryAsync(t => $"{t.SortId}{t.AttrId}", t => t);
@@ -395,8 +395,7 @@ namespace Elwig.Services {
Mouse.OverrideCursor = Cursors.Wait; Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => { await Task.Run(async () => {
try { try {
using var ctx = new AppDbContext(); using var doc = new MemberDataSheet(m);
using var doc = new MemberDataSheet(m, ctx);
await Utils.ExportDocument(doc, mode, emailData: (m, MemberDataSheet.Name, "Im Anhang finden Sie das aktuelle Stammdatenblatt")); await Utils.ExportDocument(doc, mode, emailData: (m, MemberDataSheet.Name, "Im Anhang finden Sie das aktuelle Stammdatenblatt"));
} catch (Exception exc) { } catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
@@ -409,14 +408,12 @@ namespace Elwig.Services {
Mouse.OverrideCursor = Cursors.Wait; Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => { await Task.Run(async () => {
try { try {
var b = new Billing(year); var b = await Billing.Create(year);
await b.FinishSeason(); await b.FinishSeason();
await b.CalculateBuckets(); await b.CalculateBuckets();
App.HintContextChange(); App.HintContextChange();
using var ctx = new AppDbContext(); using var doc = new DeliveryConfirmation(year, m, null);
var data = await DeliveryConfirmationDeliveryData.ForMember(ctx.DeliveryParts, year, m);
using var doc = new DeliveryConfirmation(ctx, year, m, data);
await Utils.ExportDocument(doc, mode, emailData: (m, $"{DeliveryConfirmation.Name} {year}", $"Im Anhang finden Sie die Anlieferungsbestätigung {year}")); await Utils.ExportDocument(doc, mode, emailData: (m, $"{DeliveryConfirmation.Name} {year}", $"Im Anhang finden Sie die Anlieferungsbestätigung {year}"));
} catch (Exception exc) { } catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
@@ -429,16 +426,8 @@ namespace Elwig.Services {
Mouse.OverrideCursor = Cursors.Wait; Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => { await Task.Run(async () => {
try { try {
using var ctx = new AppDbContext(); using var doc = await CreditNote.Initialize(year, avnr, m.MgNr, null);
var v = (await ctx.PaymentVariants.FindAsync(year, avnr))!; await Utils.ExportDocument(doc, mode, emailData: (m, $"{CreditNote.Name} {doc.Payment.Variant.Name}", $"Im Anhang finden Sie die Traubengutschrift {doc.Payment.Variant.Name}"));
var data = await CreditNoteDeliveryData.ForPaymentVariant(ctx.CreditNoteDeliveryRows, ctx.PaymentVariants, year, avnr);
var p = (await ctx.MemberPayments.FindAsync(year, avnr, m.MgNr))!;
var b = BillingData.FromJson((await ctx.PaymentVariants.FindAsync(year, avnr))!.Data);
using var doc = new CreditNote(ctx, p, data[m.MgNr],
b.ConsiderContractPenalties, b.ConsiderTotalPenalty, b.ConsiderAutoBusinessShares, b.ConsiderCustomModifiers,
await ctx.GetMemberUnderDelivery(year, m.MgNr));
await Utils.ExportDocument(doc, mode, emailData: (m, $"{CreditNote.Name} {v.Name}", $"Im Anhang finden Sie die Traubengutschrift {v.Name}"));
} catch (Exception exc) { } catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
} }
@@ -520,10 +509,8 @@ namespace Elwig.Services {
try { try {
var members = await query var members = await query
.OrderBy(m => m.MgNr) .OrderBy(m => m.MgNr)
.Include(m => m.BillingAddress)
.Include(m => m.TelephoneNumbers) .Include(m => m.TelephoneNumbers)
.Include(m => m.EmailAddresses) .Include(m => m.EmailAddresses)
.AsSplitQuery()
.ToListAsync(); .ToListAsync();
using var exporter = new VCard(d.FileName); using var exporter = new VCard(d.FileName);
await exporter.ExportAsync(members); await exporter.ExportAsync(members);
@@ -548,16 +535,13 @@ namespace Elwig.Services {
try { try {
var members = await query var members = await query
.OrderBy(m => m.MgNr) .OrderBy(m => m.MgNr)
.Include(m => m.BillingAddress)
.Include(m => m.TelephoneNumbers) .Include(m => m.TelephoneNumbers)
.Include(m => m.EmailAddresses) .Include(m => m.EmailAddresses)
.Include(m => m.DefaultWbKg!.Gl)
.AsSplitQuery()
.ToListAsync(); .ToListAsync();
var areaComs = await query var areaComs = await query
.SelectMany(m => m.AreaCommitments) .SelectMany(m => m.AreaCommitments)
.Include(c => c.Rd) .Select(c => c.Contract).Distinct()
.Include(c => c.Kg.Gl) .Include(c => c.Revisions)
.ToListAsync(); .ToListAsync();
var wbKgs = members var wbKgs = members
.Where(m => m.DefaultWbKg != null) .Where(m => m.DefaultWbKg != null)
@@ -681,19 +665,17 @@ namespace Elwig.Services {
.Where(c => c.MgNr == predecessor && (c.YearTo == null || c.YearTo >= year)) .Where(c => c.MgNr == predecessor && (c.YearTo == null || c.YearTo >= year))
.ToListAsync(); .ToListAsync();
var fbNr = await ctx.NextFbNr(); ctx.AddRange(await Task.WhenAll(areaComs.Select(async (c, i) => new AreaCom {
ctx.AddRange(areaComs.Select((c, i) => new AreaCom { FbNr = c.FbNr,
FbNr = fbNr + i, RevNr = await ctx.NextRevNr(c.FbNr),
MgNr = m.MgNr, MgNr = m.MgNr,
VtrgId = c.VtrgId, VtrgId = c.VtrgId,
CultId = c.CultId, CultId = c.CultId,
Area = c.Area, Area = c.Area,
KgNr = c.KgNr,
GstNr = c.GstNr, GstNr = c.GstNr,
RdNr = c.RdNr, YearFrom = year,
YearFrom = vm.MaintainAreaComYearFrom ? c.YearFrom : year,
YearTo = c.YearTo, YearTo = c.YearTo,
})); })));
foreach (var ac in areaComs) foreach (var ac in areaComs)
ac.YearTo = year - 1; ac.YearTo = year - 1;
@@ -725,18 +707,20 @@ namespace Elwig.Services {
public static async Task DeleteMember(int mgnr, bool deletePaymentData, bool deleteDeliveries, bool deleteAreaComs) { public static async Task DeleteMember(int mgnr, bool deletePaymentData, bool deleteDeliveries, bool deleteAreaComs) {
await Task.Run(async () => { await Task.Run(async () => {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
var l = (await ctx.Members.FindAsync(mgnr))!; using var tx = await ctx.Database.BeginTransactionAsync();
var l = await ctx.FetchMembers(mgnr).SingleAsync();
if (deletePaymentData) { if (deletePaymentData) {
ctx.RemoveRange(l.Credits); await ctx.Credits.Where(c => c.MgNr == mgnr).ExecuteDeleteAsync();
} }
if (deleteDeliveries) { if (deleteDeliveries) {
ctx.RemoveRange(l.Deliveries); await ctx.Deliveries.Where(c => c.MgNr == mgnr).ExecuteDeleteAsync();
} }
if (deleteAreaComs) { if (deleteAreaComs) {
ctx.RemoveRange(l.AreaCommitments); await ctx.AreaCommitments.Where(c => c.MgNr == mgnr).ExecuteDeleteAsync();
} }
ctx.Remove(l); ctx.Remove(l);
await ctx.SaveChangesAsync(); await ctx.SaveChangesAsync();
await tx.CommitAsync();
}); });
} }
} }

View File

@@ -214,9 +214,7 @@ namespace Elwig.Services {
Mouse.OverrideCursor = Cursors.Wait; Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => { await Task.Run(async () => {
try { try {
using var ctx = new AppDbContext(); using var doc = await PaymentVariantSummary.Initialize(v.Year, v.AvNr);
var data = await PaymentVariantSummaryData.ForPaymentVariant(v, ctx.PaymentVariantSummaryRows);
using var doc = new PaymentVariantSummary((await ctx.PaymentVariants.FindAsync(v.Year, v.AvNr))!, data);
await Utils.ExportDocument(doc, mode); await Utils.ExportDocument(doc, mode);
} catch (Exception exc) { } catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
@@ -365,21 +363,21 @@ namespace Elwig.Services {
public static async Task Calculate(int year, int avnr) { public static async Task Calculate(int year, int avnr) {
await Task.Run(async () => { await Task.Run(async () => {
var b = new BillingVariant(year, avnr); var b = await BillingVariant.Create(year, avnr);
await b.Calculate(); await b.Calculate();
}); });
} }
public static async Task Commit(int year, int avnr) { public static async Task Commit(int year, int avnr) {
await Task.Run(async () => { await Task.Run(async () => {
var b = new BillingVariant(year, avnr); var b = await BillingVariant.Create(year, avnr);
await b.Commit(); await b.Commit();
}); });
} }
public static async Task Revert(int year, int avnr) { public static async Task Revert(int year, int avnr) {
await Task.Run(async () => { await Task.Run(async () => {
var b = new BillingVariant(year, avnr); var b = await BillingVariant.Create(year, avnr);
await b.Revert(); await b.Revert();
}); });
} }

View File

@@ -16,6 +16,7 @@ namespace Elwig.Services {
public static class SyncService { public static class SyncService {
public static readonly Expression<Func<Member, bool>> ChangedMembers = (m) => ((m.XTime == null && m.MTime > 1751328000) || m.MTime > m.XTime) && (m.ITime == null || m.MTime > m.ITime); public static readonly Expression<Func<Member, bool>> ChangedMembers = (m) => ((m.XTime == null && m.MTime > 1751328000) || m.MTime > m.XTime) && (m.ITime == null || m.MTime > m.ITime);
public static readonly Expression<Func<AreaComContract, bool>> ChangedAreaComContracts = (c) => ((c.XTime == null && c.MTime > 1751328000) || c.MTime > c.XTime) && (c.ITime == null || c.MTime > c.ITime);
public static readonly Expression<Func<Delivery, bool>> ChangedDeliveries = (d) => ((d.XTime == null && d.MTime > 1751328000) || d.MTime > d.XTime) && (d.ITime == null || d.MTime > d.ITime); public static readonly Expression<Func<Delivery, bool>> ChangedDeliveries = (d) => ((d.XTime == null && d.MTime > 1751328000) || d.MTime > d.XTime) && (d.ITime == null || d.MTime > d.ITime);
public static async Task Upload(string url, string username, string password, IQueryable<Member> query, IEnumerable<string> filterNames) { public static async Task Upload(string url, string username, string password, IQueryable<Member> query, IEnumerable<string> filterNames) {
@@ -24,17 +25,14 @@ namespace Elwig.Services {
var path = Path.Combine(App.TempPath, filename); var path = Path.Combine(App.TempPath, filename);
var members = await query var members = await query
.OrderBy(m => m.MgNr) .OrderBy(m => m.MgNr)
.Include(m => m.BillingAddress)
.Include(m => m.TelephoneNumbers) .Include(m => m.TelephoneNumbers)
.Include(m => m.EmailAddresses) .Include(m => m.EmailAddresses)
.Include(m => m.DefaultWbKg!.Gl)
.AsSplitQuery()
.ToListAsync(); .ToListAsync();
var areaComs = await query var areaComs = await query
.SelectMany(m => m.AreaCommitments) .SelectMany(m => m.AreaCommitments)
.OrderBy(c => c.MgNr).ThenBy(c => c.FbNr) .Select(c => c.Contract).Distinct()
.Include(c => c.Rd) .OrderBy(c => c.FbNr)
.Include(c => c.Kg.Gl) .Include(c => c.Revisions)
.ToListAsync(); .ToListAsync();
var wbKgs = members var wbKgs = members
.Where(m => m.DefaultWbKg != null) .Where(m => m.DefaultWbKg != null)
@@ -50,7 +48,7 @@ namespace Elwig.Services {
var exportedAt = DateTime.Now; var exportedAt = DateTime.Now;
await ElwigData.Export(path, members, areaComs, wbKgs, filterNames); await ElwigData.Export(path, members, areaComs, wbKgs, filterNames);
await Utils.UploadExportData(path, url, username, password); await Utils.UploadExportData(path, url, username, password);
await UpdateExportedAt(members, [], exportedAt); await UpdateExportedAt(members, areaComs, [], exportedAt);
MessageBox.Show($"Hochladen von {members.Count:N0} Mitgliedern erfolgreich!", "Mitglieder hochgeladen", MessageBox.Show($"Hochladen von {members.Count:N0} Mitgliedern erfolgreich!", "Mitglieder hochgeladen",
MessageBoxButton.OK, MessageBoxImage.Information); MessageBoxButton.OK, MessageBoxImage.Information);
} }
@@ -70,10 +68,7 @@ namespace Elwig.Services {
var list = await query var list = await query
.Select(p => p.Delivery) .Select(p => p.Delivery)
.Distinct() .Distinct()
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers).ThenInclude(m => m.Modifier) .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(); .ToListAsync();
var wbKgs = list var wbKgs = list
.SelectMany(d => d.Parts) .SelectMany(d => d.Parts)
@@ -89,7 +84,7 @@ namespace Elwig.Services {
var exportedAt = DateTime.Now; var exportedAt = DateTime.Now;
await ElwigData.Export(path, list, wbKgs, filterNames); await ElwigData.Export(path, list, wbKgs, filterNames);
await Utils.UploadExportData(path, url, username, password); await Utils.UploadExportData(path, url, username, password);
await UpdateExportedAt([], list, exportedAt); await UpdateExportedAt([], [], list, exportedAt);
MessageBox.Show($"Hochladen von {list.Count:N0} Lieferungen erfolgreich!", "Lieferungen hochgeladen", MessageBox.Show($"Hochladen von {list.Count:N0} Lieferungen erfolgreich!", "Lieferungen hochgeladen",
MessageBoxButton.OK, MessageBoxImage.Information); MessageBoxButton.OK, MessageBoxImage.Information);
} }
@@ -106,32 +101,24 @@ namespace Elwig.Services {
try { try {
var path = Path.Combine(App.TempPath, $"{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{App.ZwstId}.elwig.zip"); var path = Path.Combine(App.TempPath, $"{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{App.ZwstId}.elwig.zip");
List<Member> members; List<Member> members;
List<AreaCom> areaComs; List<AreaComContract> areaComs;
List<Delivery> deliveries; List<Delivery> deliveries;
using (var ctx = new AppDbContext()) { using (var ctx = new AppDbContext()) {
members = await ctx.Members members = await ctx.Members
.Where(ChangedMembers) .Where(ChangedMembers)
.Include(m => m.BillingAddress)
.Include(m => m.TelephoneNumbers) .Include(m => m.TelephoneNumbers)
.Include(m => m.EmailAddresses) .Include(m => m.EmailAddresses)
.Include(m => m.DefaultWbKg!.Gl)
.OrderBy(m => m.MgNr) .OrderBy(m => m.MgNr)
.AsSplitQuery()
.ToListAsync(); .ToListAsync();
areaComs = await ctx.Members areaComs = await ctx.AreaCommitmentContracts
.Where(ChangedMembers) .Where(ChangedAreaComContracts)
.SelectMany(m => m.AreaCommitments) .Include(c => c.Revisions)
.Include(c => c.Rd) .OrderBy(c => c.FbNr)
.Include(c => c.Kg.Gl)
.OrderBy(c => c.MgNr).ThenBy(c => c.FbNr)
.ToListAsync(); .ToListAsync();
deliveries = await ctx.Deliveries deliveries = await ctx.Deliveries
.Where(ChangedDeliveries) .Where(ChangedDeliveries)
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers).ThenInclude(m => m.Modifier) .Include(d => d.Parts).ThenInclude(p => p.PartModifiers)
.Include(d => d.Parts).ThenInclude(p => p.Rd)
.Include(d => d.Parts).ThenInclude(p => p.Kg).ThenInclude(k => k!.Gl)
.OrderBy(d => d.DateString).ThenBy(d => d.TimeString).ThenBy(d => d.LsNr) .OrderBy(d => d.DateString).ThenBy(d => d.TimeString).ThenBy(d => d.LsNr)
.AsSplitQuery()
.ToListAsync(); .ToListAsync();
} }
var wbKgs = members var wbKgs = members
@@ -151,13 +138,13 @@ namespace Elwig.Services {
var exportedAt = DateTime.Now; var exportedAt = DateTime.Now;
await (new ElwigData.ElwigExport { await (new ElwigData.ElwigExport {
Members = (members, ["geändert seit letztem Export"]), Members = (members, ["geändert seit letztem Export"]),
AreaComs = (areaComs, ["von exportierten Mitgliedern"]), AreaComs = (areaComs, ["geändert seit letztem Export"]),
Deliveries = (deliveries, ["geändert seit letzem Export"]), Deliveries = (deliveries, ["geändert seit letzem Export"]),
WbKgs = (wbKgs, ["von exportierten Mitgliedern, Flächenbindungen und Lieferungen"]), WbKgs = (wbKgs, ["von exportierten Mitgliedern, Flächenbindungen und Lieferungen"]),
}).Export(path); }).Export(path);
await Utils.UploadExportData(path, url, username, password); await Utils.UploadExportData(path, url, username, password);
await UpdateExportedAt(members, deliveries, exportedAt); await UpdateExportedAt(members, areaComs, deliveries, exportedAt);
MessageBox.Show($"Hochladen von {members.Count:N0} Mitgliedern und {deliveries.Count:N0} Lieferungen erfolgreich!", "Mitglieder und Lieferungen hochladen", MessageBox.Show($"Hochladen von {members.Count:N0} Mitgliedern, {areaComs.Count:N0} Flächenbindungsverträgen, und {deliveries.Count:N0} Lieferungen erfolgreich!", "Mitglieder und Lieferungen hochladen",
MessageBoxButton.OK, MessageBoxImage.Information); MessageBoxButton.OK, MessageBoxImage.Information);
} }
} catch (HttpRequestException exc) { } catch (HttpRequestException exc) {
@@ -176,11 +163,8 @@ namespace Elwig.Services {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
var deliveries = await ctx.Deliveries var deliveries = await ctx.Deliveries
.Where(d => d.Year == year && d.ZwstId == App.ZwstId) .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.PartModifiers)
.Include(d => d.Parts).ThenInclude(p => p.Rd)
.Include(d => d.Parts).ThenInclude(p => p.Kg).ThenInclude(k => k!.Gl)
.OrderBy(d => d.DateString).ThenBy(d => d.TimeString).ThenBy(d => d.LsNr) .OrderBy(d => d.DateString).ThenBy(d => d.TimeString).ThenBy(d => d.LsNr)
.AsSplitQuery()
.ToListAsync(); .ToListAsync();
var wbKgs = deliveries var wbKgs = deliveries
.SelectMany(d => d.Parts) .SelectMany(d => d.Parts)
@@ -195,7 +179,7 @@ namespace Elwig.Services {
var exportedAt = DateTime.Now; var exportedAt = DateTime.Now;
await ElwigData.Export(path, deliveries, wbKgs, [$"{year}", $"Zweigstelle {App.BranchName}"]); await ElwigData.Export(path, deliveries, wbKgs, [$"{year}", $"Zweigstelle {App.BranchName}"]);
await Utils.UploadExportData(path, url, username, password); await Utils.UploadExportData(path, url, username, password);
await UpdateExportedAt([], deliveries, exportedAt); await UpdateExportedAt([], [], deliveries, exportedAt);
MessageBox.Show($"Hochladen von {deliveries.Count:N0} Lieferungen erfolgreich!", "Lieferungen hochladen", MessageBox.Show($"Hochladen von {deliveries.Count:N0} Lieferungen erfolgreich!", "Lieferungen hochladen",
MessageBoxButton.OK, MessageBoxImage.Information); MessageBoxButton.OK, MessageBoxImage.Information);
} }
@@ -251,16 +235,18 @@ namespace Elwig.Services {
} }
} }
private static async Task UpdateExportedAt(IEnumerable<Member> member, IEnumerable<Delivery> deliveries, DateTime dateTime) { private static async Task UpdateExportedAt(IEnumerable<Member> member, IEnumerable<AreaComContract> contracts, IEnumerable<Delivery> deliveries, DateTime dateTime) {
var timestamp = ((DateTimeOffset)dateTime.ToUniversalTime()).ToUnixTimeSeconds(); var timestamp = ((DateTimeOffset)dateTime.ToUniversalTime()).ToUnixTimeSeconds();
var mgnrs = string.Join(",", member.Select(m => $"{m.MgNr}").Append("0")); var mgnrs = string.Join(",", member.Select(m => $"{m.MgNr}").Append("0"));
var fbnrs = string.Join(",", contracts.Select(c => $"{c.FbNr}").Append("0"));
var dids = string.Join(",", deliveries.Select(d => $"({d.Year},{d.DId})").Append("(0,0)")); var dids = string.Join(",", deliveries.Select(d => $"({d.Year},{d.DId})").Append("(0,0)"));
using (var cnx = await AppDbContext.ConnectAsync()) { using (var cnx = await AppDbContext.ConnectAsync()) {
await cnx.ExecuteBatch($""" await cnx.ExecuteBatch($"""
BEGIN; BEGIN;
UPDATE client_parameter SET value = '0' WHERE param = 'ENABLE_TIME_TRIGGERS'; UPDATE client_parameter SET value = '0' WHERE param = 'ENABLE_TIME_TRIGGERS';
UPDATE member SET xtime = {timestamp} WHERE mgnr IN ({mgnrs}); UPDATE member SET xtime = {timestamp} WHERE mgnr IN ({mgnrs});
UPDATE area_commitment SET xtime = {timestamp} WHERE mgnr IN ({mgnrs}); UPDATE area_commitment_contract SET xtime = {timestamp} WHERE fbnr IN ({fbnrs});
UPDATE area_commitment SET xtime = {timestamp} WHERE fbnr IN ({fbnrs});
UPDATE delivery SET xtime = {timestamp} WHERE (year, did) IN ({dids}); UPDATE delivery SET xtime = {timestamp} WHERE (year, did) IN ({dids});
UPDATE delivery_part SET xtime = {timestamp} WHERE (year, did) IN ({dids}); UPDATE delivery_part SET xtime = {timestamp} WHERE (year, did) IN ({dids});
UPDATE client_parameter SET value = '1' WHERE param = 'ENABLE_TIME_TRIGGERS'; UPDATE client_parameter SET value = '1' WHERE param = 'ENABLE_TIME_TRIGGERS';
@@ -272,7 +258,7 @@ namespace Elwig.Services {
public static async Task<bool> ChangesAvailable(AppDbContext ctx, string url, string username, string password) { public static async Task<bool> ChangesAvailable(AppDbContext ctx, string url, string username, string password) {
try { try {
return await ctx.Members.AnyAsync(ChangedMembers) || 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 { } catch {
return false; return false;
} }

View File

@@ -20,7 +20,11 @@ namespace Elwig.ViewModels {
} }
[ObservableProperty] [ObservableProperty]
private bool _showOnlyActiveAreaComs; private string? _filterSeasonString;
public int? FilterSeason {
get => int.TryParse(FilterSeasonString, out var year) ? year : null;
set => FilterSeasonString = $"{value}";
}
[ObservableProperty] [ObservableProperty]
private string? _fbNrString; private string? _fbNrString;
@@ -46,6 +50,8 @@ namespace Elwig.ViewModels {
get => int.TryParse(YearToString, out var year) ? year : null; get => int.TryParse(YearToString, out var year) ? year : null;
set => YearToString = $"{value}"; set => YearToString = $"{value}";
} }
[ObservableProperty]
private string? _period;
[ObservableProperty] [ObservableProperty]
private AreaComType? _areaComType; private AreaComType? _areaComType;

View File

@@ -11,7 +11,6 @@ namespace Elwig.ViewModels {
public partial class MemberAdminViewModel : ObservableObject { public partial class MemberAdminViewModel : ObservableObject {
public int? TransferPredecessorAreaComs = null; public int? TransferPredecessorAreaComs = null;
public bool MaintainAreaComYearFrom = false;
public int? CancelAreaComs = null; public int? CancelAreaComs = null;
public ObservableCollection<KeyValuePair<string, string>> PhoneNrTypes { get; set; } = new(Utils.PhoneNrTypes); public ObservableCollection<KeyValuePair<string, string>> PhoneNrTypes { get; set; } = new(Utils.PhoneNrTypes);
@@ -21,7 +20,7 @@ namespace Elwig.ViewModels {
public List<string> TextFilter => [.. SearchQuery?.ToLower().Split(' ').ToList().FindAll(e => e.Length > 0) ?? []]; public List<string> TextFilter => [.. SearchQuery?.ToLower().Split(' ').ToList().FindAll(e => e.Length > 0) ?? []];
[ObservableProperty] [ObservableProperty]
private bool _showOnlyActiveMembers; private bool _showOnlyActiveMembers = true;
[ObservableProperty] [ObservableProperty]
private Member? _selectedMember; private Member? _selectedMember;

View File

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

View File

@@ -7,8 +7,7 @@
xmlns:local="clr-namespace:Elwig.Windows" xmlns:local="clr-namespace:Elwig.Windows"
xmlns:ctrl="clr-namespace:Elwig.Controls" xmlns:ctrl="clr-namespace:Elwig.Controls"
xmlns:vm="clr-namespace:Elwig.ViewModels" xmlns:vm="clr-namespace:Elwig.ViewModels"
Title="{Binding Title}" Height="600" MinHeight="450" Width="1000" MinWidth="860" Title="{Binding Title}" Height="600" MinHeight="550" Width="1000" MinWidth="860">
Loaded="Window_Loaded">
<Window.DataContext> <Window.DataContext>
<vm:AreaComAdminViewModel/> <vm:AreaComAdminViewModel/>
</Window.DataContext> </Window.DataContext>
@@ -57,7 +56,7 @@
<RowDefinition Height="24"/> <RowDefinition Height="24"/>
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="3*" MinWidth="500"/> <ColumnDefinition Width="2*" MinWidth="500"/>
<ColumnDefinition Width="5"/> <ColumnDefinition Width="5"/>
<ColumnDefinition Width="*" MinWidth="280"/> <ColumnDefinition Width="*" MinWidth="280"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
@@ -78,7 +77,7 @@
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<TextBox x:Name="SearchInput" Text="{Binding SearchQuery, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" <TextBox x:Name="SearchInput" Text="{Binding SearchQuery, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Grid.ColumnSpan="3" Margin="5,5,190,0" IsReadOnly="False" Grid.ColumnSpan="3" Margin="5,5,66,0" IsReadOnly="False"
TextChanged="SearchInput_TextChanged"> TextChanged="SearchInput_TextChanged">
<TextBox.ToolTip> <TextBox.ToolTip>
<TextBlock> <TextBlock>
@@ -94,9 +93,10 @@
</TextBlock> </TextBlock>
</TextBox.ToolTip> </TextBox.ToolTip>
</TextBox> </TextBox>
<CheckBox x:Name="ActiveAreaCommitmentInput" Content="Nur laufende anzeigen (2020)" IsChecked="{Binding ShowOnlyActiveAreaComs}" <ctrl:IntegerUpDown x:Name="SeasonInput" Text="{Binding FilterSeasonString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Checked="ActiveAreaCommitmentInput_Changed" Unchecked="ActiveAreaCommitmentInput_Changed" Grid.ColumnSpan="3" Height="25" Width="56" FontSize="14" Minimum="1900" Maximum="9999"
HorizontalAlignment="Right" Margin="0,10,10,0" VerticalAlignment="Top" Grid.Column="1" Grid.ColumnSpan="2"/> Margin="0,5,5,0" VerticalAlignment="Top" HorizontalAlignment="Right"
TextChanged="SeasonInput_TextChanged"/>
<DataGrid x:Name="AreaCommitmentList" AutoGenerateColumns="False" HeadersVisibility="Column" IsReadOnly="True" GridLinesVisibility="None" SelectionMode="Single" <DataGrid x:Name="AreaCommitmentList" AutoGenerateColumns="False" HeadersVisibility="Column" IsReadOnly="True" GridLinesVisibility="None" SelectionMode="Single"
CanUserDeleteRows="False" CanUserResizeRows="False" CanUserAddRows="False" SelectionChanged="AreaCommitmentList_SelectionChanged" Grid.Column="0" Grid.Row="1" CanUserDeleteRows="False" CanUserResizeRows="False" CanUserAddRows="False" SelectionChanged="AreaCommitmentList_SelectionChanged" Grid.Column="0" Grid.Row="1"
@@ -110,25 +110,24 @@
</DataGridTextColumn.CellStyle> </DataGridTextColumn.CellStyle>
</DataGridTextColumn> </DataGridTextColumn>
<DataGridTextColumn Header="Katastralgemeinde" Binding="{Binding Kg.AtKg.Name}" Width="130"/> <DataGridTextColumn Header="Katastralgemeinde" Binding="{Binding Kg.AtKg.Name}" Width="130"/>
<DataGridTextColumn Header="Sorte" Binding="{Binding AreaComType.WineVar.SortId}" Width="50"> <DataGridTextColumn Header="Sorte" Binding="{Binding Latest.AreaComType.VtrgId}" Width="50">
<DataGridTextColumn.CellStyle> <DataGridTextColumn.CellStyle>
<Style> <Style>
<Setter Property="TextBlock.Foreground" Value="{Binding AreaComType.WineVar.Color}"/> <Setter Property="TextBlock.Foreground" Value="{Binding Latest.AreaComType.WineVar.Color}"/>
<Setter Property="TextBlock.TextAlignment" Value="Center"/> <Setter Property="TextBlock.TextAlignment" Value="Center"/>
</Style> </Style>
</DataGridTextColumn.CellStyle> </DataGridTextColumn.CellStyle>
</DataGridTextColumn> </DataGridTextColumn>
<DataGridTextColumn Header="Fläche" Binding="{Binding Area, StringFormat='{}{0:N0} m² '}" Width="80"> <DataGridTextColumn Header="Fläche" Binding="{Binding Latest.Area, StringFormat='{}{0:N0} m² '}" Width="80">
<DataGridTextColumn.CellStyle> <DataGridTextColumn.CellStyle>
<Style> <Style>
<Setter Property="TextBlock.TextAlignment" Value="Right"/> <Setter Property="TextBlock.TextAlignment" Value="Right"/>
</Style> </Style>
</DataGridTextColumn.CellStyle> </DataGridTextColumn.CellStyle>
</DataGridTextColumn> </DataGridTextColumn>
<DataGridTextColumn Header="Attribut" Binding="{Binding AreaComType.WineAttr.Name}" Width="100"/>
<DataGridTextColumn Header="Ried" Binding="{Binding Rd.Name}" Width="130"/> <DataGridTextColumn Header="Ried" Binding="{Binding Rd.Name}" Width="130"/>
<DataGridTextColumn Header="Parzelle" Binding="{Binding GstNr}" Width="130"/> <DataGridTextColumn Header="Parzelle" Binding="{Binding Latest.GstNr}" Width="130"/>
<DataGridTextColumn Header="Bewirt." Binding="{Binding WineCult.Name}" Width="60"/> <DataGridTextColumn Header="Bewirt." Binding="{Binding Latest.WineCult.Name}" Width="60"/>
<DataGridTextColumn Header="Von" Binding="{Binding YearFrom}" Width="48"/> <DataGridTextColumn Header="Von" Binding="{Binding YearFrom}" Width="48"/>
<DataGridTextColumn Header="Bis" Binding="{Binding YearTo}" Width="48"/> <DataGridTextColumn Header="Bis" Binding="{Binding YearTo}" Width="48"/>
</DataGrid.Columns> </DataGrid.Columns>
@@ -177,91 +176,119 @@
<Grid Grid.Column="2" Grid.Row="1"> <Grid Grid.Column="2" Grid.Row="1">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="1.125*"/> <RowDefinition Height="*"/>
<RowDefinition Height="1*"/> <RowDefinition Height="230"/>
</Grid.RowDefinitions> </Grid.RowDefinitions>
<GroupBox Header="Vertrag" Grid.Column="2" Grid.Row="0" Grid.RowSpan="1" Margin="5,5,5,5"> <GroupBox Header="Vertrag" Grid.Row="0" Margin="5,5,5,5">
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="80"/> <ColumnDefinition Width="80"/>
<ColumnDefinition Width="48"/> <ColumnDefinition Width="60"/>
<ColumnDefinition Width="60"/> <ColumnDefinition Width="60"/>
<ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Label Content="MgNr.:" Margin="10,10,0,0" Grid.Column="0"/> <Label Content="FB-Nr.:" Margin="10,10,0,0" Grid.Column="0"/>
<TextBox x:Name="MgNrInput" Text="{Binding MgNrString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsEnabled="False"
Margin="0,10,0,0" Width="48" HorizontalAlignment="Left" Grid.Column="1" TextAlignment="Right"/>
<Label Content="FbNr.:" Margin="10,10,0,0" Grid.Column="2"/>
<TextBox x:Name="FbNrInput" Text="{Binding FbNrString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" <TextBox x:Name="FbNrInput" Text="{Binding FbNrString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,10,10,0" Width="56" HorizontalAlignment="Left" Grid.Column="3" TextAlignment="Right" Margin="0,10,0,0" Width="56" HorizontalAlignment="Left" Grid.Column="1" TextAlignment="Right"
TextChanged="FbNrInput_TextChanged" LostFocus="FbNrInput_LostFocus"/> TextChanged="FbNrInput_TextChanged" LostFocus="FbNrInput_LostFocus"/>
<Label Content="Zeitraum:" Margin="10,40,0,0" Grid.Column="0"/> <Label Content="Laufzeit:" Margin="10,10,0,0" Grid.Column="2"/>
<TextBox x:Name="YearFromInput" Text="{Binding YearFromString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" <TextBlock x:Name="Period" Text="{Binding Period}"
Margin="0,40,10,0" Width="40" HorizontalAlignment="Left" Grid.Column="1" Grid.ColumnSpan="2" TextAlignment="Right" Margin="0,14,10,0" Grid.Column="3" TextWrapping="NoWrap" VerticalAlignment="Top"/>
TextChanged="IntegerInput_TextChanged"/>
<Label Content="" Grid.Column="1" Grid.ColumnSpan="3" Margin="45,40,0,0"/>
<TextBox x:Name="YearToInput" Text="{Binding YearToString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="60,40,10,0" Width="40" HorizontalAlignment="Left" Grid.Column="1" Grid.ColumnSpan="3" TextAlignment="Right"
TextChanged="IntegerInput_TextChanged"/>
<Label Content="Vertragsart:" Margin="10,70,0,0" Grid.Column="0" Grid.ColumnSpan="2"/> <Label Content="KG:" Margin="10,40,0,0" Grid.Column="0"/>
<ComboBox x:Name="AreaComTypeInput" SelectedItem="{Binding AreaComType, Mode=TwoWay}" ItemsSource="{Binding AreaComTypeSource, Mode=TwoWay}" <ComboBox x:Name="KgInput" SelectedItem="{Binding Kg, Mode=TwoWay}" ItemsSource="{Binding KgSource, Mode=TwoWay}"
ItemTemplate="{StaticResource AreaCommitmentTypeTemplate}" TextSearch.TextPath="DisplayName" ItemTemplate="{StaticResource KgNrTemplate}" TextSearch.TextPath="Name"
HorizontalAlignment="Stretch" Margin="0,70,40,10" Grid.Column="1" Grid.ColumnSpan="3"/> HorizontalAlignment="Stretch" Margin="0,40,40,10" Grid.Column="1" Grid.ColumnSpan="3"
<Button x:Name="AreaComTypeDetailsButton" Content="&#xE712;" FontFamily="Segoe MDL2 Assets" FontSize="14" Padding="0,1,0,0" SelectionChanged="KgInput_SelectionChanged"/>
Click="AreaComTypeDetailsButton_Click" <Button x:Name="KgDetailsButton" Content="&#xE712;" FontFamily="Segoe MDL2 Assets" FontSize="14" Padding="0,1,0,0"
Click="KgDetailsButton_Click"
Grid.Column="3" VerticalAlignment="Top" HorizontalAlignment="Right" Width="25" Height="25" Margin="10,40,10,10"/>
<Label Content="Ried:" Margin="10,70,0,0" Grid.Column="0"/>
<ComboBox x:Name="RdInput" SelectedItem="{Binding RdObj, Mode=TwoWay}" ItemsSource="{Binding RdSource, Mode=TwoWay}"
DisplayMemberPath="Name" TextSearch.TextPath="Name" IsEditable="True"
HorizontalAlignment="Stretch" Margin="0,70,40,10" Grid.Column="1" Grid.ColumnSpan="3"
SelectionChanged="RdInput_SelectionChanged"/>
<Button x:Name="RdAddButton" Content="&#xE73E;" FontFamily="Segoe MDL2 Assets" FontSize="16" Padding="0,0,0,0" IsEnabled="False"
Click="RdAddButton_Click"
Grid.Column="3" VerticalAlignment="Top" HorizontalAlignment="Right" Width="25" Height="25" Margin="10,70,10,10"/> Grid.Column="3" VerticalAlignment="Top" HorizontalAlignment="Right" Width="25" Height="25" Margin="10,70,10,10"/>
<Label Content="Bewirt.-Art:" Margin="10,100,0,0" Grid.Column="0" Grid.ColumnSpan="2"/> <Label Content="Anmerkung:" Margin="10,100,0,0" Grid.Column="0" Grid.ColumnSpan="2"/>
<ComboBox x:Name="WineCultivationInput" SelectedItem="{Binding WineCultObj, Mode=TwoWay}" ItemsSource="{Binding WineCultSource, Mode=TwoWay}"
DisplayMemberPath="Name" TextSearch.TextPath="Name"
HorizontalAlignment="Stretch" Margin="0,100,10,0" Grid.Column="1" Grid.ColumnSpan="3"/>
<Label Content="Anmerkung:" Margin="10,130,0,0" Grid.Column="0" Grid.ColumnSpan="2"/>
<TextBox x:Name="CommentInput" Text="{Binding Comment, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" <TextBox x:Name="CommentInput" Text="{Binding Comment, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
TextChanged="TextBox_TextChanged" TextChanged="TextBox_TextChanged"
HorizontalAlignment="Stretch" Margin="0,130,10,0" Grid.Column="1" Grid.ColumnSpan="3"/> HorizontalAlignment="Stretch" Margin="0,100,10,0" Grid.Column="1" Grid.ColumnSpan="3"/>
<ListBox x:Name="RevisionList" Grid.ColumnSpan="4" Margin="5,135,5,5"
SelectionChanged="RevisionList_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding YearFrom}" Width="28" TextAlignment="Right" Margin="0,0,0,0"/>
<TextBlock Text="&#x2013;" TextAlignment="Center" Margin="0,0,0,0"/>
<TextBlock Text="{Binding YearTo}" Width="28" TextAlignment="Left" Margin="0,0,0,0"/>
<TextBlock Text="{Binding VtrgId}" Width="40" TextAlignment="Center" Foreground="{Binding AreaComType.WineVar.Color}"/>
<TextBlock Text="{Binding Area, StringFormat='{}{0:N0} m²'}" Width="60" TextAlignment="Right" Padding="0,0,10,0"/>
<TextBlock Text="{Binding Member.AdministrativeName}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid> </Grid>
</GroupBox> </GroupBox>
<GroupBox Header="Lage" Grid.Column="2" Grid.Row="1" Grid.RowSpan="1" Margin="5,5,5,10"> <GroupBox Header="Revision" Grid.Row="1" Margin="5,5,5,10">
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="80"/> <ColumnDefinition Width="80"/>
<ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Label Content="KG:" Margin="10,10,0,0" Grid.Column="0"/> <Label Content="Mitglied:" Margin="10,10,0,0" Grid.Column="0"/>
<ComboBox x:Name="KgInput" SelectedItem="{Binding Kg, Mode=TwoWay}" ItemsSource="{Binding KgSource, Mode=TwoWay}" <TextBox x:Name="MgNrInput" Text="{Binding MgNrString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
ItemTemplate="{StaticResource KgNrTemplate}" TextSearch.TextPath="Name" Width="48" Grid.Row="1" Grid.Column="1" Margin="0,10,0,0" HorizontalAlignment="Left" TextAlignment="Right"
HorizontalAlignment="Stretch" Margin="0,10,40,10" Grid.Column="1" TextChanged="MgNrInput_TextChanged" LostFocus="MgNrInput_LostFocus"/>
SelectionChanged="KgInput_SelectionChanged"/> <ComboBox x:Name="MemberInput"
<Button x:Name="KgDetailsButton" Content="&#xE712;" FontFamily="Segoe MDL2 Assets" FontSize="14" Padding="0,1,0,0" Grid.Column="1" Margin="53,10,40,10" IsEditable="True"
Click="KgDetailsButton_Click" ItemTemplate="{StaticResource MemberAdminNameTemplate}" TextSearch.TextPath="AdministrativeName"
Grid.Column="1" VerticalAlignment="Top" HorizontalAlignment="Right" Width="25" Height="25" Margin="10,10,10,10"/> SelectionChanged="MemberInput_SelectionChanged"/>
<Button x:Name="MemberReferenceButton" Grid.Column="1" Height="25" Width="25" FontFamily="Segoe MDL2 Assets" Content="&#xEE35;" Padding="0,0,0,0"
Margin="10,10,10,10" VerticalAlignment="Top" HorizontalAlignment="Right" ToolTip="Zu Mitglied springen"
Click="MemberReferenceButton_Click"/>
<Label Content="Ried:" Margin="10,40,0,0" Grid.Column="0"/> <Label Content="Laufzeit:" Margin="10,40,0,0" Grid.Column="0"/>
<ComboBox x:Name="RdInput" SelectedItem="{Binding RdObj, Mode=TwoWay}" ItemsSource="{Binding RdSource, Mode=TwoWay}" <TextBox x:Name="YearFromInput" Text="{Binding YearFromString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
DisplayMemberPath="Name" TextSearch.TextPath="Name" IsEditable="True" Margin="0,40,10,0" Width="40" HorizontalAlignment="Left" Grid.Column="1" TextAlignment="Right"
HorizontalAlignment="Stretch" Margin="0,40,40,10" Grid.Column="1" TextChanged="IntegerInput_TextChanged"/>
SelectionChanged="RdInput_SelectionChanged"/> <Label Content="&#x2013;" Grid.Column="1" Margin="45,40,0,0"/>
<Button x:Name="RdAddButton" Content="&#xE73E;" FontFamily="Segoe MDL2 Assets" FontSize="16" Padding="0,0,0,0" IsEnabled="False" <TextBox x:Name="YearToInput" Text="{Binding YearToString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Click="RdAddButton_Click" Margin="60,40,10,0" Width="40" HorizontalAlignment="Left" Grid.Column="1" TextAlignment="Right"
Grid.Column="1" VerticalAlignment="Top" HorizontalAlignment="Right" Width="25" Height="25" Margin="10,40,10,10"/> TextChanged="IntegerInput_TextChanged"/>
<Label Content="Parzelle(n):" Margin="10,70,0,0" Grid.Column="0"/> <Label Content="Vertragsart:" Margin="10,70,0,0" Grid.Column="0"/>
<TextBox x:Name="GstNrInput" Text="{Binding GstNr, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" <ComboBox x:Name="AreaComTypeInput" SelectedItem="{Binding AreaComType, Mode=TwoWay}" ItemsSource="{Binding AreaComTypeSource, Mode=TwoWay}"
Margin="0,70,10,0" Grid.Column="1" HorizontalAlignment="Stretch" ItemTemplate="{StaticResource AreaCommitmentTypeTemplate}" TextSearch.TextPath="DisplayName"
TextChanged="TextBox_TextChanged"/> HorizontalAlignment="Stretch" Margin="0,70,40,10" Grid.Column="1"/>
<Button x:Name="AreaComTypeDetailsButton" Content="&#xE712;" FontFamily="Segoe MDL2 Assets" FontSize="14" Padding="0,1,0,0"
Click="AreaComTypeDetailsButton_Click"
Grid.Column="3" VerticalAlignment="Top" HorizontalAlignment="Right" Width="25" Height="25" Margin="10,70,10,10"/>
<Label Content="Fläche:" Margin="10,100,0,0" Grid.Column="0"/> <Label Content="Bewirt.-Art:" Margin="10,100,0,0" Grid.Column="0"/>
<ComboBox x:Name="WineCultivationInput" SelectedItem="{Binding WineCultObj, Mode=TwoWay}" ItemsSource="{Binding WineCultSource, Mode=TwoWay}"
DisplayMemberPath="Name" TextSearch.TextPath="Name"
HorizontalAlignment="Stretch" Margin="0,100,10,0" Grid.Column="1"/>
<Label Content="Fläche:" Margin="10,130,0,0" Grid.Column="0"/>
<ctrl:UnitTextBox x:Name="AreaInput" Unit="m²" Text="{Binding AreaString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" <ctrl:UnitTextBox x:Name="AreaInput" Unit="m²" Text="{Binding AreaString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
TextChanged="IntegerInput_TextChanged" TextChanged="IntegerInput_TextChanged"
Grid.Column="1" Width="70" Margin="0,100,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"/> Grid.Column="1" Width="70" Margin="0,130,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"/>
<Label Content="Parzelle(n):" Margin="10,160,0,0" Grid.Column="0"/>
<TextBox x:Name="GstNrInput" Text="{Binding GstNr, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,160,10,0" Grid.Column="1" HorizontalAlignment="Stretch"
TextChanged="TextBox_TextChanged"/>
</Grid> </Grid>
</GroupBox> </GroupBox>
</Grid> </Grid>

View File

@@ -25,23 +25,18 @@ namespace Elwig.Windows {
ViewModel.FilterMember = ctx.Members.Find(mgnr) ?? throw new ArgumentException("MgNr argument has invalid value"); ViewModel.FilterMember = ctx.Members.Find(mgnr) ?? throw new ArgumentException("MgNr argument has invalid value");
ViewModel.Title = $"Flächenbindungen - {ViewModel.FilterMember.AdministrativeName} - Elwig"; ViewModel.Title = $"Flächenbindungen - {ViewModel.FilterMember.AdministrativeName} - Elwig";
ExemptInputs = [ ExemptInputs = [
MgNrInput, AreaCommitmentList, NewAreaCommitmentButton, AreaCommitmentList, RevisionList,
EditAreaCommitmentButton, DeleteAreaCommitmentButton, SaveButton, NewAreaCommitmentButton, EditAreaCommitmentButton, DeleteAreaCommitmentButton, SaveButton,
ResetButton, CancelButton, SearchInput, ActiveAreaCommitmentInput ResetButton, CancelButton, SearchInput, SeasonInput
]; ];
RequiredInputs = [ RequiredInputs = [
FbNrInput, YearFromInput, KgInput, RdInput, FbNrInput, MgNrInput, MemberInput, YearFromInput, KgInput, RdInput,
GstNrInput, AreaInput, AreaComTypeInput, WineCultivationInput GstNrInput, AreaInput, AreaComTypeInput, WineCultivationInput
]; ];
ControlUtils.InitializeDelayTimer(SearchInput, SearchInput_TextChanged); ControlUtils.InitializeDelayTimer(SearchInput, SearchInput_TextChanged);
SearchInput.TextChanged -= SearchInput_TextChanged; SearchInput.TextChanged -= SearchInput_TextChanged;
ActiveAreaCommitmentInput.Content = ((string)ActiveAreaCommitmentInput.Content).Replace("2020", $"{Utils.CurrentLastSeason}"); ViewModel.FilterSeason = Utils.CurrentYear;
}
private void Window_Loaded(object sender, RoutedEventArgs e) {
ActiveAreaCommitmentInput.IsChecked = true;
LockInputs();
} }
private void FocusSearchInput(object sender, RoutedEventArgs evt) { private void FocusSearchInput(object sender, RoutedEventArgs evt) {
@@ -52,40 +47,49 @@ namespace Elwig.Windows {
} }
private async Task RefreshList(bool updateSort = false) { private async Task RefreshList(bool updateSort = false) {
var vm = ViewModel;
var cursor = Mouse.OverrideCursor != null;
if (!cursor) Mouse.OverrideCursor = Cursors.Wait;
var query = (vm.SearchQuery, vm.FilterSeason);
var (filter, contracts, areaComs, areaComCount, stat) = await Task.Run(async () => {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
var (_, areaComQuery, filter) = await ViewModel.GetFilters(ctx); var (_, contractQuery, areaComQuery, filter) = await vm.GetFilters(ctx);
var areaComs = await areaComQuery var contracts = await contractQuery
.Include(a => a.Kg.AtKg) .Include(c => c.Revisions).ThenInclude(a => a.Member)
.Include(a => a.Rd!.Kg.AtKg)
.Include(a => a.WineCult)
.Include(a => a.AreaComType.WineAttr)
.Include(a => a.AreaComType.WineVar)
.ToListAsync(); .ToListAsync();
var areaComs = await areaComQuery.ToListAsync();
if (filter.Count > 0 && areaComs.Count > 0) { if (filter.Count > 0 && contracts.Count > 0) {
var dict = areaComs.AsParallel() var dict = contracts.AsParallel()
.ToDictionary(d => d, d => d.SearchScore(ViewModel.TextFilter)) .ToDictionary(d => d, d => d.SearchScore(vm.TextFilter))
.OrderByDescending(c => c.Value); .OrderByDescending(c => c.Value);
var threshold = dict.Select(a => a.Value).Max() * 3 / 4; var threshold = dict.Max(a => a.Value) * 3 / 4;
areaComs = dict contracts = [.. dict
.Where(a => a.Value > threshold) .Where(a => a.Value > threshold)
.Select(a => a.Key) .Select(a => a.Key)];
.ToList();
} }
ControlUtils.RenewItemsSource(AreaCommitmentList, areaComs, var areaComCount = await areaComQuery.CountAsync();
AreaCommitmentList_SelectionChanged, filter.Count > 0 ? ControlUtils.RenewSourceDefault.IfOnly : ControlUtils.RenewSourceDefault.None, !updateSort); var season = await ctx.FetchSeasons().FirstOrDefaultAsync();
var stat = await AreaComService.GenerateToolTipData(areaComQuery, season?.MaxKgPerHa ?? 10_000);
return (filter, contracts, areaComs, areaComCount, stat);
});
if (!cursor) Mouse.OverrideCursor = null;
if (query != (ViewModel.SearchQuery, ViewModel.FilterSeason)) return;
ControlUtils.RenewItemsSource(AreaCommitmentList, contracts,
AreaCommitmentList_SelectionChanged, ViewModel.TextFilter.Count > 0 ? ControlUtils.RenewSourceDefault.IfOnly : ControlUtils.RenewSourceDefault.None, !updateSort);
RefreshInputs(); RefreshInputs();
if (filter.Count == 0) { if (filter.Count == 0) {
ViewModel.StatusAreaCommitments = $"{await areaComQuery.CountAsync():N0}"; ViewModel.StatusAreaCommitments = $"{areaComCount:N0}";
var s = await ctx.Seasons.FindAsync(await ctx.Seasons.MaxAsync(s => s.Year)); var (text, gridData) = stat;
var (text, gridData) = await AreaComService.GenerateToolTipData(areaComQuery, s?.MaxKgPerHa ?? 10_000);
ViewModel.StatusArea = text; ViewModel.StatusArea = text;
ViewModel.StatusAreaToolTip = AreaComService.GenerateToolTip(gridData); ViewModel.StatusAreaToolTip = AreaComService.GenerateToolTip(gridData);
} else { } else {
ViewModel.StatusAreaCommitments = $"{areaComs.Count:N0}"; ViewModel.StatusAreaCommitments = $"{contracts.Count:N0}";
ViewModel.StatusArea = $"{areaComs.Select(a => a.Area).Sum():N0} m²"; ViewModel.StatusArea = $"{areaComs.Sum(a => a.Area):N0} m²";
ViewModel.StatusAreaToolTip = null; ViewModel.StatusAreaToolTip = null;
} }
var groups = areaComs.GroupBy(a => $"{a.AreaComType.SortId}{a.AreaComType.AttrId}").Select(a => (a.Key, a.Sum(b => b.Area))).OrderByDescending(a => a.Item2).ToList(); var groups = areaComs.GroupBy(a => $"{a.AreaComType.SortId}{a.AreaComType.AttrId}").Select(a => (a.Key, a.Sum(b => b.Area))).OrderByDescending(a => a.Item2).ToList();
@@ -94,12 +98,25 @@ namespace Elwig.Windows {
ViewModel.StatusContracts += $" ({string.Join(", ", groups.Select(g => g.Key))})"; ViewModel.StatusContracts += $" ({string.Join(", ", groups.Select(g => g.Key))})";
} }
private async Task RefreshRevisions() {
using var ctx = new AppDbContext();
if (AreaCommitmentList.SelectedItem is AreaComContract c) {
ControlUtils.RenewItemsSource(RevisionList, c.Revisions.OrderByDescending(p => p.RevNr).ToList(), RevisionList_SelectionChanged, ControlUtils.RenewSourceDefault.First);
} else {
RevisionList.ItemsSource = null;
}
}
private void RefreshInputs(bool validate = false) { private void RefreshInputs(bool validate = false) {
ClearInputStates(); ClearInputStates();
if (AreaCommitmentList.SelectedItem is AreaCom a) { if (RevisionList.SelectedItem is AreaCom a) {
EditAreaCommitmentButton.IsEnabled = true; EditAreaCommitmentButton.IsEnabled = true;
DeleteAreaCommitmentButton.IsEnabled = true; DeleteAreaCommitmentButton.IsEnabled = true;
FillInputs(a); FillInputs(a);
} else if (AreaCommitmentList.SelectedItem is AreaComContract c) {
EditAreaCommitmentButton.IsEnabled = true;
DeleteAreaCommitmentButton.IsEnabled = true;
FillInputs(c);
} else { } else {
EditAreaCommitmentButton.IsEnabled = false; EditAreaCommitmentButton.IsEnabled = false;
DeleteAreaCommitmentButton.IsEnabled = false; DeleteAreaCommitmentButton.IsEnabled = false;
@@ -111,7 +128,15 @@ namespace Elwig.Windows {
GC.Collect(); GC.Collect();
} }
private void FillInputs(AreaComContract c) {
ClearOriginalValues();
ClearDefaultValues();
ViewModel.FillInputs(c);
FinishInputFilling();
}
private void FillInputs(AreaCom a) { private void FillInputs(AreaCom a) {
FillInputs(a.Contract);
ClearOriginalValues(); ClearOriginalValues();
ClearDefaultValues(); ClearDefaultValues();
ViewModel.FillInputs(a); ViewModel.FillInputs(a);
@@ -126,10 +151,15 @@ namespace Elwig.Windows {
ValidateRequiredInputs(); ValidateRequiredInputs();
} }
new protected void ClearInputs(bool validate = false) {
ViewModel.ClearInputs();
base.ClearInputs(validate);
}
protected override async Task OnRenewContext(AppDbContext ctx) { protected override async Task OnRenewContext(AppDbContext ctx) {
await base.OnRenewContext(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(); Close();
return; return;
} }
@@ -146,9 +176,8 @@ namespace Elwig.Windows {
.Include(c => c.WineAttr) .Include(c => c.WineAttr)
.OrderBy(v => v.VtrgId) .OrderBy(v => v.VtrgId)
.ToListAsync()); .ToListAsync());
var cultList = await ctx.WineCultivations ControlUtils.RenewItemsSource(MemberInput, await ctx.FetchMembers(includeNotActive: true).ToListAsync());
.OrderBy(c => c.Name) var cultList = await ctx.FetchWineCultivations().Cast<object>().ToListAsync();
.Cast<object>().ToListAsync();
cultList.Insert(0, new NullItem()); cultList.Insert(0, new NullItem());
ControlUtils.RenewItemsSource(WineCultivationInput, cultList, null, ControlUtils.RenewSourceDefault.First); ControlUtils.RenewItemsSource(WineCultivationInput, cultList, null, ControlUtils.RenewSourceDefault.First);
await RefreshList(); await RefreshList();
@@ -164,6 +193,7 @@ namespace Elwig.Windows {
IsCreating = true; IsCreating = true;
AreaCommitmentList.IsEnabled = false; AreaCommitmentList.IsEnabled = false;
AreaCommitmentList.SelectedItem = null; AreaCommitmentList.SelectedItem = null;
RevisionList.IsEnabled = false;
HideNewEditDeleteButtons(); HideNewEditDeleteButtons();
ShowSaveResetCancelButtons(); ShowSaveResetCancelButtons();
UnlockInputs(); UnlockInputs();
@@ -184,6 +214,7 @@ namespace Elwig.Windows {
IsEditing = true; IsEditing = true;
AreaCommitmentList.IsEnabled = false; AreaCommitmentList.IsEnabled = false;
RevisionList.IsEnabled = false;
HideNewEditDeleteButtons(); HideNewEditDeleteButtons();
ShowSaveResetCancelButtons(); ShowSaveResetCancelButtons();
@@ -198,10 +229,10 @@ namespace Elwig.Windows {
} }
private async void DeleteAreaCommitmentButton_Click(object? sender, RoutedEventArgs? evt) { private async void DeleteAreaCommitmentButton_Click(object? sender, RoutedEventArgs? evt) {
if (AreaCommitmentList.SelectedItem is not AreaCom a) if (RevisionList.SelectedItem is not AreaCom a)
return; return;
var d = new AreaComModifyDialog(a.YearFrom, a.YearTo, a.Area, true); var d = new AreaComModifyDialog(a.YearFrom, a.YearTo, a.Area, true, RevisionList.ItemsSource.Cast<object>().FirstOrDefault() != a);
if (d.ShowDialog() != true) if (d.ShowDialog() != true)
return; return;
@@ -209,7 +240,7 @@ namespace Elwig.Windows {
try { try {
if (d.YearTo is int yearTo) { if (d.YearTo is int yearTo) {
ViewModel.YearTo = yearTo; ViewModel.YearTo = yearTo;
await ViewModel.UpdateAreaCommitment((AreaCommitmentList.SelectedItem as AreaCom)?.FbNr); await ViewModel.UpdateAreaCommitment(a.FbNr, a.RevNr);
} else { } else {
await AreaComService.DeleteAreaCom(a.FbNr); await AreaComService.DeleteAreaCom(a.FbNr);
} }
@@ -232,42 +263,38 @@ namespace Elwig.Windows {
SaveButton.IsEnabled = false; SaveButton.IsEnabled = false;
int? yearTo = null; int? yearTo = null;
if (InputHasChanged(AreaInput) || InputHasChanged(AreaComTypeInput)) { if (InputHasChanged(AreaInput) || InputHasChanged(AreaComTypeInput) || InputHasChanged(MgNrInput)) {
var a = (AreaCommitmentList.SelectedItem as AreaCom)!; var a = (RevisionList.SelectedItem as AreaCom)!;
var d = new AreaComModifyDialog(a.YearFrom, a.YearTo, a.Area, false); var d = new AreaComModifyDialog(a.YearFrom, a.YearTo, a.Area, false, RevisionList.ItemsSource.Cast<object>().FirstOrDefault() != a);
if (d.ShowDialog() != true) if (d.ShowDialog() != true) {
SaveButton.IsEnabled = true;
return; return;
}
yearTo = d.YearTo; yearTo = d.YearTo;
} }
int fbnr; int fbnr, revnr;
Mouse.OverrideCursor = Cursors.Wait; Mouse.OverrideCursor = Cursors.Wait;
try { try {
AreaCom? temp = null; AreaCom? temp = null;
if (yearTo != null && (!ViewModel.YearTo.HasValue || yearTo < ViewModel.YearTo)) { if (yearTo != null && (!ViewModel.YearTo.HasValue || yearTo < ViewModel.YearTo)) {
temp = new AreaCom { temp = new AreaCom {
FbNr = ViewModel.FbNr!.Value,
MgNr = ViewModel.MgNr!.Value, MgNr = ViewModel.MgNr!.Value,
YearFrom = ViewModel.YearFrom, YearFrom = ViewModel.YearFrom,
YearTo = ViewModel.YearTo, YearTo = ViewModel.YearTo,
VtrgId = ViewModel.AreaComType!.VtrgId, VtrgId = ViewModel.AreaComType!.VtrgId,
CultId = ViewModel.WineCult?.CultId, CultId = ViewModel.WineCult?.CultId,
Comment = ViewModel.Comment,
KgNr = ViewModel.Kg!.KgNr,
RdNr = ViewModel.Rd?.RdNr,
GstNr = ViewModel.GstNr?.Trim() ?? "-", GstNr = ViewModel.GstNr?.Trim() ?? "-",
Area = ViewModel.Area!.Value, Area = ViewModel.Area!.Value,
}; };
RefreshInputs(); RefreshInputs();
ViewModel.YearTo = yearTo; ViewModel.YearTo = yearTo;
} }
fbnr = await ViewModel.UpdateAreaCommitment((AreaCommitmentList.SelectedItem as AreaCom)?.FbNr); (fbnr, revnr) = await ViewModel.UpdateAreaCommitment((AreaCommitmentList.SelectedItem as AreaComContract)?.FbNr, (RevisionList.SelectedItem as AreaCom)?.RevNr);
if (temp is AreaCom t) { if (temp is AreaCom t) {
await ViewModel.InitInputs();
t.FbNr = ViewModel.FbNr!.Value;
t.YearFrom = yearTo + 1; t.YearFrom = yearTo + 1;
ViewModel.FillInputs(t); ViewModel.FillInputs(t);
fbnr = await ViewModel.UpdateAreaCommitment(null); (fbnr, revnr) = await ViewModel.UpdateAreaCommitment((AreaCommitmentList.SelectedItem as AreaComContract)?.FbNr, null);
} }
App.HintContextChange(); App.HintContextChange();
} catch (Exception exc) { } catch (Exception exc) {
@@ -282,6 +309,7 @@ namespace Elwig.Windows {
IsEditing = false; IsEditing = false;
IsCreating = false; IsCreating = false;
AreaCommitmentList.IsEnabled = true; AreaCommitmentList.IsEnabled = true;
RevisionList.IsEnabled = true;
HideSaveResetCancelButtons(); HideSaveResetCancelButtons();
ShowNewEditDeleteButtons(); ShowNewEditDeleteButtons();
LockInputs(); LockInputs();
@@ -290,7 +318,9 @@ namespace Elwig.Windows {
await EnsureContextRenewed(); await EnsureContextRenewed();
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
ViewModel.SearchQuery = ""; ViewModel.SearchQuery = "";
ControlUtils.SelectItem(AreaCommitmentList, AreaCommitmentList.ItemsSource.Cast<AreaCom>().Where(a => a.FbNr == fbnr).FirstOrDefault()); ViewModel.FilterSeason = ViewModel.YearTo ?? ViewModel.YearFrom ?? ViewModel.FilterSeason;
ControlUtils.SelectItemWithPk(AreaCommitmentList, fbnr);
ControlUtils.SelectItemWithPk(RevisionList, fbnr, revnr);
} }
protected override void ShortcutReset() { protected override void ShortcutReset() {
@@ -312,6 +342,7 @@ namespace Elwig.Windows {
IsEditing = false; IsEditing = false;
IsCreating = false; IsCreating = false;
AreaCommitmentList.IsEnabled = true; AreaCommitmentList.IsEnabled = true;
RevisionList.IsEnabled = true;
HideSaveResetCancelButtons(); HideSaveResetCancelButtons();
ShowNewEditDeleteButtons(); ShowNewEditDeleteButtons();
RefreshInputs(); RefreshInputs();
@@ -373,34 +404,65 @@ namespace Elwig.Windows {
private void LockSearchInputs() { private void LockSearchInputs() {
SearchInput.IsEnabled = false; SearchInput.IsEnabled = false;
ActiveAreaCommitmentInput.IsEnabled = false; SeasonInput.IsEnabled = false;
} }
private void UnlockSearchInputs() { private void UnlockSearchInputs() {
SearchInput.IsEnabled = true; SearchInput.IsEnabled = true;
ActiveAreaCommitmentInput.IsEnabled = true; SeasonInput.IsEnabled = true;
} }
private void AreaCommitmentList_SelectionChanged(object sender, SelectionChangedEventArgs evt) { private async void AreaCommitmentList_SelectionChanged(object sender, SelectionChangedEventArgs evt) {
if (AreaCommitmentList.SelectedItem != null) if (AreaCommitmentList.SelectedItem != null)
AreaCommitmentList.ScrollIntoView(AreaCommitmentList.SelectedItem); AreaCommitmentList.ScrollIntoView(AreaCommitmentList.SelectedItem);
RefreshInputs(); await RefreshRevisions();
} }
private void AttributesInput_SelectionChanged(object sender, SelectionChangedEventArgs evt) { private void RevisionList_SelectionChanged(object? sender, SelectionChangedEventArgs? evt) {
RefreshInputs();
if (RevisionList.SelectedItem is AreaCom c) {
EditAreaCommitmentButton.IsEnabled = true;
} else {
EditAreaCommitmentButton.IsEnabled = false;
}
}
private void MgNrInput_TextChanged(object sender, TextChangedEventArgs evt) {
var valid = InputTextChanged((TextBox)sender, Validator.CheckMgNr);
var text = MgNrInput.Text;
var caret = MgNrInput.CaretIndex;
ControlUtils.SelectItemWithPk(MemberInput, valid ? ViewModel.MgNr : null);
MgNrInput.Text = text;
MgNrInput.CaretIndex = caret;
}
private void MgNrInput_LostFocus(object sender, RoutedEventArgs evt) {
var valid = InputLostFocus((TextBox)sender, Validator.CheckMgNr);
ControlUtils.SelectItemWithPk(MemberInput, valid ? ViewModel.MgNr : null);
}
private void MemberInput_SelectionChanged(object? sender, SelectionChangedEventArgs? evt) {
var m = MemberInput.SelectedItem as Member;
ViewModel.MgNr = m?.MgNr;
} }
private async void ActiveAreaCommitmentInput_Changed(object sender, RoutedEventArgs evt) { private async void ActiveAreaCommitmentInput_Changed(object sender, RoutedEventArgs evt) {
if (!HasContextLoaded) return;
await RefreshList(); await RefreshList();
} }
private async void SearchInput_TextChanged(object sender, RoutedEventArgs evt) { private async void SearchInput_TextChanged(object sender, RoutedEventArgs evt) {
if (!HasContextLoaded) return;
var binding = ((TextBox)sender).GetBindingExpression(TextBox.TextProperty); var binding = ((TextBox)sender).GetBindingExpression(TextBox.TextProperty);
binding?.UpdateSource(); binding?.UpdateSource();
await RefreshList(true); await RefreshList(true);
} }
private async void SeasonInput_TextChanged(object sender, TextChangedEventArgs evt) {
if (!HasContextLoaded || ViewModel.FilterSeason == null) return;
await RefreshList();
}
private void KgInput_SelectionChanged(object sender, SelectionChangedEventArgs evt) { private void KgInput_SelectionChanged(object sender, SelectionChangedEventArgs evt) {
if (KgInput.SelectedItem is AT_Kg kg) { if (KgInput.SelectedItem is AT_Kg kg) {
var rdList = kg.WbKg!.Rds.OrderBy(r => r.Name).Cast<object>().ToList(); var rdList = kg.WbKg!.Rds.OrderBy(r => r.Name).Cast<object>().ToList();
@@ -438,12 +500,12 @@ namespace Elwig.Windows {
RdInput.SelectedIndex = s.Count(); RdInput.SelectedIndex = s.Count();
} }
protected void InputTextChanged(TextBox input, Func<TextBox, bool, AreaCom?, ValidationResult> checker) { protected void InputTextChanged(TextBox input, Func<TextBox, bool, AreaComContract?, ValidationResult> checker) {
InputTextChanged(input, checker(input, SenderIsRequired(input), (AreaCom)AreaCommitmentList.SelectedItem)); InputTextChanged(input, checker(input, SenderIsRequired(input), (AreaComContract)AreaCommitmentList.SelectedItem));
} }
protected void InputLostFocus(TextBox input, Func<TextBox, bool, AreaCom?, ValidationResult> checker, string? msg = null) { protected void InputLostFocus(TextBox input, Func<TextBox, bool, AreaComContract?, ValidationResult> checker, string? msg = null) {
InputLostFocus(input, checker(input, SenderIsRequired(input), (AreaCom)AreaCommitmentList.SelectedItem), msg); InputLostFocus(input, checker(input, SenderIsRequired(input), (AreaComContract)AreaCommitmentList.SelectedItem), msg);
} }
private void FbNrInput_TextChanged(object sender, RoutedEventArgs evt) { private void FbNrInput_TextChanged(object sender, RoutedEventArgs evt) {
@@ -453,5 +515,10 @@ namespace Elwig.Windows {
private void FbNrInput_LostFocus(object sender, RoutedEventArgs evt) { private void FbNrInput_LostFocus(object sender, RoutedEventArgs evt) {
InputLostFocus((TextBox)sender, Validator.CheckFbNr); InputLostFocus((TextBox)sender, Validator.CheckFbNr);
} }
private void MemberReferenceButton_Click(object sender, RoutedEventArgs evt) {
if (MemberInput.SelectedItem is not Member m) return;
App.FocusMember(m.MgNr);
}
} }
} }

View File

@@ -8,8 +8,7 @@
xmlns:local="clr-namespace:Elwig.Windows" xmlns:local="clr-namespace:Elwig.Windows"
xmlns:ctrl="clr-namespace:Elwig.Controls" xmlns:ctrl="clr-namespace:Elwig.Controls"
mc:Ignorable="d" mc:Ignorable="d"
Title="Stammdaten - Elwig" Height="520" MinHeight="400" Width="860" MinWidth="810" Title="Stammdaten - Elwig" Height="520" MinHeight="400" Width="860" MinWidth="810">
Loaded="Window_Loaded">
<Window.Resources> <Window.Resources>
<Style TargetType="Label"> <Style TargetType="Label">
<Setter Property="HorizontalAlignment" Value="Left"/> <Setter Property="HorizontalAlignment" Value="Left"/>

View File

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

View File

@@ -19,10 +19,7 @@ namespace Elwig.Windows {
private bool _branchUpdate = false; private bool _branchUpdate = false;
private async Task BranchesInitEditing(AppDbContext ctx) { private async Task BranchesInitEditing(AppDbContext ctx) {
_branchList = new(await ctx.Branches _branchList = new(await ctx.FetchBranches().ToListAsync());
.OrderBy(b => b.Name)
.Include(b => b.PostalDest!.AtPlz)
.ToListAsync());
_branches = _branchList.ToDictionary(b => b.ZwstId, b => (string?)b.ZwstId); _branches = _branchList.ToDictionary(b => b.ZwstId, b => (string?)b.ZwstId);
_branchIds = _branchList.ToDictionary(b => b, b => b.ZwstId); _branchIds = _branchList.ToDictionary(b => b, b => b.ZwstId);
ControlUtils.RenewItemsSource(BranchList, _branchList); ControlUtils.RenewItemsSource(BranchList, _branchList);
@@ -30,10 +27,7 @@ namespace Elwig.Windows {
} }
private async Task BranchesFinishEditing(AppDbContext ctx) { private async Task BranchesFinishEditing(AppDbContext ctx) {
ControlUtils.RenewItemsSource(BranchList, await ctx.Branches ControlUtils.RenewItemsSource(BranchList, await ctx.FetchBranches().ToListAsync());
.OrderBy(b => b.Name)
.Include(b => b.PostalDest!.AtPlz)
.ToListAsync());
_branchList = null; _branchList = null;
_branches = null; _branches = null;
_branchIds = null; _branchIds = null;
@@ -47,9 +41,10 @@ namespace Elwig.Windows {
if (!_branchChanged || _branchList == null || _branches == null || _branchIds == null) if (!_branchChanged || _branchList == null || _branches == null || _branchIds == null)
return; return;
foreach (var (zwstid, _) in _branches.Where(b => b.Value == null)) { var tx = await ctx.Database.BeginTransactionAsync();
ctx.Remove(ctx.Branches.Find(zwstid)!); 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) { foreach (var (branch, old) in _branchIds) {
branch.ZwstId = old; branch.ZwstId = old;
} }
@@ -61,13 +56,13 @@ namespace Elwig.Windows {
foreach (var (old, zwstid) in _branches.Where(b => b.Value != null)) { 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.Database.ExecuteSqlAsync($"UPDATE branch SET zwstid = {zwstid} WHERE zwstid = {old}");
} }
await ctx.SaveChangesAsync();
foreach (var branch in _branchList.Where(b => !_branchIds.ContainsKey(b))) { foreach (var branch in _branchList.Where(b => !_branchIds.ContainsKey(b))) {
if (branch.ZwstId == null) continue; if (branch.ZwstId == null) continue;
ctx.Add(branch); ctx.Add(branch);
} }
await ctx.SaveChangesAsync(); await ctx.SaveChangesAsync();
await tx.CommitAsync();
} }
private void BranchList_SelectionChanged(object? sender, SelectionChangedEventArgs? evt) { private void BranchList_SelectionChanged(object? sender, SelectionChangedEventArgs? evt) {

View File

@@ -22,10 +22,7 @@ namespace Elwig.Windows {
private async Task ModifiersInitEditing(AppDbContext ctx) { private async Task ModifiersInitEditing(AppDbContext ctx) {
SeasonList.IsEnabled = false; SeasonList.IsEnabled = false;
var year = (SeasonList.SelectedItem as Season)?.Year; var year = (SeasonList.SelectedItem as Season)?.Year;
_modList = new(await ctx.Modifiers _modList = new(await ctx.FetchModifiers(year ?? 0).ToListAsync());
.Where(m => m.Year == year)
.OrderBy(m => m.Ordering)
.ToListAsync());
_mods = _modList.ToDictionary(m => m.ModId, m => (string?)m.ModId); _mods = _modList.ToDictionary(m => m.ModId, m => (string?)m.ModId);
_modIds = _modList.ToDictionary(m => m, m => m.ModId); _modIds = _modList.ToDictionary(m => m, m => m.ModId);
ControlUtils.RenewItemsSource(SeasonModifierList, _modList); ControlUtils.RenewItemsSource(SeasonModifierList, _modList);
@@ -34,10 +31,7 @@ namespace Elwig.Windows {
private async Task ModifiersFinishEditing(AppDbContext ctx) { private async Task ModifiersFinishEditing(AppDbContext ctx) {
var year = (SeasonList.SelectedItem as Season)?.Year; var year = (SeasonList.SelectedItem as Season)?.Year;
ControlUtils.RenewItemsSource(SeasonModifierList, await ctx.Modifiers ControlUtils.RenewItemsSource(SeasonModifierList, await ctx.FetchModifiers(year ?? 0).ToListAsync());
.Where(m => m.Year == year)
.OrderBy(m => m.Ordering)
.ToListAsync());
_modList = null; _modList = null;
_mods = null; _mods = null;
_modIds = null; _modIds = null;

View File

@@ -19,22 +19,14 @@ namespace Elwig.Windows {
private async Task SeasonsInitEditing(AppDbContext ctx) { private async Task SeasonsInitEditing(AppDbContext ctx) {
SeasonAddButton.IsEnabled = false; SeasonAddButton.IsEnabled = false;
SeasonRemoveButton.IsEnabled = false; SeasonRemoveButton.IsEnabled = false;
ControlUtils.RenewItemsSource(SeasonList, await ctx.Seasons ControlUtils.RenewItemsSource(SeasonList, await ctx.FetchSeasons(includeModifiers: true).ToListAsync());
.OrderByDescending(s => s.Year)
.Include(s => s.Modifiers)
.Include(s => s.Currency)
.ToListAsync());
SeasonList_SelectionChanged(null, null); SeasonList_SelectionChanged(null, null);
} }
private async Task SeasonsFinishEditing(AppDbContext ctx) { private async Task SeasonsFinishEditing(AppDbContext ctx) {
SeasonAddButton.IsEnabled = true; SeasonAddButton.IsEnabled = true;
SeasonRemoveButton.IsEnabled = true; SeasonRemoveButton.IsEnabled = true;
ControlUtils.RenewItemsSource(SeasonList, await ctx.Seasons ControlUtils.RenewItemsSource(SeasonList, await ctx.FetchSeasons(includeModifiers: true).ToListAsync());
.OrderByDescending(s => s.Year)
.Include(s => s.Modifiers)
.Include(s => s.Currency)
.ToListAsync());
_seasonChanged = false; _seasonChanged = false;
} }

View File

@@ -19,9 +19,7 @@ namespace Elwig.Windows {
private bool _attrUpdate = false; private bool _attrUpdate = false;
private async Task WineAttributesInitEditing(AppDbContext ctx) { private async Task WineAttributesInitEditing(AppDbContext ctx) {
_attrList = new(await ctx.WineAttributes _attrList = new(await ctx.FetchWineAttributes().ToListAsync());
.OrderBy(a => a.Name)
.ToListAsync());
_attrs = _attrList.ToDictionary(a => a.AttrId, a => (string?)a.AttrId); _attrs = _attrList.ToDictionary(a => a.AttrId, a => (string?)a.AttrId);
_attrIds = _attrList.ToDictionary(a => a, a => a.AttrId); _attrIds = _attrList.ToDictionary(a => a, a => a.AttrId);
ControlUtils.RenewItemsSource(WineAttributeList, _attrList); ControlUtils.RenewItemsSource(WineAttributeList, _attrList);
@@ -29,9 +27,7 @@ namespace Elwig.Windows {
} }
private async Task WineAttributesFinishEditing(AppDbContext ctx) { private async Task WineAttributesFinishEditing(AppDbContext ctx) {
ControlUtils.RenewItemsSource(WineAttributeList, await ctx.WineAttributes ControlUtils.RenewItemsSource(WineAttributeList, await ctx.FetchWineAttributes().ToListAsync());
.OrderBy(a => a.Name)
.ToListAsync());
_attrList = null; _attrList = null;
_attrs = null; _attrs = null;
_attrIds = null; _attrIds = null;
@@ -45,9 +41,9 @@ namespace Elwig.Windows {
if (!_attrChanged || _attrList == null || _attrs == null || _attrIds == null) if (!_attrChanged || _attrList == null || _attrs == null || _attrIds == null)
return; return;
foreach (var (attrid, _) in _attrs.Where(a => a.Value == null)) { using var tx = await ctx.Database.BeginTransactionAsync();
ctx.Remove(ctx.WineAttributes.Find(attrid)!); 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) { foreach (var (attr, old) in _attrIds) {
attr.AttrId = old; 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.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.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))) { foreach (var attr in _attrList.Where(a => !_attrIds.ContainsKey(a))) {
if (attr.AttrId == null) continue; if (attr.AttrId == null) continue;
ctx.Add(attr); ctx.Add(attr);
} }
await ctx.SaveChangesAsync(); await ctx.SaveChangesAsync();
await tx.CommitAsync();
} }
private void WineAttributeList_SelectionChanged(object? sender, SelectionChangedEventArgs? evt) { private void WineAttributeList_SelectionChanged(object? sender, SelectionChangedEventArgs? evt) {

View File

@@ -19,9 +19,7 @@ namespace Elwig.Windows {
private bool _cultUpdate = false; private bool _cultUpdate = false;
private async Task WineCultivationsInitEditing(AppDbContext ctx) { private async Task WineCultivationsInitEditing(AppDbContext ctx) {
_cultList = new(await ctx.WineCultivations _cultList = new(await ctx.FetchWineCultivations().ToListAsync());
.OrderBy(c => c.Name)
.ToListAsync());
_cults = _cultList.ToDictionary(c => c.CultId, c => (string?)c.CultId); _cults = _cultList.ToDictionary(c => c.CultId, c => (string?)c.CultId);
_cultIds = _cultList.ToDictionary(c => c, c => c.CultId); _cultIds = _cultList.ToDictionary(c => c, c => c.CultId);
ControlUtils.RenewItemsSource(WineCultivationList, _cultList); ControlUtils.RenewItemsSource(WineCultivationList, _cultList);
@@ -29,9 +27,7 @@ namespace Elwig.Windows {
} }
private async Task WineCultivationsFinishEditing(AppDbContext ctx) { private async Task WineCultivationsFinishEditing(AppDbContext ctx) {
ControlUtils.RenewItemsSource(WineCultivationList, await ctx.WineCultivations ControlUtils.RenewItemsSource(WineCultivationList, await ctx.FetchWineCultivations().ToListAsync());
.OrderBy(c => c.Name)
.ToListAsync());
_cultList = null; _cultList = null;
_cults = null; _cults = null;
_cultIds = null; _cultIds = null;
@@ -45,9 +41,9 @@ namespace Elwig.Windows {
if (!_cultChanged || _cultList == null || _cults == null || _cultIds == null) if (!_cultChanged || _cultList == null || _cults == null || _cultIds == null)
return; return;
foreach (var (cultid, _) in _cults.Where(c => c.Value == null)) { using var tx = await ctx.Database.BeginTransactionAsync();
ctx.Remove(ctx.WineCultivations.Find(cultid)!); 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) { foreach (var (cult, old) in _cultIds) {
cult.CultId = old; 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.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.Database.ExecuteSqlRawAsync($"UPDATE payment_variant SET data = REPLACE(data, '-{old}\"', '-{cultid}\"')");
} }
await ctx.SaveChangesAsync();
foreach (var cult in _cultList.Where(c => !_cultIds.ContainsKey(c))) { foreach (var cult in _cultList.Where(c => !_cultIds.ContainsKey(c))) {
if (cult.CultId == null) continue; if (cult.CultId == null) continue;
ctx.Add(cult); ctx.Add(cult);
} }
await ctx.SaveChangesAsync(); await ctx.SaveChangesAsync();
await tx.CommitAsync();
} }
private void WineCultivationList_SelectionChanged(object? sender, SelectionChangedEventArgs? evt) { private void WineCultivationList_SelectionChanged(object? sender, SelectionChangedEventArgs? evt) {

View File

@@ -153,44 +153,22 @@ namespace Elwig.Windows {
ParameterExportEbicsAddress.IsEnabled = true; ParameterExportEbicsAddress.IsEnabled = true;
} }
private void Window_Loaded(object sender, RoutedEventArgs evt) {
LockInputs();
}
protected override async Task OnRenewContext(AppDbContext ctx) { protected override async Task OnRenewContext(AppDbContext ctx) {
await base.OnRenewContext(ctx); await base.OnRenewContext(ctx);
FillInputs(App.Client, await ctx.Seasons.FindAsync(Utils.CurrentLastSeason)); FillInputs(App.Client, await ctx.FetchSeasons(Utils.CurrentLastSeason).SingleOrDefaultAsync());
ControlUtils.RenewItemsSource(SeasonList, await ctx.Seasons ControlUtils.RenewItemsSource(SeasonList, await ctx.FetchSeasons(includeModifiers: true).ToListAsync(), null, ControlUtils.RenewSourceDefault.First);
.OrderByDescending(s => s.Year)
.Include(s => s.Modifiers)
.Include(s => s.Currency)
.ToListAsync(), null, ControlUtils.RenewSourceDefault.First);
var year = (SeasonList.SelectedItem as Season)?.Year; var year = (SeasonList.SelectedItem as Season)?.Year;
ControlUtils.RenewItemsSource(BranchList, await ctx.Branches ControlUtils.RenewItemsSource(BranchList, await ctx.FetchBranches().ToListAsync(), null, ControlUtils.RenewSourceDefault.First);
.OrderBy(b => b.Name) ControlUtils.RenewItemsSource(WineAttributeList, await ctx.FetchWineAttributes().ToListAsync(), null, ControlUtils.RenewSourceDefault.First);
.Include(b => b.PostalDest!.AtPlz) ControlUtils.RenewItemsSource(AreaCommitmentTypeWineVariantInput, await ctx.FetchWineVarieties().ToListAsync());
.ToListAsync(), null, ControlUtils.RenewSourceDefault.First); var attrList = await ctx.FetchWineAttributes().Cast<object>().ToListAsync();
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();
attrList.Insert(0, new NullItem("")); attrList.Insert(0, new NullItem(""));
ControlUtils.RenewItemsSource(AreaCommitmentTypeWineAttributeInput, attrList); ControlUtils.RenewItemsSource(AreaCommitmentTypeWineAttributeInput, attrList);
ControlUtils.RenewItemsSource(AreaCommitmentTypeList, await ctx.AreaCommitmentTypes ControlUtils.RenewItemsSource(AreaCommitmentTypeList, await ctx.AreaCommitmentTypes
.OrderBy(t => t.VtrgId) .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); .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() { protected override void UpdateButtons() {
@@ -286,7 +264,7 @@ namespace Elwig.Windows {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
ClearInputStates(); ClearInputStates();
FillInputs(App.Client, await ctx.Seasons.FindAsync(Utils.CurrentLastSeason)); FillInputs(App.Client, await ctx.FetchSeasons(Utils.CurrentLastSeason).SingleOrDefaultAsync());
LockInputs(); LockInputs();
} }
@@ -306,7 +284,7 @@ namespace Elwig.Windows {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
ClearInputStates(); ClearInputStates();
FillInputs(App.Client, await ctx.Seasons.FindAsync(Utils.CurrentLastSeason)); FillInputs(App.Client, await ctx.FetchSeasons(Utils.CurrentLastSeason).SingleOrDefaultAsync());
UpdateButtons(); UpdateButtons();
} }
@@ -342,7 +320,7 @@ namespace Elwig.Windows {
using (var ctx = new AppDbContext()) { using (var ctx = new AppDbContext()) {
ClearInputStates(); ClearInputStates();
FillInputs(App.Client, await ctx.Seasons.FindAsync(Utils.CurrentLastSeason)); FillInputs(App.Client, await ctx.FetchSeasons(Utils.CurrentLastSeason).SingleOrDefaultAsync());
LockInputs(); LockInputs();
} }
@@ -430,7 +408,7 @@ namespace Elwig.Windows {
private async Task UpdateParameters(int year) { private async Task UpdateParameters(int year) {
try { try {
using var ctx = new AppDbContext(); 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; return;
s.Billing_AllowAttrsIntoLower = ParameterAllowAttrIntoLowerInput.IsChecked ?? false; s.Billing_AllowAttrsIntoLower = ParameterAllowAttrIntoLowerInput.IsChecked ?? false;

View File

@@ -9,7 +9,6 @@
xmlns:ScottPlot="clr-namespace:ScottPlot.WPF;assembly=ScottPlot.WPF" xmlns:ScottPlot="clr-namespace:ScottPlot.WPF;assembly=ScottPlot.WPF"
mc:Ignorable="d" mc:Ignorable="d"
Title="Auszahlung - Elwig" Height="700" Width="1500" MinWidth="1000" MinHeight="500" Title="Auszahlung - Elwig" Height="700" Width="1500" MinWidth="1000" MinHeight="500"
Loaded="Window_Loaded"
Closing="Window_Closing"> Closing="Window_Closing">
<Window.Resources> <Window.Resources>

View File

@@ -80,9 +80,6 @@ namespace Elwig.Windows {
LockContext = true; LockContext = true;
} }
private void Window_Loaded(object sender, RoutedEventArgs evt) {
}
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) { private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) {
if (HasChanged) { if (HasChanged) {
var r = MessageBox.Show("Soll das Fenster wirklich geschlossen werden? Nicht gespeicherte Änderungen werden NICHT übernommen!", "Schließen bestätigen", var r = MessageBox.Show("Soll das Fenster wirklich geschlossen werden? Nicht gespeicherte Änderungen werden NICHT übernommen!", "Schließen bestätigen",
@@ -101,17 +98,17 @@ namespace Elwig.Windows {
private async Task RefreshGraphList(AppDbContext ctx) { private async Task RefreshGraphList(AppDbContext ctx) {
PaymentVar = await ctx.PaymentVariants.FindAsync(Year, AvNr) ?? throw new ArgumentException("PaymentVar not found"); 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; CurrencySymbol = Season.Currency.Symbol ?? Season.Currency.Code;
PriceInput.Unit = $"{CurrencySymbol}/kg"; PriceInput.Unit = $"{CurrencySymbol}/kg";
GebundenFlatBonus.Unit = $"{CurrencySymbol}/kg"; GebundenFlatBonus.Unit = $"{CurrencySymbol}/kg";
try { try {
var data = EditBillingData.FromJson(PaymentVar.Data, Utils.GetVaributes(ctx, Year)); var data = EditBillingData.FromJson(PaymentVar.Data, await Utils.GetVaributes(ctx, Year));
var paymentEntries = data.GetPaymentGraphEntries(ctx, Season); var paymentEntries = await data.GetPaymentGraphEntries(ctx, Season);
GraphEntries = [ GraphEntries = [
..paymentEntries, ..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) { } catch (KeyNotFoundException ex) {
var key = ex.Message.Split('\'')[1].Split('\'')[0]; var key = ex.Message.Split('\'')[1].Split('\'')[0];
@@ -126,7 +123,7 @@ namespace Elwig.Windows {
MessageBox.Show("Fehler beim Laden der Auszahlungsvariante:\n\n" + ex.Message, "Fehler", MessageBox.Show("Fehler beim Laden der Auszahlungsvariante:\n\n" + ex.Message, "Fehler",
MessageBoxButton.OK, MessageBoxImage.Error); MessageBoxButton.OK, MessageBoxImage.Error);
} }
Vaributes = Utils.GetVaributeList(ctx, Year); Vaributes = await Utils.GetVaributeList(ctx, Year);
GraphEntries.ForEach(e => { GraphEntries.ForEach(e => {
e.Vaributes.ForEach(v => { 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); var found = Vaributes.Find(a => a.Variety?.SortId == v.Variety?.SortId && a.Attribute?.AttrId == v.Attribute?.AttrId && a.Cultivation?.CultId == v.Cultivation?.CultId);
@@ -645,7 +642,7 @@ namespace Elwig.Windows {
await Task.Run(async () => { await Task.Run(async () => {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
var origData = BillingData.FromJson(PaymentVar.Data); 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); AllVaributesAssigned, AllVaributesAssignedAbgew);
PaymentVar.Data = data.ToJsonString(); PaymentVar.Data = data.ToJsonString();
@@ -663,7 +660,7 @@ namespace Elwig.Windows {
try { try {
await Task.Run(async () => { 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); await b.Calculate(false);
}); });
} catch (KeyNotFoundException exc) { } catch (KeyNotFoundException exc) {

View File

@@ -18,6 +18,8 @@ namespace Elwig.Windows {
} }
} }
protected bool HasContextLoaded { get; private set; }
private bool _renewPending = false; private bool _renewPending = false;
private readonly RoutedCommand CtrlR = new("CtrlR", typeof(ContextWindow), [new KeyGesture(Key.R, ModifierKeys.Control)]); private readonly RoutedCommand CtrlR = new("CtrlR", typeof(ContextWindow), [new KeyGesture(Key.R, ModifierKeys.Control)]);
@@ -30,27 +32,41 @@ namespace Elwig.Windows {
} }
public async void ForceContextReload(object sender, EventArgs evt) { 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; _renewPending = true;
}
public async Task TryContextReload() {
if (LockContext) return; if (LockContext) return;
await EnsureContextRenewed(); await EnsureContextRenewed();
} }
protected async void OnLoaded(object? sender, RoutedEventArgs? evt) { protected async void OnLoaded(object? sender, RoutedEventArgs? evt) {
Mouse.OverrideCursor = Cursors.AppStarting;
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
await OnRenewContext(ctx); await OnRenewContext(ctx);
HasContextLoaded = true;
await OnInit(ctx);
Mouse.OverrideCursor = null;
} }
protected async Task EnsureContextRenewed() { protected async Task EnsureContextRenewed() {
if (!_renewPending) return; if (!_renewPending) return;
_renewPending = false;
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
await OnRenewContext(ctx); await OnRenewContext(ctx);
_renewPending = false;
} }
virtual protected async Task OnInit(AppDbContext ctx) { }
abstract protected Task OnRenewContext(AppDbContext ctx); abstract protected Task OnRenewContext(AppDbContext ctx);
} }
} }

View File

@@ -6,8 +6,7 @@
xmlns:local="clr-namespace:Elwig.Windows" xmlns:local="clr-namespace:Elwig.Windows"
xmlns:vm="clr-namespace:Elwig.ViewModels" xmlns:vm="clr-namespace:Elwig.ViewModels"
xmlns:ctrl="clr-namespace:Elwig.Controls" xmlns:ctrl="clr-namespace:Elwig.Controls"
Title="{Binding Title}" Height="720" Width="1150" MinHeight="720" MinWidth="1000" Title="{Binding Title}" Height="720" Width="1150" MinHeight="720" MinWidth="1000">
Loaded="Window_Loaded">
<Window.DataContext> <Window.DataContext>
<vm:DeliveryAdminViewModel/> <vm:DeliveryAdminViewModel/>
</Window.DataContext> </Window.DataContext>

View File

@@ -37,6 +37,7 @@ namespace Elwig.Windows {
private readonly Button[] WeighingButtons; private readonly Button[] WeighingButtons;
private List<WineQualLevel> WineQualityLevels = []; private List<WineQualLevel> WineQualityLevels = [];
private Dictionary<int, List<Modifier>> Modifiers = [];
public DeliveryAdminWindow(bool receipt = false) { public DeliveryAdminWindow(bool receipt = false) {
InitializeComponent(); InitializeComponent();
@@ -122,20 +123,20 @@ namespace Elwig.Windows {
Menu_Export_UploadSeason.IsEnabled = App.Config.SyncUrl != null; 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.FilterMember = DeliveryService.GetMember(mgnr) ?? throw new ArgumentException("MgNr argument has invalid value");
ViewModel.Title = $"Lieferungen - {ViewModel.FilterMember.AdministrativeName} - Elwig"; ViewModel.Title = $"Lieferungen - {ViewModel.FilterMember.AdministrativeName} - Elwig";
ViewModel.EnableAllSeasons = true; ViewModel.EnableAllSeasons = true;
} }
private void Window_Loaded(object sender, RoutedEventArgs evt) { protected override async Task OnInit(AppDbContext ctx) {
await base.OnInit(ctx);
OnSecondPassed(null, null); OnSecondPassed(null, null);
SecondsTimer.Start(); SecondsTimer.Start();
LockInputs();
if (ViewModel.IsReceipt) { if (ViewModel.IsReceipt) {
NewDeliveryButton_Click(null, null); NewDeliveryButton_Click(null, null);
using var ctx = new AppDbContext(); if (await ctx.FetchSeasons(Utils.CurrentYear).SingleOrDefaultAsync() == null) {
if (ctx.Seasons.Find(Utils.CurrentYear) == 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...)", 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); "Saison noch nicht erstellt", MessageBoxButton.OK, MessageBoxImage.Warning);
} }
@@ -420,45 +421,55 @@ namespace Elwig.Windows {
} }
private async Task RefreshList(bool updateSort = false) { private async Task RefreshList(bool updateSort = false) {
var vm = ViewModel;
var cursor = Mouse.OverrideCursor != null;
if (!cursor) Mouse.OverrideCursor = Cursors.Wait;
var query = (vm.SearchQuery, vm.FilterSeason, vm.FilterAllSeasons, vm.FilterTodayOnly);
var (filter, deliveries, deliveryPartsNum, varieties, members, stat) = await Task.Run(async () => {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
var (_, deliveryQuery, deliveryPartsQuery, predicate, filter) = await ViewModel.GetFilters(ctx); var (_, deliveryQuery, deliveryPartsQuery, predicate, filter) = await vm.GetFilters(ctx);
var deliveries = await deliveryQuery var deliveries = await deliveryQuery
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers).ThenInclude(m => m.Modifier) .Include(d => d.Parts).ThenInclude(p => p.PartModifiers).ThenInclude(m => m.Modifier)
.Include(d => d.Parts).ThenInclude(p => p.Attribute)
.Include(d => d.Parts).ThenInclude(p => p.Cultivation)
.Include(d => d.Parts).ThenInclude(p => p.Variety) .Include(d => d.Parts).ThenInclude(p => p.Variety)
.Include(d => d.Member.EmailAddresses) .IgnoreAutoIncludes()
.AsSplitQuery() .AsSplitQuery()
.ToListAsync(); .ToListAsync();
deliveries.Reverse(); deliveries.Reverse();
if (filter.Count > 0 && deliveries.Count > 0) { if (filter.Count > 0 && deliveries.Count > 0) {
var dict = deliveries.AsParallel() var dict = deliveries.AsParallel()
.ToDictionary(d => d, d => d.SearchScore(ViewModel.TextFilter)) .ToDictionary(d => d, d => d.SearchScore(vm.TextFilter))
.OrderByDescending(a => a.Value) .OrderByDescending(a => a.Value)
.ThenBy(a => a.Key.DateTime); .ThenBy(a => a.Key.DateTime);
var threshold = dict.Select(a => a.Value).Max() * 3 / 4; var threshold = dict.Max(a => a.Value) * 3 / 4;
deliveries = dict deliveries = [.. dict
.Where(a => a.Value > threshold) .Where(a => a.Value > threshold)
.Select(a => a.Key) .Select(a => a.Key)];
.ToList();
} }
deliveries.ForEach(d => { d.PartFilter = predicate; }); deliveries.ForEach(d => { d.PartFilter = predicate; });
var deliveryPartsNum = await deliveryPartsQuery.CountAsync();
var varieties = await deliveryPartsQuery.Select(d => d.SortId).Distinct().ToListAsync();
var members = await deliveryQuery.Select(d => d.Member).Distinct().IgnoreAutoIncludes().ToListAsync();
var stat = await DeliveryService.GenerateToolTipData(deliveryPartsQuery);
return (filter, deliveries, deliveryPartsNum, varieties, members, stat);
});
if (!cursor) Mouse.OverrideCursor = null;
if (query != (ViewModel.SearchQuery, ViewModel.FilterSeason, ViewModel.FilterAllSeasons, ViewModel.FilterTodayOnly)) return;
ControlUtils.RenewItemsSource(DeliveryList, deliveries, ControlUtils.RenewItemsSource(DeliveryList, deliveries,
DeliveryList_SelectionChanged, filter.Count > 0 ? ControlUtils.RenewSourceDefault.IfOnly : ControlUtils.RenewSourceDefault.None, !updateSort); DeliveryList_SelectionChanged, ViewModel.TextFilter.Count > 0 ? ControlUtils.RenewSourceDefault.IfOnly : ControlUtils.RenewSourceDefault.None, !updateSort);
await RefreshDeliveryParts(); await RefreshDeliveryParts();
var members = deliveries.Select(d => d.Member).DistinctBy(m => m.MgNr).ToList();
ViewModel.StatusMembers = $"{members.Count:N0}" + (members.Count > 0 && members.Count <= 4 ? $" ({string.Join(", ", members.Select(m => m.AdministrativeName))})" : ""); ViewModel.StatusMembers = $"{members.Count:N0}" + (members.Count > 0 && members.Count <= 4 ? $" ({string.Join(", ", members.Select(m => m.AdministrativeName))})" : "");
ViewModel.StatusDeliveries = $"{deliveries.Count:N0}"; ViewModel.StatusDeliveries = $"{deliveries.Count:N0}";
if (filter.Count == 0) { if (filter.Count == 0) {
var deliveryParts = deliveryPartsQuery; ViewModel.StatusDeliveries = $"{deliveries.Count:N0} ({deliveryPartsNum:N0})";
ViewModel.StatusDeliveries = $"{deliveries.Count:N0} ({await deliveryParts.CountAsync():N0})";
var varieties = await deliveryParts.Select(d => d.SortId).Distinct().ToListAsync();
ViewModel.StatusVarieties = $"{varieties.Count:N0}" + (varieties.Count > 0 && varieties.Count <= 10 ? $" ({string.Join(", ", varieties)})" : ""); ViewModel.StatusVarieties = $"{varieties.Count:N0}" + (varieties.Count > 0 && varieties.Count <= 10 ? $" ({string.Join(", ", varieties)})" : "");
var (wText, wData, gText, gData) = await DeliveryService.GenerateToolTipData(deliveryParts); var (wText, wData, gText, gData) = stat;
ViewModel.StatusWeight = wText; ViewModel.StatusWeight = wText;
ViewModel.StatusGradation = gText; ViewModel.StatusGradation = gText;
(ViewModel.StatusWeightToolTip, ViewModel.StatusGradationToolTip) = DeliveryService.GenerateToolTip(wData, gData); (ViewModel.StatusWeightToolTip, ViewModel.StatusGradationToolTip) = DeliveryService.GenerateToolTip(wData, gData);
@@ -486,7 +497,7 @@ namespace Elwig.Windows {
int year = 0; int year = 0;
Menu_Bki_SaveList.Items.Clear(); Menu_Bki_SaveList.Items.Clear();
foreach (var s in await ctx.Seasons.OrderByDescending(s => s.Year).ToListAsync()) { foreach (var s in await ctx.FetchSeasons().ToListAsync()) {
if (s.Year > year) year = s.Year; if (s.Year > year) year = s.Year;
var i = new MenuItem { var i = new MenuItem {
Header = $"Saison {s.Year}", Header = $"Saison {s.Year}",
@@ -495,6 +506,9 @@ namespace Elwig.Windows {
Menu_Bki_SaveList.Items.Add(i); 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"); var font = new FontFamily("Segoe MDL2 Assets");
Menu_BulkAction_SetAttribute.Items.Clear(); Menu_BulkAction_SetAttribute.Items.Clear();
var noAttr = new MenuItem { var noAttr = new MenuItem {
@@ -503,7 +517,7 @@ namespace Elwig.Windows {
}; };
noAttr.Click += Menu_BulkAction_SetAttribute_Click; noAttr.Click += Menu_BulkAction_SetAttribute_Click;
Menu_BulkAction_SetAttribute.Items.Add(noAttr); Menu_BulkAction_SetAttribute.Items.Add(noAttr);
foreach (var attr in await ctx.WineAttributes.OrderBy(a => a.AttrId).ToListAsync()) { foreach (var attr in attributes) {
var i = new MenuItem { var i = new MenuItem {
Header = attr.Name, Header = attr.Name,
}; };
@@ -513,7 +527,7 @@ namespace Elwig.Windows {
Menu_BulkAction_AddModifier.Items.Clear(); Menu_BulkAction_AddModifier.Items.Clear();
Menu_BulkAction_RemoveModifier.Items.Clear(); Menu_BulkAction_RemoveModifier.Items.Clear();
foreach (var mod in await ctx.Modifiers.Where(m => m.Year == year).OrderBy(m => m.ModId).ToListAsync()) { foreach (var mod in Modifiers.GetValueOrDefault(ViewModel.SelectedDelivery?.Year ?? 0, []).Where(m => m.IsActive || !IsCreating)) {
var i1 = new MenuItem { var i1 = new MenuItem {
Header = mod.Name, Header = mod.Name,
}; };
@@ -527,44 +541,34 @@ namespace Elwig.Windows {
} }
await RefreshList(); await RefreshList();
var d = DeliveryList.SelectedItem as Delivery;
var y = d?.Year ?? ViewModel.FilterSeason; ControlUtils.RenewItemsSource(MemberInput, await ctx.FetchMembers(includeNotActive: !IsCreating, includeContactInfo: true).ToListAsync());
ControlUtils.RenewItemsSource(MemberInput, await ctx.Members ControlUtils.RenewItemsSource(BranchInput, await ctx.FetchBranches().ToListAsync());
.Where(m => m.IsActive || !IsCreating) ControlUtils.RenewItemsSource(WineVarietyInput, await ctx.FetchWineVarieties().ToListAsync());
.Include(m => m.PostalDest.AtPlz!.Ort) var attrList = attributes.Cast<object>().ToList();
.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();
attrList.Insert(0, new NullItem("")); attrList.Insert(0, new NullItem(""));
ControlUtils.RenewItemsSource(AttributeInput, attrList, null, ControlUtils.RenewSourceDefault.First); 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("")); cultList.Insert(0, new NullItem(""));
ControlUtils.RenewItemsSource(CultivationInput, cultList, null, ControlUtils.RenewSourceDefault.First); ControlUtils.RenewItemsSource(CultivationInput, cultList, null, ControlUtils.RenewSourceDefault.First);
WineQualityLevels = await ctx.WineQualityLevels.ToListAsync(); WineQualityLevels = await ctx.FetchWineQualityLevels().ToListAsync();
ControlUtils.RenewItemsSource(WineQualityLevelInput, WineQualityLevels); ControlUtils.RenewItemsSource(WineQualityLevelInput, WineQualityLevels);
ControlUtils.RenewItemsSource(ModifiersInput, await ctx.Modifiers ControlUtils.RenewItemsSource(ModifiersInput, Modifiers.GetValueOrDefault(year, []).Where(m => m.IsActive || !IsCreating).ToList());
.Where(m => m.Year == y && (!IsCreating || m.IsActive)) var origins = await ctx.WineOrigins.ToListAsync();
.OrderBy(m => m.Ordering) origins.ForEach(o => { origins.FirstOrDefault(p => p.HkId == o.ParentHkId)?.Children.Add(o); });
.Include(m => m.Season.Currency) origins = [.. origins.OrderByDescending(o => o.SortKey).ThenBy(o => o.HkId)];
.ToListAsync()); ControlUtils.RenewItemsSource(WineOriginInput, origins);
ControlUtils.RenewItemsSource(WineOriginInput, (await ctx.WineOrigins.ToListAsync()).OrderByDescending(o => o.SortKey).ThenBy(o => o.HkId));
var kgList = (await ctx.Katastralgemeinden var kgList = (await ctx.Katastralgemeinden
.Where(k => k.WbKg != null) .Where(k => k.WbKg != null)
.Include(k => k.WbKg) .Include(k => k.WbKg)
.Include(k => k.Gem.WbGem) .Include(k => k.Gem.WbGem)
.OrderBy(k => k.Name) .OrderBy(k => k.Name)
.AsSplitQuery()
.ToListAsync()).Cast<object>().ToList(); .ToListAsync()).Cast<object>().ToList();
kgList.Insert(0, new NullItem()); kgList.Insert(0, new NullItem());
ControlUtils.RenewItemsSource(WineKgInput, kgList); ControlUtils.RenewItemsSource(WineKgInput, kgList);
UpdateRdInput(); UpdateRdInput();
if (IsCreating) await UpdateLsNr(); if (IsCreating) await UpdateLsNr();
await RefreshDeliveryParts();
RefreshInputs(); RefreshInputs();
} }
@@ -576,30 +580,22 @@ namespace Elwig.Windows {
} }
private async Task RefreshDeliveryParts() { private async Task RefreshDeliveryParts() {
using var ctx = new AppDbContext();
if (DeliveryList.SelectedItem is Delivery d) { if (DeliveryList.SelectedItem is Delivery d) {
ControlUtils.RenewItemsSource(ModifiersInput, await ctx.Modifiers ControlUtils.RenewItemsSource(ModifiersInput, Modifiers.GetValueOrDefault(d.Year, []).Where(m => m.IsActive || !IsCreating).ToList());
.Where(m => m.Year == d.Year && (!IsCreating || m.IsActive)) ControlUtils.RenewItemsSource(DeliveryPartList, d.Parts, DeliveryPartList_SelectionChanged, ControlUtils.RenewSourceDefault.First);
.OrderBy(m => m.Ordering)
.Include(m => m.Season.Currency)
.ToListAsync());
ControlUtils.RenewItemsSource(DeliveryPartList, d.FilteredParts.OrderBy(p => p.DPNr).ToList(), DeliveryPartList_SelectionChanged, ControlUtils.RenewSourceDefault.First);
} else { } else {
ControlUtils.RenewItemsSource(ModifiersInput, await ctx.Modifiers ControlUtils.RenewItemsSource(ModifiersInput, Modifiers.GetValueOrDefault(ViewModel.FilterSeason ?? 0, []).Where(m => m.IsActive || !IsCreating).ToList());
.Where(m => m.Year == ViewModel.FilterSeason && (!IsCreating || m.IsActive))
.OrderBy(m => m.Ordering)
.Include(m => m.Season.Currency)
.ToListAsync());
DeliveryPartList.ItemsSource = null; DeliveryPartList.ItemsSource = null;
} }
} }
private void RefreshInputs(bool validate = false) { private void RefreshInputs(bool validate = false) {
ClearInputStates(); ClearInputStates();
if (DeliveryList.SelectedItem is Delivery d) {
FillInputs(d);
if (DeliveryPartList.SelectedItem is DeliveryPart p) { if (DeliveryPartList.SelectedItem is DeliveryPart p) {
FillInputs(p); FillInputs(p);
} else if (DeliveryList.SelectedItem is Delivery d) { }
FillInputs(d);
} else { } else {
ClearOriginalValues(); ClearOriginalValues();
ClearDefaultValues(); ClearDefaultValues();
@@ -617,7 +613,6 @@ namespace Elwig.Windows {
} }
private void FillInputs(DeliveryPart p) { private void FillInputs(DeliveryPart p) {
FillInputs(p.Delivery);
ClearOriginalValues(); ClearOriginalValues();
ClearDefaultValues(); ClearDefaultValues();
ViewModel.FillInputs(p); ViewModel.FillInputs(p);
@@ -681,17 +676,19 @@ namespace Elwig.Windows {
} }
private async void SearchInput_TextChanged(object sender, RoutedEventArgs evt) { private async void SearchInput_TextChanged(object sender, RoutedEventArgs evt) {
if (!HasContextLoaded) return;
await RefreshList(true); await RefreshList(true);
} }
private async void SeasonInput_TextChanged(object sender, TextChangedEventArgs evt) { 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; TodayOnlyInput.IsChecked = false;
AllSeasonsInput.IsChecked = false; AllSeasonsInput.IsChecked = false;
await RefreshList(); await RefreshList();
} }
private async void TodayOnlyInput_Changed(object sender, RoutedEventArgs evt) { private async void TodayOnlyInput_Changed(object sender, RoutedEventArgs evt) {
if (!HasContextLoaded) return;
if (TodayOnlyInput.IsChecked == true && AllSeasonsInput.IsChecked == false) { if (TodayOnlyInput.IsChecked == true && AllSeasonsInput.IsChecked == false) {
ViewModel.FilterSeason = Utils.Today.Year; ViewModel.FilterSeason = Utils.Today.Year;
ViewModel.FilterTodayOnly = true; ViewModel.FilterTodayOnly = true;
@@ -700,6 +697,7 @@ namespace Elwig.Windows {
} }
private async void AllSeasonsInput_Changed(object sender, RoutedEventArgs evt) { private async void AllSeasonsInput_Changed(object sender, RoutedEventArgs evt) {
if (!HasContextLoaded) return;
if (AllSeasonsInput.IsChecked == true) { if (AllSeasonsInput.IsChecked == true) {
SeasonInput.IsEnabled = false; SeasonInput.IsEnabled = false;
ViewModel.FilterSeason = null; ViewModel.FilterSeason = null;
@@ -719,7 +717,7 @@ namespace Elwig.Windows {
Menu_DeliveryNote_Show.IsEnabled = !IsEditing && !IsCreating; Menu_DeliveryNote_Show.IsEnabled = !IsEditing && !IsCreating;
Menu_DeliveryNote_SavePdf.IsEnabled = !IsEditing && !IsCreating; Menu_DeliveryNote_SavePdf.IsEnabled = !IsEditing && !IsCreating;
Menu_DeliveryNote_Print.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_ExportSelected.IsEnabled = !IsEditing && !IsCreating;
Menu_Export_UploadSelected.IsEnabled = !IsEditing && !IsCreating && App.Config.SyncUrl != null; Menu_Export_UploadSelected.IsEnabled = !IsEditing && !IsCreating && App.Config.SyncUrl != null;
} else { } else {
@@ -812,11 +810,12 @@ namespace Elwig.Windows {
} }
EmptyScale(); EmptyScale();
await EnsureContextRenewed(); await EnsureContextRenewed();
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
ControlUtils.SelectItem(DeliveryList, p?.Delivery); ControlUtils.SelectItemWithPk(DeliveryList, p?.Year, p?.DId);
DeliveryPartList.SelectedItem = null; DeliveryPartList.SelectedItem = null;
DeliveryPartList.ScrollIntoView(DeliveryPartList.ItemsSource.Cast<object>().Last()); DeliveryPartList.ScrollIntoView(DeliveryPartList.ItemsSource.Cast<object>().LastOrDefault());
InitialInputs(); InitialInputs();
} }
@@ -849,25 +848,22 @@ namespace Elwig.Windows {
} }
EmptyScale(); EmptyScale();
await EnsureContextRenewed();
if (p?.Delivery != null) { Utils.RunBackground("Lieferschein drucken", async () => {
try { using var doc = await DeliveryNote.Initialize(p.Year, p.DId);
using var ctx = new AppDbContext(); using (var ctx = new AppDbContext()) {
using var doc = new DeliveryNote((await ctx.Deliveries.FindAsync(p.Year, p.DId))!, ctx); await doc.Generate(ctx);
await doc.Generate(); }
if (App.Config.Debug) { if (App.Config.Debug) {
doc.Show(); doc.Show();
} else { } else {
await doc.Print(2); await doc.Print(2);
} }
} catch (Exception exc) { });
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
await EnsureContextRenewed();
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
DeliveryList.SelectedItem = null; DeliveryList.SelectedItem = null;
await EnsureContextRenewed();
InitInputs(); InitInputs();
} }
@@ -879,16 +875,10 @@ namespace Elwig.Windows {
} }
using var ctx = new AppDbContext(); 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("")); attrList.Insert(0, new NullItem(""));
ControlUtils.RenewItemsSource(AttributeInput, attrList, null, ControlUtils.RenewSourceDefault.First); ControlUtils.RenewItemsSource(AttributeInput, attrList, null, ControlUtils.RenewSourceDefault.First);
ControlUtils.RenewItemsSource(MemberInput, await ctx.Members ControlUtils.RenewItemsSource(MemberInput, await ctx.FetchMembers(includeNotActive: !ViewModel.IsReceipt, includeContactInfo: true).ToListAsync());
.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());
if (DeliveryList.SelectedItem is not Delivery d) { if (DeliveryList.SelectedItem is not Delivery d) {
// switch away from creating mode // switch away from creating mode
IsCreating = false; IsCreating = false;
@@ -920,21 +910,11 @@ namespace Elwig.Windows {
ViewModel.FilterTodayOnly = true; ViewModel.FilterTodayOnly = true;
ViewModel.SearchQuery = ""; ViewModel.SearchQuery = "";
using var ctx = new AppDbContext(); 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("")); attrList.Insert(0, new NullItem(""));
ControlUtils.RenewItemsSource(AttributeInput, attrList, null, ControlUtils.RenewSourceDefault.First); ControlUtils.RenewItemsSource(AttributeInput, attrList, null, ControlUtils.RenewSourceDefault.First);
ControlUtils.RenewItemsSource(ModifiersInput, await ctx.Modifiers ControlUtils.RenewItemsSource(ModifiersInput, Modifiers.GetValueOrDefault(ViewModel.FilterSeason ?? 0, []).Where(m => m.IsActive).ToList());
.Where(m => m.Year == ViewModel.FilterSeason && m.IsActive) ControlUtils.RenewItemsSource(MemberInput, await ctx.FetchMembers(includeNotActive: !ViewModel.IsReceipt, includeContactInfo: true).ToListAsync());
.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());
IsCreating = true; IsCreating = true;
DeliveryList.IsEnabled = false; DeliveryList.IsEnabled = false;
DeliveryPartList.IsEnabled = false; DeliveryPartList.IsEnabled = false;

View File

@@ -8,8 +8,7 @@
xmlns:local="clr-namespace:Elwig.Windows" xmlns:local="clr-namespace:Elwig.Windows"
xmlns:vm="clr-namespace:Elwig.ViewModels" xmlns:vm="clr-namespace:Elwig.ViewModels"
xmlns:ctrl="clr-namespace:Elwig.Controls" xmlns:ctrl="clr-namespace:Elwig.Controls"
Title="Anmeldungen - Elwig" Height="700" Width="980" MinWidth="600" MinHeight="400" Title="Anmeldungen - Elwig" Height="700" Width="980" MinWidth="600" MinHeight="400">
Loaded="Window_Loaded">
<Window.DataContext> <Window.DataContext>
<vm:DeliveryAncmtAdminViewModel/> <vm:DeliveryAncmtAdminViewModel/>
</Window.DataContext> </Window.DataContext>

View File

@@ -36,11 +36,7 @@ namespace Elwig.Windows {
ControlUtils.InitializeDelayTimer(SearchInput, SearchInput_TextChanged); ControlUtils.InitializeDelayTimer(SearchInput, SearchInput_TextChanged);
SearchInput.TextChanged -= SearchInput_TextChanged; SearchInput.TextChanged -= SearchInput_TextChanged;
ViewModel.FilterSeason = Utils.CurrentLastSeason; ViewModel.FilterSeason = Utils.CurrentLastSeason;
}
private void Window_Loaded(object sender, RoutedEventArgs evt) {
ViewModel.FilterOnlyUpcoming = true; ViewModel.FilterOnlyUpcoming = true;
LockInputs();
} }
private void Input_KeyUp(object sender, KeyEventArgs evt) { private void Input_KeyUp(object sender, KeyEventArgs evt) {
@@ -85,7 +81,6 @@ namespace Elwig.Windows {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
var list = await ctx.DeliverySchedules var list = await ctx.DeliverySchedules
.Where(s => s.Year == ViewModel.FilterSeason) .Where(s => s.Year == ViewModel.FilterSeason)
.Include(s => s.Branch)
.OrderBy(s => s.DateString) .OrderBy(s => s.DateString)
.ThenBy(s => s.Branch.Name) .ThenBy(s => s.Branch.Name)
.ThenBy(s => s.Description) .ThenBy(s => s.Description)
@@ -103,14 +98,14 @@ namespace Elwig.Windows {
} }
private async Task RefreshList(bool updateSort = false) { private async Task RefreshList(bool updateSort = false) {
var vm = ViewModel;
var cursor = Mouse.OverrideCursor != null;
if (!cursor) Mouse.OverrideCursor = Cursors.Wait;
var query = (vm.SearchQuery, vm.FilterSeason, vm.FilterOnlyUpcoming, vm.FilterOnlyUpcoming);
var (filter, deliveryAncmts, stat) = await Task.Run(async () => {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
var (_, deliveryAncmtQuery, filter) = await ViewModel.GetFilters(ctx); var (_, deliveryAncmtQuery, filter) = await vm.GetFilters(ctx);
var deliveryAncmts = await deliveryAncmtQuery var deliveryAncmts = await deliveryAncmtQuery.ToListAsync();
.Include(a => a.Member.BillingAddress)
.Include(a => a.Schedule)
.Include(a => a.Variety)
.AsSplitQuery()
.ToListAsync();
if (filter.Count > 0 && deliveryAncmts.Count > 0) { if (filter.Count > 0 && deliveryAncmts.Count > 0) {
var dict = deliveryAncmts.AsParallel() var dict = deliveryAncmts.AsParallel()
@@ -120,20 +115,25 @@ namespace Elwig.Windows {
.ThenBy(a => a.Key.Member.Name) .ThenBy(a => a.Key.Member.Name)
.ThenBy(a => a.Key.Member.GivenName) .ThenBy(a => a.Key.Member.GivenName)
.ThenBy(a => a.Key.Member.MgNr); .ThenBy(a => a.Key.Member.MgNr);
var threshold = dict.Select(a => a.Value).Max() * 3 / 4; var threshold = dict.Max(a => a.Value) * 3 / 4;
deliveryAncmts = dict deliveryAncmts = [.. dict
.Where(a => a.Value > threshold) .Where(a => a.Value > threshold)
.Select(a => a.Key) .Select(a => a.Key)];
.ToList();
} else { } else {
deliveryAncmts = deliveryAncmts deliveryAncmts = [.. deliveryAncmts
.OrderBy(a => a.Schedule.DateString) .OrderBy(a => a.Schedule.DateString)
.ThenBy(a => a.Member.Name) .ThenBy(a => a.Member.Name)
.ThenBy(a => a.Member.GivenName) .ThenBy(a => a.Member.GivenName)
.ThenBy(a => a.Member.MgNr) .ThenBy(a => a.Member.MgNr)];
.ToList();
} }
var stat = await DeliveryAncmtService.GenerateToolTipData(deliveryAncmtQuery);
return (filter, deliveryAncmts, stat);
});
if (!cursor) Mouse.OverrideCursor = null;
if (query != (ViewModel.SearchQuery, ViewModel.FilterSeason, ViewModel.FilterOnlyUpcoming, ViewModel.FilterOnlyUpcoming)) return;
ControlUtils.RenewItemsSource(DeliveryAncmtList, deliveryAncmts, ControlUtils.RenewItemsSource(DeliveryAncmtList, deliveryAncmts,
DeliveryAncmtList_SelectionChanged, ViewModel.TextFilter.Count > 0 ? ControlUtils.RenewSourceDefault.IfOnly : ControlUtils.RenewSourceDefault.None, !updateSort); DeliveryAncmtList_SelectionChanged, ViewModel.TextFilter.Count > 0 ? ControlUtils.RenewSourceDefault.IfOnly : ControlUtils.RenewSourceDefault.None, !updateSort);
if (updateSort && DeliveryAncmtList.SelectedItem != null) if (updateSort && DeliveryAncmtList.SelectedItem != null)
@@ -141,9 +141,9 @@ namespace Elwig.Windows {
ViewModel.StatusAncmts = $"{deliveryAncmts.Count:N0}"; ViewModel.StatusAncmts = $"{deliveryAncmts.Count:N0}";
if (filter.Count == 0) { if (filter.Count == 0) {
var (text, grid) = await DeliveryAncmtService.GenerateToolTip(deliveryAncmtQuery); var (text, data) = stat;
ViewModel.StatusWeight = text; ViewModel.StatusWeight = text;
ViewModel.StatusWeightToolTip = grid; ViewModel.StatusWeightToolTip = DeliveryAncmtService.GenerateToolTip(data);
} else { } else {
ViewModel.StatusWeight = $"{deliveryAncmts.Sum(a => a.Weight):N0} kg"; ViewModel.StatusWeight = $"{deliveryAncmts.Sum(a => a.Weight):N0} kg";
ViewModel.StatusWeightToolTip = null; ViewModel.StatusWeightToolTip = null;
@@ -177,15 +177,8 @@ namespace Elwig.Windows {
protected override async Task OnRenewContext(AppDbContext ctx) { protected override async Task OnRenewContext(AppDbContext ctx) {
await base.OnRenewContext(ctx); await base.OnRenewContext(ctx);
ControlUtils.RenewItemsSource(MemberInput, await ctx.Members ControlUtils.RenewItemsSource(MemberInput, await ctx.FetchMembers(includeNotActive: !IsCreating).ToListAsync());
.Where(m => m.IsActive || !IsCreating) ControlUtils.RenewItemsSource(WineVarietyInput, await ctx.FetchWineVarieties().ToListAsync());
.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());
await RefreshDeliveryScheduleList(); await RefreshDeliveryScheduleList();
await RefreshList(); await RefreshList();
@@ -196,6 +189,7 @@ namespace Elwig.Windows {
} }
private async void DeliveryScheduleList_SelectionChanged(object sender, RoutedEventArgs evt) { private async void DeliveryScheduleList_SelectionChanged(object sender, RoutedEventArgs evt) {
if (!HasContextLoaded) return;
await RefreshList(); await RefreshList();
if (DeliveryScheduleList.SelectedItem is DeliverySchedule s) { if (DeliveryScheduleList.SelectedItem is DeliverySchedule s) {
Menu_DeliveryAncmtList_SaveSelected.IsEnabled = !IsEditing && !IsCreating; Menu_DeliveryAncmtList_SaveSelected.IsEnabled = !IsEditing && !IsCreating;
@@ -217,11 +211,13 @@ namespace Elwig.Windows {
} }
private async void OnlyUpcomingInput_Changed(object sender, RoutedEventArgs evt) { private async void OnlyUpcomingInput_Changed(object sender, RoutedEventArgs evt) {
if (!HasContextLoaded) return;
await RefreshDeliveryScheduleList(); await RefreshDeliveryScheduleList();
await RefreshList(true); await RefreshList(true);
} }
private async void FromAllSchedulesInput_Changed(object sender, RoutedEventArgs evt) { private async void FromAllSchedulesInput_Changed(object sender, RoutedEventArgs evt) {
if (!HasContextLoaded) return;
if (ViewModel.FilterFromAllSchedules) { if (ViewModel.FilterFromAllSchedules) {
DeliveryScheduleList.SelectedItem = null; DeliveryScheduleList.SelectedItem = null;
} else if (DeliveryScheduleList.SelectedItem == null) { } else if (DeliveryScheduleList.SelectedItem == null) {
@@ -231,11 +227,12 @@ namespace Elwig.Windows {
} }
private async void SearchInput_TextChanged(object sender, TextChangedEventArgs evt) { private async void SearchInput_TextChanged(object sender, TextChangedEventArgs evt) {
if (!HasContextLoaded) return;
await RefreshList(true); await RefreshList(true);
} }
private async void SeasonInput_TextChanged(object sender, TextChangedEventArgs evt) { private async void SeasonInput_TextChanged(object sender, TextChangedEventArgs evt) {
if (ViewModel.FilterSeason == null) return; if (!HasContextLoaded || ViewModel.FilterSeason == null) return;
ViewModel.FilterOnlyUpcoming = false; ViewModel.FilterOnlyUpcoming = false;
await RefreshDeliveryScheduleList(); await RefreshDeliveryScheduleList();
await RefreshList(); await RefreshList();
@@ -274,14 +271,7 @@ namespace Elwig.Windows {
ViewModel.SelectedDeliveryAncmt = null; ViewModel.SelectedDeliveryAncmt = null;
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
ControlUtils.RenewItemsSource(MemberInput, await ctx.Members ControlUtils.RenewItemsSource(MemberInput, await ctx.FetchMembers(includeNotActive: !IsCreating).ToListAsync());
.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());
HideNewEditDeleteButtons(); HideNewEditDeleteButtons();
ShowSaveResetCancelButtons(); ShowSaveResetCancelButtons();
@@ -403,14 +393,7 @@ namespace Elwig.Windows {
DeliveryAncmtList.IsEnabled = true; DeliveryAncmtList.IsEnabled = true;
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
ControlUtils.RenewItemsSource(MemberInput, await ctx.Members ControlUtils.RenewItemsSource(MemberInput, await ctx.FetchMembers(includeNotActive: !IsCreating).ToListAsync());
.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());
HideSaveResetCancelButtons(); HideSaveResetCancelButtons();
ShowNewEditDeleteButtons(); ShowNewEditDeleteButtons();

View File

@@ -7,8 +7,7 @@
xmlns:local="clr-namespace:Elwig.Windows" xmlns:local="clr-namespace:Elwig.Windows"
xmlns:vm="clr-namespace:Elwig.ViewModels" xmlns:vm="clr-namespace:Elwig.ViewModels"
xmlns:ctrl="clr-namespace:Elwig.Controls" xmlns:ctrl="clr-namespace:Elwig.Controls"
Title="Leseplanung - Elwig" Height="600" Width="850" MinHeight="450" MinWidth="800" Title="Leseplanung - Elwig" Height="600" Width="850" MinHeight="450" MinWidth="800">
Loaded="Window_Loaded">
<Window.DataContext> <Window.DataContext>
<vm:DeliveryScheduleAdminViewModel/> <vm:DeliveryScheduleAdminViewModel/>
</Window.DataContext> </Window.DataContext>

View File

@@ -30,20 +30,19 @@ namespace Elwig.Windows {
ControlUtils.InitializeDelayTimer(SearchInput, SearchInput_TextChanged); ControlUtils.InitializeDelayTimer(SearchInput, SearchInput_TextChanged);
SearchInput.TextChanged -= SearchInput_TextChanged; SearchInput.TextChanged -= SearchInput_TextChanged;
ViewModel.FilterSeason = Utils.CurrentLastSeason; ViewModel.FilterSeason = Utils.CurrentLastSeason;
}
private void Window_Loaded(object sender, RoutedEventArgs evt) {
ViewModel.FilterOnlyUpcoming = true; ViewModel.FilterOnlyUpcoming = true;
LockInputs();
} }
private async Task RefreshList(bool updateSort = false) { private async Task RefreshList(bool updateSort = false) {
var vm = ViewModel;
var cursor = Mouse.OverrideCursor != null;
if (!cursor) Mouse.OverrideCursor = Cursors.Wait;
var query = (vm.SearchQuery, vm.FilterSeason, vm.FilterOnlyUpcoming);
var deliverySchedules = await Task.Run(async () => {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
var (_, deliveryScheduleQuery, filter) = await ViewModel.GetFilters(ctx); var (_, deliveryScheduleQuery, filter) = await vm.GetFilters(ctx);
var deliverySchedules = await deliveryScheduleQuery var deliverySchedules = await deliveryScheduleQuery
.Include(s => s.Varieties) .Include(s => s.Varieties)
.Include(s => s.Branch)
.AsSplitQuery()
.ToListAsync(); .ToListAsync();
if (filter.Count > 0 && deliverySchedules.Count > 0) { if (filter.Count > 0 && deliverySchedules.Count > 0) {
@@ -53,19 +52,22 @@ namespace Elwig.Windows {
.ThenBy(a => a.Key.DateString) .ThenBy(a => a.Key.DateString)
.ThenBy(a => a.Key.Branch.Name) .ThenBy(a => a.Key.Branch.Name)
.ThenBy(a => a.Key.Description); .ThenBy(a => a.Key.Description);
var threshold = dict.Select(a => a.Value).Max() * 3 / 4; var threshold = dict.Max(a => a.Value) * 3 / 4;
deliverySchedules = dict deliverySchedules = [.. dict
.Where(a => a.Value > threshold) .Where(a => a.Value > threshold)
.Select(a => a.Key) .Select(a => a.Key)];
.ToList();
} else { } else {
deliverySchedules = deliverySchedules deliverySchedules = [.. deliverySchedules
.OrderBy(s => s.DateString) .OrderBy(s => s.DateString)
.ThenBy(s => s.Branch.Name) .ThenBy(s => s.Branch.Name)
.ThenBy(s => s.Description) .ThenBy(s => s.Description)];
.ToList();
} }
return deliverySchedules;
});
if (!cursor) Mouse.OverrideCursor = null;
if (query != ((ViewModel.SearchQuery, ViewModel.FilterSeason, ViewModel.FilterOnlyUpcoming))) return;
ControlUtils.RenewItemsSource(DeliveryScheduleList, deliverySchedules, ControlUtils.RenewItemsSource(DeliveryScheduleList, deliverySchedules,
DeliveryScheduleList_SelectionChanged, ViewModel.TextFilter.Count > 0 ? ControlUtils.RenewSourceDefault.IfOnly : ControlUtils.RenewSourceDefault.None, !updateSort); DeliveryScheduleList_SelectionChanged, ViewModel.TextFilter.Count > 0 ? ControlUtils.RenewSourceDefault.IfOnly : ControlUtils.RenewSourceDefault.None, !updateSort);
if (updateSort && DeliveryScheduleList.SelectedItem != null) if (updateSort && DeliveryScheduleList.SelectedItem != null)
@@ -99,14 +101,14 @@ namespace Elwig.Windows {
protected override async Task OnRenewContext(AppDbContext ctx) { protected override async Task OnRenewContext(AppDbContext ctx) {
await base.OnRenewContext(ctx); await base.OnRenewContext(ctx);
ControlUtils.RenewItemsSource(BranchInput, await ctx.Branches.OrderBy(b => b.Name).ToListAsync()); ControlUtils.RenewItemsSource(BranchInput, await ctx.FetchBranches().ToListAsync());
var varieties = await ctx.WineVarieties.OrderBy(v => v.Name).ToListAsync(); var varieties = await ctx.FetchWineVarieties().ToListAsync();
ControlUtils.RenewItemsSource(MainWineVarietiesInput, varieties); ControlUtils.RenewItemsSource(MainWineVarietiesInput, varieties);
ControlUtils.RenewItemsSource(OtherWineVarietiesInput, 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 -")); attrList.Insert(0, new NullItem("- Keine Angabe -"));
ControlUtils.RenewItemsSource(AttributeInput, attrList, null, ControlUtils.RenewSourceDefault.First); 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 -")); cultList.Insert(0, new NullItem("- Kein Angabe -"));
ControlUtils.RenewItemsSource(CultivationInput, cultList, null, ControlUtils.RenewSourceDefault.First); ControlUtils.RenewItemsSource(CultivationInput, cultList, null, ControlUtils.RenewSourceDefault.First);
@@ -118,15 +120,17 @@ namespace Elwig.Windows {
} }
private async void OnlyUpcomingInput_Changed(object sender, RoutedEventArgs evt) { private async void OnlyUpcomingInput_Changed(object sender, RoutedEventArgs evt) {
if (!HasContextLoaded) return;
await RefreshList(); await RefreshList();
} }
private async void SearchInput_TextChanged(object sender, TextChangedEventArgs evt) { private async void SearchInput_TextChanged(object sender, TextChangedEventArgs evt) {
if (!HasContextLoaded) return;
await RefreshList(true); await RefreshList(true);
} }
private async void SeasonInput_TextChanged(object sender, TextChangedEventArgs evt) { private async void SeasonInput_TextChanged(object sender, TextChangedEventArgs evt) {
if (ViewModel.FilterSeason == null) return; if (!HasContextLoaded || ViewModel.FilterSeason == null) return;
ViewModel.FilterOnlyUpcoming = false; ViewModel.FilterOnlyUpcoming = false;
await RefreshList(); await RefreshList();
} }

View File

@@ -107,7 +107,7 @@ namespace Elwig.Windows {
public MailWindow(int? year = null) { public MailWindow(int? year = null) {
InitializeComponent(); InitializeComponent();
using (var ctx = new AppDbContext()) { 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"; Title = $"Rundschreiben - Lese {Year} - Elwig";
} }
@@ -155,7 +155,7 @@ namespace Elwig.Windows {
} }
protected override async Task OnRenewContext(AppDbContext ctx) { protected override async Task OnRenewContext(AppDbContext ctx) {
var season = await ctx.Seasons.FindAsync(Year); var season = await ctx.Seasons.Include(s => s.PaymentVariants).Where(s => s.Year == Year).SingleOrDefaultAsync();
var l = new List<string> { var l = new List<string> {
MemberDataSheet.Name MemberDataSheet.Name
}; };
@@ -165,10 +165,7 @@ namespace Elwig.Windows {
} }
AvaiableDocumentsList.ItemsSource = l; AvaiableDocumentsList.ItemsSource = l;
ControlUtils.RenewItemsSource(MemberBranchInput, await ctx.Branches ControlUtils.RenewItemsSource(MemberBranchInput, await ctx.FetchBranches(includeWithoutMembers: false).ToListAsync(), MemberInput_SelectionChanged);
.Where(b => b.Members.Count != 0)
.OrderBy(b => b.Name)
.ToListAsync(), MemberInput_SelectionChanged);
if (MemberBranchInput.SelectedItems.Count == 0) { if (MemberBranchInput.SelectedItems.Count == 0) {
MemberBranchInput.SelectionChanged -= MemberInput_SelectionChanged; MemberBranchInput.SelectionChanged -= MemberInput_SelectionChanged;
MemberBranchInput.SelectAll(); MemberBranchInput.SelectAll();
@@ -207,13 +204,8 @@ namespace Elwig.Windows {
.OrderBy(m => m.Name) .OrderBy(m => m.Name)
.ThenBy(m => m.GivenName) .ThenBy(m => m.GivenName)
.Include(m => m.Branch) .Include(m => m.Branch)
.Include(m => m.DefaultWbKg!.AtKg)
.Include(m => m.EmailAddresses) .Include(m => m.EmailAddresses)
.Include(m => m.TelephoneNumbers) .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); .ToListAsync(), MemberInput_SelectionChanged);
if (MemberCustomInput.SelectedItems.Count == 0) { if (MemberCustomInput.SelectedItems.Count == 0) {
MemberCustomInput.SelectionChanged -= MemberInput_SelectionChanged; MemberCustomInput.SelectionChanged -= MemberInput_SelectionChanged;
@@ -373,7 +365,7 @@ namespace Elwig.Windows {
RecipientsDeliveryMembersInput.IsChecked = true; RecipientsDeliveryMembersInput.IsChecked = true;
} else if (idx >= 2) { } else if (idx >= 2) {
var name = s.Split(" ")[^1]; 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))); SelectedDocs.Add(new(DocType.CreditNote, s, (pv.Year, pv.AvNr)));
RecipientsCreditMembersInput.IsChecked = true; RecipientsCreditMembersInput.IsChecked = true;
} }
@@ -492,13 +484,8 @@ namespace Elwig.Windows {
} }
Recipients = await query Recipients = await query
.Include(m => m.Branch) .Include(m => m.Branch)
.Include(m => m.DefaultWbKg!.AtKg)
.Include(m => m.EmailAddresses) .Include(m => m.EmailAddresses)
.Include(m => m.TelephoneNumbers) .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(); .ToListAsync();
} }
UpdatePostalEmailRecipients(); UpdatePostalEmailRecipients();
@@ -703,7 +690,7 @@ namespace Elwig.Windows {
PrintButton.IsEnabled = PrintDocument != null && !hasPreviewDocs; PrintButton.IsEnabled = PrintDocument != null && !hasPreviewDocs;
EmailButton.IsEnabled = EmailDocuments != null && !hasPreviewDocs && App.Config.Smtp != null; EmailButton.IsEnabled = EmailDocuments != null && !hasPreviewDocs && App.Config.Smtp != null;
} catch (Exception exc) { } catch (Exception exc) {
MessageBox.Show(exc.ToString(), "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
} finally { } finally {
UnlockInputs(); UnlockInputs();
GenerateButton.IsEnabled = true; GenerateButton.IsEnabled = true;
@@ -725,7 +712,7 @@ namespace Elwig.Windows {
foreach (var doc in docs) { foreach (var doc in docs) {
if (doc.Type == DocType.DeliveryConfirmation) { if (doc.Type == DocType.DeliveryConfirmation) {
var year = (int)doc.Details!; var year = (int)doc.Details!;
var b = new Billing(year); var b = await Billing.Create(year);
await b.FinishSeason(); await b.FinishSeason();
await b.CalculateBuckets(); await b.CalculateBuckets();
App.HintContextChange(); App.HintContextChange();
@@ -755,10 +742,13 @@ namespace Elwig.Windows {
Member = m, Member = m,
Docs = docs.SelectMany<SelectedDoc, GeneratedDoc>(doc => { Docs = docs.SelectMany<SelectedDoc, GeneratedDoc>(doc => {
try { try {
App.MainDispatcher.Invoke(() => {
ProgressBar.Value = offset + 100.0 * i / 2 / totalNum;
});
if (doc.Type == DocType.Custom) { if (doc.Type == DocType.Custom) {
return [new GeneratedDoc((string)doc.Details!)]; return [new GeneratedDoc((string)doc.Details!)];
} else if (doc.Type == DocType.MemberDataSheet) { } else if (doc.Type == DocType.MemberDataSheet) {
return [new GeneratedDoc(new MemberDataSheet(m, ctx) { Date = postalDate })]; return [new GeneratedDoc(new MemberDataSheet(m) { Date = postalDate })];
} else if (doc.Type == DocType.DeliveryConfirmation) { } else if (doc.Type == DocType.DeliveryConfirmation) {
var year = (int)doc.Details!; var year = (int)doc.Details!;
DeliveryConfirmationDeliveryData data; DeliveryConfirmationDeliveryData data;
@@ -769,21 +759,14 @@ namespace Elwig.Windows {
} else { } else {
return []; return [];
} }
return [new GeneratedDoc(new DeliveryConfirmation(ctx, year, m, data) { Date = postalDate })]; return [new GeneratedDoc(new DeliveryConfirmation(year, m, postalDate, data) { Date = postalDate })];
} else if (doc.Type == DocType.CreditNote) { } else if (doc.Type == DocType.CreditNote) {
var details = ((int, int))doc.Details!; var details = ((int, int))doc.Details!;
var year = details.Item1; var year = details.Item1;
var avnr = details.Item2; var avnr = details.Item2;
var data = cnData[(year, avnr)]; var data = cnData[(year, avnr)];
try { try {
return [new GeneratedDoc(new CreditNote( return [new GeneratedDoc(new CreditNote(data.Item2[m.MgNr], postalDate, data.Item3, data.Item1[m.MgNr]) { Date = postalDate })];
ctx, data.Item2[m.MgNr], data.Item1[m.MgNr],
data.Item3.ConsiderContractPenalties,
data.Item3.ConsiderTotalPenalty,
data.Item3.ConsiderAutoBusinessShares,
data.Item3.ConsiderCustomModifiers,
ctx.GetMemberUnderDelivery(year, m.MgNr).GetAwaiter().GetResult()
) { Date = postalDate })];
} catch (Exception) { } catch (Exception) {
return []; return [];
} }
@@ -827,7 +810,7 @@ namespace Elwig.Windows {
var emailRecipients = email.Select(d => d.Key.MgNr).ToHashSet(); var emailRecipients = email.Select(d => d.Key.MgNr).ToHashSet();
foreach (var item1 in email.Select((e, i) => new { Index = i, e.Key, e.Value })) { foreach (var item1 in email.Select((e, i) => new { Index = i, e.Key, e.Value })) {
foreach (var item2 in item1.Value.Select((d, i) => new { Index = i, Doc = d })) { foreach (var item2 in item1.Value.Select((d, i) => new { Index = i, Doc = d })) {
await item2.Doc.Generate(CancelGeneration?.Token, new Progress<double>(v => App.MainDispatcher.Invoke(() => { await item2.Doc.Generate(ctx, CancelGeneration?.Token, new Progress<double>(v => App.MainDispatcher.Invoke(() => {
ProgressBar.Value = offset + v * (item2.Index + 1) / item1.Value.Count / totalNum + 100.0 * item1.Index / totalNum; ProgressBar.Value = offset + v * (item2.Index + 1) / item1.Value.Count / totalNum + 100.0 * item1.Index / totalNum;
}))); })));
} }
@@ -861,7 +844,7 @@ namespace Elwig.Windows {
if (printDocs.Count > 0) { if (printDocs.Count > 0) {
var print = Document.Merge(printDocs); var print = Document.Merge(printDocs);
await print.Generate(CancelGeneration?.Token, new Progress<double>(v => App.MainDispatcher.Invoke(() => { await print.Generate(ctx, CancelGeneration?.Token, new Progress<double>(v => App.MainDispatcher.Invoke(() => {
ProgressBar.Value = offset + v * printNum / totalNum; ProgressBar.Value = offset + v * printNum / totalNum;
}))); })));
PrintDocument = print; PrintDocument = print;
@@ -1014,7 +997,7 @@ namespace Elwig.Windows {
return; return;
var name = s.Split(" ")[^1]; var name = s.Split(" ")[^1];
using var ctx = new AppDbContext(); 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))); SelectedDocs.Add(new(DocType.CreditNote, s, (pv.Year, pv.AvNr)));
SelectedDocumentsList.SelectedIndex = SelectedDocs.Count - 1; SelectedDocumentsList.SelectedIndex = SelectedDocs.Count - 1;
RecipientsCreditMembersInput.IsChecked = true; RecipientsCreditMembersInput.IsChecked = true;

View File

@@ -5,7 +5,7 @@
xmlns:local="clr-namespace:Elwig.Windows" xmlns:local="clr-namespace:Elwig.Windows"
xmlns:ctrl="clr-namespace:Elwig.Controls" xmlns:ctrl="clr-namespace:Elwig.Controls"
Title="Elwig" Height="390" Width="520" ResizeMode="CanMinimize" Title="Elwig" Height="390" Width="520" ResizeMode="CanMinimize"
Loaded="Window_Loaded" Closing="Window_Closing"> Closing="Window_Closing">
<Window.Resources> <Window.Resources>
<Style TargetType="Button"> <Style TargetType="Button">
<Setter Property="VerticalAlignment" Value="Top"/> <Setter Property="VerticalAlignment" Value="Top"/>

View File

@@ -37,11 +37,11 @@ namespace Elwig.Windows {
SyncButton.Visibility = App.Config.SyncUrl != null ? Visibility.Visible : Visibility.Hidden; SyncButton.Visibility = App.Config.SyncUrl != null ? Visibility.Visible : Visibility.Hidden;
Menu_Database_Upload.IsEnabled = App.Config.SyncUrl != null; Menu_Database_Upload.IsEnabled = App.Config.SyncUrl != null;
Menu_Database_Download.IsEnabled = App.Config.SyncUrl != null; Menu_Database_Download.IsEnabled = App.Config.SyncUrl != null;
SeasonInput.Value = Utils.CurrentLastSeason;
} }
private void Window_Loaded(object sender, RoutedEventArgs evt) { protected override async Task OnInit(AppDbContext ctx) {
SeasonInput.Value = Utils.CurrentLastSeason; await base.OnInit(ctx);
if (Utils.HasInternetConnectivity()) { if (Utils.HasInternetConnectivity()) {
CheckSync(200); CheckSync(200);
} }
@@ -405,7 +405,7 @@ namespace Elwig.Windows {
private async void SeasonInput_TextChanged(object? sender, TextChangedEventArgs? evt) { private async void SeasonInput_TextChanged(object? sender, TextChangedEventArgs? evt) {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
var year = SeasonInput.Value; var year = SeasonInput.Value;
var s0 = await ctx.Seasons.FindAsync(year); var s0 = await ctx.FetchSeasons(year).SingleOrDefaultAsync();
var valid = (s0 != null); var valid = (s0 != null);
DeliveryConfirmationButton.IsEnabled = valid; DeliveryConfirmationButton.IsEnabled = valid;
PaymentButton.IsEnabled = valid; PaymentButton.IsEnabled = valid;
@@ -469,7 +469,7 @@ namespace Elwig.Windows {
Mouse.OverrideCursor = Cursors.Wait; Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => { await Task.Run(async () => {
try { try {
var b = new Billing(year); var b = await Billing.Create(year);
await b.FinishSeason(); await b.FinishSeason();
await b.CalculateBuckets(); await b.CalculateBuckets();
App.HintContextChange(); App.HintContextChange();
@@ -502,7 +502,7 @@ namespace Elwig.Windows {
Mouse.OverrideCursor = Cursors.Wait; Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => { await Task.Run(async () => {
try { try {
var b = new Billing(year); var b = await Billing.Create(year);
await b.FinishSeason(); await b.FinishSeason();
await b.CalculateBuckets(); await b.CalculateBuckets();
App.HintContextChange(); App.HintContextChange();
@@ -511,7 +511,7 @@ namespace Elwig.Windows {
using var ods = new OdsFile(d.FileName); using var ods = new OdsFile(d.FileName);
var tblTotal = await WeightBreakdownData.ForSeason(ctx.WeightBreakDownRows, year); var tblTotal = await WeightBreakdownData.ForSeason(ctx.WeightBreakDownRows, year);
await ods.AddTable(tblTotal); 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); var tbl = await WeightBreakdownData.ForSeason(ctx.WeightBreakDownRows, year, branch);
await ods.AddTable(tbl); await ods.AddTable(tbl);
} }
@@ -537,7 +537,7 @@ namespace Elwig.Windows {
Mouse.OverrideCursor = Cursors.Wait; Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => { await Task.Run(async () => {
try { try {
var b = new Billing(year); var b = await Billing.Create(year);
await b.FinishSeason(); await b.FinishSeason();
await b.CalculateBuckets(); await b.CalculateBuckets();
App.HintContextChange(); App.HintContextChange();
@@ -568,7 +568,7 @@ namespace Elwig.Windows {
Mouse.OverrideCursor = Cursors.Wait; Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => { await Task.Run(async () => {
try { try {
var b = new Billing(year); var b = await Billing.Create(year);
await b.FinishSeason(); await b.FinishSeason();
await b.CalculateBuckets(); await b.CalculateBuckets();
App.HintContextChange(); App.HintContextChange();

View File

@@ -5,8 +5,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Elwig.Windows" xmlns:local="clr-namespace:Elwig.Windows"
xmlns:vm="clr-namespace:Elwig.ViewModels" xmlns:vm="clr-namespace:Elwig.ViewModels"
Title="Mitglieder - Elwig" Height="700" Width="1250" MinHeight="650" MinWidth="1150" Title="Mitglieder - Elwig" Height="700" Width="1250" MinHeight="650" MinWidth="1150">
Loaded="Window_Loaded">
<Window.DataContext> <Window.DataContext>
<vm:MemberAdminViewModel/> <vm:MemberAdminViewModel/>
</Window.DataContext> </Window.DataContext>

View File

@@ -82,12 +82,9 @@ namespace Elwig.Windows {
Menu_Export_UploadFilters.IsEnabled = App.Config.SyncUrl != null; Menu_Export_UploadFilters.IsEnabled = App.Config.SyncUrl != null;
Menu_Export_UploadAll.IsEnabled = App.Config.SyncUrl != null; Menu_Export_UploadAll.IsEnabled = App.Config.SyncUrl != null;
}
private void Window_Loaded(object sender, RoutedEventArgs evt) {
ViewModel.ShowOnlyActiveMembers = true; ViewModel.ShowOnlyActiveMembers = true;
UpdateContactInfoVisibility(); UpdateContactInfoVisibility();
LockInputs();
} }
public void FocusMember(int mgnr) { public void FocusMember(int mgnr) {
@@ -113,17 +110,17 @@ namespace Elwig.Windows {
} }
private async Task RefreshList(bool updateSort = false) { private async Task RefreshList(bool updateSort = false) {
var vm = ViewModel;
var cursor = Mouse.OverrideCursor != null;
if (!cursor) Mouse.OverrideCursor = Cursors.Wait;
var query = (vm.SearchQuery, vm.ShowOnlyActiveMembers);
var (members, totalMemberCount, totalBusinessShares) = await Task.Run(async () => {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
var (_, memberQuery, filter) = await ViewModel.GetFilters(ctx); var (_, memberQuery, filter) = await vm.GetFilters(ctx);
var members = await memberQuery var members = await memberQuery
.Include(m => m.Branch)
.Include(m => m.DefaultWbKg!.AtKg)
.Include(m => m.EmailAddresses) .Include(m => m.EmailAddresses)
.Include(m => m.TelephoneNumbers) .Include(m => m.TelephoneNumbers)
.Include(m => m.PostalDest.AtPlz!.Ort) .AsSplitQuery()
.Include(m => m.PostalDest.AtPlz!.Country)
.Include(m => m.BillingAddress!.PostalDest.AtPlz!.Ort)
.Include(m => m.BillingAddress!.PostalDest.AtPlz!.Country)
.ToListAsync(); .ToListAsync();
if (filter.Count > 0 && members.Count > 0) { if (filter.Count > 0 && members.Count > 0) {
@@ -134,25 +131,31 @@ namespace Elwig.Windows {
.ThenBy(a => a.Key.GivenName) .ThenBy(a => a.Key.GivenName)
.ThenBy(a => a.Key.MgNr); .ThenBy(a => a.Key.MgNr);
var threshold = dict.Select(a => a.Value).Max() * 3 / 4; var threshold = dict.Select(a => a.Value).Max() * 3 / 4;
members = dict members = [.. dict
.Where(a => a.Value > threshold) .Where(a => a.Value > threshold)
.Select(a => a.Key) .Select(a => a.Key)];
.ToList();
} else { } else {
members = members members = [.. members
.OrderBy(m => m.Name) .OrderBy(m => m.Name)
.ThenBy(m => m.GivenName) .ThenBy(m => m.GivenName)
.ThenBy(m => m.MgNr) .ThenBy(m => m.MgNr)];
.ToList();
} }
var totalMemberCount = await ctx.Members.CountAsync();
var totalBusinessShares = await ctx.Members.SumAsync(m => m.BusinessShares);
return (members, totalMemberCount, totalBusinessShares);
});
if (!cursor) Mouse.OverrideCursor = null;
if (query != (ViewModel.SearchQuery, ViewModel.ShowOnlyActiveMembers)) return;
ControlUtils.RenewItemsSource(MemberList, members, ControlUtils.RenewItemsSource(MemberList, members,
MemberList_SelectionChanged, ViewModel.TextFilter.Count > 0 ? ControlUtils.RenewSourceDefault.IfOnly : ControlUtils.RenewSourceDefault.None, !updateSort); MemberList_SelectionChanged, ViewModel.TextFilter.Count > 0 ? ControlUtils.RenewSourceDefault.IfOnly : ControlUtils.RenewSourceDefault.None, !updateSort);
if (updateSort && MemberList.SelectedItem != null) if (updateSort && MemberList.SelectedItem != null)
MemberList.ScrollIntoView(MemberList.SelectedItem); MemberList.ScrollIntoView(MemberList.SelectedItem);
ViewModel.StatusMembers = $"{members.Count:N0} ({await ctx.Members.CountAsync():N0})"; ViewModel.StatusMembers = $"{members.Count:N0} ({totalMemberCount:N0})";
ViewModel.StatusBusinessShares = $"{members.Sum(m => m.BusinessShares):N0} ({await ctx.Members.SumAsync(m => m.BusinessShares):N0})"; ViewModel.StatusBusinessShares = $"{members.Sum(m => m.BusinessShares):N0} ({totalBusinessShares:N0})";
} }
private void RefreshInputs(bool validate = false) { private void RefreshInputs(bool validate = false) {
@@ -184,12 +187,12 @@ namespace Elwig.Windows {
protected override async Task OnRenewContext(AppDbContext ctx) { protected override async Task OnRenewContext(AppDbContext ctx) {
await base.OnRenewContext(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()); 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"); var font = new System.Windows.Media.FontFamily("Segoe MDL2 Assets");
MenuItem? temp = null; MenuItem? temp = null;
var seasons = await ctx.Seasons.OrderByDescending(s => s.Year).ToListAsync(); var seasons = await ctx.Seasons.Include(s => s.PaymentVariants).OrderByDescending(s => s.Year).ToListAsync();
Menu_DeliveryConfirmation.Items.Clear(); Menu_DeliveryConfirmation.Items.Clear();
foreach (var s in seasons) { foreach (var s in seasons) {
var i = new MenuItem { var i = new MenuItem {
@@ -328,6 +331,7 @@ namespace Elwig.Windows {
} }
private async void ActiveMemberInput_Changed(object sender, RoutedEventArgs evt) { private async void ActiveMemberInput_Changed(object sender, RoutedEventArgs evt) {
if (!HasContextLoaded) return;
await RefreshList(); await RefreshList();
} }
@@ -384,10 +388,9 @@ namespace Elwig.Windows {
int areaComs = 0, deliveries = 0, credits = 0; int areaComs = 0, deliveries = 0, credits = 0;
using (var ctx = new AppDbContext()) { using (var ctx = new AppDbContext()) {
var l = (await ctx.Members.FindAsync(m.MgNr))!; areaComs = await ctx.AreaCommitments.Where(c => c.MgNr == m.MgNr).CountAsync();
areaComs = l.AreaCommitments.Count; deliveries = await ctx.Deliveries.Where(d => d.MgNr == m.MgNr).CountAsync();
deliveries = l.Deliveries.Count; credits = await ctx.Credits.Where(c => c.MgNr == m.MgNr).CountAsync();
credits = l.Credits.Count;
} }
var d = new DeleteMemberDialog(m.MgNr, m.AdministrativeName, areaComs, deliveries, credits); var d = new DeleteMemberDialog(m.MgNr, m.AdministrativeName, areaComs, deliveries, credits);
if (d.ShowDialog() == true) { if (d.ShowDialog() == true) {
@@ -484,6 +487,7 @@ namespace Elwig.Windows {
} }
private async void SearchInput_TextChanged(object sender, RoutedEventArgs evt) { private async void SearchInput_TextChanged(object sender, RoutedEventArgs evt) {
if (!HasContextLoaded) return;
await RefreshList(true); await RefreshList(true);
} }
@@ -498,7 +502,9 @@ namespace Elwig.Windows {
try { try {
await Task.Run(async () => { await Task.Run(async () => {
using var doc = new Letterhead(m); using var doc = new Letterhead(m);
await doc.Generate(); using (var ctx = new AppDbContext()) {
await doc.Generate(ctx);
}
if (!App.Config.Debug) { if (!App.Config.Debug) {
await doc.Print(); await doc.Print();
} else { } else {
@@ -787,7 +793,7 @@ namespace Elwig.Windows {
if (areaComs.Count == 0) if (areaComs.Count == 0)
return; return;
var oldMember = (await ctx.Members.FindAsync(mgnr))!; var oldMember = await ctx.FetchMembers(mgnr).SingleAsync();
var newName = $"{ViewModel.Name?.Replace('ß', 'ẞ').ToUpper()} " + var newName = $"{ViewModel.Name?.Replace('ß', 'ẞ').ToUpper()} " +
$"{ViewModel.Prefix}{(!string.IsNullOrEmpty(ViewModel.Prefix) ? " " : "")}" + $"{ViewModel.Prefix}{(!string.IsNullOrEmpty(ViewModel.Prefix) ? " " : "")}" +
$"{ViewModel.GivenName}{(!string.IsNullOrEmpty(ViewModel.GivenName) ? " " : "")}" + $"{ViewModel.GivenName}{(!string.IsNullOrEmpty(ViewModel.GivenName) ? " " : "")}" +
@@ -796,7 +802,6 @@ namespace Elwig.Windows {
if (d.ShowDialog() != true) if (d.ShowDialog() != true)
return; return;
ViewModel.TransferPredecessorAreaComs = d.SuccessorSeason; ViewModel.TransferPredecessorAreaComs = d.SuccessorSeason;
ViewModel.MaintainAreaComYearFrom = d.MaintainYearFrom;
if (IsEditing) if (IsEditing)
SetOriginalValue(PredecessorMgNrInput, -1); // hack to allow user to save SetOriginalValue(PredecessorMgNrInput, -1); // hack to allow user to save
UpdateButtons(); UpdateButtons();

View File

@@ -21,12 +21,11 @@ namespace Elwig.Windows {
} }
protected override async Task OnRenewContext(AppDbContext ctx) { protected override async Task OnRenewContext(AppDbContext ctx) {
var origins = (await ctx.WineOrigins var origins = await ctx.WineOrigins
.Include("Gems.AtGem.Kgs.WbKg.Gl") .Include(o => o.Gems).ThenInclude(g => g.AtGem.Kgs).ThenInclude(k => k.WbKg!.Gl)
.AsSplitQuery() .ToListAsync();
.ToListAsync()) origins.ForEach(o => { origins.FirstOrDefault(p => p.HkId == o.ParentHkId)?.Children.Add(o); });
.OrderByDescending(o => o.SortKey) origins = [.. origins.OrderByDescending(o => o.SortKey).ThenBy(o => o.HkId)];
.ThenBy(o => o.HkId);
ControlUtils.RenewItemsSource(WineOrigins, origins, WineOrigins_SelectionChanged); ControlUtils.RenewItemsSource(WineOrigins, origins, WineOrigins_SelectionChanged);
if (WineOrigins.SelectedItem == null) { if (WineOrigins.SelectedItem == null) {
var hkid = await ctx.WbKgs var hkid = await ctx.WbKgs
@@ -39,8 +38,7 @@ namespace Elwig.Windows {
} }
var gls = await ctx.WbGls var gls = await ctx.WbGls
.OrderBy(g => g.GlNr) .OrderBy(g => g.GlNr)
.Include("Kgs.Rds") .Include(g => g.Kgs).ThenInclude(k => k.Rds)
.AsSplitQuery()
.ToListAsync(); .ToListAsync();
ControlUtils.RenewItemsSource(WbGls, gls, WbGls_SelectionChanged, ControlUtils.RenewSourceDefault.First); ControlUtils.RenewItemsSource(WbGls, gls, WbGls_SelectionChanged, ControlUtils.RenewSourceDefault.First);
UpdateWbGems(); UpdateWbGems();
@@ -100,8 +98,8 @@ namespace Elwig.Windows {
var allMembers = await ctx.Members.Where(m => m.DefaultKgNr == k.KgNr).CountAsync(); var allMembers = await ctx.Members.Where(m => m.DefaultKgNr == k.KgNr).CountAsync();
StatusDefaultKgs.Text += $"{activeMembers:N0} ({allMembers:N0})"; StatusDefaultKgs.Text += $"{activeMembers:N0} ({allMembers:N0})";
var year = Utils.CurrentNextSeason; var year = Utils.CurrentNextSeason;
var activeAreaComs = await Utils.ActiveAreaCommitments(ctx.AreaCommitments.Where(c => c.KgNr == k.KgNr), year).CountAsync(); var activeAreaComs = await Utils.ActiveAreaCommitments(ctx.AreaCommitments.Where(c => c.Contract.KgNr == k.KgNr), year).CountAsync();
var allAreaComs = await ctx.AreaCommitments.Where(c => c.KgNr == k.KgNr).CountAsync(); var allAreaComs = await ctx.AreaCommitments.Where(c => c.Contract.KgNr == k.KgNr).CountAsync();
StatusAreaCommitments.Text += $"{activeAreaComs:N0} ({allAreaComs:N0})"; StatusAreaCommitments.Text += $"{activeAreaComs:N0} ({allAreaComs:N0})";
var deliveryParts = await ctx.DeliveryParts.Where(p => p.KgNr == k.KgNr).CountAsync(); var deliveryParts = await ctx.DeliveryParts.Where(p => p.KgNr == k.KgNr).CountAsync();
var deliveries = await ctx.Deliveries.Where(d => d.Parts.Any(p => p.KgNr == k.KgNr)).CountAsync(); var deliveries = await ctx.Deliveries.Where(d => d.Parts.Any(p => p.KgNr == k.KgNr)).CountAsync();
@@ -214,7 +212,7 @@ namespace Elwig.Windows {
App.HintContextChange(); App.HintContextChange();
ControlUtils.SelectItemWithPk(WbKgs, k.KgNr); ControlUtils.SelectItemWithPk(WbKgs, k.KgNr);
} catch (Exception exc) { } catch (Exception exc) {
await HintContextChange(); await ForceContextReload();
var str = "Der Eintrag konnte nicht aus der Datenbank gelöscht werden!\n\n" + exc.Message; 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; if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Katastralgemeinde deaktivieren", MessageBoxButton.OK, MessageBoxImage.Error); 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) { protected override async Task OnRenewContext(AppDbContext ctx) {
var members = await ctx.Members var members = await ctx.FetchMembers(includeNotActive: true)
.Select(m => new { .Select(m => new {
m.MgNr, m.MgNr,
m.Name, m.Name,
@@ -48,11 +48,8 @@ namespace Elwig.Windows {
m.BusinessShares, m.BusinessShares,
m.IsActive, m.IsActive,
}) })
.OrderBy(m => m.Name)
.ThenBy(m => m.GivenName)
.ThenBy(m => m.MgNr)
.ToListAsync(); .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 contracts = await ctx.AreaCommitmentTypes.ToDictionaryAsync(t => t.VtrgId, t => t);
var tbl1 = await OverUnderDeliveryData.ForSeason(ctx.OverUnderDeliveryRows, Year); 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}"; 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}"; NonDeliveries.Text = $"{list.Count(r => r.Weight == 0):N0}";
ControlUtils.RenewItemsSource(MemberInput, await ctx.Members ControlUtils.RenewItemsSource(MemberInput, await ctx.FetchMembers(includeNotActive: true).ToListAsync());
.OrderBy(m => m.Name)
.ThenBy(m => m.GivenName)
.ThenBy(m => m.MgNr)
.ToListAsync());
CustomAmountInput.Unit = sym; CustomAmountInput.Unit = sym;
} }
@@ -170,7 +163,7 @@ namespace Elwig.Windows {
await Task.Run(async () => { await Task.Run(async () => {
await App.Client.UpdateValues(); 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); await b.AutoAdjustBusinessShares(new DateOnly(Year, 11, 30), kg ?? default, bs ?? default, kgPerBs ?? default, percent / 100.0 ?? default, minBs ?? default);
}); });
App.HintContextChange(); App.HintContextChange();
@@ -186,7 +179,7 @@ namespace Elwig.Windows {
Mouse.OverrideCursor = Cursors.Wait; Mouse.OverrideCursor = Cursors.Wait;
try { try {
await Task.Run(async () => { await Task.Run(async () => {
var b = new Billing(Year); var b = await Billing.Create(Year);
await b.UnAdjustBusinessShares(); await b.UnAdjustBusinessShares();
}); });
App.HintContextChange(); App.HintContextChange();

View File

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

View File

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

View File

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

View File

@@ -1,8 +1,9 @@
<Project Sdk="WixToolset.Sdk/6"> <Project Sdk="WixToolset.Sdk/7">
<PropertyGroup> <PropertyGroup>
<OutputType>Bundle</OutputType> <OutputType>Bundle</OutputType>
<OutputName>Elwig</OutputName> <OutputName>Elwig</OutputName>
<Cultures>de-AT</Cultures> <Cultures>de-AT</Cultures>
<AcceptEula>wix7</AcceptEula>
</PropertyGroup> </PropertyGroup>
<Target Name="CustomBeforeBuild" BeforeTargets="BeforeBuild"> <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;" /> <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> </Target>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Installer\Installer.wixproj" /> <ProjectReference Include="..\Installer\Installer.wixproj" />
<PackageReference Include="WixToolset.Bal.wixext" Version="6.0.2" /> <PackageReference Include="WixToolset.Bal.wixext" Version="7.0.0" />
<PackageReference Include="WixToolset.Util.wixext" Version="6.0.2" /> <PackageReference Include="WixToolset.Util.wixext" Version="7.0.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -2,6 +2,7 @@ using Elwig;
using Elwig.Helpers; using Elwig.Helpers;
using Elwig.Helpers.Billing; using Elwig.Helpers.Billing;
using Microsoft.Data.Sqlite; using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using System.Reflection; using System.Reflection;
namespace Tests { namespace Tests {
@@ -22,7 +23,7 @@ namespace Tests {
public void Setup_2_Client() { public void Setup_2_Client() {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
App.Client = new ClientParameters(ctx); App.Client = new ClientParameters(ctx);
App.SetBranch(ctx.Branches.Single()); App.SetBranch(ctx.Branches.Include(b => b.PostalDest).Single());
} }
[OneTimeSetUp] [OneTimeSetUp]

View File

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

View File

@@ -3,7 +3,7 @@
DELETE FROM credit; DELETE FROM credit;
DELETE FROM payment_variant; DELETE FROM payment_variant;
DELETE FROM delivery; DELETE FROM delivery;
DELETE FROM area_commitment; DELETE FROM area_commitment_contract;
DELETE FROM area_commitment_type; DELETE FROM area_commitment_type;
DELETE FROM season; DELETE FROM season;
DELETE FROM wine_attribute; DELETE FROM wine_attribute;

View File

@@ -22,10 +22,15 @@ INSERT INTO area_commitment_type (vtrgid, sortid, attrid, disc, min_kg_per_ha, p
('GVQ', 'GV', 'Q', NULL, 5000, 1000, 1000000, NULL), ('GVQ', 'GV', 'Q', NULL, 5000, 1000, 1000000, NULL),
('GVR', 'GV', 'R', NULL, 5000, 1000, 1000000, NULL); ('GVR', 'GV', 'R', NULL, 5000, 1000, 1000000, NULL);
INSERT INTO area_commitment (fbnr, mgnr, vtrgid, cultid, area, kgnr, gstnr, rdnr, year_from, year_to) VALUES INSERT INTO area_commitment_contract (fbnr, kgnr, rdnr) VALUES
( 1, 101, 'GV', 'KIP', 10000, 06109, '123/4', NULL, 2000, 2019), ( 1, 06109, NULL),
( 2, 101, 'GV', 'KIP', 10000, 06109, '123/5', NULL, 2025, 2030), ( 2, 06109, NULL),
( 3, 101, 'GV', 'KIP', 10000, 06109, '123/6', NULL, 2021, 2031); ( 3, 06109, NULL);
INSERT INTO area_commitment (fbnr, revnr, mgnr, vtrgid, cultid, area, gstnr, year_from, year_to) VALUES
( 1, 1, 101, 'GV', 'KIP', 10000, '123/4', 2000, 2019),
( 2, 1, 101, 'GV', 'KIP', 10000, '123/5', 2025, 2030),
( 3, 1, 101, 'GV', 'KIP', 10000, '123/6', 2021, 2031);
INSERT INTO season (year, currency, min_kg_per_bs, max_kg_per_bs, penalty_per_kg, penalty_amount, penalty_none, start_date, end_date) VALUES INSERT INTO season (year, currency, min_kg_per_bs, max_kg_per_bs, penalty_per_kg, penalty_amount, penalty_none, start_date, end_date) VALUES
(2020, 'EUR', 1000, 2000, NULL, NULL, NULL, NULL, NULL), (2020, 'EUR', 1000, 2000, NULL, NULL, NULL, NULL, NULL),

View File

@@ -64,6 +64,10 @@ INSERT INTO delivery_part (year, did, dpnr, sortid, attrid, cultid, weight, kmw,
(2020, 12, 1, 'BP', NULL, NULL, 2410, 18.0, 'KAB', 'WLNO', 15224, TRUE, FALSE, FALSE, NULL, NULL, NULL), (2020, 12, 1, 'BP', NULL, NULL, 2410, 18.0, 'KAB', 'WLNO', 15224, TRUE, FALSE, FALSE, NULL, NULL, NULL),
(2020, 12, 2, 'BP', NULL, NULL, 2313, 18.1, 'KAB', 'WLNO', 15224, TRUE, FALSE, FALSE, NULL, NULL, NULL); (2020, 12, 2, 'BP', NULL, NULL, 2313, 18.1, 'KAB', 'WLNO', 15224, TRUE, FALSE, FALSE, NULL, NULL, NULL);
INSERT INTO delivery_part_modifier (year, did, dpnr, modid) VALUES
(2020, 2, 1, 'S'),
(2020, 2, 2, 'A');
INSERT INTO delivery_part_bucket (year, did, dpnr, bktnr, discr, value) VALUES INSERT INTO delivery_part_bucket (year, did, dpnr, bktnr, discr, value) VALUES
(2020, 1, 1, 0, '_', 3219), (2020, 1, 1, 0, '_', 3219),
(2020, 3, 1, 0, '_', 2561), (2020, 3, 1, 0, '_', 2561),

View File

@@ -4,7 +4,7 @@ DELETE FROM credit;
DELETE FROM payment_variant; DELETE FROM payment_variant;
DELETE FROM delivery; DELETE FROM delivery;
DELETE FROM season; DELETE FROM season;
DELETE FROM area_commitment; DELETE FROM area_commitment_contract;
DELETE FROM area_commitment_type; DELETE FROM area_commitment_type;
DELETE FROM member WHERE mgnr >= 200; DELETE FROM member WHERE mgnr >= 200;
DELETE FROM wine_cultivation; DELETE FROM wine_cultivation;

View File

@@ -29,11 +29,17 @@ INSERT INTO member_email_address (mgnr, nr, address, comment) VALUES
INSERT INTO area_commitment_type (vtrgid, sortid, attrid, disc, min_kg_per_ha, penalty_per_kg, penalty_amount, penalty_none) VALUES INSERT INTO area_commitment_type (vtrgid, sortid, attrid, disc, min_kg_per_ha, penalty_per_kg, penalty_amount, penalty_none) VALUES
('GV', 'GV', NULL, NULL, 5000, 500, NULL, NULL); ('GV', 'GV', NULL, NULL, 5000, 500, NULL, NULL);
INSERT INTO area_commitment (fbnr, mgnr, vtrgid, cultid, area, kgnr, gstnr, rdnr, year_from, year_to) VALUES INSERT INTO area_commitment_contract (fbnr, kgnr, rdnr) VALUES
( 1, 203, 'GV', NULL, 10000, 15224, '321/9', NULL, NULL, NULL), ( 1, 15224, NULL),
( 2, 204, 'GV', NULL, 10000, 15224, '123/1', NULL, 2000, 2019), ( 2, 15224, NULL),
( 3, 204, 'GV', NULL, 10000, 15224, '123/2', NULL, 2025, 2030), ( 3, 15224, NULL),
( 4, 204, 'GV', NULL, 10000, 15224, '123/3', NULL, 2021, 2031); ( 4, 15224, NULL);
INSERT INTO area_commitment (fbnr, revnr, mgnr, vtrgid, cultid, area, gstnr, year_from, year_to) VALUES
( 1, 1, 203, 'GV', NULL, 10000, '321/9', NULL, NULL),
( 2, 1, 204, 'GV', NULL, 10000, '123/1', 2000, 2019),
( 3, 1, 204, 'GV', NULL, 10000, '123/2', 2025, 2030),
( 4, 1, 204, 'GV', NULL, 10000, '123/3', 2021, 2031);
INSERT INTO season (year, currency, min_kg_per_bs, max_kg_per_bs, penalty_per_kg, penalty_amount, penalty_none, start_date, end_date) VALUES INSERT INTO season (year, currency, min_kg_per_bs, max_kg_per_bs, penalty_per_kg, penalty_amount, penalty_none, start_date, end_date) VALUES

View File

@@ -19,7 +19,7 @@
</Target> </Target>
<ItemGroup> <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="Appium.WebDriver" Version="4.4.5" />
<PackageReference Include="NReco.PdfRenderer" Version="1.6.0" /> <PackageReference Include="NReco.PdfRenderer" Version="1.6.0" />
<PackageReference Include="NUnit" Version="4.5.1" /> <PackageReference Include="NUnit" Version="4.5.1" />

View File

@@ -1,7 +1,4 @@
using Elwig.Documents; using Elwig.Documents;
using Elwig.Helpers;
using Elwig.Models.Dtos;
using Microsoft.EntityFrameworkCore;
namespace Tests.UnitTests.DocumentTests { namespace Tests.UnitTests.DocumentTests {
[TestFixture] [TestFixture]
@@ -9,12 +6,7 @@ namespace Tests.UnitTests.DocumentTests {
[Test] [Test]
public async Task Test_01_VirtualCreditNote() { public async Task Test_01_VirtualCreditNote() {
using var ctx = new AppDbContext(); using var doc = await CreditNote.Initialize(2020, 1, 101, null);
var m = await ctx.Members.FindAsync(101);
var p = await ctx.MemberPayments.Where(p => p.Year == 2020 && p.AvNr == 1).SingleAsync();
var data = await CreditNoteDeliveryData.ForPaymentVariant(ctx.CreditNoteDeliveryRows, ctx.PaymentVariants, 2020, 1);
using var doc = new CreditNote(ctx, p, data[m!.MgNr], false, false, false, false,
ctx.GetMemberUnderDelivery(2020, m!.MgNr).GetAwaiter().GetResult());
var text = await Utils.GeneratePdfText(doc); var text = await Utils.GeneratePdfText(doc);
Assert.Multiple(() => { Assert.Multiple(() => {
Assert.That(text, Contains.Substring(""" Assert.That(text, Contains.Substring("""

View File

@@ -9,9 +9,9 @@ namespace Tests.UnitTests.DocumentTests {
[Test] [Test]
public async Task Test_01_SimpleDeliveryConfirmation() { public async Task Test_01_SimpleDeliveryConfirmation() {
using var ctx = new AppDbContext(); 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!); var data = await DeliveryConfirmationDeliveryData.ForMember(ctx.DeliveryParts, 2020, m!);
using var doc = new DeliveryConfirmation(ctx, 2020, m!, data); using var doc = new DeliveryConfirmation(2020, m!, null, data);
var text = await Utils.GeneratePdfText(doc); var text = await Utils.GeneratePdfText(doc);
Assert.Multiple(() => { Assert.Multiple(() => {
Assert.That(text, Contains.Substring(""" Assert.That(text, Contains.Substring("""

View File

@@ -1,5 +1,4 @@
using Elwig.Documents; using Elwig.Documents;
using Elwig.Helpers;
namespace Tests.UnitTests.DocumentTests { namespace Tests.UnitTests.DocumentTests {
[TestFixture] [TestFixture]
@@ -7,9 +6,7 @@ namespace Tests.UnitTests.DocumentTests {
[Test] [Test]
public async Task Test_01_OneDeliveryPart() { public async Task Test_01_OneDeliveryPart() {
using var ctx = new AppDbContext(); using var doc = await DeliveryNote.Initialize(2020, 1);
var d = await ctx.Deliveries.FindAsync(2020, 1);
using var doc = new DeliveryNote(d!, ctx);
var text = await Utils.GeneratePdfText(doc); var text = await Utils.GeneratePdfText(doc);
Assert.Multiple(() => { Assert.Multiple(() => {
Assert.That(text, Contains.Substring(""" Assert.That(text, Contains.Substring("""
@@ -19,7 +16,7 @@ namespace Tests.UnitTests.DocumentTests {
""")); """));
Assert.That(text, Contains.Substring("0123463")); // Betriebsnummer Assert.That(text, Contains.Substring("0123463")); // Betriebsnummer
Assert.That(text, Contains.Substring("pauschaliert")); Assert.That(text, Contains.Substring("pauschaliert"));
Assert.That(text, Contains.Substring($"Wolkersdorf, am {Elwig.Helpers.Utils.Today:dd.MM.yyyy}")); Assert.That(text, Contains.Substring($"Wolkersdorf, am {DateTime.Now:dd.MM.yyyy}"));
Assert.That(text, Contains.Substring("Traubenübernahmeschein Nr. 20201001X001")); Assert.That(text, Contains.Substring("Traubenübernahmeschein Nr. 20201001X001"));
Assert.That(text, Contains.Substring("Das Mitglied erklärt, dass die gelieferte Ware dem österreichischen Weingesetz entspricht")); Assert.That(text, Contains.Substring("Das Mitglied erklärt, dass die gelieferte Ware dem österreichischen Weingesetz entspricht"));
Assert.That(text, Contains.Substring(""" Assert.That(text, Contains.Substring("""
@@ -34,9 +31,7 @@ namespace Tests.UnitTests.DocumentTests {
[Test] [Test]
public async Task Test_02_TwoDeliveryParts() { public async Task Test_02_TwoDeliveryParts() {
using var ctx = new AppDbContext(); using var doc = await DeliveryNote.Initialize(2020, 4);
var d = await ctx.Deliveries.FindAsync(2020, 4);
using var doc = new DeliveryNote(d!, ctx);
var text = await Utils.GeneratePdfText(doc); var text = await Utils.GeneratePdfText(doc);
Assert.Multiple(() => { Assert.Multiple(() => {
Assert.That(text, Contains.Substring(""" Assert.That(text, Contains.Substring("""
@@ -47,7 +42,7 @@ namespace Tests.UnitTests.DocumentTests {
""")); """));
Assert.That(text, Contains.Substring("0123471")); // Betriebsnummer Assert.That(text, Contains.Substring("0123471")); // Betriebsnummer
Assert.That(text, Contains.Substring("pauschaliert")); Assert.That(text, Contains.Substring("pauschaliert"));
Assert.That(text, Contains.Substring($"Wolkersdorf, am {Elwig.Helpers.Utils.Today:dd.MM.yyyy}")); Assert.That(text, Contains.Substring($"Wolkersdorf, am {DateTime.Now:dd.MM.yyyy}"));
Assert.That(text, Contains.Substring("Traubenübernahmeschein Nr. 20201001X004")); Assert.That(text, Contains.Substring("Traubenübernahmeschein Nr. 20201001X004"));
Assert.That(text, Contains.Substring("Das Mitglied erklärt, dass die gelieferte Ware dem österreichischen Weingesetz entspricht")); Assert.That(text, Contains.Substring("Das Mitglied erklärt, dass die gelieferte Ware dem österreichischen Weingesetz entspricht"));
Assert.That(text, Contains.Substring(""" Assert.That(text, Contains.Substring("""
@@ -68,9 +63,7 @@ namespace Tests.UnitTests.DocumentTests {
[Test] [Test]
public async Task Test_03_DeliveryPartsWithAttribute() { public async Task Test_03_DeliveryPartsWithAttribute() {
using var ctx = new AppDbContext(); using var doc = await DeliveryNote.Initialize(2020, 3);
var d = await ctx.Deliveries.FindAsync(2020, 3);
using var doc = new DeliveryNote(d!, ctx);
var text = await Utils.GeneratePdfText(doc); var text = await Utils.GeneratePdfText(doc);
Assert.Multiple(() => { Assert.Multiple(() => {
Assert.That(text, Contains.Substring(""" Assert.That(text, Contains.Substring("""
@@ -80,7 +73,7 @@ namespace Tests.UnitTests.DocumentTests {
""")); """));
Assert.That(text, Contains.Substring("0123463")); // Betriebsnummer Assert.That(text, Contains.Substring("0123463")); // Betriebsnummer
Assert.That(text, Contains.Substring("pauschaliert")); Assert.That(text, Contains.Substring("pauschaliert"));
Assert.That(text, Contains.Substring($"Wolkersdorf, am {Elwig.Helpers.Utils.Today:dd.MM.yyyy}")); Assert.That(text, Contains.Substring($"Wolkersdorf, am {DateTime.Now:dd.MM.yyyy}"));
Assert.That(text, Contains.Substring("Traubenübernahmeschein Nr. 20201001X003")); Assert.That(text, Contains.Substring("Traubenübernahmeschein Nr. 20201001X003"));
Assert.That(text, Contains.Substring("Das Mitglied erklärt, dass die gelieferte Ware dem österreichischen Weingesetz entspricht")); Assert.That(text, Contains.Substring("Das Mitglied erklärt, dass die gelieferte Ware dem österreichischen Weingesetz entspricht"));
Assert.That(text, Contains.Substring(""" Assert.That(text, Contains.Substring("""
@@ -107,9 +100,7 @@ namespace Tests.UnitTests.DocumentTests {
[Test] [Test]
public async Task Test_04_DeliveryPartsWithCultivation() { public async Task Test_04_DeliveryPartsWithCultivation() {
using var ctx = new AppDbContext(); using var doc = await DeliveryNote.Initialize(2020, 7);
var d = await ctx.Deliveries.FindAsync(2020, 7);
using var doc = new DeliveryNote(d!, ctx);
var text = await Utils.GeneratePdfText(doc); var text = await Utils.GeneratePdfText(doc);
Assert.Multiple(() => { Assert.Multiple(() => {
Assert.That(text, Contains.Substring(""" Assert.That(text, Contains.Substring("""
@@ -119,7 +110,7 @@ namespace Tests.UnitTests.DocumentTests {
""")); """));
Assert.That(text, Contains.Substring("0123480")); // Betriebsnummer Assert.That(text, Contains.Substring("0123480")); // Betriebsnummer
Assert.That(text, Contains.Substring("pauschaliert")); Assert.That(text, Contains.Substring("pauschaliert"));
Assert.That(text, Contains.Substring($"Wolkersdorf, am {Elwig.Helpers.Utils.Today:dd.MM.yyyy}")); Assert.That(text, Contains.Substring($"Wolkersdorf, am {DateTime.Now:dd.MM.yyyy}"));
Assert.That(text, Contains.Substring("Traubenübernahmeschein Nr. 20201002X001")); Assert.That(text, Contains.Substring("Traubenübernahmeschein Nr. 20201002X001"));
Assert.That(text, Contains.Substring("Das Mitglied erklärt, dass die gelieferte Ware dem österreichischen Weingesetz entspricht")); Assert.That(text, Contains.Substring("Das Mitglied erklärt, dass die gelieferte Ware dem österreichischen Weingesetz entspricht"));
Assert.That(text, Contains.Substring(""" Assert.That(text, Contains.Substring("""
@@ -139,5 +130,37 @@ namespace Tests.UnitTests.DocumentTests {
Assert.That(text, Contains.Substring("Gesamt: 78 15,9 5 332")); Assert.That(text, Contains.Substring("Gesamt: 78 15,9 5 332"));
}); });
} }
[Test]
public async Task Test_05_DeliveryPartsWithModifier() {
using var doc = await DeliveryNote.Initialize(2020, 2);
var text = await Utils.GeneratePdfText(doc);
Assert.Multiple(() => {
Assert.That(text, Contains.Substring("""
W&B Weinbauer GesbR
WEINBAUER Wernhardt
Winzerstraße 2
2223 Hohenruppersdorf
"""));
Assert.That(text, Contains.Substring("0123471")); // Betriebsnummer
Assert.That(text, Contains.Substring("pauschaliert"));
Assert.That(text, Contains.Substring($"Wolkersdorf, am {DateTime.Now:dd.MM.yyyy}"));
Assert.That(text, Contains.Substring("Traubenübernahmeschein Nr. 20201001X002"));
Assert.That(text, Contains.Substring("Das Mitglied erklärt, dass die gelieferte Ware dem österreichischen Weingesetz entspricht"));
Assert.That(text, Contains.Substring("""
1 Grüner Veltliner Kabinett Kabinett 86 17,5 2 987
Herkunft: Österreich / Weinland / Niederösterreich
/ Matzner Hügel / Hohenruppersdorf / KG Hohenruppersdorf
Zu-/Abschläge: Geschädigte Trauben 10,00 %
Waage: ?, ID: ? (gerebelt gewogen)
2 Grüner Veltliner Kabinett Kabinett 87 17,7 1 873
Herkunft: Österreich / Weinland / Niederösterreich
/ Matzner Hügel / Hohenruppersdorf / KG Hohenruppersdorf
Zu-/Abschläge: Keine Voranmeldung 0,1000 /kg
Waage: ?, ID: ? (gerebelt gewogen)
Gesamt: 87 17,6 4 860
"""));
});
}
} }
} }

View File

@@ -8,7 +8,7 @@ namespace Tests.UnitTests.DocumentTests {
[Test] [Test]
public async Task Test_01_SimpleLetterhead() { public async Task Test_01_SimpleLetterhead() {
using var ctx = new AppDbContext(); 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!); using var doc = new Letterhead(m!);
var text = await Utils.GeneratePdfText(doc); var text = await Utils.GeneratePdfText(doc);
Assert.Multiple(() => { Assert.Multiple(() => {

View File

@@ -1,5 +1,4 @@
using Elwig.Documents; using Elwig.Documents;
using Elwig.Helpers;
namespace Tests.UnitTests.DocumentTests { namespace Tests.UnitTests.DocumentTests {
[TestFixture] [TestFixture]
@@ -7,9 +6,7 @@ namespace Tests.UnitTests.DocumentTests {
[Test] [Test]
public async Task Test_01_SimpleMember() { public async Task Test_01_SimpleMember() {
using var ctx = new AppDbContext(); using var doc = await MemberDataSheet.Initialize(104);
var m = await ctx.Members.FindAsync(104);
using var doc = new MemberDataSheet(m!, ctx);
var text = await Utils.GeneratePdfText(doc); var text = await Utils.GeneratePdfText(doc);
Assert.Multiple(() => { Assert.Multiple(() => {
Assert.That(text, Contains.Substring(""" Assert.That(text, Contains.Substring("""

View File

@@ -1,6 +1,4 @@
using Elwig.Documents; using Elwig.Documents;
using Elwig.Helpers;
using Elwig.Models.Dtos;
namespace Tests.UnitTests.DocumentTests { namespace Tests.UnitTests.DocumentTests {
[TestFixture] [TestFixture]
@@ -8,16 +6,13 @@ namespace Tests.UnitTests.DocumentTests {
[Test] [Test]
public async Task Test_01_PaymentVariant2020() { public async Task Test_01_PaymentVariant2020() {
using var ctx = new AppDbContext(); using var doc = await PaymentVariantSummary.Initialize(2020, 1);
var v = (await ctx.PaymentVariants.FindAsync(2020, 1))!;
var data = await PaymentVariantSummaryData.ForPaymentVariant(v, ctx.PaymentVariantSummaryRows);
using var doc = new PaymentVariantSummary(v, data);
var text = await Utils.GeneratePdfText(doc, true); var text = await Utils.GeneratePdfText(doc, true);
var table = Utils.ExtractTable(text); var table = Utils.ExtractTable(text);
Assert.Multiple(() => { Assert.Multiple(() => {
Assert.That(text, Contains.Substring("Auszahlungsvariante")); Assert.That(text, Contains.Substring("Auszahlungsvariante"));
Assert.That(text, Contains.Substring(v.Name)); Assert.That(text, Contains.Substring(doc.Variant.Name));
Assert.That(table.Skip(17).ToArray(), Is.EqualTo(new string[][] { Assert.That(table.Skip(19).ToArray(), Is.EqualTo(new string[][] {
["Sorte/Attr./Bewirt.", "Gradation", "ungebunden", "attributlos gebunden", "gebunden", "Gesamt" ], ["Sorte/Attr./Bewirt.", "Gradation", "ungebunden", "attributlos gebunden", "gebunden", "Gesamt" ],
["Qualitätsstufe", "[°Oe]", "[kg]", "[/kg]", "[kg]", "[/kg]", "[kg]", "[/kg]", "[]" ], ["Qualitätsstufe", "[°Oe]", "[kg]", "[/kg]", "[kg]", "[/kg]", "[kg]", "[/kg]", "[]" ],
["Grüner Veltliner", "3 219", "0", "0", "1 609,50"], ["Grüner Veltliner", "3 219", "0", "0", "1 609,50"],

View File

@@ -1,4 +1,5 @@
using Elwig.Documents; using Elwig.Documents;
using Elwig.Helpers;
using NReco.PdfRenderer; using NReco.PdfRenderer;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
@@ -8,7 +9,9 @@ namespace Tests.UnitTests.DocumentTests {
private static readonly string FileName = Path.Combine(Path.GetTempPath(), "test_document.pdf"); private static readonly string FileName = Path.Combine(Path.GetTempPath(), "test_document.pdf");
public static async Task<string> GeneratePdfText(Document doc, bool preserveLayout = false) { public static async Task<string> GeneratePdfText(Document doc, bool preserveLayout = false) {
await doc.Generate(); using (var ctx = new AppDbContext()) {
await doc.Generate(ctx);
}
try { try {
doc.SaveTo(FileName); doc.SaveTo(FileName);
var conv = new PdfToTextConverter { CustomArgs = preserveLayout ? "-layout " : "-raw " }; var conv = new PdfToTextConverter { CustomArgs = preserveLayout ? "-layout " : "-raw " };

View File

@@ -135,7 +135,7 @@ namespace Tests.UnitTests.HelperTests {
Assert.That(delivery["GVK"], Is.EqualTo( 4_000)); 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); await b.CalculateBuckets(false, false, false);
var payment = await GetMemberPaymentBuckets(year, mgnr); var payment = await GetMemberPaymentBuckets(year, mgnr);
Assert.Multiple(() => { Assert.Multiple(() => {
@@ -179,7 +179,7 @@ namespace Tests.UnitTests.HelperTests {
Assert.That(delivery["GVK"], Is.EqualTo( 4_000)); 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); await b.CalculateBuckets(false, false, false, Connection);
var payment = await GetMemberPaymentBuckets(year, mgnr); var payment = await GetMemberPaymentBuckets(year, mgnr);
Assert.Multiple(() => { Assert.Multiple(() => {
@@ -225,7 +225,7 @@ namespace Tests.UnitTests.HelperTests {
Assert.That(delivery["GVK"], Is.EqualTo( 4_000)); 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); await b.CalculateBuckets(true, false, false, Connection);
var payment = await GetMemberPaymentBuckets(year, mgnr); var payment = await GetMemberPaymentBuckets(year, mgnr);
Assert.Multiple(() => { Assert.Multiple(() => {

View File

@@ -33,7 +33,7 @@ namespace Tests.UnitTests.HelperTests {
DateString = "2021-01-31", DateString = "2021-01-31",
}; };
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
var members = ctx.Members.ToList(); var members = await ctx.FetchMembers().ToListAsync();
Assert.That(members, Has.Count.GreaterThan(0)); Assert.That(members, Has.Count.GreaterThan(0));
using var exporter = new Ebics(v, FileName, version, mode); using var exporter = new Ebics(v, FileName, version, mode);
await exporter.ExportAsync(members.Select(m => new Transaction(m, 1234.56m, "EUR", m.MgNr % 100))); 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) { private static async Task InitViewModel(DeliveryAdminViewModel vm) {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
vm.MemberSource = await ctx.Members.ToListAsync(); vm.MemberSource = await ctx.FetchMembers(includeNotActive: true).ToListAsync();
vm.BranchSource = await ctx.Branches.ToListAsync(); vm.BranchSource = await ctx.FetchBranches().ToListAsync();
vm.WineVarSource = await ctx.WineVarieties.ToListAsync(); vm.WineVarSource = await ctx.FetchWineVarieties().ToListAsync();
List<object> attrs = (await ctx.WineAttributes.ToListAsync()).Cast<object>().ToList(); List<object> attrs = await ctx.FetchWineAttributes().Cast<object>().ToListAsync();
attrs.Insert(0, new NullItem()); attrs.Insert(0, new NullItem());
vm.WineAttrSource = attrs; 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()); cults.Insert(0, new NullItem());
vm.WineCultSource = cults; vm.WineCultSource = cults;
vm.WineQualityLevelSource = await ctx.WineQualityLevels.ToListAsync(); vm.WineQualityLevelSource = await ctx.FetchWineQualityLevels().ToListAsync();
vm.WineOriginSource = await ctx.WineOrigins.ToListAsync(); vm.WineOriginSource = await ctx.WineOrigins.ToListAsync();
vm.WineKgSource = await ctx.Katastralgemeinden.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) { private static async Task<Delivery?> GetDelivery(string lsnr) {
@@ -32,7 +32,6 @@ namespace Tests.UnitTests.ServiceTests {
.Include(d => d.Parts) .Include(d => d.Parts)
.ThenInclude(p => p.PartModifiers) .ThenInclude(p => p.PartModifiers)
.ThenInclude(m => m.Modifier) .ThenInclude(m => m.Modifier)
.AsSplitQuery()
.FirstOrDefaultAsync(); .FirstOrDefaultAsync();
} }

View File

@@ -10,10 +10,10 @@ namespace Tests.UnitTests.ServiceTests {
private static async Task InitViewModel(MemberAdminViewModel vm) { private static async Task InitViewModel(MemberAdminViewModel vm) {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
vm.BranchSource = await ctx.Branches.ToListAsync(); vm.BranchSource = await ctx.FetchBranches().ToListAsync();
vm.DefaultKgSource = await ctx.Katastralgemeinden.ToListAsync(); vm.DefaultKgSource = await ctx.Katastralgemeinden.ToListAsync();
vm.OrtSource = await ctx.PlzDestinations.Include(p => p.Ort).ToListAsync(); vm.OrtSource = await ctx.PlzDestinations.ToListAsync();
vm.BillingOrtSource = await ctx.PlzDestinations.Include(p => p.Ort).ToListAsync(); vm.BillingOrtSource = await ctx.PlzDestinations.ToListAsync();
} }
[Test] [Test]
@@ -31,22 +31,14 @@ namespace Tests.UnitTests.ServiceTests {
Assert.That(vm.MgNr, Is.EqualTo(205)); Assert.That(vm.MgNr, Is.EqualTo(205));
using (var ctx = new AppDbContext()) { 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)); Assert.DoesNotThrowAsync(async () => await vm.UpdateMember(null));
Member? m; Member m;
using (var ctx = new AppDbContext()) { using (var ctx = new AppDbContext()) {
m = await ctx.Members m = await ctx.FetchMembers(vm.MgNr, includeNotActive: true, includeContactInfo: true).SingleAsync();
.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();
} }
Assert.That(m, Is.Not.Null); Assert.That(m, Is.Not.Null);
@@ -119,22 +111,14 @@ namespace Tests.UnitTests.ServiceTests {
vm.IsFunktionär = true; vm.IsFunktionär = true;
using (var ctx = new AppDbContext()) { 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)); Assert.DoesNotThrowAsync(async () => await vm.UpdateMember(null));
Member? m; Member m;
using (var ctx = new AppDbContext()) { using (var ctx = new AppDbContext()) {
m = await ctx.Members m = await ctx.FetchMembers(vm.MgNr, includeNotActive: true, includeContactInfo: true).SingleAsync();
.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();
} }
Assert.That(m, Is.Not.Null); Assert.That(m, Is.Not.Null);
@@ -234,15 +218,7 @@ namespace Tests.UnitTests.ServiceTests {
var vm = new MemberAdminViewModel(); var vm = new MemberAdminViewModel();
await InitViewModel(vm); await InitViewModel(vm);
using (var ctx = new AppDbContext()) { using (var ctx = new AppDbContext()) {
vm.FillInputs(await ctx.Members vm.FillInputs(await ctx.FetchMembers(202, includeNotActive: true, includeContactInfo: true).SingleAsync());
.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());
} }
Assert.That(vm.IsActive, Is.True); Assert.That(vm.IsActive, Is.True);
@@ -253,17 +229,9 @@ namespace Tests.UnitTests.ServiceTests {
Assert.DoesNotThrowAsync(async () => await vm.UpdateMember(202)); Assert.DoesNotThrowAsync(async () => await vm.UpdateMember(202));
Member? m; Member m;
using (var ctx = new AppDbContext()) { using (var ctx = new AppDbContext()) {
m = await ctx.Members m = await ctx.FetchMembers(202, includeNotActive: true, includeContactInfo: true).SingleAsync();
.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();
} }
Assert.That(m, Is.Not.Null); Assert.That(m, Is.Not.Null);
@@ -286,15 +254,7 @@ namespace Tests.UnitTests.ServiceTests {
var vm = new MemberAdminViewModel(); var vm = new MemberAdminViewModel();
await InitViewModel(vm); await InitViewModel(vm);
using (var ctx = new AppDbContext()) { using (var ctx = new AppDbContext()) {
vm.FillInputs(await ctx.Members vm.FillInputs(await ctx.FetchMembers(203, includeNotActive: true, includeContactInfo: true).SingleAsync());
.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());
} }
Assert.Multiple(() => { Assert.Multiple(() => {
@@ -306,17 +266,9 @@ namespace Tests.UnitTests.ServiceTests {
vm.MgNr = 210; vm.MgNr = 210;
Assert.DoesNotThrowAsync(async () => await vm.UpdateMember(203)); Assert.DoesNotThrowAsync(async () => await vm.UpdateMember(203));
Member? m; Member m;
using (var ctx = new AppDbContext()) { using (var ctx = new AppDbContext()) {
m = await ctx.Members m = await ctx.FetchMembers(210, includeNotActive: true, includeContactInfo: true).SingleAsync();
.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();
} }
Assert.That(m, Is.Not.Null); Assert.That(m, Is.Not.Null);
@@ -334,27 +286,27 @@ namespace Tests.UnitTests.ServiceTests {
[Test] [Test]
public async Task TestDelete_01_NoReferences() { public async Task TestDelete_01_NoReferences() {
using (var ctx = new AppDbContext()) { 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)); Assert.DoesNotThrowAsync(async () => await MemberService.DeleteMember(201, false, false, false));
using (var ctx = new AppDbContext()) { 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] [Test]
public async Task TestDelete_02_AllReferences() { public async Task TestDelete_02_AllReferences() {
using (var ctx = new AppDbContext()) { 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++) { for (int i = 0; i < 7; i++) {
Assert.ThrowsAsync<DbUpdateException>(async () => await MemberService.DeleteMember(204, (i & 1) != 0, (i & 2) != 0, (i & 4) != 0)); Assert.ThrowsAsync<DbUpdateException>(async () => await MemberService.DeleteMember(204, (i & 1) != 0, (i & 2) != 0, (i & 4) != 0));
using var ctx = new AppDbContext(); 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)); Assert.DoesNotThrowAsync(async () => await MemberService.DeleteMember(204, true, true, true));
using (var ctx = new AppDbContext()) { 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=36" -u "elwig:ganzGeheim123!" -o "Resources\Sql\Create.sql" curl --fail -s -L "https://elwig.at/files/create.sql?v=38" -u "elwig:ganzGeheim123!" -o "Resources\Sql\Create.sql"