Compare commits

..

1 Commits

Author SHA1 Message Date
lorenz.stechauner f600609356 [WIP] Entities: Add AreaComContract to group area commitments together
Test / Run tests (push) Failing after 1m57s
2026-03-30 19:35:53 +02:00
112 changed files with 1842 additions and 2104 deletions
-10
View File
@@ -23,16 +23,6 @@ jobs:
echo "No files with BOM found"
exit 0
}
- name: Check for code smells
shell: powershell
run: |
git grep -IEn "\.(Single|First|Min|Max|Any)(OrDefault)?Async\([^)]|^using System.Data.Entity;"
if ( $lastexitcode -ne 1 ) {
exit 1
} else {
echo "No files with code smells found"
exit 0
}
- name: Setup MSBuild
uses: microsoft/setup-msbuild@v1.1
- name: Setup NuGet
-1
View File
@@ -7,4 +7,3 @@ Tests/Resources/Sql/Create.sql
*.exe
!WinziPrint.exe
*.sqlite3
*.zip
-119
View File
@@ -2,125 +2,6 @@
Changelog
=========
[v1.0.5.6][v1.0.5.6] (2026-06-25) {#v1.0.5.6}
---------------------------------------------
### Behobene Fehler {#v1.0.5.6-bugfixes}
* Beim Speichern von Auszahlungsvarianten wurden Einstellungen für Abwertungen nicht immer übernommen. (15de07a4c3)
* Im Stammdaten-Fenster (`BaseDataWindow`) war es nicht möglich Zweigstellen, Attribute, oder Bewirtschaftungsarten zu bearbeiten/erstellen/löschen. (1261be001c)
### Sonstiges {#v1.0.5.6-misc}
* Mandant `Seewinkel` hinzugefügt. (1ad97a78ff)
[v1.0.5.6]: https://git.necronda.net/winzer/elwig/releases/tag/v1.0.5.6
[v1.0.5.5][v1.0.5.5] (2026-06-24) {#v1.0.5.5}
---------------------------------------------
### Behobene Fehler {#v1.0.5.5-bugfixes}
* Beim Exportieren der Überweisungsdaten (EBICS) im Auszahlungsvarianten-Fenster (`PaymentVariantsWindow`) kam es zu einem Absturz. (3f65b2350b)
* Einige Einstellungen einer Auszahlungsvariante wurden vom Auszahlungsvariante-Fenster (`ChartWindow`) beim Speichern überschrieben. (f32ff945ec)
### Sonstiges {#v1.0.5.5-misc}
* Traubengutschriften mit negativem Betrag sind nun wieder möglich. (ba3f66591e)
* Abhängigkeiten aktualisiert. (4e027a9add)
[v1.0.5.5]: https://git.necronda.net/winzer/elwig/releases/tag/v1.0.5.5
[v1.0.5.4][v1.0.5.4] (2026-06-22) {#v1.0.5.4}
---------------------------------------------
### Behobene Fehler {#v1.0.5.4-bugfixes}
* Seit [v1.0.5.0](#v1.0.5.0) (2026-04-08) war es bei nicht-aktiven Mitgliedern nicht möglich Lieferungen oder Flächenbindungen anzusehen. (d0ce377d92)
### Sonstiges {#v1.0.5.4-misc}
* Bei der Installation wird nun auch der Quellcode mit ausgeliefert. (5db5876905)
* Abhängigkeiten aktualisiert. (b4ab8349b4, f8b3147c72, 7a993585c3)
[v1.0.5.4]: https://git.necronda.net/winzer/elwig/releases/tag/v1.0.5.4
[v1.0.5.3][v1.0.5.3] (2026-04-29) {#v1.0.5.3}
---------------------------------------------
### Behobene Fehler {#v1.0.5.3-bugfixes}
* Manche Anlieferungsbestätigungen und Traubengutschriften konnten nicht angezeigt werden. Dies lag an einem internen Fehler, der manchmal bei Zu-/Abschlägen auftrat. (72155fc54e, 9dfe71d6d0)
[v1.0.5.3]: https://git.necronda.net/winzer/elwig/releases/tag/v1.0.5.3
[v1.0.5.2][v1.0.5.2] (2026-04-24) {#v1.0.5.2}
---------------------------------------------
### Behobene Fehler {#v1.0.5.2-bugfixes}
* Im Lieferungen-Fenster (`DeliveryAdminWindow`) sind Attribut/Bewirtschaftungsart in der Liste für Teil-Lieferungen nicht angezeigt worden. (5c2fae1855)
### Sonstiges {#v1.0.5.2-misc}
* Abhängigkeiten aktualisiert. (2915f08a6b)
[v1.0.5.2]: https://git.necronda.net/winzer/elwig/releases/tag/v1.0.5.2
[v1.0.5.1][v1.0.5.1] (2026-04-20) {#v1.0.5.1}
---------------------------------------------
### Behobene Fehler {#v1.0.5.1-bugfixes}
* Zu-/Abschläge mit absolutem Wert (z.B. `€/kg`) wurden bei der Auszahlung nie mit der Menge multipliziert. (ea2b6db1fc)
* Massenaktionen im Lieferungen-Fenster (`DeliveryAdminWindow`) haben für Zu-/Abschläge nicht funktioniert. (4eac8cd629, cf48f005e2)
### Sonstiges {#v1.0.5.1-misc}
* Behebung von Kleinigkeiten im Layout bei Dokumenten (`CreditNote`, `PaymentVariantSummary`). (7edf395497, a852dbb242)
* Zuordnung von zwei Gemeinden vom Weinbaugebiet Neusiedlersee (`WLNS`) zu Leithaberg (`WLLB`). (2b3c293730)
* Abhängigkeiten aktualisiert. (20fd5d5826, 7861a15e2e)
[v1.0.5.1]: https://git.necronda.net/winzer/elwig/releases/tag/v1.0.5.1
[v1.0.5.0][v1.0.5.0] (2026-04-08) {#v1.0.5.0}
---------------------------------------------
### Neue Funktionen {#v1.0.5.0-features}
* Flächenbindungen werden nun in _Verträgen_ zusammengefasst um bessere Übersicht und historische Nachvollziehbarkeit zu gewährleisten. ([#77][i77])
### Sonstiges {#v1.0.5.0-misc}
* Erhebliche Verbesserung der Leistung/Geschwindigkeit. ([#79][i79], e5e5e10cd7, 22fbb0772f)
* Am Stammdatenblatt (`MemberDataSheet`) wird nun als Datum das Datum der letzten Bearbeitung angegeben. (0a9c800116)
* Abhängigkeiten aktualisiert. (07d93dd384, ce1a55df86, cc6e31a006)
[v1.0.5.0]: https://git.necronda.net/winzer/elwig/releases/tag/v1.0.5.0
[i77]: https://git.necronda.net/winzer/elwig/issues/77
[i79]: https://git.necronda.net/winzer/elwig/issues/79
[v1.0.4.1][v1.0.4.1] (2026-03-27) {#v1.0.4.1}
---------------------------------------------
+23 -25
View File
@@ -5,9 +5,7 @@ using Elwig.Helpers.Export;
using Elwig.Helpers.Printing;
using Elwig.Helpers.Weighing;
using Elwig.Models.Entities;
using Elwig.Services;
using Elwig.Windows;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Data;
@@ -92,11 +90,11 @@ namespace Elwig {
try {
await AppDbUpdater.CheckDb();
} catch (Exception exc) {
} catch (Exception e) {
if (Config.UpdateUrl != null && Utils.HasInternetConnectivity()) {
await CheckForUpdates();
}
InteractionService.ShowException("Fehlerhafte Datenbank", "Fehlerhafte Datenbank", exc);
MessageBox.Show($"Invalid Database:\n\n{e.Message}", "Invalid Database", MessageBoxButton.OK, MessageBoxImage.Error);
Shutdown();
return;
}
@@ -106,13 +104,11 @@ namespace Elwig {
Dictionary<string, (string, string, int?, string?, string?, string?, string?, string?)> branches = [];
using (var ctx = new AppDbContext()) {
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();
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));
try {
Client = new(ctx);
} catch (Exception exc) {
InteractionService.ShowException("Fehler", "Fehler beim Laden der Mandantendaten", exc);
} catch (Exception e) {
MessageBox.Show($"Fehler beim Laden der Mandantendaten:\n\n{e.Message}", "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
Shutdown();
return;
}
@@ -146,17 +142,18 @@ namespace Elwig {
foreach (var s in Config.Scales) {
try {
list.Add(Scale.FromConfig(s));
} catch (Exception exc) {
} catch (Exception e) {
list.Add(new InvalidScale(s.Id));
if (s.Required)
InteractionService.ShowException("Waagenfehler", $"Verbindung zu Waage {s.Id} konnte nicht hergestellt werden", exc);
MessageBox.Show($"Verbindung zu Waage {s.Id} konnte nicht hergestellt werden:\n\n{e.Message}", "Waagenfehler",
MessageBoxButton.OK, MessageBoxImage.Error);
}
}
Scales = list;
if (Config.Branch != null) {
if (!branches.ContainsKey(Config.Branch.ToLower())) {
InteractionService.ShowError("Ungültige Zweigstelle", "Ungültige Zweigstelle in Konfigurationsdatei!");
MessageBox.Show("Ungültige Zweigstelle in Konfigurationsdatei!", "Ungültige Zweigstelle", MessageBoxButton.OK, MessageBoxImage.Error);
Shutdown();
} else {
SetBranch(branches[Config.Branch.ToLower()]);
@@ -164,7 +161,7 @@ namespace Elwig {
} else if (branches.Count == 1) {
SetBranch(branches.First().Value);
} else {
InteractionService.ShowError("Ungültige Zweigstelle", "Erkennen der lokalen Zweigstelle nicht möglich!");
MessageBox.Show("Erkennen der lokalen Zweigstelle nicht möglich!", "Ungültige Zweigstelle", MessageBoxButton.OK, MessageBoxImage.Error);
Shutdown();
}
@@ -201,7 +198,6 @@ namespace Elwig {
BranchName = entry.Item2;
BranchPlz = entry.Item3;
BranchLocation = entry.Item4?
.Split(",")[0]
.Split(" in ")[0]
.Split(" im ")[0]
.Split(" an ")[0]
@@ -222,8 +218,7 @@ namespace Elwig {
MainDispatcher.Invoke(() => {
foreach (Window w in CurrentApp.Windows) {
if (w is not ContextWindow c) continue;
MainDispatcher.Invoke(c.HintContextChange);
MainDispatcher.BeginInvoke(c.TryContextReload);
MainDispatcher.BeginInvoke(c.HintContextChange);
}
});
}
@@ -254,13 +249,14 @@ namespace Elwig {
if (Scales[i] is InvalidScale) {
try {
Scales[i] = Scale.FromConfig(s);
InteractionService.ShowInformation($"Waage {s.Id}", $"Verbindung zu Waage {s.Id} wieder hergestellt!");
} catch (Exception exc) {
MessageBox.Show($"Verbindung zu Waage {s.Id} wieder hergestellt!", $"Waage {s.Id}", MessageBoxButton.OK, MessageBoxImage.Information);
} catch (Exception e) {
Scales[i] = new InvalidScale(s.Id);
InteractionService.ShowException("Waagenfehler", $"Verbindung zu Waage {s.Id} konnte nicht hergestellt werden", exc);
MessageBox.Show($"Verbindung zu Waage {s.Id} konnte nicht hergestellt werden:\n\n{e.Message}", "Waagenfehler",
MessageBoxButton.OK, MessageBoxImage.Error);
}
} else if (Scales[i] is IEventScale) {
InteractionService.ShowInformation($"Waage {s.Id}", $"Verbindung zu Waage {s.Id} wieder hergestellt!");
MessageBox.Show($"Verbindung zu Waage {s.Id} wieder hergestellt!", $"Waage {s.Id}", MessageBoxButton.OK, MessageBoxImage.Information);
}
}
}
@@ -271,7 +267,7 @@ namespace Elwig {
for (var i = 0; i < Config.Scales.Count; i++) {
var s = Config.Scales[i];
if ((s.Connection?.StartsWith($"serial://{name}:") ?? false) && Scales[i] is not InvalidScale) {
InteractionService.ShowWarning($"Waagen {s.Id}", $"Verbindung zu Waage {s.Id} unterbrochen!");
MessageBox.Show($"Verbindung zu Waage {s.Id} unterbrochen!", $"Waagen {s.Id}", MessageBoxButton.OK, MessageBoxImage.Warning);
if (Scales[i] is ICommandScale) {
try {
Scales[i].Dispose();
@@ -306,9 +302,11 @@ namespace Elwig {
});
} else if (showAlert) {
if (latest == null) {
InteractionService.ShowError("Nach Updates suchen", "Informationen konnten nicht abgerufen werden!");
MessageBox.Show("Informationen konnten nicht abgerufen werden!", "Nach Updates suchen",
MessageBoxButton.OK, MessageBoxImage.Error);
} else {
InteractionService.ShowInformation("Nach Updates suchen", $"Elwig ist auf dem aktuellsten Stand! (Version: {latest.Value.Version})");
MessageBox.Show($"Elwig ist auf dem aktuellsten Stand! (Version: {latest.Value.Version})", "Nach Updates suchen",
MessageBoxButton.OK, MessageBoxImage.Information);
}
}
}
@@ -318,11 +316,11 @@ namespace Elwig {
await Task.Run(async () => {
await Database.Import(filename);
});
InteractionService.ShowInformation("Datenbank ersetzen", "Das Ersetzen war erfolgreich!\n\nBitte starten Sie Elwig neu!");
MessageBox.Show("Das Ersetzen war erfolgreich!\n\nBitte starten Sie Elwig neu!", "Datenbank ersetzen", MessageBoxButton.OK, MessageBoxImage.Information);
ForceShutdown = true;
Current.Shutdown();
} catch (Exception exc) {
InteractionService.ShowException("Datenbank ersetzen", "Fehler beim Ersetzen", exc);
MessageBox.Show("Fehler beim Ersetzen:\n\n" + exc.Message, "Datenbank ersetzen", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
+3 -3
View File
@@ -47,15 +47,15 @@ namespace Elwig.Controls {
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;
incButton?.IsEnabled = Maximum != null && Value < Maximum;
decButton?.IsEnabled = Minimum != null && Value > Minimum;
}
private void IntegerUpDown_TextChanged(object sender, TextChangedEventArgs evt) {
var idx = CaretIndex;
Text = new string([.. Text.Where(char.IsAsciiDigit).Take(4)]);
CaretIndex = idx;
evt.Handled = !((!Minimum.HasValue || Value >= Minimum) && (!Maximum.HasValue || Value <= Maximum));
evt.Handled = !(Value >= Minimum && Value <= Maximum);
if (idx >= 4) {
if (Value < Minimum) {
Value = Minimum;
+2 -5
View File
@@ -1,5 +1,4 @@
using Elwig.Helpers;
using System;
using System.Windows;
using System.Windows.Controls;
@@ -20,7 +19,6 @@ namespace Elwig.Dialogs {
InitializeComponent();
Title = delete ? "Flächenbindung löschen" : "Flächenbindung 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) {
QuestionBlock1.Visibility = Visibility.Hidden;
@@ -28,8 +26,7 @@ namespace Elwig.Dialogs {
DescBlock1.Visibility = Visibility.Hidden;
DescBlock2.Visibility = Visibility.Visible;
}
SeasonInput.Minimum = yearFrom.HasValue ? yearFrom + 1 : null;
SeasonInput.Maximum = yearTo.HasValue ? yearTo : null;
SeasonInput.Minimum = yearFrom + 1;
if (forceRetroactive || (yearTo.HasValue && yearTo < Utils.CurrentYear) || (yearFrom.HasValue && yearFrom >= Utils.CurrentYear)) {
RetroactiveInput.IsChecked = true;
} else {
@@ -53,7 +50,7 @@ namespace Elwig.Dialogs {
DescBlock2.Visibility = Visibility.Hidden;
} else {
SeasonInput.IsEnabled = true;
SeasonInput.Text = $"{Math.Max(SeasonInput.Minimum ?? Utils.CurrentYear, Utils.CurrentYear)}";
SeasonInput.Text = $"{Utils.CurrentYear}";
DescBlock1.Visibility = QuestionBlock1.Visibility;
DescBlock2.Visibility = QuestionBlock2.Visibility;
}
@@ -44,10 +44,15 @@ namespace Elwig.Dialogs {
}
protected override async Task OnRenewContext(AppDbContext ctx) {
ControlUtils.RenewItemsSource(MemberInput, await ctx.FetchMembers().ToListAsync());
ControlUtils.RenewItemsSource(MemberInput, await ctx.Members
.Where(m => m.IsActive)
.OrderBy(m => m.Name)
.ThenBy(m => m.GivenName)
.ToListAsync());
ControlUtils.RenewItemsSource(DeliveryInput, await ctx.Deliveries
.Where(d => d.DateString == $"{_delivery.Date:yyyy-MM-dd}" && d.ZwstId == _delivery.ZwstId)
.OrderBy(d => d.LsNr)
.Include(d => d.Member)
.Include(d => d.Parts)
.ToListAsync());
if (DeliveryInput.SelectedItem == null)
+1 -2
View File
@@ -1,5 +1,4 @@
using Elwig.Helpers;
using Elwig.Services;
using System;
using System.Diagnostics;
using System.IO;
@@ -52,7 +51,7 @@ namespace Elwig.Dialogs {
File.Delete(fileName);
return;
} catch (Exception exc) {
InteractionService.ShowException(exc);
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
Process.Start(fileName);
DialogResult = true;
+7 -7
View File
@@ -22,7 +22,6 @@ namespace Elwig.Documents {
public bool IncludeSender = false;
public bool UseBillingAddress = false;
public bool ShowDateAndLocation = false;
public DateOnly? DateFrom;
protected Table? Aside;
public string Address {
@@ -48,12 +47,11 @@ namespace Elwig.Documents {
return NewAsideCell(new KernedParagraph(text, 10), colspan, isName);
}
public BusinessDocument(string title, Member m, DateOnly? dateFrom, bool includeSender = false) :
public BusinessDocument(string title, Member m, bool includeSender = false) :
base(title) {
Member = m;
Location = App.BranchLocation;
IncludeSender = includeSender;
DateFrom = dateFrom;
}
protected override void BeforeRenderBody(iText.Layout.Document doc, PdfDocument pdf) {
@@ -107,7 +105,7 @@ namespace Elwig.Documents {
}
}
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(ShowDateAndLocation ? $"{Location}, am {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));
}
@@ -263,7 +261,7 @@ namespace Elwig.Documents {
}
protected Table NewBucketTable(
Season season, Dictionary<string, MemberBucket> buckets, int deliveredWeight,
Season season, Dictionary<string, MemberBucket> buckets,
bool includeDelivery = true, bool includePayment = false,
bool isTiny = false, IEnumerable<string>? filter = null
) {
@@ -317,8 +315,10 @@ namespace Elwig.Documents {
.OrderBy(b => b.Value.Name);
tbl.AddCell(NewBucketTh("Gesamtlieferung lt. gez. GA", isTiny: isTiny));
tbl.AddCells(FormatRow(Member.BusinessShares * season.MinKgPerBusinessShare, Member.BusinessShares * season.MaxKgPerBusinessShare,
deliveredWeight, isGa: true, showPayment: includePayment, showArea: !includeDelivery, isTiny: isTiny));
tbl.AddCells(FormatRow(Member.BusinessShares * season.MinKgPerBusinessShare,
Member.BusinessShares * season.MaxKgPerBusinessShare,
season.Deliveries.Where(d => d.MgNr == Member.MgNr).Sum(d => d.Weight),
isGa: true, showPayment: includePayment, showArea: !includeDelivery, isTiny: isTiny));
if (fbs.Any()) {
tbl.AddCell(NewBucketSubHdr("Flächenbindungen" + (vtr.Any() ? " (inkl. Verträge)" : "") + ":", includePayment ? 8 : 7, isTiny: isTiny));
+45 -72
View File
@@ -1,82 +1,55 @@
using Elwig.Helpers;
using Elwig.Helpers.Billing;
using Elwig.Models.Dtos;
using Elwig.Models.Entities;
using iText.Kernel.Pdf;
using iText.Layout.Borders;
using iText.Layout.Element;
using iText.Layout.Properties;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Elwig.Documents {
public class CreditNote : BusinessDocument {
public new static string Name => "Traubengutschrift";
public PaymentMember Payment;
public PaymentMember? Payment;
public Credit? Credit;
public CreditNoteDeliveryData Data;
public string? Text;
public string CurrencySymbol;
public int Precision;
public string? MemberModifier;
public string MemberModifier;
public List<(string Name, int Kg, decimal Amount)>? MemberUnderDeliveries;
public decimal MemberTotalUnderDelivery;
public int MemberAutoBusinessShares;
public decimal MemberAutoBusinessSharesAmount;
public PaymentCustom? CustomPayment;
protected bool ConsiderContractPenalties;
protected bool ConsiderTotalPenalty;
protected bool ConsiderAutoBusinessShares;
protected bool ConsiderCustomModifiers;
private CreditNoteDeliveryData? _data;
private Dictionary<string, UnderDelivery>? _underDeliveries;
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) {
public CreditNote(
AppDbContext ctx,
PaymentMember p,
CreditNoteDeliveryData data,
bool considerContractPenalties,
bool considerTotalPenalty,
bool considerAutoBusinessShares,
bool considerCustomModifiers,
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) {
UseBillingAddress = true;
ShowDateAndLocation = true;
Data = data;
Payment = p;
Credit = p.Credit;
Text = App.Client.TextCreditNote;
DocumentId = $"Tr.-Gutschr. " + (Credit != null ? $"{Credit.Year}/{Credit.TgNr:000}" : Payment.MgNr);
IsPreview = Credit == null;
_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;
}
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);
IsPreview = Payment == null || Credit == null;
var season = p.Variant.Season;
if (considerCustomModifiers) {
CustomPayment = ctx.CustomPayments.Find(p.Year, p.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;
var mod = App.Client.IsMatzen ? ctx.Modifiers.Where(m => m.Year == season.Year && m.Name.StartsWith("Treue")).FirstOrDefault() : null;
if (CustomPayment?.ModComment != null) {
MemberModifier = CustomPayment.ModComment;
} else if (mod != null) {
@@ -84,28 +57,32 @@ namespace Elwig.Documents {
} else {
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) {
var total = _data.Rows.SelectMany(r => r.Buckets).Sum(b => b.Value);
var totalUnderDelivery = total - Member.BusinessShares * season.MinKgPerBusinessShare;
if (considerTotalPenalty) {
var total = data.Rows.SelectMany(r => r.Buckets).Sum(b => b.Value);
var totalUnderDelivery = total - p.Member.BusinessShares * season.MinKgPerBusinessShare;
MemberTotalUnderDelivery = totalUnderDelivery < 0 ? totalUnderDelivery * (season.PenaltyPerKg ?? 0) - (season.PenaltyAmount ?? 0) - (season.PenaltyPerBsAmount * Math.Floor(-(decimal)totalUnderDelivery / season.MinKgPerBusinessShare) ?? 0) : 0;
if (total == 0)
MemberTotalUnderDelivery -= (season.PenaltyNone ?? 0) + (season.PenaltyPerBsNone * Member.BusinessShares ?? 0);
MemberTotalUnderDelivery -= (season.PenaltyNone ?? 0) + (season.PenaltyPerBsNone * p.Member.BusinessShares ?? 0);
}
if (ConsiderAutoBusinessShares) {
if (considerAutoBusinessShares) {
var fromDate = $"{season.Year}-01-01";
var toDate = $"{season.Year}-12-31";
MemberAutoBusinessShares = await ctx.MemberHistory
.Where(h => h.MgNr == Member.MgNr && h.Type == "auto")
MemberAutoBusinessShares = ctx.MemberHistory
.Where(h => h.MgNr == p.Member.MgNr && h.Type == "auto")
.Where(h => h.DateString.CompareTo(fromDate) >= 0 && h.DateString.CompareTo(toDate) <= 0)
.SumAsync(h => h.BusinessShares);
.Sum(h => h.BusinessShares);
MemberAutoBusinessSharesAmount = MemberAutoBusinessShares * (-season.BusinessShareValue ?? 0);
}
if (ConsiderContractPenalties) {
var varieties = await ctx.FetchWineVarieties().ToDictionaryAsync(v => v.SortId, v => v);
var attributes = await ctx.FetchWineAttributes().ToDictionaryAsync(a => a.AttrId, a => a);
var comTypes = await ctx.AreaCommitmentTypes.ToDictionaryAsync(t => t.VtrgId, t => t);
MemberUnderDeliveries = _underDeliveries?
if (considerContractPenalties) {
var varieties = ctx.WineVarieties.ToDictionary(v => v.SortId, v => v);
var attributes = ctx.WineAttributes.ToDictionary(a => a.AttrId, a => a);
var comTypes = ctx.AreaCommitmentTypes.ToDictionary(t => t.VtrgId, t => t);
MemberUnderDeliveries = underDeliveries?
.OrderBy(u => u.Key)
.Select(u => (
varieties[u.Key[..2]].Name + (u.Key.Length > 2 ? " " + attributes[u.Key[2..]].Name : ""),
@@ -127,9 +104,8 @@ namespace Elwig.Documents {
}
protected override void RenderBody(iText.Layout.Document doc, PdfDocument pdf) {
if (_data == null) throw new Exception("Call LoadData before RenderBody");
base.RenderBody(doc, pdf);
doc.Add(NewCreditTable(_data));
doc.Add(NewCreditTable(Data));
var div = new Table(ColsMM(60, 105))
.SetWidth(UnitValue.CreatePercentValue(100)).SetFixedLayout()
@@ -155,7 +131,7 @@ namespace Elwig.Documents {
.SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE)
.SetKeepTogether(true);
var sum = _data.Rows.Sum(p => p.Amount);
var sum = Data.Rows.Sum(p => p.Amount);
if (Payment == null) {
tbl1.AddCells(FormatRow("Gesamt", sum, bold: true, noTopBorder: true));
} else {
@@ -163,7 +139,7 @@ namespace Elwig.Documents {
if (Payment.NetAmount != Payment.Amount) {
tbl1.AddCells(FormatRow("Zwischensumme", Payment.NetAmount, noTopBorder: noBorder));
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) {
tbl1.AddCells(FormatRow("Gesamtbetrag", Payment.Amount, bold: true, noTopBorder: noBorder));
@@ -296,14 +272,11 @@ namespace Elwig.Documents {
if (p.QualId == "WEI") varibute.Add(Italic("abgew."));
sub.AddCell(NewCell(colspan: 2))
.AddCell(NewTd(varibute, colspan: 3).SetPaddingTop(0));
} else if (i - (rows - p.Modifiers.Length) < p.Modifiers.Length) {
sub.AddCell(NewCell(colspan: 2))
.AddCell(NewTd(p.Modifiers[i - (rows - p.Modifiers.Length)], 8, colspan: 3).SetPaddingTop(0).SetPaddingLeftMM(5));
} else {
var idx = i - (rows - p.Modifiers.Length);
if (idx >= 0 && idx < p.Modifiers.Length) {
sub.AddCell(NewCell(colspan: 2))
.AddCell(NewTd(p.Modifiers[idx], 8, colspan: 3).SetPaddingTop(0).SetPaddingLeftMM(5));
} else {
sub.AddCell(NewCell(colspan: 5));
}
sub.AddCell(NewCell(colspan: 5));
}
if (i < p.Buckets.Length) {
@@ -324,7 +297,7 @@ namespace Elwig.Documents {
var totalMod = p.TotalModifiers ?? 0;
var pad = i == 0 ? 0.5f : 0;
sub.AddCell(NewTd(rebelMod == 0 ? "-" : (Utils.GetSign(rebelMod) + $"{Math.Abs(rebelMod):0.0##}"), 6, center: true)
.SetPaddingTopMM(pad).SetPaddingLeft(0).SetPaddingRight(0))
.SetPaddingTopMM(pad))
.AddCell(NewTd(totalMod == 0 ? "-" : Utils.GetSign(totalMod) + $"{Math.Abs(totalMod):N2}", center: totalMod == 0, right: true)
.SetPaddingTopMM(pad))
.AddCell(NewTd($"{p.Amount:N2}", right: true)
+18 -36
View File
@@ -5,48 +5,33 @@ using iText.Kernel.Pdf;
using iText.Layout.Borders;
using iText.Layout.Element;
using iText.Layout.Properties;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Elwig.Documents {
public class DeliveryConfirmation : BusinessDocument {
public new static string Name => "Anlieferungsbestätigung";
private readonly int _year;
public Season? Season;
public int MemberDeliveredWeight;
public DeliveryConfirmationDeliveryData? Data;
public Season Season;
public DeliveryConfirmationDeliveryData Data;
public string? Text = App.Client.TextDeliveryConfirmation;
public Dictionary<string, MemberBucket> MemberBuckets = [];
public List<MemberStat> MemberStats = [];
public Dictionary<string, MemberBucket> MemberBuckets;
public List<MemberStat> MemberStats;
public DeliveryConfirmation(int year, Member m, DateOnly? dateFrom, DeliveryConfirmationDeliveryData? data = null) :
base($"{Name} {year}", m, dateFrom) {
_year = year;
public DeliveryConfirmation(AppDbContext ctx, int year, Member m, DeliveryConfirmationDeliveryData data) :
base($"{Name} {year}", m) {
Season = ctx.Seasons.Find(year) ?? throw new ArgumentException("invalid season");
ShowDateAndLocation = true;
UseBillingAddress = true;
DocumentId = $"Anl.-Best. {_year}/{m.MgNr}";
DocumentId = $"Anl.-Best. {Season.Year}/{m.MgNr}";
Data = data;
}
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);
MemberBuckets = ctx.GetMemberBuckets(Season.Year, m.MgNr).GetAwaiter().GetResult();
MemberStats = AppDbContext.GetMemberStats(Season.Year, m.MgNr).GetAwaiter().GetResult();
}
protected override void BeforeRenderBody(iText.Layout.Document doc, PdfDocument pdf) {
if (Data == null) throw new Exception("Call LoadData before BeforeRenderBody");
base.BeforeRenderBody(doc, pdf);
var firstDay = Data.Rows.MinBy(r => r.Date)?.Date;
var lastDay = Data.Rows.MaxBy(r => r.Date)?.Date;
@@ -57,13 +42,12 @@ namespace Elwig.Documents {
}
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);
doc.Add(NewDeliveryListTable(Data));
doc.Add(NewWeightsTable(MemberStats)
.SetMarginTopMM(10).SetKeepTogether(true));
doc.Add(NewBucketTable(Season, MemberBuckets, MemberDeliveredWeight, includePayment: true)
doc.Add(NewBucketTable(Season, MemberBuckets, includePayment: true)
.SetMarginTopMM(10).SetKeepTogether(true));
if (Text != null) {
@@ -114,14 +98,13 @@ namespace Elwig.Documents {
} else if (i == 1 && attr) {
sub.AddCell(NewCell(colspan: 2))
.AddCell(NewTd($"{p.Attribute}{(p.Attribute != null && p.Cultivation != null ? " / " : "")}{p.Cultivation}", 8, colspan: 2)
.SetPaddingTop(0))
.SetPaddingsMM(0.125f, 1, 0.125f, 1))
.AddCell(NewCell(colspan: 2));
} else {
sub.AddCell(NewCell(colspan: 2));
var idx = i - (rows - p.Modifiers.Length);
if (idx >= 0 && idx < p.Modifiers.Length) {
sub.AddCell(NewTd(p.Modifiers[idx], 8, colspan: 2)
.SetPaddingTop(0).SetPaddingLeftMM(5));
if (i - (rows - p.Modifiers.Length) < p.Modifiers.Length) {
sub.AddCell(NewTd(p.Modifiers[i - (rows - p.Modifiers.Length)], 8, colspan: 2)
.SetPaddingsMM(0.125f, 0, 0.125f, 5));
} else {
sub.AddCell(NewCell(colspan: 2));
}
@@ -130,15 +113,14 @@ namespace Elwig.Documents {
if (i < p.Buckets.Length) {
var bucket = p.Buckets[i];
var pad = i == 0 ? 0.5f : 0;
sub.AddCell(NewTd($"{bucket.Name}:", 8).SetHeight(10).SetPaddingTopMM(pad));
sub.AddCell(NewTd($"{bucket.Value:N0}", right: true).SetPaddingTopMM(pad));
sub.AddCell(NewTd($"{bucket.Name}:", 8).SetHeight(10).SetPaddingsMM(0.125f, 0, 0.125f, 0));
sub.AddCell(NewTd($"{bucket.Value:N0}", right: true));
} else {
sub.AddCell(NewCell(colspan: 2));
}
if (i == p.Buckets.Length - 1) {
sub.AddCell(NewTd($"{p.Weight:N0}", right: true).SetPaddingTop(0));
sub.AddCell(NewTd($"{p.Weight:N0}", right: true));
sub.AddCell(NewTd(p.IsNetWeight ? "\u2611" : "\u2610", 7, right: true).SetFont(SF).SetPadding(0));
} else {
sub.AddCell(NewCell(colspan: 2));
+7 -35
View File
@@ -5,12 +5,10 @@ using iText.Layout.Borders;
using iText.Layout.Element;
using iText.Layout.Layout;
using iText.Layout.Properties;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace Elwig.Documents {
public class DeliveryNote : BusinessDocument {
@@ -19,8 +17,7 @@ namespace Elwig.Documents {
public Delivery Delivery;
public string? Text;
public int MemberDeliveredWeight;
public Dictionary<string, MemberBucket> MemberBuckets = [];
public Dictionary<string, MemberBucket> MemberBuckets;
// 0 - none
// 1 - GA only
@@ -28,41 +25,16 @@ namespace Elwig.Documents {
// 3 - full
public int DisplayStats = App.Client.ModeDeliveryNoteStats;
public DeliveryNote(Delivery d) :
base($"{Name} Nr. {d.LsNr}", d.Member, DateOnly.FromDateTime(d.ModifiedAt)) {
public DeliveryNote(Delivery d, AppDbContext? ctx = null) :
base($"{Name} Nr. {d.LsNr}", d.Member) {
UseBillingAddress = true;
ShowDateAndLocation = true;
Delivery = d;
Text = App.Client.TextDeliveryNote;
DocumentId = d.LsNr;
}
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) ?? [];
Date = DateOnly.FromDateTime(d.ModifiedAt);
IsDoublePaged = true;
MemberBuckets = ctx?.GetMemberBuckets(d.Year, d.Member.MgNr).GetAwaiter().GetResult() ?? [];
}
protected override void BeforeRenderBody(iText.Layout.Document doc, PdfDocument pdf) {
@@ -81,7 +53,7 @@ namespace Elwig.Documents {
doc.Add(new KernedParagraph($"Anmerkung zur Lieferung: {Delivery.Comment}", 10).SetMarginsMM(5, 0, 0, 0));
}
if (DisplayStats > 0) {
doc.Add(NewBucketTable(Delivery.Season, MemberBuckets, MemberDeliveredWeight, isTiny: true,
doc.Add(NewBucketTable(Delivery.Season, MemberBuckets, isTiny: true,
filter: DisplayStats > 2 ? null : DisplayStats == 1 ? [] : Delivery.Parts.Select(p => p.SortId).Distinct().ToList())
.SetKeepTogether(true)
.SetMarginsMM(5, 0, 0, 0));
+3 -5
View File
@@ -49,12 +49,14 @@ namespace Elwig.Documents {
public bool IsPreview = false;
private iText.Layout.Document? _doc;
public int CurrentNextSeason;
public string? DocumentId;
public string Title;
public string Author;
public DateOnly Date;
public Document(string title) {
CurrentNextSeason = Utils.CurrentNextSeason;
Title = title;
Author = App.Client.NameFull;
Date = DateOnly.FromDateTime(Utils.Today);
@@ -126,8 +128,6 @@ namespace Elwig.Documents {
}
}
protected virtual async Task LoadData(AppDbContext ctx) { }
protected virtual void BeforeRenderBody(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);
}
public async Task Generate(AppDbContext ctx, CancellationToken? cancelToken = null, IProgress<double>? progress = null) {
public async Task Generate(CancellationToken? cancelToken = null, IProgress<double>? progress = null) {
if (_pdfFile != null)
return;
progress?.Report(0.0);
@@ -181,7 +181,6 @@ namespace Elwig.Documents {
merger.Merge(src, 1, src.GetNumberOfPages());
p += src.GetNumberOfPages();
} else {
await doc.LoadData(ctx);
int pageNum = doc.Render(tmpPdf.FilePath);
if (IsDoublePaged && doc is Letterhead) {
using var reader = new PdfReader(tmpPdf.FilePath);
@@ -234,7 +233,6 @@ namespace Elwig.Documents {
throw new OperationCanceledException("Dokumentenerzeugung abgebrochen!");
var pdf = new TempFile("pdf");
try {
await LoadData(ctx);
TotalPages = Render(pdf.FilePath);
} catch {
pdf.Dispose();
+1 -1
View File
@@ -6,7 +6,7 @@ using iText.Layout;
namespace Elwig.Documents {
public class Letterhead : BusinessDocument {
public Letterhead(Member m) :
base($"Briefkopf {m.FullName}", m, null, includeSender: true) {
base($"Briefkopf {m.FullName}", m, true) {
}
protected override void RenderBody(iText.Layout.Document doc, PdfDocument pdf) {
+16 -36
View File
@@ -5,52 +5,32 @@ using iText.Kernel.Pdf;
using iText.Layout.Borders;
using iText.Layout.Element;
using iText.Layout.Properties;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace Elwig.Documents {
public class MemberDataSheet : BusinessDocument {
public new static string Name => "Stammdatenblatt";
public Season? Season;
public int MemberDeliveredWeight;
public Dictionary<string, MemberBucket> MemberBuckets = [];
public List<AreaCom> ActiveAreaCommitments = [];
public Season Season;
public Dictionary<string, MemberBucket> MemberBuckets;
public List<AreaCom> ActiveAreaCommitments;
public MemberDataSheet(Member m) :
base($"{Name} {m.AdministrativeName}", m, DateOnly.FromDateTime(m.ModifiedAt)) {
ShowDateAndLocation = true;
public MemberDataSheet(Member m, AppDbContext ctx) :
base($"{Name} {m.AdministrativeName}", m) {
DocumentId = $"{Name} {m.MgNr}";
}
public static async Task<MemberDataSheet> Initialize(int mgnr) {
using var ctx = new AppDbContext();
return new MemberDataSheet(await ctx.FetchMembers(mgnr, includeContactInfo: 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);
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)];
}
protected override void RenderBody(iText.Layout.Document doc, PdfDocument pdf) {
if (Season == null) throw new Exception("Call LoadData before RenderBody");
base.RenderBody(doc, pdf);
doc.Add(NewMemberData(Season).SetMarginBottomMM(5));
doc.Add(NewBucketTable(Season, MemberBuckets, MemberDeliveredWeight, includeDelivery: false));
doc.Add(NewMemberData().SetMarginBottomMM(5));
doc.Add(NewBucketTable(Season, MemberBuckets, includeDelivery: false));
if (ActiveAreaCommitments.Count != 0) {
bool firstOnPage = false;
if (pdf.GetNumberOfPages() == 1) {
@@ -58,7 +38,7 @@ namespace Elwig.Documents {
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(NewAreaComTable(ActiveAreaCommitments));
doc.Add(NewAreaComTable());
}
}
@@ -72,7 +52,7 @@ namespace Elwig.Documents {
.SetPaddingRightMM(0);
}
protected Table NewMemberData(Season season) {
protected Table NewMemberData() {
var tbl = new Table(ColsMM(30.0, 51.5, 20.0, 12.0, 18.0, 31.5))
.SetWidth(UnitValue.CreatePercentValue(100)).SetFixedLayout()
.SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE)
@@ -137,7 +117,7 @@ namespace Elwig.Documents {
.AddCell(NewDataTh("UID:", colspan: 2)).AddCell(NewTd(Member.UstIdNr, colspan: 2))
.AddCell(NewDataTh("Stammgemeinde:")).AddCell(NewTd(Member.DefaultKg?.Name))
.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("Bio:", colspan: 2)).AddCell(NewTd(Member.IsOrganic ? "Ja" : "Nein", colspan: 2))
.AddCell(NewDataHdr("Genossenschaft", colspan: 6))
@@ -154,8 +134,8 @@ namespace Elwig.Documents {
return tbl;
}
protected Table NewAreaComTable(IEnumerable<AreaCom> activeAreaComs) {
var areaComs = activeAreaComs.GroupBy(a => a.AreaComType).Select(group => new {
protected Table NewAreaComTable() {
var areaComs = ActiveAreaCommitments.GroupBy(a => a.AreaComType).Select(group => new {
Type = group.Key,
AreaComs = group.OrderBy(c => c.Contract.Kg.AtKg.Name).ToList(),
Size = group.Sum(c => c.Area)
@@ -197,7 +177,7 @@ namespace Elwig.Documents {
}
tbl.AddCell(NewTd("Gesamt:", 12, colspan: 2, 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($"{ActiveAreaCommitments.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));
return tbl;
+40 -60
View File
@@ -7,60 +7,40 @@ using iText.Kernel.Pdf;
using iText.Layout.Borders;
using iText.Layout.Element;
using iText.Layout.Properties;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Elwig.Documents {
public class PaymentVariantSummary : Document {
public new static string Name => "Auszahlungsvariante";
public PaymentVariantSummaryData? Data;
public PaymentVariantSummaryData Data;
public PaymentVar Variant;
public BillingData BillingData;
public string CurrencySymbol;
public int MemberNum;
public int DeliveryNum;
public int DeliveryPartNum;
public List<ModifierStat>? ModifierStat;
public Dictionary<string, Modifier>? Modifiers;
public List<ModifierStat> ModifierStat;
public Dictionary<string, Modifier> Modifiers;
private List<Credit> _credits = [];
private List<PaymentDeliveryPart> _parts = [];
public PaymentVariantSummary(PaymentVar v, PaymentVariantSummaryData? data = null) :
public PaymentVariantSummary(PaymentVar v, PaymentVariantSummaryData data) :
base($"{Name} {v.Year} - {v.Name}") {
Variant = v;
BillingData = BillingData.FromJson(v.Data);
Data = data;
CurrencySymbol = v.Season.Currency.Symbol ?? v.Season.Currency.Code;
}
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;
MemberNum = v.Credits.Count;
IsPreview = MemberNum == 0;
DeliveryNum = await ctx.Deliveries.Where(d => d.Year == Variant.Year).CountAsync();
DeliveryPartNum = await ctx.DeliveryParts.Where(d => d.Year == Variant.Year).CountAsync();
Data ??= await PaymentVariantSummaryData.ForPaymentVariant(Variant, ctx.PaymentVariantSummaryRows);
ModifierStat = await AppDbContext.GetModifierStats(Variant.Year, Variant.AvNr);
Modifiers = await ctx.FetchModifiers(Variant.Year).ToDictionaryAsync(m => m.ModId);
DeliveryNum = v.DeliveryPartPayments.DistinctBy(p => p.DeliveryPart.Delivery).Count();
DeliveryPartNum = v.DeliveryPartPayments.Count;
ModifierStat = AppDbContext.GetModifierStats(v.Year, v.AvNr).GetAwaiter().GetResult();
Modifiers = v.Season.Modifiers.ToDictionary(m => m.ModId);
}
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);
doc.Add(new KernedParagraph($"{Name} Lese {Variant.Year}", 24)
.SetTextAlignment(TextAlignment.CENTER).SetFont(BF)
@@ -68,10 +48,10 @@ namespace Elwig.Documents {
doc.Add(new KernedParagraph(Variant.Name, 14)
.SetTextAlignment(TextAlignment.CENTER).SetFont(BF)
.SetMarginsMM(0, 0, 10, 0));
doc.Add(NewVariantStatTable(Data).SetMarginBottomMM(10));
doc.Add(NewModifierStatTable(Modifiers, ModifierStat));
doc.Add(NewVariantStatTable().SetMarginBottomMM(10));
doc.Add(NewModifierStatTable());
doc.Add(new AreaBreak(AreaBreakType.NEXT_PAGE));
doc.Add(NewPriceTable(Data));
doc.Add(NewPriceTable());
}
protected Cell NewSectionHdr(string text, int colspan = 1, bool borderLeft = false) {
@@ -87,33 +67,33 @@ namespace Elwig.Documents {
.SetBorderLeft(borderLeft ? new SolidBorder(BorderThickness) : Border.NO_BORDER);
}
protected Table NewVariantStatTable(PaymentVariantSummaryData data) {
protected Table NewVariantStatTable() {
var tbl = new Table(ColsMM(20, 30, 4.5, 4.5, 23.5, 47.5, 15, 20))
.SetWidth(UnitValue.CreatePercentValue(100)).SetFixedLayout()
.SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE)
.SetBorder(new SolidBorder(BorderThickness));
//var sum1 = _parts.Sum(p => p.NetAmount);
//var sum2 = _credits.Sum(p => p.); //Variant.MemberPayments.Sum(p => p.Amount);
var deliveryModifiers = _parts.Sum(p => p.Amount - p.NetAmount);
var memberModifiers = _credits.Sum(c => c.Payment.Amount - c.Payment.NetAmount);
var sum2 = _credits.Sum(p => p.NetAmount);
//var sum1 = Variant.DeliveryPartPayments.Sum(p => p.NetAmount);
//var sum2 = Variant.Credits.Sum(p => p.); //Variant.MemberPayments.Sum(p => p.Amount);
var deliveryModifiers = Variant.DeliveryPartPayments.Sum(p => p.Amount - p.NetAmount);
var memberModifiers = Variant.Credits.Sum(c => c.Payment.Amount - c.Payment.NetAmount);
var sum2 = Variant.Credits.Sum(p => p.NetAmount);
var sum1 = sum2 - deliveryModifiers - memberModifiers;
var payed = -_credits.Sum(p => p.PrevNetAmount ?? 0m);
var netSum = _credits.Sum(p => p.NetAmount) - _credits.Sum(p => p.PrevNetAmount ?? 0m);
var vat = _credits.Sum(p => p.VatAmount);
var grossSum = _credits.Sum(p => p.GrossAmount);
var totalMods = _credits.Sum(p => p.Modifiers ?? 0m);
var considered = -_credits.Sum(p => p.PrevModifiers ?? 0m);
var totalSum = _credits.Sum(p => p.Amount);
var payed = -Variant.Credits.Sum(p => p.PrevNetAmount ?? 0m);
var netSum = Variant.Credits.Sum(p => p.NetAmount) - Variant.Credits.Sum(p => p.PrevNetAmount ?? 0m);
var vat = Variant.Credits.Sum(p => p.VatAmount);
var grossSum = Variant.Credits.Sum(p => p.GrossAmount);
var totalMods = Variant.Credits.Sum(p => p.Modifiers ?? 0m);
var considered = -Variant.Credits.Sum(p => p.PrevModifiers ?? 0m);
var totalSum = Variant.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 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 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)
.Select(r => r.Geb.MaxPrice - r.Ungeb.MinPrice);
var minGeb = gebRows.Min();
@@ -183,21 +163,21 @@ namespace Elwig.Documents {
.AddCell(NewTd(CurrencySymbol))
.AddCell(NewTd($"{Math.Abs(payed):N2}", right: true))
.AddCell(NewSectionTh("Preis (abgewertet):", borderTop: true, borderLeft: true))
.AddCell(NewTd(minWei == null && maxWei == null ? "-" : (minWei != maxWei ? $"{minWei:N4}\u2013{maxWei:N4}" : $"{minWei:N4}") + $" {CurrencySymbol}/kg", colspan: 2, center: true, borderTop: true))
.AddCell(NewTd((minWei != maxWei ? $"{minWei:N4}\u2013{maxWei:N4}" : $"{minWei:N4}") + $" {CurrencySymbol}/kg", colspan: 2, center: true, borderTop: true))
.AddCell(NewSectionTh("Nettosumme:", colspan: 2))
.AddCell(NewTd(borderTop: true))
.AddCell(NewTd(CurrencySymbol, borderTop: true))
.AddCell(NewTd($"{netSum:N2}", right: true, borderTop: true))
.AddCell(NewSectionTh("Preis (ungeb., nicht abgew.):", borderLeft: true))
.AddCell(NewTd(minPrice == null && maxPrice == null ? "-" : (minPrice != maxPrice ? $"{minPrice:N4}{maxPrice:N4}" : $"{minPrice:N4}") + $" {CurrencySymbol}/kg", colspan: 2, center: true))
.AddCell(NewTd((minPrice != maxPrice ? $"{minPrice:N4}{maxPrice:N4}" : $"{minPrice:N4}") + $" {CurrencySymbol}/kg", colspan: 2, center: true))
.AddCell(NewSectionTh("Mehrwertsteuer:", colspan: 2))
.AddCell(NewTd(Utils.GetSign(vat), right: true))
.AddCell(NewTd(CurrencySymbol))
.AddCell(NewTd($"{Math.Abs(vat):N2}", right: true))
.AddCell(NewSectionTh("Gebunden-Zuschlag:", borderLeft: true))
.AddCell(NewTd(minGeb == null && maxGeb == null ? "-" : minGeb != maxGeb ? $"{minGeb:N4}\u2013{maxGeb:N4} {CurrencySymbol}/kg" : minGeb == 0 ? "-" : $"{minGeb:N4} {CurrencySymbol}/kg", colspan: 2, center: true))
.AddCell(NewTd(minGeb != maxGeb ? $"{minGeb:N4}\u2013{maxGeb:N4} {CurrencySymbol}/kg" : minGeb == 0 ? "-" : $"{minGeb:N4} {CurrencySymbol}/kg", colspan: 2, center: true))
.AddCell(NewSectionTh("Bruttosumme:", colspan: 2))
.AddCell(NewTd(borderTop: true))
@@ -211,26 +191,26 @@ namespace Elwig.Documents {
.AddCell(NewTd(CurrencySymbol))
.AddCell(NewTd($"{Math.Abs(totalMods):N2}", right: 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(NewTd(Utils.GetSign(considered)))
.AddCell(NewTd(CurrencySymbol))
.AddCell(NewTd($"{Math.Abs(considered):N2}", right: 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(NewTd(borderTop: true))
.AddCell(NewTd(CurrencySymbol, borderTop: true))
.AddCell(NewTd($"{totalSum:N2}", right: true, borderTop: 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;
}
protected Table NewModifierStatTable(Dictionary<string, Modifier> modifiers, IEnumerable<ModifierStat> modStat) {
protected Table NewModifierStatTable() {
var tbl = new Table(ColsMM(35, 30, 25, 25, 25, 25))
.SetWidth(UnitValue.CreatePercentValue(100)).SetFixedLayout()
.SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE)
@@ -248,8 +228,8 @@ namespace Elwig.Documents {
.AddCell(NewTh($"[{CurrencySymbol}]"))
.AddCell(NewTh($"[{CurrencySymbol}]"));
foreach (var m in modStat) {
var mod = modifiers[m.ModId];
foreach (var m in ModifierStat) {
var mod = Modifiers[m.ModId];
tbl.AddCell(NewTd(mod.Name, italic: true))
.AddCell(NewTd(mod.ValueStr, right: true))
.AddCell(NewTd($"{m.Count:N0}", right: true))
@@ -261,7 +241,7 @@ namespace Elwig.Documents {
return tbl;
}
protected Table NewPriceTable(PaymentVariantSummaryData data) {
protected Table NewPriceTable() {
var tbl = new Table(ColsMM(25, 19, 18, 15, 18, 15, 18, 15, 22))
.SetWidth(UnitValue.CreatePercentValue(100)).SetFixedLayout()
.SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE);
@@ -282,10 +262,10 @@ namespace Elwig.Documents {
.AddHeaderCell(NewTh($"[{CurrencySymbol}]"));
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}";
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)
.ToList();
var border = lastHdr != null;
+15 -14
View File
@@ -9,7 +9,7 @@
<UseWindowsForms>true</UseWindowsForms>
<PreserveCompilationContext>true</PreserveCompilationContext>
<ApplicationIcon>Resources\Images\Elwig.ico</ApplicationIcon>
<Version>1.0.5.6</Version>
<Version>1.0.4.1</Version>
<SatelliteResourceLanguages>de-AT</SatelliteResourceLanguages>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<ApplicationManifest>app.manifest</ApplicationManifest>
@@ -23,21 +23,22 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="bblanchon.PDFium.Win32" Version="151.0.7906" />
<PackageReference Include="bblanchon.PDFium.Win32" Version="148.0.7749" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.2" />
<PackageReference Include="itext" Version="9.6.0" />
<PackageReference Include="itext.bouncy-castle-adapter" Version="9.6.0" />
<PackageReference Include="itext" Version="9.5.0" />
<PackageReference Include="itext.bouncy-castle-adapter" Version="9.5.0" />
<PackageReference Include="LinqKit" Version="1.3.11" />
<PackageReference Include="MailKit" Version="4.17.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.9" />
<PackageReference Include="Microsoft.Extensions.Configuration.Ini" Version="10.0.9" />
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.4022.49" />
<PackageReference Include="NJsonSchema" Version="11.6.1" />
<PackageReference Include="ScottPlot.WPF" Version="5.1.59" />
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="3.0.3" />
<PackageReference Include="System.IO.Hashing" Version="10.0.9" />
<PackageReference Include="System.IO.Ports" Version="10.0.9" />
<PackageReference Include="System.Management" Version="10.0.9" />
<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.Extensions.Configuration.Ini" Version="10.0.5" />
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.3856.49" />
<PackageReference Include="NJsonSchema" Version="11.5.2" />
<PackageReference Include="ScottPlot.WPF" Version="5.1.57" />
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="3.0.2" />
<PackageReference Include="System.IO.Hashing" Version="10.0.5" />
<PackageReference Include="System.IO.Ports" Version="10.0.5" />
<PackageReference Include="System.Management" Version="10.0.5" />
</ItemGroup>
</Project>
+49 -178
View File
@@ -1,6 +1,5 @@
using Elwig.Models.Dtos;
using Elwig.Models.Entities;
using Elwig.Services;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
@@ -11,6 +10,7 @@ using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
namespace Elwig.Helpers {
@@ -82,70 +82,6 @@ namespace Elwig.Helpers {
public static string? ConnectionStringOverride { get; set; } = null;
public static string ConnectionString => ConnectionStringOverride ?? $"Data Source=\"{App.Config.DatabaseFile}\"; Mode=ReadWrite; Foreign Keys=True; Cache=Default; Pooling=False";
private static readonly Func<AppDbContext, string?, bool, IAsyncEnumerable<Branch>> _compiledQueryBranches =
EF.CompileAsyncQuery<AppDbContext, string?, bool, Branch>((ctx, zwstid, includeWithoutMembers) => ctx.Branches
.Where(b => includeWithoutMembers || b.Members.Count > 0)
.Where(b => zwstid == null || b.ZwstId == zwstid)
.Include(b => b.PostalDest)
.OrderBy(b => b.Name));
private static readonly Func<AppDbContext, string?, IAsyncEnumerable<WineVar>> _compiledQueryWineVarieties =
EF.CompileAsyncQuery<AppDbContext, string?, WineVar>((ctx, sortid) => ctx.WineVarieties
.Where(v => sortid == null || v.SortId == sortid)
.OrderBy(v => v.Name));
private static readonly Func<AppDbContext, string?, bool, IAsyncEnumerable<WineAttr>> _compiledQueryWineAttributes =
EF.CompileAsyncQuery<AppDbContext, string?, bool, WineAttr>((ctx, attrid, includeNotActive) => ctx.WineAttributes
.Where(a => includeNotActive || a.IsActive)
.Where(a => attrid == null || a.AttrId == attrid)
.OrderBy(a => a.Name));
private static readonly Func<AppDbContext, string?, IAsyncEnumerable<WineCult>> _compiledQueryWineCultivations =
EF.CompileAsyncQuery<AppDbContext, string?, WineCult>((ctx, cultid) => ctx.WineCultivations
.Where(c => cultid == null || c.CultId == cultid)
.OrderBy(v => v.Name));
private static readonly Func<AppDbContext, bool, IAsyncEnumerable<WineQualLevel>> _compiledQueryWineQualityLevels =
EF.CompileAsyncQuery<AppDbContext, bool, WineQualLevel>((ctx, includePredicate) => ctx.WineQualityLevels
.Where(l => includePredicate || !l.IsPredicate)
.OrderBy(l => l.MinKmw));
private static readonly Func<AppDbContext, int?, bool, IAsyncEnumerable<Modifier>> _compiledQueryModifiers =
EF.CompileAsyncQuery<AppDbContext, int?, bool, Modifier>((ctx, year, incudeNotActive) => ctx.Modifiers
.Where(m => (year == null || m.Year == year) && (incudeNotActive || m.IsActive))
.OrderBy(m => m.Year).ThenBy(m => m.Ordering).ThenBy(m => m.Name));
private static readonly Func<AppDbContext, int?, bool, IAsyncEnumerable<Member>> _compiledQueryMembers =
EF.CompileAsyncQuery<AppDbContext, int?, bool, Member>((ctx, mgnr, includeNotActive) => ctx.Members
.Where(m => includeNotActive || m.IsActive)
.Where(m => mgnr == null || m.MgNr == mgnr)
.OrderBy(m => m.Name).ThenBy(m => m.GivenName).ThenBy(m => m.MgNr));
private static readonly Func<AppDbContext, int?, bool, IAsyncEnumerable<Member>> _compiledQueryMembersContactInfo =
EF.CompileAsyncQuery<AppDbContext, int?, bool, Member>((ctx, mgnr, includeNotActive) => ctx.Members
.Where(m => includeNotActive || m.IsActive)
.Where(m => mgnr == null || m.MgNr == mgnr)
.Include(m => m.EmailAddresses)
.Include(m => m.TelephoneNumbers)
.OrderBy(m => m.Name).ThenBy(m => m.GivenName).ThenBy(m => m.MgNr)
.AsSplitQuery());
private static readonly Func<AppDbContext, int?, IAsyncEnumerable<AreaCom>> _compiledQueryAreaCommitments =
EF.CompileAsyncQuery<AppDbContext, int?, AreaCom>((ctx, fbnr) => ctx.AreaCommitments
.Where(c => fbnr == null || c.FbNr == fbnr)
.OrderBy(c => c.FbNr).ThenBy(c => c.RevNr));
private static readonly Func<AppDbContext, int?, IAsyncEnumerable<Season>> _compiledQuerySeasons =
EF.CompileAsyncQuery<AppDbContext, int?, Season>((ctx, year) => ctx.Seasons
.Where(s => year == null || s.Year == year)
.OrderByDescending(s => s.Year));
private static readonly Func<AppDbContext, int?, IAsyncEnumerable<Season>> _compiledQuerySeasonsModifiers =
EF.CompileAsyncQuery<AppDbContext, int?, Season>((ctx, year) => ctx.Seasons
.Where(s => year == null || s.Year == year)
.Include(s => s.Modifiers)
.OrderByDescending(s => s.Year));
private readonly Dictionary<int, Dictionary<int, Dictionary<string, AreaComBucket>>> _memberAreaCommitmentBuckets = [];
private readonly Dictionary<int, Dictionary<int, Dictionary<string, int>>> _memberDeliveryBuckets = [];
private readonly Dictionary<int, Dictionary<int, Dictionary<string, int>>> _memberDeliveryBucketsStrict = [];
@@ -159,8 +95,8 @@ namespace Elwig.Helpers {
LogFile = new(file) {
AutoFlush = true
};
} catch (Exception exc) {
InteractionService.ShowException("Database Log", $"Unable to open database log file", exc);
} catch (Exception e) {
MessageBox.Show($"Unable to open database log file:\n\n{e.Message}", "Database Log", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
SavedLastWriteTime = LastWriteTime;
@@ -183,55 +119,11 @@ namespace Elwig.Helpers {
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
optionsBuilder.UseSqlite(ConnectionString);
optionsBuilder.UseLazyLoadingProxies();
optionsBuilder.LogTo(Log, LogLevel.Information);
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() {
base.Dispose();
LogFile?.Dispose();
@@ -247,23 +139,23 @@ namespace Elwig.Helpers {
}
public async Task<bool> MgNrExists(int mgnr) {
return await _compiledQueryMembers.Invoke(this, mgnr, true).AnyAsync();
return await Members.FindAsync(mgnr) != null;
}
public async Task<bool> FbNrExists(int fbnr) {
return await _compiledQueryAreaCommitments.Invoke(this, fbnr).AnyAsync();
return await AreaCommitmentContracts.FindAsync(fbnr) != null;
}
public async Task<bool> SortIdExists(string sortId) {
return await _compiledQueryWineVarieties.Invoke(this, sortId).AnyAsync();
return await WineVarieties.FindAsync(sortId) != null;
}
public async Task<bool> AttrIdExists(string attrId) {
return await _compiledQueryWineAttributes.Invoke(this, attrId, true).AnyAsync();
return await WineAttributes.FindAsync(attrId) != null;
}
public async Task<bool> CultIdExists(string cultId) {
return await _compiledQueryWineCultivations.Invoke(this, cultId).AnyAsync();
return await WineCultivations.FindAsync(cultId) != null;
}
public async Task<int> NextMgNr() {
@@ -281,107 +173,88 @@ namespace Elwig.Helpers {
}
public async Task<int> NextRevNr(int fbnr) {
return (await AreaCommitments.Where(c => c.FbNr == fbnr).Select(c => (int?)c.RevNr).MaxAsync() ?? 0) + 1;
int c = 0;
(await AreaCommitments.Where(c => c.FbNr == fbnr).Select(c => c.RevNr).ToListAsync())
.ForEach(a => { if (a <= c + 100) c = a; });
return c + 1;
}
public async Task<int> NextLNr(DateOnly date, string zwstid) {
var dateStr = date.ToString("yyyy-MM-dd");
return (await Deliveries.Where(d => d.DateString == dateStr && d.ZwstId == zwstid).Select(d => (int?)d.LNr).MaxAsync() ?? 0) + 1;
int c = 0;
(await Deliveries.Where(d => d.DateString == dateStr && d.ZwstId == zwstid).Select(d => d.LNr).ToListAsync())
.ForEach(a => { if (a <= c + 100) c = a; });
return c + 1;
}
public async Task<int> NextDId(int year) {
return (await Deliveries.Where(d => d.Year == year).Select(d => (int?)d.DId).MaxAsync() ?? 0) + 1;
int c = 0;
(await Deliveries.Where(d => d.Year == year).Select(d => d.DId).ToListAsync())
.ForEach(a => { if (a <= c + 100) c = a; });
return c + 1;
}
public async Task<int> NextDPNr(int year, int did) {
return (await DeliveryParts.Where(p => p.Year == year && p.DId == did).Select(p => (int?)p.DPNr).MaxAsync() ?? 0) + 1;
int c = 0;
(await DeliveryParts.Where(p => p.Year == year && p.DId == did).Select(d => d.DPNr).ToListAsync())
.ForEach(a => { if (a <= c + 100) c = a; });
return c + 1;
}
public async Task<int> NextRdNr(int kgnr) {
return (await WbRde.Where(r => r.KgNr == kgnr).Select(r => (int?)r.RdNr).MaxAsync() ?? 0) + 1;
int c = 0;
(await WbRde.Where(r => r.KgNr == kgnr).Select(r => r.RdNr).ToListAsync())
.ForEach(a => { if (a <= c + 100) c = a; });
return c + 1;
}
public async Task<int> NextAvNr(int year) {
return (await PaymentVariants.Where(v => v.Year == year).Select(v => (int?)v.AvNr).MaxAsync() ?? 0) + 1;
int c = 0;
(await PaymentVariants.Where(v => v.Year == year).Select(v => v.AvNr).ToListAsync())
.ForEach(a => { if (a <= c + 100) c = a; });
return c + 1;
}
public async Task<int> NextDsNr(int year) {
return (await DeliverySchedules.Where(s => s.Year == year).Select(v => (int?)v.DsNr).MaxAsync() ?? 0) + 1;
int c = 0;
(await DeliverySchedules.Where(s => s.Year == year).Select(s => s.DsNr).ToListAsync())
.ForEach(a => { if (a <= c + 100) c = a; });
return c + 1;
}
public IAsyncEnumerable<Branch> FetchBranches(string? zwstid = null, bool includeWithoutMembers = true) {
return _compiledQueryBranches.Invoke(this, zwstid, includeWithoutMembers);
}
public IAsyncEnumerable<WineVar> FetchWineVarieties() {
return _compiledQueryWineVarieties.Invoke(this, null);
}
public IAsyncEnumerable<WineAttr> FetchWineAttributes(bool incudeNotActive = true) {
return _compiledQueryWineAttributes.Invoke(this, null, incudeNotActive);
}
public IAsyncEnumerable<WineCult> FetchWineCultivations() {
return _compiledQueryWineCultivations.Invoke(this, null);
}
public IAsyncEnumerable<WineQualLevel> FetchWineQualityLevels(bool includePredicate = true) {
return _compiledQueryWineQualityLevels.Invoke(this, includePredicate);
}
public IAsyncEnumerable<Modifier> FetchModifiers(int? year, bool incudeNotActive = true) {
return _compiledQueryModifiers.Invoke(this, year, incudeNotActive);
}
public IAsyncEnumerable<Member> FetchMembers(int? mgnr = null, bool includeNotActive = false, bool includeContactInfo = false) {
if (includeContactInfo) {
return _compiledQueryMembersContactInfo.Invoke(this, mgnr, mgnr != null || includeNotActive);
} else {
return _compiledQueryMembers.Invoke(this, mgnr, mgnr != null || 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()) {
public void UpdateDeliveryPartModifiers(DeliveryPart part, IEnumerable<Modifier> oldModifiers, IEnumerable<Modifier> newModifiers) {
foreach (var m in Modifiers.Where(m => m.Year == part.Year)) {
var mod = new DeliveryPartModifier {
Year = part.Year,
DId = part.DId,
DPNr = part.DPNr,
ModId = m.ModId,
};
var old = oldModIds.Contains(m.ModId);
if (newModIds.Contains(m.ModId)) {
if (!old) {
var old = oldModifiers.Where(pa => pa.ModId == m.ModId).FirstOrDefault();
if (newModifiers.Any(md => md.ModId == m.ModId)) {
if (old == null) {
Add(mod);
} else {
Update(mod);
}
} else {
if (old) {
if (old != null) {
Remove(mod);
}
}
}
}
public async Task UpdateDeliveryScheduleWineVarieties(DeliverySchedule schedule, IEnumerable<(string, int)> oldVarieties, IEnumerable<(string, int)> newVarieties) {
foreach (var v in await FetchWineVarieties().ToArrayAsync()) {
public void UpdateDeliveryScheduleWineVarieties(DeliverySchedule schedule, IEnumerable<(WineVar, int)> oldVarieties, IEnumerable<(WineVar, int)> newVarieties) {
foreach (var v in WineVarieties) {
var e = new DeliveryScheduleWineVar {
Year = schedule.Year,
DsNr = schedule.DsNr,
SortId = v.SortId,
Priority = 1,
};
var o = oldVarieties.Where(x => x.Item1 == e.SortId).Select(x => x.Item2).FirstOrDefault(-1);
var n = newVarieties.Where(x => x.Item1 == e.SortId).Select(x => x.Item2).FirstOrDefault(-1);
var o = oldVarieties.Where(x => x.Item1.SortId == e.SortId).Select(x => x.Item2).FirstOrDefault(-1);
var n = newVarieties.Where(x => x.Item1.SortId == e.SortId).Select(x => x.Item2).FirstOrDefault(-1);
if (n != -1) {
e.Priority = n;
if (o == -1) {
@@ -526,12 +399,10 @@ namespace Elwig.Helpers {
var paymentBuckets = await GetMemberPaymentBuckets(year, mgnr, cnx);
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>();
foreach (var id in rightsAndObligations.Keys.Union(deliveryBuckets.Keys).Union(paymentBuckets.Keys)) {
var variety = varieties.GetValueOrDefault(id[..2]);
var attribute = attributes.GetValueOrDefault(id[2..]);
var variety = await WineVarieties.FindAsync(id[..2]);
var attribute = await WineAttributes.FindAsync(id[2..]);
var name = (variety?.Name ?? "") + (id[2..] == "_" ? " (kein Qual.Wein)" : attribute != null ? $" ({attribute})" : "");
buckets[id] = new(
name,
+1 -1
View File
@@ -9,7 +9,7 @@ namespace Elwig.Helpers {
public static class AppDbUpdater {
// Don't forget to update value in Tests/fetch-resources.bat!
public static readonly int RequiredSchemaVersion = 39;
public static readonly int RequiredSchemaVersion = 38;
private static int VersionOffset = 0;
+6 -22
View File
@@ -1,5 +1,6 @@
using Elwig.Models.Entities;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Globalization;
@@ -15,30 +16,13 @@ namespace Elwig.Helpers.Billing {
protected readonly Dictionary<string, (decimal?, decimal?)> Modifiers;
protected readonly Dictionary<string, (string, string?, string?, int?, decimal?)> AreaComTypes;
protected Billing(int year, Season season,
Dictionary<string, string> attributes,
Dictionary<string, (decimal?, decimal?)> modifiers,
Dictionary<string, (string, string?, string?, int?, decimal?)> areaComTypes
) {
public Billing(int 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();
var (season, attributes, modifiers, areaComTypes) = await LoadData(ctx, year);
return new Billing(year, season, attributes, modifiers, areaComTypes);
Season = ctx.Seasons.Find(Year)!;
Attributes = ctx.WineAttributes.ToDictionary(a => a.AttrId, a => a.Name);
Modifiers = ctx.Modifiers.Where(m => m.Year == Year).Include(m => m.Season).ToDictionary(m => m.ModId, m => (m.Abs, m.Rel));
AreaComTypes = ctx.AreaCommitmentTypes.ToDictionary(v => v.VtrgId, v => (v.SortId, v.AttrId, v.Discriminator, v.MinKgPerHa, v.PenaltyAmount));
}
public async Task FinishSeason() {
+23 -25
View File
@@ -5,7 +5,6 @@ using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Threading.Tasks;
@@ -93,14 +92,6 @@ namespace Elwig.Helpers.Billing {
Mode = (mode == "elwig") ? CalculationMode.Elwig : CalculationMode.WgMaster;
}
public BillingData() {
Data = new JsonObject {
["mode"] = "elwig",
["version"] = 1,
};
Mode = CalculationMode.Elwig;
}
protected static JsonObject ParseJson(string json) {
if (Schema == null) throw new InvalidOperationException("Schema has to be initialized first");
try {
@@ -116,10 +107,6 @@ namespace Elwig.Helpers.Billing {
return new(ParseJson(json));
}
public string ToJsonString(JsonSerializerOptions? options = null) {
return Data.ToJsonString(options);
}
protected JsonArray GetCurvesEntry() {
return Data[Mode == CalculationMode.Elwig ? "curves" : "Kurven"]?.AsArray() ?? throw new InvalidOperationException();
}
@@ -425,7 +412,7 @@ namespace Elwig.Helpers.Billing {
}
}
public static BillingData FromGraphEntries(
public static JsonObject FromGraphEntries(
IEnumerable<GraphEntry> graphEntries,
BillingData? origData = null,
IEnumerable<RawVaribute>? vaributes = null,
@@ -459,29 +446,40 @@ namespace Elwig.Helpers.Billing {
}
}
CollapsePaymentData(payment, payment.DeepClone().AsObject(), vaributes ?? [.. payment.Select(e => new RawVaribute(e.Key))], useDefaultPayment);
CollapsePaymentData(qualityWei, qualityWei.DeepClone().AsObject(), vaributes ?? [.. qualityWei.Select(e => new RawVaribute(e.Key))], useDefaultQuality);
CollapsePaymentData(payment, payment.DeepClone().AsObject(), vaributes ?? payment.Select(e => new RawVaribute(e.Key)).ToList(), useDefaultPayment);
CollapsePaymentData(qualityWei, qualityWei.DeepClone().AsObject(), vaributes ?? qualityWei.Select(e => new RawVaribute(e.Key)).ToList(), useDefaultQuality);
var data = new JsonObject {
["mode"] = "elwig",
["version"] = 1,
};
if (origData?.ConsiderDelieryModifiers == true)
data["consider_delivery_modifiers"] = true;
if (origData?.ConsiderContractPenalties == true)
data["consider_contract_penalties"] = true;
if (origData?.ConsiderTotalPenalty == true)
data["consider_total_penalty"] = true;
if (origData?.ConsiderAutoBusinessShares == true)
data["consider_auto_business_shares"] = true;
BillingData data = origData != null && origData.Mode == CalculationMode.Elwig ? new BillingData((JsonObject)origData.Data.DeepClone()) : new BillingData();
if (payment.Count == 0) {
data.Data["payment"] = 0;
data["payment"] = 0;
} else if (payment.Count == 1 && payment.First().Key == "default") {
data.Data["payment"] = payment.Single().Value?.DeepClone();
data["payment"] = payment.Single().Value?.DeepClone();
} else {
data.Data["payment"] = payment;
data["payment"] = payment;
}
if (qualityWei.Count == 1 && qualityWei.First().Key == "default") {
data.Data["quality"] = new JsonObject() {
data["quality"] = new JsonObject() {
["WEI"] = qualityWei.Single().Value?.DeepClone()
};
} else if (qualityWei.Count >= 1) {
data.Data["quality"] = new JsonObject() {
data["quality"] = new JsonObject() {
["WEI"] = qualityWei
};
} else {
data.Data.Remove("quality");
}
data.Data["curves"] = curves;
data["curves"] = curves;
return data;
}
+7 -25
View File
@@ -10,35 +10,17 @@ namespace Elwig.Helpers.Billing {
public class BillingVariant : Billing {
protected readonly int AvNr;
protected PaymentVar PaymentVariant;
protected PaymentBillingData Data;
protected readonly PaymentVar PaymentVariant;
protected readonly PaymentBillingData Data;
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) {
public BillingVariant(int year, int avnr) : base(year) {
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();
var (season, attributes, modifiers, areaComTypes) = await LoadData(ctx, year);
var (paymentVar, data) = await LoadData(ctx, year, avnr);
return new BillingVariant(year, avnr, season, attributes, modifiers, areaComTypes, paymentVar, data);
PaymentVariant = ctx.PaymentVariants.Include(v => v.Season).Where(v => v.Year == Year && v.AvNr == AvNr).Single() ?? throw new ArgumentException("PaymentVar not found");
Data = PaymentBillingData.FromJson(PaymentVariant.Data, Utils.GetVaributes(ctx, Year, onlyDelivered: false));
}
public async Task Calculate(bool strictPrices = true, bool? honorGebunden = null, bool? allowAttrsIntoLower = null, bool? avoidUnderDeliveries = null) {
if (PaymentVariant == null || Data == null) throw new Exception("Call Load before Calculate");
using var cnx = await AppDbContext.ConnectAsync();
using var tx = await cnx.BeginTransactionAsync();
await CalculateBuckets(honorGebunden, allowAttrsIntoLower, avoidUnderDeliveries, cnx);
@@ -98,7 +80,7 @@ namespace Elwig.Helpers.Billing {
LEFT JOIN v_penalty_area_commitments u ON (u.year, u.mgnr) = (s.year, m.mgnr)
LEFT JOIN v_auto_business_shares a ON (a.year, a.mgnr) = (s.year, m.mgnr)
LEFT JOIN payment_custom x ON (x.year, x.mgnr) = (s.year, m.mgnr)
WHERE s.year = {Year} AND v.avnr = {AvNr} AND p.amount != COALESCE(lp.amount, 0);
WHERE s.year = {Year} AND v.avnr = {AvNr} AND p.amount > COALESCE(lp.amount, 0);
""");
await cnx.ExecuteBatch($"""
UPDATE payment_variant SET test_variant = FALSE WHERE (year, avnr) = ({Year}, {AvNr});
@@ -232,7 +214,7 @@ namespace Elwig.Helpers.Billing {
SET mod_rel = mod_rel + excluded.mod_rel;
INSERT INTO payment_delivery_part (year, did, dpnr, avnr, net_amount, mod_abs, mod_rel)
SELECT d.year, d.did, d.dpnr, {AvNr}, 0, COALESCE(m.abs, 0) * d.weight, COALESCE(m.rel, 0)
SELECT d.year, d.did, d.dpnr, {AvNr}, 0, COALESCE(m.abs, 0), COALESCE(m.rel, 0)
FROM delivery_part d
LEFT JOIN delivery_part_modifier p ON (p.year, p.did, p.dpnr) = (d.year, d.did, d.dpnr)
LEFT JOIN modifier m ON (m.year, m.modid) = (d.year, p.modid)
+8 -9
View File
@@ -3,7 +3,6 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json.Nodes;
using System.Threading.Tasks;
namespace Elwig.Helpers.Billing {
public class EditBillingData : BillingData {
@@ -71,14 +70,14 @@ namespace Elwig.Helpers.Billing {
return (curves, dict3);
}
private static async Task<List<GraphEntry>> CreateGraphEntries(
private static List<GraphEntry> CreateGraphEntries(
AppDbContext ctx, int precision,
Dictionary<int, Curve> curves,
Dictionary<int, List<RawVaribute>> entries
) {
var vars = await ctx.FetchWineVarieties().ToDictionaryAsync(v => v.SortId, v => v);
var attrs = await ctx.FetchWineAttributes().ToDictionaryAsync(a => a.AttrId, a => a);
var cults = await ctx.FetchWineCultivations().ToDictionaryAsync(c => c.CultId, c => c);
var vars = ctx.WineVarieties.ToDictionary(v => v.SortId, v => v);
var attrs = ctx.WineAttributes.ToDictionary(a => a.AttrId, a => a);
var cults = ctx.WineCultivations.ToDictionary(c => c.CultId, c => c);
return entries
.Select(e => new GraphEntry(e.Key, precision, curves[e.Key], e.Value
.Select(s => new Varibute(s, vars, attrs, cults))
@@ -86,18 +85,18 @@ namespace Elwig.Helpers.Billing {
.ToList();
}
public async Task<IEnumerable<GraphEntry>> GetPaymentGraphEntries(AppDbContext ctx, Season season) {
public IEnumerable<GraphEntry> GetPaymentGraphEntries(AppDbContext ctx, Season season) {
var root = GetPaymentEntry();
var (curves, entries) = GetGraphEntries(root);
return (await CreateGraphEntries(ctx, season.Precision, curves, entries)).Where(e => e.Vaributes.Count > 0);
return CreateGraphEntries(ctx, season.Precision, curves, entries).Where(e => e.Vaributes.Count > 0);
}
public async Task<IEnumerable<GraphEntry>> GetQualityGraphEntries(AppDbContext ctx, Season season, int idOffset = 0) {
public IEnumerable<GraphEntry> GetQualityGraphEntries(AppDbContext ctx, Season season, int idOffset = 0) {
var root = GetQualityEntry();
if (root == null || root["WEI"] is not JsonNode qualityWei)
return [];
var (curves, entries) = GetGraphEntries(qualityWei);
var list = (await CreateGraphEntries(ctx, season.Precision, curves, entries)).Where(e => e.Vaributes.Count > 0);
var list = CreateGraphEntries(ctx, season.Precision, curves, entries).Where(e => e.Vaributes.Count > 0);
foreach (var e in list) {
e.Id += idOffset;
e.Abgewertet = true;
+1 -5
View File
@@ -8,18 +8,16 @@ using System.Threading.Tasks;
namespace Elwig.Helpers {
public class ClientParameters {
public enum Type { Matzen, Winzerkeller, Weinland, Baden, Seewinkel };
public enum Type { Matzen, Winzerkeller, Weinland, Baden };
public bool IsMatzen => Client == Type.Matzen;
public bool IsWinzerkeller => Client == Type.Winzerkeller;
public bool IsWeinland => Client == Type.Weinland;
public bool IsBaden => Client == Type.Baden;
public bool IsSeewinkel => Client == Type.Seewinkel;
public bool IsWolkersdorf => IsWinzerkeller && App.ZwstId == "W";
public bool IsHaugsdorf => IsWinzerkeller && App.ZwstId == "H";
public bool IsSitzendorf => IsWinzerkeller && App.ZwstId == "S";
public bool IsGrInzersdorf => IsWeinland;
public bool IsPamhagen => IsSeewinkel;
public string NameToken;
public string NameShort;
@@ -95,8 +93,6 @@ namespace Elwig.Helpers {
Client = Type.Weinland; break;
case "Winzergenossenschaft Baden - Bad Vöslau":
Client = Type.Baden; break;
case "Winzerkeller Seewinkel":
Client = Type.Seewinkel; break;
};
Plz = int.Parse(parameters["CLIENT_PLZ"] ?? "");
+34 -25
View File
@@ -1,5 +1,4 @@
using Elwig.Models.Entities;
using Elwig.Services;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
@@ -9,6 +8,7 @@ using System.IO.Compression;
using System.Linq;
using System.Text.Json.Nodes;
using System.Threading.Tasks;
using System.Windows;
namespace Elwig.Helpers.Export {
public static class ElwigData {
@@ -41,7 +41,7 @@ namespace Elwig.Helpers.Export {
List<WbGl> currentWbGls;
using (var ctx = new AppDbContext()) {
branches = await ctx.FetchBranches().ToDictionaryAsync(b => b.ZwstId);
branches = await ctx.Branches.ToDictionaryAsync(b => b.ZwstId);
currentDids = await ctx.Deliveries
.GroupBy(d => d.Year)
.ToDictionaryAsync(g => g.Key, g => g.Max(d => d.DId));
@@ -208,18 +208,23 @@ namespace Elwig.Helpers.Export {
exc is FileNotFoundException ||
exc is IOException) {
data.RemoveAt(data.Count - 1);
InteractionService.ShowException("Fehler beim Importieren", $"Die Elwig-Export-Datei '{Path.GetFileName(filename)}' konnte nicht verarbeitet werden und wird übersprungen", exc);
var str = $"Die Elwig-Export-Datei '{Path.GetFileName(filename)}' konnte nicht verarbeitet werden und wird übersprungen.\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Fehler beim Importieren", MessageBoxButton.OK, MessageBoxImage.Error);
await AddImportedFiles(Path.GetFileName(filename));
} catch (Exception exc) {
data.RemoveAt(data.Count - 1);
if (InteractionService.AskException("Fehler beim Importieren", $"Die Elwig-Export-Datei '{Path.GetFileName(filename)}' konnte nicht verarbeitet werden. Soll sie in Zukunft übersprungen werden?", exc)) {
var str = $"Die Elwig-Export-Datei '{Path.GetFileName(filename)}' konnte nicht verarbeitet werden. Soll sie in Zukunft übersprungen werden?\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
var r = MessageBox.Show(str, "Fehler beim Importieren", MessageBoxButton.YesNo, MessageBoxImage.Error, MessageBoxResult.No);
if (r == MessageBoxResult.Yes) {
await AddImportedFiles(Path.GetFileName(filename));
}
}
}
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 New, int Overwritten, int NotImported, string? Filters)>();
var importedAreaComs = new List<(string FileName, string ZwstId, string Device, int Imported, int NotImported, string? Filters)>();
var importedDeliveries = new List<(string FileName, string ZwstId, string Device, int New, int Overwritten, int NotImported, string? Filters)>();
foreach (var ((members, billingAddresses, telephoneNumbers, emailAddresses, areaCommitments, contracts, riede, wbKgs, wbGls, deliveries, deliveryParts, modifiers, timestamps), meta) in data.Zip(metaData)) {
@@ -303,9 +308,9 @@ namespace Elwig.Helpers.Export {
}
if (importDuplicateMembers) {
ctx.RemoveRange(ctx.BillingAddresses.IgnoreAutoIncludes().Where(a => duplicateMgNrs.Contains(a.MgNr)));
ctx.RemoveRange(ctx.MemberTelephoneNrs.IgnoreAutoIncludes().Where(n => duplicateMgNrs.Contains(n.MgNr)));
ctx.RemoveRange(ctx.MemberEmailAddrs.IgnoreAutoIncludes().Where(a => duplicateMgNrs.Contains(a.MgNr)));
ctx.RemoveRange(ctx.BillingAddresses.Where(a => duplicateMgNrs.Contains(a.MgNr)));
ctx.RemoveRange(ctx.MemberTelephoneNrs.Where(n => duplicateMgNrs.Contains(n.MgNr)));
ctx.RemoveRange(ctx.MemberEmailAddrs.Where(a => duplicateMgNrs.Contains(a.MgNr)));
ctx.UpdateRange(members.Where(m => duplicateMgNrs.Contains(m.MgNr)));
ctx.AddRange(billingAddresses.Where(a => duplicateMgNrs.Contains(a.MgNr)));
ctx.AddRange(telephoneNumbers.Where(n => duplicateMgNrs.Contains(n.MgNr)));
@@ -324,7 +329,7 @@ namespace Elwig.Helpers.Export {
}
if (importDuplicateContracts) {
ctx.RemoveRange(ctx.AreaCommitments.IgnoreAutoIncludes().Where(c => duplicateFbNrs.Contains(c.FbNr)));
ctx.RemoveRange(ctx.AreaCommitments.Where(c => duplicateFbNrs.Contains(c.FbNr)));
ctx.UpdateRange(contracts.Where(c => duplicateFbNrs.Contains(c.FbNr)));
ctx.AddRange(areaCommitments.Where(c => duplicateFbNrs.Contains(c.FbNr)));
}
@@ -334,9 +339,8 @@ namespace Elwig.Helpers.Export {
}
if (contracts.Count > 0) {
ctx.AddRange(riede);
var n = importNewContracts ? contracts.Count - duplicateFbNrs.Count : 0;
var o = importDuplicateContracts ? duplicateFbNrs.Count : 0;
importedAreaComs.Add((meta.FileName, meta.ZwstId, meta.Device, n, o, contracts.Count - n - o, meta.AreaComFilters));
var imported = contracts.Where(c => (importNewContracts && !duplicateFbNrs.Contains(c.FbNr)) || (importDuplicateContracts && duplicateFbNrs.Contains(c.FbNr))).ToList();
importedAreaComs.Add((meta.FileName, meta.ZwstId, meta.Device, imported.Count, areaCommitments.Count - imported.Count, meta.AreaComFilters));
}
if (allowedDuplicateLsNrs.Count > 0) {
@@ -345,10 +349,9 @@ namespace Elwig.Helpers.Export {
.Select(d => (d.Year, d.DId))
.ToList();
ctx.RemoveRange(ctx.DeliveryParts
.IgnoreAutoIncludes()
.Where(p => allowedDuplicateLsNrs.Contains(p.Delivery.LsNr))
.SelectMany(p => p.PartModifiers));
ctx.RemoveRange(ctx.DeliveryParts.IgnoreAutoIncludes().Where(p => allowedDuplicateLsNrs.Contains(p.Delivery.LsNr)));
ctx.RemoveRange(ctx.DeliveryParts.Where(p => allowedDuplicateLsNrs.Contains(p.Delivery.LsNr)));
ctx.UpdateRange(deliveries.Where(d => dids.Contains((d.Year, d.DId))));
ctx.AddRange(deliveryParts.Where(p => dids.Contains((p.Year, p.DId))));
ctx.AddRange(modifiers.Where(m => dids.Contains((m.Year, m.DId))));
@@ -360,10 +363,9 @@ namespace Elwig.Helpers.Export {
.Select(d => (d.Year, d.DId))
.ToList();
ctx.RemoveRange(ctx.DeliveryParts
.IgnoreAutoIncludes()
.Where(p => l.Contains(p.Delivery.LsNr))
.SelectMany(p => p.PartModifiers));
ctx.RemoveRange(ctx.DeliveryParts.IgnoreAutoIncludes().Where(p => l.Contains(p.Delivery.LsNr)));
ctx.RemoveRange(ctx.DeliveryParts.Where(p => l.Contains(p.Delivery.LsNr)));
ctx.UpdateRange(deliveries.Where(d => dids.Contains((d.Year, d.DId))));
ctx.AddRange(deliveryParts.Where(p => dids.Contains((p.Year, p.DId))));
ctx.AddRange(modifiers.Where(m => dids.Contains((m.Year, m.DId))));
@@ -406,7 +408,7 @@ namespace Elwig.Helpers.Export {
}
App.HintContextChange();
InteractionService.ShowInformation("Importieren erfolgreich",
MessageBox.Show(
$"Das importieren der Daten war erfolgreich!\n" +
$"Folgendes wurde importiert:\n" +
string.Join("\n", [
@@ -416,10 +418,10 @@ namespace Elwig.Helpers.Export {
$" ({d.New} neu, {d.Overwritten} überschrieben, {d.NotImported} nicht importiert)\n" +
$" Zweigstelle: {branches[d.ZwstId].Name} (Gerät {d.Device})\n" +
$" Filter: {d.Filters}"),
$"Flächenbindungen: {importedAreaComs.Sum(d => d.New + d.Overwritten)}",
$"Flächenbindungen: {importedAreaComs.Sum(d => d.Imported)}",
..importedAreaComs.Select(d =>
$" {d.FileName} ({d.New + d.Overwritten})\n" +
$" ({d.New} importiert, {d.Overwritten} überschreiben, {d.NotImported} nicht importiert)\n" +
$" {d.FileName} ({d.Imported})\n" +
$" ({d.Imported} importiert, {d.NotImported} nicht importiert)\n" +
$" Zweigstelle: {branches[d.ZwstId].Name} (Gerät {d.Device})\n" +
$" Filter: {d.Filters}"),
$"Lieferungen: {importedDeliveries.Sum(d => d.New + d.Overwritten)}",
@@ -428,18 +430,25 @@ namespace Elwig.Helpers.Export {
$" ({d.New} neu, {d.Overwritten} überschr., {d.NotImported} nicht importiert)\n" +
$" Zwst.: {branches[d.ZwstId].Name} (Gerät {d.Device})\n" +
$" Filter: {d.Filters}")
]));
]),
"Importieren erfolgreich",
MessageBoxButton.OK, MessageBoxImage.Information);
} catch (Exception exc) {
InteractionService.ShowException("Fehler beim Importieren", "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\nEvtl. muss die Datenbank manuell auf dieses Gerät kopieren werden", exc);
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\nEvtl. muss die Datenbank manuell auf dieses Gerät kopieren werden.\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Fehler beim Importieren", MessageBoxButton.OK, MessageBoxImage.Error);
}
GC.Collect();
GC.WaitForPendingFinalizers();
}
private static bool ImportQuestion(string branch, string device, string subject, bool duplicate, int number) {
return InteractionService.AskQuestion($"{subject} importieren",
return MessageBox.Show(
$"Sollen {number} {(duplicate ? "" : "neue ")}{subject} durch die Zweigstelle\n" +
$"{branch} (Gerät {device}) {(duplicate ? "überschrieben" : "importiert")} werden?", true);
$"{branch} (Gerät {device}) {(duplicate ? "überschrieben" : "importiert")} werden?",
$"{subject} importieren",
MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.Yes
) == MessageBoxResult.Yes;
}
public static Task Export(string filename, IEnumerable<Member> members, IEnumerable<WbKg> wbKgs, IEnumerable<string> filters) {
@@ -851,7 +860,7 @@ namespace Elwig.Helpers.Export {
["ried"] = p.Rd?.Name,
["net_weight"] = p.IsNetWeight,
["manual_weighing"] = p.IsManualWeighing,
["modids"] = new JsonArray(p.PartModifiers.Select(m => (JsonNode)m.ModId).ToArray()),
["modids"] = new JsonArray(p.Modifiers.Select(m => (JsonNode)m.ModId).ToArray()),
["comment"] = p.Comment,
["created_at"] = $"{p.CreatedAt:yyyy-MM-ddTHH:mm:ssK}",
["modified_at"] = $"{p.ModifiedAt:yyyy-MM-ddTHH:mm:ssK}",
+3 -3
View File
@@ -1,8 +1,8 @@
using Elwig.Services;
using Elwig.Windows;
using System;
using System.Drawing.Printing;
using System.Threading.Tasks;
using System.Windows;
namespace Elwig.Helpers.Printing {
public static class Pdf {
@@ -46,8 +46,8 @@ namespace Elwig.Helpers.Printing {
PrinterSettings = settings,
};
printDoc.Print();
} catch (Exception exc) {
InteractionService.ShowException("Fehler beim Drucken", "Beim Drucken ist ein Fehler aufgetreten", exc);
} catch (Exception e) {
MessageBox.Show("Beim Drucken ist ein Fehler aufgetreten:\n\n" + e.Message, "Fehler beim Drucken", MessageBoxButton.OK, MessageBoxImage.Error);
}
return Task.CompletedTask;
}
+34 -31
View File
@@ -3,12 +3,12 @@ using Elwig.Documents;
using Elwig.Helpers.Billing;
using Elwig.Models;
using Elwig.Models.Entities;
using Elwig.Services;
using iText.Layout.Element;
using LinqKit;
using MailKit.Net.Smtp;
using MailKit.Security;
using Microsoft.EntityFrameworkCore;
using Microsoft.Win32;
using MimeKit;
using System;
using System.Collections;
@@ -213,8 +213,8 @@ namespace Elwig.Helpers {
Task.Run(async () => {
try {
await a();
} catch (Exception exc) {
InteractionService.ShowException(title, exc);
} catch (Exception e) {
MessageBox.Show(e.ToString(), title, MessageBoxButton.OK, MessageBoxImage.Error);
}
});
}
@@ -413,8 +413,8 @@ namespace Elwig.Helpers {
return output.OrderByDescending(l => l.Count());
}
public static async Task<List<RawVaribute>> GetVaributes(AppDbContext ctx, int year, bool onlyDelivered = true) {
var varieties = await ctx.FetchWineVarieties().Select(v => new RawVaribute(v.SortId, "", null)).ToListAsync();
public static List<RawVaribute> GetVaributes(AppDbContext ctx, int year, bool onlyDelivered = true) {
var varieties = ctx.WineVarieties.Select(v => new RawVaribute(v.SortId, "", null)).ToList();
var delivered = ctx.DeliveryParts
.Where(d => d.Year == year)
.Select(d => new RawVaribute(d.SortId, d.AttrId ?? "", d.CultId ?? ""))
@@ -423,11 +423,13 @@ namespace Elwig.Helpers {
return [.. (onlyDelivered ? delivered : delivered.Union(varieties)).Order()];
}
public static async Task<List<Varibute>> GetVaributeList(AppDbContext ctx, int year, bool onlyDelivered = true) {
var varieties = await ctx.FetchWineVarieties().ToDictionaryAsync(v => v.SortId, v => v);
var attributes = await ctx.FetchWineAttributes().ToDictionaryAsync(a => a.AttrId, a => a);
var cultivations = await ctx.FetchWineCultivations().ToDictionaryAsync(c => c.CultId, c => c);
return [.. (await GetVaributes(ctx, year, onlyDelivered)).Select(s => new Varibute(s, varieties, attributes, cultivations))];
public static List<Varibute> GetVaributeList(AppDbContext ctx, int year, bool onlyDelivered = true) {
var varieties = ctx.WineVarieties.ToDictionary(v => v.SortId, v => v);
var attributes = ctx.WineAttributes.ToDictionary(a => a.AttrId, a => a);
var cultivations = ctx.WineCultivations.ToDictionary(c => c.CultId, c => c);
return GetVaributes(ctx, year, onlyDelivered)
.Select(s => new Varibute(s, varieties, attributes, cultivations))
.ToList();
}
[LibraryImport("wininet.dll")]
@@ -537,7 +539,7 @@ namespace Elwig.Helpers {
subject, docs.Select(d => d.Title).ToArray()
)]);
} catch (Exception exc) {
InteractionService.ShowException(exc);
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
return false;
} finally {
if (client != null)
@@ -551,40 +553,41 @@ namespace Elwig.Helpers {
public static async Task ExportDocument(Document doc, ExportMode mode, string? filename = null, (Member Member, string Subject, string Text)? emailData = null) {
if (mode == ExportMode.Print && !App.Config.Debug) {
if (doc.IsPreview) {
InteractionService.ShowError("Vorläufiges Dokument", "Dieses Dokument ist als vorläufig markiert und kann daher nicht ausgedruckt werden!");
MessageBox.Show("Dieses Dokument ist als vorläufig markiert und kann daher nicht ausgedruckt werden!",
"Vorläufiges Dokument", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
using (var ctx = new AppDbContext()) {
await doc.Generate(ctx);
}
await doc.Generate();
await doc.Print();
} else if (mode == ExportMode.Email && emailData is (Member, string, string) e) {
if (doc.IsPreview) {
InteractionService.ShowError("Vorläufiges Dokument", "Dieses Dokument ist als vorläufig markiert und kann daher nicht verschickt werden!");
MessageBox.Show("Dieses Dokument ist als vorläufig markiert und kann daher nicht verschickt werden!",
"Vorläufiges Dokument", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
using (var ctx = new AppDbContext()) {
await doc.Generate(ctx);
}
await doc.Generate();
var success = await SendEmail(e.Member, e.Subject, e.Text, [doc]);
if (success)
InteractionService.ShowInformation("E-Mail verschickt", "Die E-Mail wurde erfolgreich verschickt!\n\nEs kann einige Minuten dauern, bis die E-Mail im Posteingang des Empfängers aufscheint.");
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",
MessageBoxButton.OK, MessageBoxImage.Information);
} else if (mode == ExportMode.SavePdf) {
if (doc.IsPreview) {
InteractionService.ShowWarning("Vorläufiges Dokument", "Dieses Dokument ist als vorläufig markiert und sollte daher nicht langfristig gespeichert werden!");
MessageBox.Show("Dieses Dokument ist als vorläufig markiert und sollte daher nicht langfristig gespeichert werden!",
"Vorläufiges Dokument", MessageBoxButton.OK, MessageBoxImage.Warning);
}
filename = InteractionService.SaveFile(doc.Title, NormalizeFileName(filename ?? doc.Title), "pdf");
if (filename != null) {
using (var ctx = new AppDbContext()) {
await doc.Generate(ctx);
}
doc.SaveTo(filename);
Process.Start("explorer.exe", filename);
var d = new SaveFileDialog() {
FileName = $"{NormalizeFileName(filename ?? doc.Title)}.pdf",
DefaultExt = "pdf",
Filter = "PDF-Datei (*.pdf)|*.pdf",
Title = $"{doc.Title} speichern unter - Elwig"
};
if (d.ShowDialog() == true) {
await doc.Generate();
doc.SaveTo(d.FileName);
Process.Start("explorer.exe", d.FileName);
}
} else {
using (var ctx = new AppDbContext()) {
await doc.Generate(ctx);
}
await doc.Generate();
doc.Show();
}
}
+4 -3
View File
@@ -1,9 +1,9 @@
using Elwig.Services;
using System;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
namespace Elwig.Helpers.Weighing {
public class AveryEventScale : Scale, IEventScale, IDisposable {
@@ -60,8 +60,9 @@ namespace Elwig.Helpers.Weighing {
} catch (TimeoutException) {
await Task.Delay(500);
await Reconnect();
} catch (Exception exc) {
InteractionService.ShowException("Waagenfehler", "Beim Wiegen ist ein Fehler Aufgetreten", exc, showExcType: true);
} catch (Exception ex) {
MessageBox.Show($"Beim Wiegen ist ein Fehler Aufgetreten:\n\n{ex.Message} ({ex.GetType().Name})", "Waagenfehler",
MessageBoxButton.OK, MessageBoxImage.Error);
}
}
}
+4 -3
View File
@@ -1,9 +1,9 @@
using Elwig.Services;
using System;
using System.IO;
using System.IO.Ports;
using System.Net.Sockets;
using System.Text;
using System.Windows;
namespace Elwig.Helpers.Weighing {
public abstract class Scale : IDisposable {
@@ -42,10 +42,11 @@ namespace Elwig.Helpers.Weighing {
if (cnx.StartsWith("serial:")) {
try {
Serial = Utils.OpenSerialConnection(cnx);
} catch (Exception exc) {
} catch (Exception e) {
if (!softFail) throw;
if (!failSilent)
InteractionService.ShowException("Waagenfehler", "Verbindung zu Waage konnte nicht hergestellt werden", exc, isError: false);
MessageBox.Show($"Verbindung zu Waage konnte nicht hergestellt werden:\n\n{e.Message}", "Waagenfehler",
MessageBoxButton.OK, MessageBoxImage.Warning);
}
Stream = Serial?.BaseStream ?? Stream.Null;
} else if (cnx.StartsWith("tcp:")) {
+2 -2
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) {
var variant = await paymentVariants.Include(v => v.Season.Modifiers).Where(v => v.Year == year && v.AvNr == avnr).SingleAsync();
var variant = await paymentVariants.FindAsync(year, avnr);
BillingData? varData = null;
try { varData = variant.Data != null ? BillingData.FromJson(variant.Data) : null; } catch { }
try { varData = variant != null ? BillingData.FromJson(variant.Data) : null; } catch { }
return (await FromDbSet(table, year, avnr))
.GroupBy(
r => new { r.Year, r.AvNr, r.MgNr, r.TgNr, r.DId, r.DPNr },
+6 -1
View File
@@ -28,7 +28,12 @@ namespace Elwig.Models.Dtos {
}
public static async Task<DeliveryAncmtListData> FromQuery(IQueryable<DeliveryAncmt> query, List<string> filterNames) {
return new((await query.ToListAsync()).Select(d => new DeliveryAncmtListRow(d)), filterNames);
return new((await query
.Include(a => a.Schedule.Branch)
.Include(a => a.Member)
.Include(a => a.Variety)
.AsSplitQuery()
.ToListAsync()).Select(d => new DeliveryAncmtListRow(d)), filterNames);
}
}
@@ -52,8 +52,12 @@ namespace Elwig.Models.Dtos {
if (mgnr != null) q = q.Where(p => p.Delivery.MgNr == mgnr);
await q
.Include(p => p.Delivery)
.Include(p => p.Variety)
.Include(p => p.Attribute)
.Include(p => p.Quality)
.Include(p => p.Buckets)
.Include(p => p.PartModifiers).ThenInclude(m => m.Modifier)
.Include(p => p.PartModifiers)
.ThenInclude(m => m.Modifier)
.LoadAsync();
return await table.FromSqlRaw($"""
SELECT p.*
@@ -61,7 +65,7 @@ namespace Elwig.Models.Dtos {
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)
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
""").IgnoreAutoIncludes().ToListAsync();
""").ToListAsync();
}
}
+5
View File
@@ -40,7 +40,12 @@ namespace Elwig.Models.Dtos {
.Include(p => p.Delivery.Member.Branch)
.Include(p => p.Delivery.Branch)
.Include(p => p.PartModifiers).ThenInclude(m => m.Modifier)
.Include(p => p.Variety)
.Include(p => p.Attribute)
.Include(p => p.Cultivation)
.Include(p => p.Origin)
.Include(p => p.Quality)
.AsSplitQuery()
.ToListAsync()).Select(d => new DeliveryJournalRow(d)), filterNames);
}
}
+5 -1
View File
@@ -47,11 +47,15 @@ namespace Elwig.Models.Dtos {
}
public static async Task<MemberListData> FromQuery(IQueryable<Member> query, List<string> filterNames, IEnumerable<string> filterAreaCom) {
var areaComs = await query.Include(m => m.AreaCommitments).ToDictionaryAsync(m => m.MgNr, m => Utils.ActiveAreaCommitments(m.AreaCommitments));
var areaComs = await query.ToDictionaryAsync(m => m.MgNr, m => Utils.ActiveAreaCommitments(m.AreaCommitments));
return new((await query
.Include(m => m.DefaultWbKg!.AtKg)
.Include(m => m.Branch)
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.BillingAddress!.PostalDest.AtPlz!.Ort)
.Include(m => m.TelephoneNumbers)
.Include(m => m.EmailAddresses)
.AsSplitQuery()
.ToListAsync()).Select(m => new MemberListRow(m,
areaComs[m.MgNr].Sum(c => c.Area),
areaComs[m.MgNr].Where(c => filterAreaCom.Contains(c.VtrgId)).GroupBy(c => c.VtrgId).ToDictionary(g => g.Key, g => g.Sum(c => c.Area)))),
+6 -6
View File
@@ -106,21 +106,21 @@ namespace Elwig.Models.Entities {
[InverseProperty(nameof(DeliveryPart.Delivery))]
public virtual ICollection<DeliveryPart> Parts { get; private set; } = null!;
[NotMapped]
public IEnumerable<DeliveryPart> FilteredParts => PartFilter == null ? Parts : Parts.Where(p => PartFilter(p));
public IEnumerable<DeliveryPart> FilteredParts => PartFilter == null ? Parts : Parts.Where(p => PartFilter(p));
[NotMapped]
public Predicate<DeliveryPart>? PartFilter { get; set; }
public int Weight => Parts.Sum(p => p.Weight);
public int FilteredWeight => FilteredParts.Sum(p => p.Weight);
public int Weight => Parts.Select(p => p.Weight).Sum();
public int FilteredWeight => FilteredParts.Select(p => p.Weight).Sum();
public IEnumerable<RawVaribute> Vaributes => Parts
.GroupBy(p => (p.SortId, p.AttrId, p.CultId))
.OrderByDescending(g => g.Sum(p => p.Weight))
.OrderByDescending(g => g.Select(p => p.Weight).Sum())
.Select(g => new RawVaribute(g.Key.SortId, g.Key.AttrId, g.Key.CultId));
public IEnumerable<RawVaribute> FilteredVaributes => FilteredParts
.GroupBy(p => (p.SortId, p.AttrId, p.CultId))
.OrderByDescending(g => g.Sum(p => p.Weight))
.OrderByDescending(g => g.Select(p => p.Weight).Sum())
.Select(g => new RawVaribute(g.Key.SortId, g.Key.AttrId, g.Key.CultId));
public string VaributeString => string.Join(", ", Vaributes);
public string FilteredVaributeString => string.Join(", ", FilteredVaributes);
@@ -153,7 +153,7 @@ namespace Elwig.Models.Entities {
Member.Name, Member.MiddleName, Member.GivenName, Member.BillingAddress?.FullName,
Comment
}.ToList();
list.AddRange(FilteredParts.Select(p => p.Comment).Distinct());
list.AddRange(Parts.Select(p => p.Comment).Distinct());
return Utils.GetSearchScore(list, keywords);
}
}
+2 -4
View File
@@ -27,15 +27,13 @@ namespace Elwig.Models.Entities {
public virtual ICollection<WbGem> Gems { get; private set; } = null!;
[InverseProperty(nameof(Parent))]
public virtual ICollection<WineOrigin> RealChildren { get; private set; } = null!;
[NotMapped]
public List<WineOrigin> Children { get; private set; } = [];
public virtual ICollection<WineOrigin> Children { get; private set; } = null!;
public int Level => (Parent?.Level + 1) ?? 0;
public string HkIdLevel => $"{new string(' ', Level * 2)}{HkId}";
public int TotalChildNum => 1 + Children.Sum(c => c.TotalChildNum);
public int TotalChildNum => 1 + Children.Select(c => c.TotalChildNum).Sum();
private int SortKey1 => (Parent?.SortKey1 ?? 0) | (TotalChildNum << ((3 - Level) * 8));
public int SortKey => SortKey1 | ((Level < 3) ? (-1 >>> (Level * 8 + 8)) : 0);
-21
View File
@@ -153,27 +153,6 @@ 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
-8
View File
@@ -1,8 +0,0 @@
-- schema version 38 to 39
PRAGMA writable_schema = ON;
UPDATE sqlite_schema SET sql = REPLACE(sql, '{2,}', '{2,64}')
WHERE type = 'table' AND name = 'member_email_address';
PRAGMA writable_schema = OFF;
UPDATE wb_gem SET hkid = 'WLLB' WHERE gkz IN (10710, 10723);
+3 -4
View File
@@ -20,7 +20,6 @@ namespace Elwig.Services {
}
public static void ClearInputs(this AreaComAdminViewModel vm) {
vm.Period = null;
}
public static void FillInputs(this AreaComAdminViewModel vm, AreaComContract c) {
@@ -56,9 +55,9 @@ namespace Elwig.Services {
var filter = vm.TextFilter;
if (filter.Count > 0) {
var var = await ctx.FetchWineVarieties().ToDictionaryAsync(v => v.SortId, v => v);
var attrId = await ctx.FetchWineAttributes().ToDictionaryAsync(a => a.AttrId, a => a);
var attr = attrId.Values.ToDictionary(a => a.Name.ToLower().Split(" ")[0], a => a);
var var = await ctx.WineVarieties.ToDictionaryAsync(v => v.SortId, v => v);
var attr = await ctx.WineAttributes.ToDictionaryAsync(a => a.Name.ToLower().Split(" ")[0], a => a);
var attrId = await ctx.WineAttributes.ToDictionaryAsync(a => a.AttrId, a => a);
for (int i = 0; i < filter.Count; i++) {
var e = filter[i];
+29 -31
View File
@@ -8,6 +8,7 @@ using Microsoft.EntityFrameworkCore;
using Elwig.Documents;
using Elwig.Helpers.Export;
using Elwig.Models.Dtos;
using Microsoft.Win32;
using System.Windows.Input;
using System.Windows;
using System;
@@ -64,11 +65,11 @@ namespace Elwig.Services {
var filter = vm.TextFilter;
if (filter.Count > 0) {
var var = await ctx.FetchWineVarieties().ToDictionaryAsync(v => v.SortId, v => v);
var mgnr = await ctx.FetchMembers(includeNotActive: true).ToDictionaryAsync(m => m.MgNr.ToString(), m => m);
var zwst = await ctx.FetchBranches().ToDictionaryAsync(b => b.Name.ToLower().Split(' ')[0], b => b);
var attr = await ctx.FetchWineAttributes().ToDictionaryAsync(a => a.Name.ToLower().Split(' ')[0], a => a);
var cult = await ctx.FetchWineCultivations().ToDictionaryAsync(c => c.Name.ToLower().Split(' ')[0], c => c);
var var = await ctx.WineVarieties.ToDictionaryAsync(v => v.SortId, v => v);
var mgnr = await ctx.Members.ToDictionaryAsync(m => m.MgNr.ToString(), m => m);
var zwst = await ctx.Branches.ToDictionaryAsync(b => b.Name.ToLower().Split(' ')[0], b => b);
var attr = await ctx.WineAttributes.ToDictionaryAsync(a => a.Name.ToLower().Split(' ')[0], a => a);
var cult = await ctx.WineCultivations.ToDictionaryAsync(c => c.Name.ToLower().Split(' ')[0], c => c);
for (int i = 0; i < filter.Count; i++) {
var e = filter[i];
@@ -260,16 +261,21 @@ namespace Elwig.Services {
.ThenBy(a => a.Member.MgNr);
if (mode == ExportMode.SaveList) {
var filename = InteractionService.SaveFile(DeliveryAncmtList.Name, DeliveryAncmtList.Name, "ods");
if (filename != null) {
var d = new SaveFileDialog() {
FileName = $"{DeliveryAncmtList.Name}.ods",
DefaultExt = "ods",
Filter = "OpenDocument Format Spreadsheet (*.ods)|*.ods",
Title = $"{DeliveryAncmtList.Name} speichern unter - Elwig"
};
if (d.ShowDialog() == true) {
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
var data = await DeliveryAncmtListData.FromQuery(query, filterNames);
using var ods = new OdsFile(filename);
using var ods = new OdsFile(d.FileName);
await ods.AddTable(data);
} catch (Exception exc) {
InteractionService.ShowException(exc);
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
@@ -282,7 +288,7 @@ namespace Elwig.Services {
using var doc = new DeliveryAncmtList(string.Join(" / ", filterNames), data);
await Utils.ExportDocument(doc, mode);
} catch (Exception exc) {
InteractionService.ShowException(exc);
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
@@ -312,13 +318,18 @@ namespace Elwig.Services {
AddToolTipCell(grid, $"{weight * 100.0 / total2:N1} %", row, 4, 1, bold, true);
}
public static async Task<(string Text, (string?, string?, int, int?, int)[] Grid)> GenerateToolTipData(IQueryable<DeliveryAncmt> deliveryAncmts) {
var grid = new List<(string?, string?, int, int?, int)>();
public static async Task<(string, Grid)> GenerateToolTip(IQueryable<DeliveryAncmt> deliveryAncmts) {
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) });
var text = "-";
var weight = await deliveryAncmts.SumAsync(p => p.Weight);
text = $"{weight:N0} kg";
grid.Add(("Menge", null, weight, null, weight));
AddToolTipRow(grid, 0, "Menge", null, weight, null, weight);
if (await deliveryAncmts.AnyAsync()) {
var attrGroups = await deliveryAncmts
@@ -359,11 +370,13 @@ namespace Elwig.Services {
.ThenBy(g => g.SortId)
.ToListAsync();
int rowNum = 1;
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;
grid.Add((name, null, attrG.Weight, attrG.Weight, weight));
AddToolTipRow(grid, rowNum++, 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)) {
grid.Add((null, g.SortId, g.Weight, attrG.Weight, weight));
AddToolTipRow(grid, rowNum++, null, g.SortId, g.Weight, attrG.Weight, weight);
}
}
@@ -382,22 +395,7 @@ namespace Elwig.Services {
}
}
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;
return (text, grid);
}
}
}
+5 -5
View File
@@ -60,8 +60,8 @@ namespace Elwig.Services {
var filter = vm.TextFilter;
if (filter.Count > 0) {
var var = await ctx.FetchWineVarieties().ToDictionaryAsync(v => v.SortId, v => v);
var zwst = await ctx.FetchBranches().ToDictionaryAsync(b => b.Name.ToLower().Split(" ")[0], b => b);
var var = await ctx.WineVarieties.ToDictionaryAsync(v => v.SortId, v => v);
var zwst = await ctx.Branches.ToDictionaryAsync(b => b.Name.ToLower().Split(" ")[0], b => b);
for (int i = 0; i < filter.Count; i++) {
var e = filter[i];
@@ -174,12 +174,12 @@ namespace Elwig.Services {
ctx.Add(s);
}
await ctx.UpdateDeliveryScheduleWineVarieties(s, (await ctx.DeliveryScheduleWineVarieties
ctx.UpdateDeliveryScheduleWineVarieties(s, (await ctx.DeliveryScheduleWineVarieties
.Where(v => v.Year == s.Year && v.DsNr == s.DsNr)
.Select(v => new { v.Variety, v.Priority })
.ToListAsync())
.Select(v => (v.Variety.SortId, v.Priority))
.ToList(), vm.MainVarieties.Select(v => (v.SortId, 1)).Union(vm.OtherVarieties.Select(v => (v.SortId, 2))).ToList());
.Select(v => (v.Variety, v.Priority))
.ToList(), vm.MainVarieties.Select(v => (v, 1)).Union(vm.OtherVarieties.Select(v => (v, 2))).ToList());
await ctx.SaveChangesAsync();
});
+111 -105
View File
@@ -3,6 +3,7 @@ using Elwig.Helpers.Export;
using Elwig.Helpers;
using Elwig.Models.Dtos;
using Elwig.Models.Entities;
using Microsoft.Win32;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
@@ -26,7 +27,10 @@ namespace Elwig.Services {
public static async Task<Member?> GetMemberAsync(int mgnr) {
using var ctx = new AppDbContext();
return await ctx.FetchMembers(mgnr).SingleOrDefaultAsync();
return await ctx.Members
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.DefaultWbKg!.AtKg)
.FirstOrDefaultAsync(m => m.MgNr == mgnr);
}
public static Member? GetMember(int mgnr) {
@@ -67,7 +71,7 @@ namespace Elwig.Services {
vm.IsNetWeight = p.IsNetWeight;
vm.Modifiers.Clear();
foreach (var m in p.PartModifiers) {
foreach (var m in p.Modifiers) {
vm.Modifiers.Add((Modifier)ControlUtils.GetItemFromSourceWithPk(vm.ModifiersSource, m.Year, m.ModId)!);
}
@@ -125,12 +129,12 @@ namespace Elwig.Services {
var filter = vm.TextFilter;
if (filter.Count > 0) {
var var = await ctx.FetchWineVarieties().ToDictionaryAsync(v => v.SortId, v => v);
var qual = await ctx.FetchWineQualityLevels(false).ToDictionaryAsync(q => q.QualId, q => q);
var mgnr = await ctx.FetchMembers(includeNotActive: true).ToDictionaryAsync(m => m.MgNr.ToString(), m => m);
var zwst = await ctx.FetchBranches().ToDictionaryAsync(b => b.Name.ToLower().Split(' ')[0], b => b);
var attr = await ctx.FetchWineAttributes().ToDictionaryAsync(a => a.Name.ToLower().Split(' ')[0], a => a);
var cult = await ctx.FetchWineCultivations().ToDictionaryAsync(c => c.Name.ToLower().Split(' ')[0], c => c);
var var = await ctx.WineVarieties.ToDictionaryAsync(v => v.SortId, v => v);
var qual = await ctx.WineQualityLevels.Where(q => !q.IsPredicate).ToDictionaryAsync(q => q.QualId, q => q);
var mgnr = await ctx.Members.ToDictionaryAsync(m => m.MgNr.ToString(), m => m);
var zwst = await ctx.Branches.ToDictionaryAsync(b => b.Name.ToLower().Split(' ')[0], b => b);
var attr = await ctx.WineAttributes.ToDictionaryAsync(a => a.Name.ToLower().Split(' ')[0], a => a);
var cult = await ctx.WineCultivations.ToDictionaryAsync(c => c.Name.ToLower().Split(' ')[0], c => c);
for (int i = 0; i < filter.Count; i++) {
var e = filter[i];
@@ -468,7 +472,6 @@ namespace Elwig.Services {
DeliveryPart p;
using var ctx = new AppDbContext();
using var tx = await ctx.Database.BeginTransactionAsync();
int year = oldYear ?? Utils.CurrentYear;
int did = oldDid ?? await ctx.NextDId(year);
int dpnr = oldDpnr ?? await ctx.NextDPNr(year, did);
@@ -545,21 +548,21 @@ namespace Elwig.Services {
ctx.Add(p);
}
await ctx.UpdateDeliveryPartModifiers(p, await ctx.DeliveryPartModifiers
ctx.UpdateDeliveryPartModifiers(p, await ctx.DeliveryPartModifiers
.Where(m => m.Year == p.Year && m.DId == p.DId && m.DPNr == p.DPNr)
.Select(m => m.ModId)
.ToListAsync(), vm.Modifiers.Select(m => m.ModId).ToList());
.Select(m => m.Modifier)
.ToListAsync(), vm.Modifiers);
if (originalMgNr != null && originalMgNr.Value != d.MgNr) {
// update origin (KgNr), if default is selected
var newKgNr = (await ctx.FetchMembers(d.MgNr).SingleOrDefaultAsync())?.DefaultKgNr;
await ctx.DeliveryParts
.Where(p => p.Year == d.Year && p.DId == d.DId && p.DPNr != dpnr && p.KgNr == originalMemberKgNr)
.ExecuteUpdateAsync(u => u.SetProperty(p => p.KgNr, newKgNr));
var newKgNr = (await ctx.Members.FindAsync(d.MgNr))?.DefaultKgNr;
foreach (var part in d.Parts.Where(part => part.DPNr != dpnr && part.KgNr == originalMemberKgNr)) {
part.KgNr = newKgNr;
ctx.Update(part);
}
}
await ctx.SaveChangesAsync();
await tx.CommitAsync();
return p;
});
@@ -571,10 +574,7 @@ namespace Elwig.Services {
using var ctx = new AppDbContext();
bool anyLeft = false;
var d = await ctx.Deliveries
.Where(d => d.Year == year && d.DId == did)
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers)
.SingleAsync();
var d = (await ctx.Deliveries.FindAsync(year, did))!;
var lnr = await ctx.NextLNr(d.Date, d.ZwstId);
n = new Delivery {
Year = year,
@@ -601,11 +601,7 @@ namespace Elwig.Services {
anyLeft = true;
p.Weight -= w;
ctx.Update(p);
var s = new DeliveryPart {
SortId = null!,
QualId = null!,
HkId = null!,
};
var s = ctx.CreateProxy<DeliveryPart>();
var values = ctx.Entry(p).CurrentValues;
ctx.Entry(s).CurrentValues.SetValues(values);
s.Year = n.Year;
@@ -636,11 +632,8 @@ namespace Elwig.Services {
Delivery n;
using var ctx = new AppDbContext();
var anyLeft = false;
n = (await ctx.Deliveries.Where(d => d.LsNr == lsnr).FirstAsync())!;
var d = await ctx.Deliveries
.Where(d => d.Year == year && d.DId == did)
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers)
.SingleAsync();
n = (await ctx.Deliveries.FirstAsync(d => d.LsNr == lsnr))!;
var d = (await ctx.Deliveries.FindAsync(year, did))!;
var dpnr = await ctx.NextDPNr(n.Year, n.DId);
foreach (var (p, w) in d.Parts.ToList().Zip(weights)) {
if (w <= 0) {
@@ -652,11 +645,7 @@ namespace Elwig.Services {
anyLeft = true;
p.Weight -= w;
ctx.Update(p);
var s = new DeliveryPart {
SortId = null!,
QualId = null!,
HkId = null!,
};
var s = ctx.CreateProxy<DeliveryPart>();
var values = ctx.Entry(p).CurrentValues;
ctx.Entry(s).CurrentValues.SetValues(values);
s.Year = n.Year;
@@ -685,10 +674,7 @@ namespace Elwig.Services {
public static async Task DepreciateDelivery(int year, int did, int[] weights) {
await Task.Run(async () => {
using var ctx = new AppDbContext();
var d = await ctx.Deliveries
.Where(d => d.Year == year && d.DId == did)
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers)
.SingleAsync();
var d = (await ctx.Deliveries.FindAsync(year, did))!;
var dpnr = await ctx.NextDPNr(year, did);
foreach (var (p, w) in d.Parts.ToList().Zip(weights)) {
if (w <= 0) {
@@ -700,11 +686,7 @@ namespace Elwig.Services {
} else {
p.Weight -= w;
ctx.Update(p);
var n = new DeliveryPart {
SortId = null!,
QualId = null!,
HkId = null!,
};
var n = ctx.CreateProxy<DeliveryPart>();
var values = ctx.Entry(p).CurrentValues;
ctx.Entry(n).CurrentValues.SetValues(values);
n.DPNr = dpnr++;
@@ -729,10 +711,12 @@ namespace Elwig.Services {
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
using var doc = await DeliveryNote.Initialize(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 ctx = new AppDbContext();
var d = (await ctx.Deliveries.FindAsync(year, did))!;
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) {
InteractionService.ShowException(exc);
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
@@ -772,24 +756,35 @@ namespace Elwig.Services {
.ThenBy(p => p.DPNr);
if (mode == ExportMode.SaveList) {
var filename = InteractionService.SaveFile(DeliveryJournal.Name, DeliveryJournal.Name, "ods");
if (filename != null) {
var d = new SaveFileDialog() {
FileName = $"{DeliveryJournal.Name}.ods",
DefaultExt = "ods",
Filter = "OpenDocument Format Spreadsheet (*.ods)|*.ods",
Title = $"{DeliveryJournal.Name} speichern unter - Elwig"
};
if (d.ShowDialog() == true) {
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
var data = await DeliveryJournalData.FromQuery(query, filterNames);
using var ods = new OdsFile(filename);
using var ods = new OdsFile(d.FileName);
await ods.AddTable(data);
} catch (Exception exc) {
InteractionService.ShowException(exc);
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
}
} else if (mode == ExportMode.Export) {
var filename = InteractionService.SaveFile(DeliveryJournal.Name, subject == ExportSubject.Selected ? $"Lieferung_{vm.SelectedDelivery?.LsNr}" : $"Lieferungen_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{App.ZwstId}", "elwig.zip");
if (filename != null) {
if (!filename.EndsWith(".elwig.zip")) filename += ".elwig.zip";
var d = new SaveFileDialog() {
FileName = subject == ExportSubject.Selected ? $"Lieferung_{vm.SelectedDelivery?.LsNr}.elwig.zip" : $"Lieferungen_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{App.ZwstId}.elwig.zip",
DefaultExt = "elwig.zip",
Filter = "Elwig-Export-Datei (*.elwig.zip)|*.elwig.zip",
Title = $"{DeliveryJournal.Name} speichern unter - Elwig",
AddExtension = false,
};
if (d.ShowDialog() == true) {
if (!d.FileName.EndsWith(".elwig.zip")) d.FileName += ".elwig.zip";
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
@@ -797,6 +792,9 @@ namespace Elwig.Services {
.Select(p => p.Delivery)
.Distinct()
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers)
.Include(d => d.Parts).ThenInclude(p => p.Rd)
.Include(d => d.Parts).ThenInclude(p => p.Kg!.Gl)
.AsSplitQuery()
.ToListAsync();
var wbKgs = list
.SelectMany(d => d.Parts)
@@ -805,9 +803,9 @@ namespace Elwig.Services {
.DistinctBy(k => k.KgNr)
.OrderBy(k => k.KgNr)
.ToList();
await ElwigData.Export(filename, list, wbKgs, filterNames);
await ElwigData.Export(d.FileName, list, wbKgs, filterNames);
} catch (Exception exc) {
InteractionService.ShowException(exc);
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
@@ -826,7 +824,7 @@ namespace Elwig.Services {
using var doc = new DeliveryJournal(string.Join(" / ", filterNames), data);
await Utils.ExportDocument(doc, mode);
} catch (Exception exc) {
InteractionService.ShowException(exc);
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
@@ -857,7 +855,7 @@ namespace Elwig.Services {
using var doc = new WineQualityStatistics(string.Join(" / ", filterNames), data);
await Utils.ExportDocument(doc, mode);
} catch (Exception exc) {
InteractionService.ShowException(exc);
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
@@ -876,16 +874,21 @@ namespace Elwig.Services {
throw new ArgumentException("Invalid value for ExportSubject");
}
var filename = InteractionService.SaveFile("Lieferstatistik pro Ort", $"Lieferstatistik-{vm.FilterSeason ?? Utils.CurrentLastSeason}", "ods");
if (filename != null) {
var d = new SaveFileDialog() {
FileName = $"Lieferstatistik-{vm.FilterSeason ?? Utils.CurrentLastSeason}.ods",
DefaultExt = "ods",
Filter = "OpenDocument Format Spreadsheet (*.ods)|*.ods",
Title = $"Lieferstatistik pro Ort speichern unter - Elwig"
};
if (d.ShowDialog() == true) {
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
using var ods = new OdsFile(filename);
using var ods = new OdsFile(d.FileName);
var tbl = await WineLocalityStatisticsData.FromQuery(query, filterNames);
await ods.AddTable(tbl);
} catch (Exception exc) {
InteractionService.ShowException(exc);
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
@@ -919,24 +922,29 @@ namespace Elwig.Services {
filterNames.Remove("abgewertet");
if (mode == ExportMode.SaveList) {
var filename = InteractionService.SaveFile(DeliveryDepreciationList.Name, $"{DeliveryDepreciationList.Name}-{vm.FilterSeason ?? Utils.CurrentLastSeason}", "ods");
if (filename != null) {
var d = new SaveFileDialog() {
FileName = $"{DeliveryDepreciationList.Name}-{vm.FilterSeason ?? Utils.CurrentLastSeason}.ods",
DefaultExt = "ods",
Filter = "OpenDocument Format Spreadsheet (*.ods)|*.ods",
Title = $"{DeliveryDepreciationList.Name} speichern unter - Elwig"
};
if (d.ShowDialog() == true) {
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
using var ods = new OdsFile(filename);
using var ods = new OdsFile(d.FileName);
var tblTotal = await DeliveryJournalData.FromQuery(query, filterNames);
tblTotal.FullName = DeliveryDepreciationList.Name;
tblTotal.Name = "Gesamt";
await ods.AddTable(tblTotal);
foreach (var branch in await ctx.FetchBranches().ToListAsync()) {
foreach (var branch in await ctx.Branches.OrderBy(b => b.Name).ToListAsync()) {
var tbl = await DeliveryJournalData.FromQuery(query.Where(p => p.Delivery.ZwstId == branch.ZwstId), filterNames);
tbl.FullName = DeliveryDepreciationList.Name;
tbl.Name = branch.Name;
await ods.AddTable(tbl);
}
} catch (Exception exc) {
InteractionService.ShowException(exc);
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
@@ -949,7 +957,7 @@ namespace Elwig.Services {
using var doc = new DeliveryDepreciationList(string.Join(" / ", filterNames), data);
await Utils.ExportDocument(doc, mode);
} catch (Exception exc) {
InteractionService.ShowException(exc);
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
@@ -979,18 +987,23 @@ namespace Elwig.Services {
.ThenBy(p => p.AttrId)
.ThenBy(p => p.CultId);
var filename = InteractionService.SaveFile("Liefermengen", "Liefermengen", "ods");
if (filename != null) {
var d = new SaveFileDialog() {
FileName = $"Liefermengen.ods",
DefaultExt = "ods",
Filter = "OpenDocument Format Spreadsheet (*.ods)|*.ods",
Title = $"Liefermengen speichern unter - Elwig"
};
if (d.ShowDialog() == true) {
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
using var ods = new OdsFile(filename);
using var ods = new OdsFile(d.FileName);
var tblTotal = await MemberDeliveryData.FromQuery(query, filterNames);
var tbl = await MemberDeliveryPerVarietyData.FromQuery(query, filterNames);
await ods.AddTable(tblTotal);
await ods.AddTable(tbl);
} catch (Exception exc) {
InteractionService.ShowException(exc);
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
@@ -1035,23 +1048,16 @@ namespace Elwig.Services {
var gGrid = new List<(string?, string?, double, double, double)>();
var gText = "-";
var stat = (await deliveryParts.GroupBy(p => 0)
.Select(g => new {
Weight = g.Sum(p => p.Weight),
Min = g.Select(p => (double?)p.Kmw).DefaultIfEmpty().Min(),
Avg = g.Sum(p => p.Kmw * p.Weight) / g.Sum(p => p.Weight),
Max = g.Select(p => (double?)p.Kmw).DefaultIfEmpty().Max(),
})
.ToListAsync())
.DefaultIfEmpty(new { Weight = 0, Min = (double?)null, Avg = (double)0, Max = (double?)null })
.Single();
var weight = await deliveryParts.SumAsync(p => p.Weight);
wText = $"{weight:N0} kg";
wGrid.Add(("Menge", null, weight, null, weight));
wText = $"{stat.Weight:N0} kg";
wGrid.Add(("Menge", null, stat.Weight, null, stat.Weight));
if (stat.Min != null && stat.Max != null) {
gText = $"{stat.Min:N1}° / {stat.Avg:N1}° / {stat.Max:N1}°";
gGrid.Add(("Gradation", null, stat.Min.Value, stat.Avg, stat.Max.Value));
if (await deliveryParts.AnyAsync()) {
var kmwMin = await deliveryParts.MinAsync(p => p.Kmw);
var kmwAvg = Utils.AggregateDeliveryPartsKmw(deliveryParts);
var kmwMax = await deliveryParts.MaxAsync(p => p.Kmw);
gText = $"{kmwMin:N1}° / {kmwAvg:N1}° / {kmwMax:N1}°";
gGrid.Add(("Gradation", null, kmwMin, kmwAvg, kmwMax));
var attrGroups = await deliveryParts
.GroupBy(p => new { Attr = p.Attribute!.Name, Cult = p.Cultivation!.Name })
@@ -1102,9 +1108,9 @@ namespace Elwig.Services {
foreach (var attrG in attrGroups) {
var name = attrG.Attr == null && attrG.Cult == null ? null : attrG.Attr + (attrG.Attr != null && attrG.Cult != null ? " / " : "") + attrG.Cult;
wGrid.Add((name, null, attrG.Weight, attrG.Weight, stat.Weight));
wGrid.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)) {
wGrid.Add((null, g.SortId, g.Weight, attrG.Weight, stat.Weight));
wGrid.Add((null, g.SortId, g.Weight, attrG.Weight, weight));
}
}
foreach (var attrG in attrGroups) {
@@ -1123,12 +1129,12 @@ namespace Elwig.Services {
gText += $" [{name}]";
}
if (sortGroups.Count > 1 && sortGroups.Count <= 4) {
wText += $" = {string.Join(" + ", sortGroups.Select(g => $"{g.Weight:N0} kg ({(double)g.Weight / stat.Weight:0%})" + (g.SortId == null ? "" : $" [{g.SortId}]")))}";
wText += $" = {string.Join(" + ", sortGroups.Select(g => $"{g.Weight:N0} kg ({(double)g.Weight / weight:0%})" + (g.SortId == null ? "" : $" [{g.SortId}]")))}";
gText += $" = {string.Join(" + ", sortGroups.Select(g => $"{g.Min:N1}/{g.Avg:N1}/{g.Max:N1}" + (g.SortId == null ? "" : $" [{g.SortId}]")))}";
}
} else if (attrGroups.Count <= 4) {
wText += $" = {string.Join(" + ", attrGroups.Select(g => $"{g.Weight:N0} kg ({(double)g.Weight / stat.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 / 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}]")))}";
}
}
@@ -1192,9 +1198,9 @@ namespace Elwig.Services {
attrid = $"'{attr.AttrId}'";
}
var dids = await vm.GetDidsFromFilters();
if (!InteractionService.AskContinue("Massenaktion: Attribut setzen",
$"Soll wirklich für {dids.Length:N0} Teillieferung(en) das Attribut\n'{attributeName}' gesetz werden?"))
return;
var res = MessageBox.Show($"Soll wirklich für {dids.Length:N0} Teillieferung(en) das Attribut\n'{attributeName}' gesetz werden?",
"Massenaktion: Attribut setzen", MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
if (res != MessageBoxResult.OK) return;
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
@@ -1207,7 +1213,7 @@ namespace Elwig.Services {
App.HintContextChange();
});
} catch (Exception exc) {
InteractionService.ShowException(exc);
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
} finally {
Mouse.OverrideCursor = null;
}
@@ -1222,9 +1228,9 @@ namespace Elwig.Services {
}
var dids = await vm.GetDidsFromFilters();
if (!InteractionService.AskContinue("Massenaktion: Zu-/Abschlag hinzufügen",
$"Soll wirklich für {dids.Length:N0} Teillieferung(en) der Zu-/Abschlag\n'{modifierName}' hinzugefügt werden?"))
return;
var res = MessageBox.Show($"Soll wirklich für {dids.Length:N0} Teillieferung(en) der Zu-/Abschlag\n'{modifierName}' hinzugefügt werden?",
"Massenaktion: Zu-/Abschlag hinzufügen", MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
if (res != MessageBoxResult.OK) return;
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
@@ -1238,7 +1244,7 @@ namespace Elwig.Services {
App.HintContextChange();
});
} catch (Exception exc) {
InteractionService.ShowException(exc);
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
} finally {
Mouse.OverrideCursor = null;
}
@@ -1253,9 +1259,9 @@ namespace Elwig.Services {
}
var dids = await vm.GetDidsFromFilters();
if (!InteractionService.AskContinue("Massenaktion: Zu-/Abschlag entfernen",
$"Soll wirklich für {dids.Length:N0} Teillieferung(en) der Zu-/Abschlag\n'{modifierName}' entfernt werden?"))
return;
var res = MessageBox.Show($"Soll wirklich für {dids.Length:N0} Teillieferung(en) der Zu-/Abschlag\n'{modifierName}' entfernt werden?",
"Massenaktion: Zu-/Abschlag entfernen", MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
if (res != MessageBoxResult.OK) return;
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
@@ -1268,7 +1274,7 @@ namespace Elwig.Services {
App.HintContextChange();
});
} catch (Exception exc) {
InteractionService.ShowException(exc);
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
} finally {
Mouse.OverrideCursor = null;
}
-118
View File
@@ -1,118 +0,0 @@
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Windows;
namespace Elwig.Services {
public static class InteractionService {
public static Func<string, string, string, string?>? Override;
public static readonly Dictionary<string, string> ExtensionFilters = new() {
["pdf"] = "PDF-Datei (*.pdf)|*.pdf",
["ods"] = "OpenDocument Format Spreadsheet (*.ods)|*.ods",
["vcf"] = "vCard-Datei (*.vcf)|*.vcf",
["xml"] = "EBICS-Datei (*.xml)|*.xml",
["csv"] = "CSV-Datei (*.csv)|*.csv",
["sql.zip"] = "Komprimierte SQL-Datei (*.sql.zip)|*.sql.zip",
["elwig.zip"] = "Elwig-Export-Datei (*.elwig.zip)|*.elwig.zip",
};
public static void ShowInformation(string title, string text) {
if (Override != null) {
Override("information", title, text);
} else {
MessageBox.Show(text, title, MessageBoxButton.OK, MessageBoxImage.Information);
}
}
public static bool AskContinue(string title, string text) {
if (Override != null) {
return Override("continue", title, text) != null;
} else {
return MessageBox.Show(text, title, MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel) == MessageBoxResult.OK;
}
}
public static bool AskConfirmation(string title, string text) {
if (Override != null) {
return Override("confirm", title, text) != null;
} else {
return MessageBox.Show(text, title, MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No) == MessageBoxResult.Yes;
}
}
public static bool AskQuestion(string title, string text, bool defaultResult) {
if (Override != null) {
return Override("question", title, text) != null;
} else {
return MessageBox.Show(text, title, MessageBoxButton.YesNo, MessageBoxImage.Question, defaultResult ? MessageBoxResult.Yes : MessageBoxResult.No) == MessageBoxResult.Yes;
}
}
public static void ShowWarning(string title, string text) {
if (Override != null) {
Override("warning", title, text);
} else {
MessageBox.Show(text, title, MessageBoxButton.OK, MessageBoxImage.Warning);
}
}
public static void ShowError(string title, string text) {
if (Override != null) {
Override("error", title, text);
} else {
MessageBox.Show(text, title, MessageBoxButton.OK, MessageBoxImage.Error);
}
}
public static void ShowException(Exception exc, bool showExcType = false, bool isError = true) {
ShowException("Fehler", exc, showExcType, isError);
}
public static void ShowException(string title, Exception exc, bool showExcType = false, bool isError = true) {
ShowException(title, exc, showExcType, isError);
}
public static void ShowException(string title, string? text, Exception exc, bool showExcType = false, bool isError = true) {
text = text == null ? "" : text + (text.EndsWith('.') || text.EndsWith('!') || text.EndsWith('?') ? "" : ":") + "\n\n";
text += exc.Message + (showExcType ? $" ({exc.GetType().Name})" : "");
if (exc.InnerException != null) text += "\n\n" + exc.InnerException.Message;
if (isError) {
ShowError(title, text);
} else {
ShowWarning(title, text);
}
}
public static void ShowDbException(string title, Exception exc) {
ShowException(title, "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!", exc);
}
public static bool AskException(string title, string? text, Exception exc) {
text = text == null ? "" : text + (text.EndsWith('.') || text.EndsWith('!') || text.EndsWith('?') ? "" : ":") + "\n\n";
text += exc.Message;
if (exc.InnerException != null) text += "\n\n" + exc.InnerException.Message;
if (Override != null) {
return Override("error", title, text) != null;
} else {
return MessageBox.Show(text, title, MessageBoxButton.YesNo, MessageBoxImage.Error, MessageBoxResult.No) == MessageBoxResult.Yes;
}
}
public static string? SaveFile(string title, string defaultFileName, string extension) {
if (Override != null) {
return Override("save", title, $"{defaultFileName}.{extension}");
} else {
var d = new SaveFileDialog() {
FileName = $"{defaultFileName}.{extension}",
DefaultExt = extension,
Filter = ExtensionFilters.GetValueOrDefault(extension, ""),
Title = $"{title} speichern unter - Elwig",
AddExtension = !extension.Contains('.'),
};
return d.ShowDialog() == true ? d.FileName : null;
}
}
}
}
+65 -31
View File
@@ -6,10 +6,12 @@ using Elwig.Models.Dtos;
using Elwig.Models.Entities;
using Elwig.ViewModels;
using Microsoft.EntityFrameworkCore;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
namespace Elwig.Services {
@@ -170,7 +172,7 @@ namespace Elwig.Services {
var c = m.ActiveAreaCommitments(ctx, Utils.CurrentLastSeason);
int maxKgPerHa = 10_000;
try {
var s = await ctx.FetchSeasons().FirstOrDefaultAsync();
var s = await ctx.Seasons.FindAsync(await ctx.Seasons.MaxAsync(s => s.Year));
if (s != null) maxKgPerHa = s.MaxKgPerHa;
} catch { }
var (text, gridData) = await AreaComService.GenerateToolTipData(c, maxKgPerHa);
@@ -223,8 +225,8 @@ namespace Elwig.Services {
var filter = vm.TextFilter;
if (filter.Count > 0) {
var branches = await ctx.FetchBranches().ToListAsync();
var mgnr = await ctx.FetchMembers(includeNotActive: true).ToDictionaryAsync(m => m.MgNr.ToString(), m => m);
var branches = await ctx.Branches.ToListAsync();
var mgnr = await ctx.Members.ToDictionaryAsync(m => m.MgNr.ToString(), m => m);
var kgs = await ctx.WbKgs.ToDictionaryAsync(k => k.AtKg.Name.ToLower(), k => k.AtKg);
var areaComs = await ctx.AreaCommitmentTypes.ToDictionaryAsync(t => $"{t.SortId}{t.AttrId}", t => t);
@@ -393,10 +395,11 @@ namespace Elwig.Services {
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
using var doc = new MemberDataSheet(m);
using var ctx = new AppDbContext();
using var doc = new MemberDataSheet(m, ctx);
await Utils.ExportDocument(doc, mode, emailData: (m, MemberDataSheet.Name, "Im Anhang finden Sie das aktuelle Stammdatenblatt"));
} catch (Exception exc) {
InteractionService.ShowException(exc);
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
@@ -406,15 +409,17 @@ namespace Elwig.Services {
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
var b = await Billing.Create(year);
var b = new Billing(year);
await b.FinishSeason();
await b.CalculateBuckets();
App.HintContextChange();
using var doc = new DeliveryConfirmation(year, m, null);
using var ctx = new AppDbContext();
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}"));
} catch (Exception exc) {
InteractionService.ShowException(exc);
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
@@ -424,10 +429,18 @@ namespace Elwig.Services {
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
using var doc = await CreditNote.Initialize(year, avnr, m.MgNr, null);
await Utils.ExportDocument(doc, mode, emailData: (m, $"{CreditNote.Name} {doc.Payment.Variant.Name}", $"Im Anhang finden Sie die Traubengutschrift {doc.Payment.Variant.Name}"));
using var ctx = new AppDbContext();
var v = (await ctx.PaymentVariants.FindAsync(year, avnr))!;
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) {
InteractionService.ShowException(exc);
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
@@ -475,54 +488,77 @@ namespace Elwig.Services {
}
if (mode == ExportMode.SaveList) {
var filename = InteractionService.SaveFile(MemberList.Name, MemberList.Name, "ods");
if (filename != null) {
var d = new SaveFileDialog() {
FileName = $"{MemberList.Name}.ods",
DefaultExt = "ods",
Filter = "OpenDocument Format Spreadsheet (*.ods)|*.ods",
Title = $"{MemberList.Name} speichern unter - Elwig"
};
if (d.ShowDialog() == true) {
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
var data = await MemberListData.FromQuery(query, filterNames, filterNames.Where(f => f.StartsWith("Flächenbindung")).Select(f => f.Split(' ')[^1]));
using var ods = new OdsFile(filename);
using var ods = new OdsFile(d.FileName);
await ods.AddTable(data);
} catch (Exception exc) {
InteractionService.ShowException(exc);
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
}
} else if (mode == ExportMode.Vcf) {
var filename = InteractionService.SaveFile("Kontakte", "Mitglieder", "vcf");
if (filename != null) {
var d = new SaveFileDialog() {
FileName = "Mitglieder.vcf",
DefaultExt = "vcf",
Filter = "vCard-Datei (*.vcf)|*.vcf",
Title = "Kontakte speichern unter - Elwig"
};
if (d.ShowDialog() == true) {
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
var members = await query
.OrderBy(m => m.MgNr)
.Include(m => m.BillingAddress)
.Include(m => m.TelephoneNumbers)
.Include(m => m.EmailAddresses)
.AsSplitQuery()
.ToListAsync();
using var exporter = new VCard(filename);
using var exporter = new VCard(d.FileName);
await exporter.ExportAsync(members);
} catch (Exception exc) {
InteractionService.ShowException(exc);
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
}
} else if (mode == ExportMode.Export) {
var filename = InteractionService.SaveFile(MemberList.Name, subject == ExportSubject.Selected ? $"Mitglied_{vm.SelectedMember?.MgNr}" : $"Mitglieder_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{App.ZwstId}", "elwig.zip");
if (filename != null) {
if (!filename.EndsWith(".elwig.zip")) filename += ".elwig.zip";
var d = new SaveFileDialog() {
FileName = subject == ExportSubject.Selected ? $"Mitglied_{vm.SelectedMember?.MgNr}.elwig.zip" : $"Mitglieder_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{App.ZwstId}.elwig.zip",
DefaultExt = "elwig.zip",
Filter = "Elwig-Export-Datei (*.elwig.zip)|*.elwig.zip",
Title = $"{MemberList.Name} speichern unter - Elwig",
AddExtension = false,
};
if (d.ShowDialog() == true) {
if (!d.FileName.EndsWith(".elwig.zip")) d.FileName += ".elwig.zip";
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
var members = await query
.OrderBy(m => m.MgNr)
.Include(m => m.BillingAddress)
.Include(m => m.TelephoneNumbers)
.Include(m => m.EmailAddresses)
.Include(m => m.DefaultWbKg!.Gl)
.AsSplitQuery()
.ToListAsync();
var areaComs = await query
.SelectMany(m => m.AreaCommitments)
.Select(c => c.Contract).Distinct()
.Include(c => c.Rd)
.Include(c => c.Kg.Gl)
.Include(c => c.Revisions)
.ToListAsync();
var wbKgs = members
@@ -532,9 +568,9 @@ namespace Elwig.Services {
.Distinct()
.OrderBy(k => k.KgNr)
.ToList();
await ElwigData.Export(filename, members, areaComs, wbKgs, filterNames);
await ElwigData.Export(d.FileName, members, areaComs, wbKgs, filterNames);
} catch (Exception exc) {
InteractionService.ShowException(exc);
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
@@ -553,7 +589,7 @@ namespace Elwig.Services {
using var doc = new MemberList(string.Join(" / ", filterNames), data);
await Utils.ExportDocument(doc, mode);
} catch (Exception exc) {
InteractionService.ShowException(exc);
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
@@ -689,20 +725,18 @@ namespace Elwig.Services {
public static async Task DeleteMember(int mgnr, bool deletePaymentData, bool deleteDeliveries, bool deleteAreaComs) {
await Task.Run(async () => {
using var ctx = new AppDbContext();
using var tx = await ctx.Database.BeginTransactionAsync();
var l = await ctx.FetchMembers(mgnr).SingleAsync();
var l = (await ctx.Members.FindAsync(mgnr))!;
if (deletePaymentData) {
await ctx.Credits.Where(c => c.MgNr == mgnr).ExecuteDeleteAsync();
ctx.RemoveRange(l.Credits);
}
if (deleteDeliveries) {
await ctx.Deliveries.Where(c => c.MgNr == mgnr).ExecuteDeleteAsync();
ctx.RemoveRange(l.Deliveries);
}
if (deleteAreaComs) {
await ctx.AreaCommitments.Where(c => c.MgNr == mgnr).ExecuteDeleteAsync();
ctx.RemoveRange(l.AreaCommitments);
}
ctx.Remove(l);
await ctx.SaveChangesAsync();
await tx.CommitAsync();
});
}
}
+47 -59
View File
@@ -6,8 +6,8 @@ using Elwig.Models.Dtos;
using Elwig.Models.Entities;
using Elwig.ViewModels;
using Microsoft.EntityFrameworkCore;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
@@ -142,7 +142,7 @@ namespace Elwig.Services {
});
var credits = ctx.Credits.Where(c => c.Year == v.Year && c.AvNr == v.AvNr);
if (!(await credits.AnyAsync())) {
if (!credits.Any()) {
long lastTotalSum = 0;
decimal vatSum = 0;
var currentPayments = await ctx.MemberPayments
@@ -150,7 +150,8 @@ namespace Elwig.Services {
.ToDictionaryAsync(p => p.MgNr);
var lastV = await ctx.PaymentVariants
.Where(l => l.Year == v.Year && !l.TestVariant)
.OrderByDescending(l => l.TransferDateString ?? l.DateString).ThenByDescending(l => l.AvNr)
.OrderByDescending(l => l.TransferDateString ?? l.DateString)
.ThenByDescending(l => l.AvNr)
.FirstOrDefaultAsync();
if (lastV != null) {
var lastPayments = await ctx.MemberPayments
@@ -159,8 +160,8 @@ namespace Elwig.Services {
lastTotalSum = lastPayments.Sum(e => e.Value.AmountValue);
foreach (int mgnr in currentPayments.Keys) {
var c = currentPayments[mgnr];
var l = lastPayments.GetValueOrDefault(mgnr);
vatSum += (c.Amount - (l?.Amount ?? 0)) * (decimal)(c.Member.IsBuchführend ? v.Season.VatNormal : v.Season.VatFlatrate);
var l = lastPayments[mgnr];
vatSum += (c.Amount - l.Amount) * (decimal)(c.Member.IsBuchführend ? v.Season.VatNormal : v.Season.VatFlatrate);
}
} else {
vatSum = currentPayments.Sum(e => e.Value.Amount * (decimal)(e.Value.Member.IsBuchführend ? v.Season.VatNormal : v.Season.VatFlatrate));
@@ -189,18 +190,23 @@ namespace Elwig.Services {
public static async Task GenerateSummary(PaymentVar v, ExportMode mode) {
if (mode == ExportMode.SaveList) {
var filename = InteractionService.SaveFile($"Variantendaten {v.Name}", $"Variantendaten-{v.Name.Trim().Replace(' ', '-')}", "ods");
if (filename == null)
var d = new SaveFileDialog() {
FileName = $"Variantendaten-{v.Name.Trim().Replace(' ', '-')}.ods",
DefaultExt = "ods",
Filter = "OpenDocument Format Spreadsheet (*.ods)|*.ods",
Title = $"Variantendaten {v.Name} speichern unter - Elwig"
};
if (d.ShowDialog() == false)
return;
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
using var ctx = new AppDbContext();
var data = await PaymentVariantSummaryData.ForPaymentVariant(v, ctx.PaymentVariantSummaryRows);
using var ods = new OdsFile(filename);
using var ods = new OdsFile(d.FileName);
await ods.AddTable(data);
} catch (Exception exc) {
InteractionService.ShowException(exc);
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
@@ -208,10 +214,12 @@ namespace Elwig.Services {
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
using var doc = await PaymentVariantSummary.Initialize(v.Year, v.AvNr);
using var ctx = new AppDbContext();
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);
} catch (Exception exc) {
InteractionService.ShowException(exc);
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
@@ -220,30 +228,35 @@ namespace Elwig.Services {
public static async Task GenerateEbics(int year, int avnr) {
using var ctx = new AppDbContext();
var v = await ctx.PaymentVariants.Include(v => v.Credits).Where(v => v.Year == year && v.AvNr == avnr).SingleAsync();
var v = (await ctx.PaymentVariants.FindAsync(year, avnr))!;
var withoutIban = v.Credits.Count(c => c.Member.Iban == null);
if (withoutIban > 0) {
if (!InteractionService.AskContinue("Mitglieder ohne IBAN",
$"Achtung: Für {withoutIban:N0} Mitglieder ist kein IBAN hinterlegt.\n\nDiese werden NICHT exportiert."))
return;
var r = MessageBox.Show($"Achtung: Für {withoutIban:N0} Mitglieder ist kein IBAN hinterlegt.\n\nDiese werden NICHT exportiert.",
"Mitglieder ohne IBAN", MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
if (r != MessageBoxResult.OK) return;
}
var withNegAmount = v.Credits.Count(c => c.Amount <= 0);
if (withNegAmount > 0) {
if (!InteractionService.AskContinue("Traubengutschriften mit negativem Betrag",
$"Achtung: Es gibt {withNegAmount:N0} Traubengutschriften mit negativem Betrag.\n\nDiese werden NICHT exportiert."))
return;
var r = MessageBox.Show($"Achtung: Es gibt {withNegAmount:N0} Traubengutschriften mit negativem Betrag.\n\nDiese werden NICHT exportiert.",
"Traubengutschriften mit negativem Betrag", MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.OK);
if (r != MessageBoxResult.OK) return;
}
var filename = InteractionService.SaveFile("Überweisungsdaten", $"{App.Client.NameToken}-Überweisungsdaten-{v.Year}-{v.Name.Trim().Replace(' ', '-')}", Ebics.FileExtension);
if (filename != null) {
var d = new SaveFileDialog() {
FileName = $"{App.Client.NameToken}-Überweisungsdaten-{v.Year}-{v.Name.Trim().Replace(' ', '-')}.{Ebics.FileExtension}",
DefaultExt = Ebics.FileExtension,
Filter = "EBICS-Datei (*.xml)|*.xml",
Title = $"Überweisungsdaten speichern unter - Elwig",
};
if (d.ShowDialog() == true) {
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
using var e = new Ebics(v, filename, App.Client.ExportEbicsVersion, (Ebics.AddressMode)App.Client.ExportEbicsAddress);
using var e = new Ebics(v, d.FileName, App.Client.ExportEbicsVersion, (Ebics.AddressMode)App.Client.ExportEbicsAddress);
await e.ExportAsync(Transaction.FromPaymentVariant(v));
} catch (Exception exc) {
InteractionService.ShowException(exc);
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
@@ -251,17 +264,22 @@ namespace Elwig.Services {
}
public static async Task GenerateAccountingList(int year, int avnr, string name) {
var filename = InteractionService.SaveFile("Buchungsliste", $"{App.Client.NameToken}-Buchungsliste-{year}-{name.Trim().Replace(' ', '-')}", "ods");
if (filename != null) {
var d = new SaveFileDialog() {
FileName = $"{App.Client.NameToken}-Buchungsliste-{year}-{name.Trim().Replace(' ', '-')}.ods",
DefaultExt = "ods",
Filter = "OpenDocument Format Spreadsheet (*.ods)|*.ods",
Title = $"Buchungsliste speichern unter - Elwig"
};
if (d.ShowDialog() == true) {
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
using var ctx = new AppDbContext();
var tbl = await CreditNoteData.ForPaymentVariant(ctx, year, avnr);
using var ods = new OdsFile(filename);
using var ods = new OdsFile(d.FileName);
await ods.AddTable(tbl);
} catch (Exception exc) {
InteractionService.ShowException(exc);
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
@@ -347,51 +365,21 @@ namespace Elwig.Services {
public static async Task Calculate(int year, int avnr) {
await Task.Run(async () => {
var b = await BillingVariant.Create(year, avnr);
var b = new BillingVariant(year, avnr);
await b.Calculate();
});
}
public static async Task Commit(int year, int avnr) {
List<Member> membersLess = [];
using (var ctx = new AppDbContext()) {
var lastAvNr = await ctx.PaymentVariants
.Where(v => v.Year == year && !v.TestVariant)
.OrderByDescending(v => v.TransferDateString ?? v.DateString).ThenByDescending(v => v.AvNr)
.Select(v => v.AvNr)
.FirstOrDefaultAsync();
if (lastAvNr != 0) {
var cur = await ctx.MemberPayments.Include(p => p.Member).Where(p => p.Year == year && p.AvNr == avnr).ToDictionaryAsync(p => p.Member.MgNr, p => p);
var last = await ctx.MemberPayments.Include(p => p.Member).Where(p => p.Year == year && p.AvNr == lastAvNr).ToDictionaryAsync(p => p.Member.MgNr, p => p);
membersLess = [.. last.Where(p => (cur.TryGetValue(p.Key, out var c) ? c.Amount : 0) < p.Value.Amount).Select(p => p.Value.Member)];
}
}
if (membersLess.Count > 0) {
if (!InteractionService.AskContinue("Kleinerer Gesamtbetrag",
$"Achtung: Bei {membersLess.Count:N0} Mitglied(ern) ist der Soll-Betrag der Auszahlung (\"Gesamtbetrag\") kleiner als bei der letzten Auszahlung. Das sollte nicht vorkommen!\n\n" +
$"{string.Join(", ", membersLess.Select(m => $"{m.AdministrativeName} ({m.MgNr})"))}\n\n" +
"Soll trotzdem forgefahren werden?"))
return;
}
await Task.Run(async () => {
var b = await BillingVariant.Create(year, avnr);
var b = new BillingVariant(year, avnr);
await b.Commit();
});
List<Member> membersNeg = [];
using (var ctx = new AppDbContext()) {
membersNeg = await ctx.Credits.Where(c => c.Year == year && c.AvNr == avnr && c.AmountValue < 0).Select(c => c.Member).ToListAsync();
}
if (membersNeg.Count > 0) {
InteractionService.ShowWarning("Negativer Auszahlungsbetrag", $"Achtung: Bei {membersNeg.Count:N0} Mitglied(ern) ist der Auszahlungsbetrag negativ!\n\n" +
$"{string.Join(", ", membersNeg.Select(m => $"{m.AdministrativeName} ({m.MgNr})"))}");
}
}
public static async Task Revert(int year, int avnr) {
await Task.Run(async () => {
var b = await BillingVariant.Create(year, avnr);
var b = new BillingVariant(year, avnr);
await b.Revert();
});
}
+55 -27
View File
@@ -10,6 +10,7 @@ using System.Linq;
using System.Linq.Expressions;
using System.Net.Http;
using System.Threading.Tasks;
using System.Windows;
namespace Elwig.Services {
public static class SyncService {
@@ -24,13 +25,18 @@ namespace Elwig.Services {
var path = Path.Combine(App.TempPath, filename);
var members = await query
.OrderBy(m => m.MgNr)
.Include(m => m.BillingAddress)
.Include(m => m.TelephoneNumbers)
.Include(m => m.EmailAddresses)
.Include(m => m.DefaultWbKg!.Gl)
.AsSplitQuery()
.ToListAsync();
var areaComs = await query
.SelectMany(m => m.AreaCommitments)
.Select(c => c.Contract).Distinct()
.OrderBy(c => c.FbNr)
.Include(c => c.Rd)
.Include(c => c.Kg.Gl)
.Include(c => c.Revisions)
.ToListAsync();
var wbKgs = members
@@ -41,20 +47,22 @@ namespace Elwig.Services {
.OrderBy(k => k.KgNr)
.ToList();
if (members.Count == 0) {
InteractionService.ShowError("Mitglieder hochladen", "Es wurden keine Mitglieder zum Hochladen ausgewählt!");
MessageBox.Show("Es wurden keine Mitglieder zum Hochladen ausgewählt!", "Mitglieder hochladen",
MessageBoxButton.OK, MessageBoxImage.Error);
} else {
var exportedAt = DateTime.Now;
await ElwigData.Export(path, members, areaComs, wbKgs, filterNames);
await Utils.UploadExportData(path, url, username, password);
await UpdateExportedAt(members, areaComs, [], exportedAt);
InteractionService.ShowInformation("Mitglieder hochgeladen", $"Hochladen von {members.Count:N0} Mitgliedern erfolgreich!");
MessageBox.Show($"Hochladen von {members.Count:N0} Mitgliedern erfolgreich!", "Mitglieder hochgeladen",
MessageBoxButton.OK, MessageBoxImage.Information);
}
} catch (HttpRequestException exc) {
InteractionService.ShowException("Mitglieder hochladen", "Eventuell Internetverbindung prüfen!", exc);
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Mitglieder hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
} catch (TaskCanceledException exc) {
InteractionService.ShowException("Mitglieder hochladen", "Eventuell Internetverbindung prüfen!", exc);
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Mitglieder hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
} catch (Exception exc) {
InteractionService.ShowException("Mitglieder hochladen", exc);
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
@@ -65,7 +73,10 @@ namespace Elwig.Services {
var list = await query
.Select(p => p.Delivery)
.Distinct()
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers)
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers).ThenInclude(m => m.Modifier)
.Include(d => d.Parts).ThenInclude(p => p.Rd)
.Include(d => d.Parts).ThenInclude(p => p.Kg!.Gl)
.AsSplitQuery()
.ToListAsync();
var wbKgs = list
.SelectMany(d => d.Parts)
@@ -75,20 +86,22 @@ namespace Elwig.Services {
.OrderBy(k => k.KgNr)
.ToList();
if (list.Count == 0) {
InteractionService.ShowError("Lieferungen hochladen", "Es wurden keine Lieferungen zum Hochladen ausgewählt!");
MessageBox.Show("Es wurden keine Lieferungen zum Hochladen ausgewählt!", "Lieferungen hochladen",
MessageBoxButton.OK, MessageBoxImage.Error);
} else {
var exportedAt = DateTime.Now;
await ElwigData.Export(path, list, wbKgs, filterNames);
await Utils.UploadExportData(path, url, username, password);
await UpdateExportedAt([], [], list, exportedAt);
InteractionService.ShowInformation("Lieferungen hochgeladen", $"Hochladen von {list.Count:N0} Lieferungen erfolgreich!");
MessageBox.Show($"Hochladen von {list.Count:N0} Lieferungen erfolgreich!", "Lieferungen hochgeladen",
MessageBoxButton.OK, MessageBoxImage.Information);
}
} catch (HttpRequestException exc) {
InteractionService.ShowException("Lieferungen hochladen", "Eventuell Internetverbindung prüfen!", exc);
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Lieferungen hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
} catch (TaskCanceledException exc) {
InteractionService.ShowException("Lieferungen hochladen", "Eventuell Internetverbindung prüfen!", exc);
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
} catch (Exception exc) {
InteractionService.ShowException("Lieferungen hochladen", exc);
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
@@ -101,19 +114,27 @@ namespace Elwig.Services {
using (var ctx = new AppDbContext()) {
members = await ctx.Members
.Where(ChangedMembers)
.Include(m => m.BillingAddress)
.Include(m => m.TelephoneNumbers)
.Include(m => m.EmailAddresses)
.Include(m => m.DefaultWbKg!.Gl)
.OrderBy(m => m.MgNr)
.AsSplitQuery()
.ToListAsync();
areaComs = await ctx.AreaCommitmentContracts
.Where(ChangedAreaComContracts)
.Include(c => c.Rd)
.Include(c => c.Kg.Gl)
.Include(c => c.Revisions)
.OrderBy(c => c.FbNr)
.ToListAsync();
deliveries = await ctx.Deliveries
.Where(ChangedDeliveries)
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers)
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers).ThenInclude(m => m.Modifier)
.Include(d => d.Parts).ThenInclude(p => p.Rd)
.Include(d => d.Parts).ThenInclude(p => p.Kg).ThenInclude(k => k!.Gl)
.OrderBy(d => d.DateString).ThenBy(d => d.TimeString).ThenBy(d => d.LsNr)
.AsSplitQuery()
.ToListAsync();
}
var wbKgs = members
@@ -127,7 +148,8 @@ namespace Elwig.Services {
.OrderBy(k => k.KgNr)
.ToList();
if (members.Count == 0 && deliveries.Count == 0) {
InteractionService.ShowInformation("Mitglieder und Lieferungen hochladen", "Es gibt keine geänderten Mitglieder oder Lieferungen, die hochgeladen werden könnten!");
MessageBox.Show("Es gibt keine geänderten Mitglieder oder Lieferungen, die hochgeladen werden könnten!", "Mitglieder und Lieferungen hochladen",
MessageBoxButton.OK, MessageBoxImage.Information);
} else {
var exportedAt = DateTime.Now;
await (new ElwigData.ElwigExport {
@@ -138,14 +160,15 @@ namespace Elwig.Services {
}).Export(path);
await Utils.UploadExportData(path, url, username, password);
await UpdateExportedAt(members, areaComs, deliveries, exportedAt);
InteractionService.ShowInformation("Mitglieder und Lieferungen hochladen", $"Hochladen von {members.Count:N0} Mitgliedern, {areaComs.Count:N0} Flächenbindungsverträgen, und {deliveries.Count:N0} Lieferungen erfolgreich!");
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);
}
} catch (HttpRequestException exc) {
InteractionService.ShowException("Mitglieder und Lieferungen hochladen", "Eventuell Internetverbindung prüfen!", exc);
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Mitglieder und Lieferungen hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
} catch (TaskCanceledException exc) {
InteractionService.ShowException("Mitglieder und Lieferungen hochladen", "Eventuell Internetverbindung prüfen!", exc);
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Mitglieder und Lieferungen hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
} catch (Exception exc) {
InteractionService.ShowException("Mitglieder und Lieferungen hochladen", exc);
MessageBox.Show(exc.Message, "Mitglieder und Lieferungen hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
@@ -156,8 +179,11 @@ namespace Elwig.Services {
using var ctx = new AppDbContext();
var deliveries = await ctx.Deliveries
.Where(d => d.Year == year && d.ZwstId == App.ZwstId)
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers)
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers).ThenInclude(m => m.Modifier)
.Include(d => d.Parts).ThenInclude(p => p.Rd)
.Include(d => d.Parts).ThenInclude(p => p.Kg).ThenInclude(k => k!.Gl)
.OrderBy(d => d.DateString).ThenBy(d => d.TimeString).ThenBy(d => d.LsNr)
.AsSplitQuery()
.ToListAsync();
var wbKgs = deliveries
.SelectMany(d => d.Parts)
@@ -166,20 +192,22 @@ namespace Elwig.Services {
.DistinctBy(k => k.KgNr)
.ToList();
if (deliveries.Count == 0) {
InteractionService.ShowError("Lieferungen hochladen", "Es gibt keine Lieferungen, die hochgeladen werden können!");
MessageBox.Show("Es gibt keine Lieferungen, die hochgeladen werden können!", "Lieferungen hochladen",
MessageBoxButton.OK, MessageBoxImage.Error);
} else {
var exportedAt = DateTime.Now;
await ElwigData.Export(path, deliveries, wbKgs, [$"{year}", $"Zweigstelle {App.BranchName}"]);
await Utils.UploadExportData(path, url, username, password);
await UpdateExportedAt([], [], deliveries, exportedAt);
InteractionService.ShowInformation("Lieferungen hochladen", $"Hochladen von {deliveries.Count:N0} Lieferungen erfolgreich!");
MessageBox.Show($"Hochladen von {deliveries.Count:N0} Lieferungen erfolgreich!", "Lieferungen hochladen",
MessageBoxButton.OK, MessageBoxImage.Information);
}
} catch (HttpRequestException exc) {
InteractionService.ShowException("Lieferungen hochladen", "Eventuell Internetverbindung prüfen!", exc);
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Lieferungen hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
} catch (TaskCanceledException exc) {
InteractionService.ShowException("Lieferungen hochladen", "Eventuell Internetverbindung prüfen!", exc);
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Lieferungen hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
} catch (Exception exc) {
InteractionService.ShowException("Lieferungen hochladen", exc);
MessageBox.Show(exc.Message, "Lieferungen hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
@@ -218,11 +246,11 @@ namespace Elwig.Services {
}
await ElwigData.Import(paths, ElwigData.ImportMode.FromBranches);
} catch (HttpRequestException exc) {
InteractionService.ShowException("Daten herunterladen", "Eventuell Internetverbindung prüfen!", exc);
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Daten herunterladen", MessageBoxButton.OK, MessageBoxImage.Error);
} catch (TaskCanceledException exc) {
InteractionService.ShowException("Daten herunterladen", "Eventuell Internetverbindung prüfen!", exc);
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Daten herunterladen", MessageBoxButton.OK, MessageBoxImage.Error);
} catch (Exception exc) {
InteractionService.ShowException("Daten herunterladen", exc);
MessageBox.Show(exc.Message, "Daten herunterladen", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
@@ -249,7 +277,7 @@ namespace Elwig.Services {
public static async Task<bool> ChangesAvailable(AppDbContext ctx, string url, string username, string password) {
try {
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);
return await ctx.Members.AnyAsync(ChangedMembers) || await ctx.AreaCommitmentContracts.AnyAsync(ChangedAreaComContracts) || await ctx.Deliveries.AnyAsync(ChangedDeliveries) || (Utils.HasInternetConnectivity() && (await GetFilesToImport(url, username, password)).Count > 0);
} catch {
return false;
}
+1 -1
View File
@@ -20,7 +20,7 @@ namespace Elwig.ViewModels {
public List<string> TextFilter => [.. SearchQuery?.ToLower().Split(' ').ToList().FindAll(e => e.Length > 0) ?? []];
[ObservableProperty]
private bool _showOnlyActiveMembers = true;
private bool _showOnlyActiveMembers;
[ObservableProperty]
private Member? _selectedMember;
+1 -1
View File
@@ -15,7 +15,7 @@
<Bold>Website:</Bold> <Hyperlink NavigateUri="https://elwig.at/" RequestNavigate="Hyperlink_RequestNavigate">https://elwig.at/</Hyperlink><LineBreak/>
<Bold>Entwickler:</Bold> Lorenz Stechauner, Thomas Hilscher<LineBreak/>
<Bold>Kontakt:</Bold> <Hyperlink NavigateUri="mailto:lorenz.stechauner@necronda.net" RequestNavigate="Hyperlink_RequestNavigate">lorenz.stechauner@necronda.net</Hyperlink>, <Hyperlink NavigateUri="mailto:thomas.hilscher@gmail.com" RequestNavigate="Hyperlink_RequestNavigate">thomas.hilscher@gmail.com</Hyperlink><LineBreak/>
<Bold>Quellcode:</Bold> <Hyperlink NavigateUri="C:\Program Files\Elwig\src" RequestNavigate="Hyperlink_RequestNavigate_Explorer">C:\Program Files\Elwig\src</Hyperlink>, <Hyperlink NavigateUri="https://git.necronda.net/winzer/elwig" RequestNavigate="Hyperlink_RequestNavigate">https://git.necronda.net/winzer/elwig</Hyperlink><LineBreak/>
<Bold>Quellcode:</Bold> <Hyperlink NavigateUri="https://git.necronda.net/winzer/elwig" RequestNavigate="Hyperlink_RequestNavigate">https://git.necronda.net/winzer/elwig</Hyperlink><LineBreak/>
<Bold>Entwicklungszeitraum:</Bold> 20222026<LineBreak/>
<LineBreak/>
<Bold>Verwendete Technologien:</Bold><LineBreak/>
+1 -9
View File
@@ -11,15 +11,7 @@ namespace Elwig.Windows {
}
private void Hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e) {
try {
Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri) { UseShellExecute = true });
} catch { }
}
private void Hyperlink_RequestNavigate_Explorer(object sender, RequestNavigateEventArgs e) {
try {
Process.Start("explorer.exe", e.Uri.AbsoluteUri);
} catch { }
Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri) { UseShellExecute = true });
}
}
}
+5 -4
View File
@@ -9,7 +9,6 @@ using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Elwig.Services;
namespace Elwig.Windows {
public abstract class AdministrationWindow : ContextWindow {
@@ -105,12 +104,13 @@ namespace Elwig.Windows {
cb.SelectionChanged += ComboBox_SelectionChanged;
foreach (var lb in ListBoxInputs)
lb.SelectionChanged += ComboBox_SelectionChanged;
LockInputs();
}
private void OnClosing(object? sender, CancelEventArgs evt) {
if ((IsCreating || IsEditing) && HasChanged) {
if (!InteractionService.AskConfirmation("Schließen bestätigen", "Soll das Fenster wirklich geschlossen werden?")) {
var r = MessageBox.Show("Soll das Fenster wirklich geschlossen werden?", "Schließen bestätigen",
MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No);
if (r != MessageBoxResult.Yes) {
evt.Cancel = true;
return;
}
@@ -349,6 +349,7 @@ namespace Elwig.Windows {
using var ctx = new AppDbContext();
list = await ctx.PlzDestinations
.Where(p => p.Plz == plz)
.Include(p => p.Ort)
.ToListAsync();
}
@@ -389,7 +390,7 @@ namespace Elwig.Windows {
protected bool InputLostFocus(TextBox input, ValidationResult res, string? msg = null) {
if (DoShowWarningWindows && !res.IsValid && !IsClosing && (IsEditing || IsCreating))
InteractionService.ShowWarning(msg ?? res.ErrorContent?.ToString() ?? "", res.ErrorContent?.ToString() ?? "");
MessageBox.Show(res.ErrorContent?.ToString(), msg ?? res.ErrorContent?.ToString(), MessageBoxButton.OK, MessageBoxImage.Warning);
return res.IsValid;
}
+2 -1
View File
@@ -7,7 +7,8 @@
xmlns:local="clr-namespace:Elwig.Windows"
xmlns:ctrl="clr-namespace:Elwig.Controls"
xmlns:vm="clr-namespace:Elwig.ViewModels"
Title="{Binding Title}" Height="600" MinHeight="550" Width="1000" MinWidth="860">
Title="{Binding Title}" Height="600" MinHeight="550" Width="1000" MinWidth="860"
Loaded="Window_Loaded">
<Window.DataContext>
<vm:AreaComAdminViewModel/>
</Window.DataContext>
+47 -46
View File
@@ -39,6 +39,10 @@ namespace Elwig.Windows {
ViewModel.FilterSeason = Utils.CurrentYear;
}
private void Window_Loaded(object sender, RoutedEventArgs e) {
LockInputs();
}
private void FocusSearchInput(object sender, RoutedEventArgs evt) {
if (!IsEditing && !IsCreating) {
SearchInput.Focus();
@@ -47,44 +51,42 @@ namespace Elwig.Windows {
}
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();
var (_, contractQuery, areaComQuery, filter) = await vm.GetFilters(ctx);
var contracts = await contractQuery
.Include(c => c.Revisions).ThenInclude(a => a.Member)
.ToListAsync();
var areaComs = await areaComQuery.ToListAsync();
using var ctx = new AppDbContext();
var (_, contractQuery, areaComQuery, filter) = await ViewModel.GetFilters(ctx);
var contracts = await contractQuery
.Include(c => c.Kg.AtKg)
.Include(c => c.Rd!.Kg.AtKg)
.Include(c => c.Revisions).ThenInclude(a => a.WineCult)
.Include(c => c.Revisions).ThenInclude(a => a.AreaComType.WineAttr)
.Include(c => c.Revisions).ThenInclude(a => a.AreaComType.WineVar)
.Include(c => c.Revisions).ThenInclude(a => a.Member)
.ToListAsync();
var areaComs = await areaComQuery
.Include(c => c.Contract.Kg.AtKg)
.Include(c => c.Contract.Rd!.Kg.AtKg)
.Include(a => a.WineCult)
.Include(a => a.AreaComType.WineAttr)
.Include(a => a.AreaComType.WineVar)
.ToListAsync();
if (filter.Count > 0 && contracts.Count > 0) {
var dict = contracts.AsParallel()
.ToDictionary(d => d, d => d.SearchScore(vm.TextFilter))
.OrderByDescending(c => c.Value);
var threshold = dict.Max(a => a.Value) * 3 / 4;
contracts = [.. dict
if (filter.Count > 0 && contracts.Count > 0) {
var dict = contracts.AsParallel()
.ToDictionary(d => d, d => d.SearchScore(ViewModel.TextFilter))
.OrderByDescending(c => c.Value);
var threshold = dict.Max(a => a.Value) * 3 / 4;
contracts = [.. dict
.Where(a => a.Value > threshold)
.Select(a => a.Key)];
}
var areaComCount = await areaComQuery.CountAsync();
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);
AreaCommitmentList_SelectionChanged, filter.Count > 0 ? ControlUtils.RenewSourceDefault.IfOnly : ControlUtils.RenewSourceDefault.None, !updateSort);
RefreshInputs();
if (filter.Count == 0) {
ViewModel.StatusAreaCommitments = $"{areaComCount:N0}";
var (text, gridData) = stat;
ViewModel.StatusAreaCommitments = $"{await areaComQuery.CountAsync():N0}";
var s = await ctx.Seasons.FindAsync(await ctx.Seasons.MaxAsync(s => s.Year));
var (text, gridData) = await AreaComService.GenerateToolTipData(areaComQuery, s?.MaxKgPerHa ?? 10_000);
ViewModel.StatusArea = text;
ViewModel.StatusAreaToolTip = AreaComService.GenerateToolTip(gridData);
} else {
@@ -151,15 +153,10 @@ namespace Elwig.Windows {
ValidateRequiredInputs();
}
new protected void ClearInputs(bool validate = false) {
ViewModel.ClearInputs();
base.ClearInputs(validate);
}
protected override async Task OnRenewContext(AppDbContext ctx) {
await base.OnRenewContext(ctx);
if (await ctx.FetchMembers(ViewModel.FilterMember.MgNr).SingleOrDefaultAsync() is not Member m) {
if (await ctx.Members.FindAsync(ViewModel.FilterMember.MgNr) is not Member m) {
Close();
return;
}
@@ -176,8 +173,12 @@ namespace Elwig.Windows {
.Include(c => c.WineAttr)
.OrderBy(v => v.VtrgId)
.ToListAsync());
ControlUtils.RenewItemsSource(MemberInput, await ctx.FetchMembers(includeNotActive: true).ToListAsync());
var cultList = await ctx.FetchWineCultivations().Cast<object>().ToListAsync();
ControlUtils.RenewItemsSource(MemberInput, await ctx.Members
.OrderBy(m => m.Name).ThenBy(m => m.GivenName).ThenBy(m => m.MgNr)
.ToListAsync());
var cultList = await ctx.WineCultivations
.OrderBy(c => c.Name)
.Cast<object>().ToListAsync();
cultList.Insert(0, new NullItem());
ControlUtils.RenewItemsSource(WineCultivationInput, cultList, null, ControlUtils.RenewSourceDefault.First);
await RefreshList();
@@ -246,7 +247,9 @@ namespace Elwig.Windows {
}
App.HintContextChange();
} catch (Exception exc) {
InteractionService.ShowDbException("Flächenbindung löschen", exc);
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Flächenbindung löschen", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = null;
}
@@ -264,10 +267,8 @@ namespace Elwig.Windows {
if (InputHasChanged(AreaInput) || InputHasChanged(AreaComTypeInput) || InputHasChanged(MgNrInput)) {
var a = (RevisionList.SelectedItem as AreaCom)!;
var d = new AreaComModifyDialog(a.YearFrom, a.YearTo, a.Area, false, RevisionList.ItemsSource.Cast<object>().FirstOrDefault() != a);
if (d.ShowDialog() != true) {
SaveButton.IsEnabled = true;
if (d.ShowDialog() != true)
return;
}
yearTo = d.YearTo;
}
@@ -296,7 +297,9 @@ namespace Elwig.Windows {
}
App.HintContextChange();
} catch (Exception exc) {
InteractionService.ShowDbException("Flächenbindung aktualisieren", exc);
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Flächenbindung aktualisieren", MessageBoxButton.OK, MessageBoxImage.Error);
SaveButton.IsEnabled = true;
Mouse.OverrideCursor = null;
return;
@@ -443,19 +446,17 @@ namespace Elwig.Windows {
}
private async void ActiveAreaCommitmentInput_Changed(object sender, RoutedEventArgs evt) {
if (!HasContextLoaded) return;
await RefreshList();
}
private async void SearchInput_TextChanged(object sender, RoutedEventArgs evt) {
if (!HasContextLoaded) return;
var binding = ((TextBox)sender).GetBindingExpression(TextBox.TextProperty);
binding?.UpdateSource();
await RefreshList(true);
}
private async void SeasonInput_TextChanged(object sender, TextChangedEventArgs evt) {
if (!HasContextLoaded || ViewModel.FilterSeason == null) return;
if (ViewModel.FilterSeason == null) return;
await RefreshList();
}
+2 -1
View File
@@ -8,7 +8,8 @@
xmlns:local="clr-namespace:Elwig.Windows"
xmlns:ctrl="clr-namespace:Elwig.Controls"
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>
<Style TargetType="Label">
<Setter Property="HorizontalAlignment" Value="Left"/>
@@ -21,6 +21,8 @@ namespace Elwig.Windows {
private async Task AreaCommitmentTypesInitEditing(AppDbContext ctx) {
_actList = new(await ctx.AreaCommitmentTypes
.OrderBy(v => v.VtrgId)
.Include(t => t.WineVar)
.Include(t => t.WineAttr)
.ToListAsync());
_acts = _actList.ToDictionary(v => v.VtrgId, v => (string?)v.VtrgId);
_actIds = _actList.ToDictionary(v => v, v => v.VtrgId);
+12 -5
View File
@@ -19,7 +19,10 @@ namespace Elwig.Windows {
private bool _branchUpdate = false;
private async Task BranchesInitEditing(AppDbContext ctx) {
_branchList = new(await ctx.FetchBranches().ToListAsync());
_branchList = new(await ctx.Branches
.OrderBy(b => b.Name)
.Include(b => b.PostalDest!.AtPlz)
.ToListAsync());
_branches = _branchList.ToDictionary(b => b.ZwstId, b => (string?)b.ZwstId);
_branchIds = _branchList.ToDictionary(b => b, b => b.ZwstId);
ControlUtils.RenewItemsSource(BranchList, _branchList);
@@ -27,7 +30,10 @@ namespace Elwig.Windows {
}
private async Task BranchesFinishEditing(AppDbContext ctx) {
ControlUtils.RenewItemsSource(BranchList, await ctx.FetchBranches().ToListAsync());
ControlUtils.RenewItemsSource(BranchList, await ctx.Branches
.OrderBy(b => b.Name)
.Include(b => b.PostalDest!.AtPlz)
.ToListAsync());
_branchList = null;
_branches = null;
_branchIds = null;
@@ -41,9 +47,9 @@ namespace Elwig.Windows {
if (!_branchChanged || _branchList == null || _branches == null || _branchIds == null)
return;
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 (zwstid, _) in _branches.Where(b => b.Value == null)) {
ctx.Remove(ctx.Branches.Find(zwstid)!);
}
foreach (var (branch, old) in _branchIds) {
branch.ZwstId = old;
}
@@ -55,6 +61,7 @@ namespace Elwig.Windows {
foreach (var (old, zwstid) in _branches.Where(b => b.Value != null)) {
await ctx.Database.ExecuteSqlAsync($"UPDATE branch SET zwstid = {zwstid} WHERE zwstid = {old}");
}
await ctx.SaveChangesAsync();
foreach (var branch in _branchList.Where(b => !_branchIds.ContainsKey(b))) {
if (branch.ZwstId == null) continue;
+8 -2
View File
@@ -22,7 +22,10 @@ namespace Elwig.Windows {
private async Task ModifiersInitEditing(AppDbContext ctx) {
SeasonList.IsEnabled = false;
var year = (SeasonList.SelectedItem as Season)?.Year;
_modList = new(await ctx.FetchModifiers(year ?? 0).ToListAsync());
_modList = new(await ctx.Modifiers
.Where(m => m.Year == year)
.OrderBy(m => m.Ordering)
.ToListAsync());
_mods = _modList.ToDictionary(m => m.ModId, m => (string?)m.ModId);
_modIds = _modList.ToDictionary(m => m, m => m.ModId);
ControlUtils.RenewItemsSource(SeasonModifierList, _modList);
@@ -31,7 +34,10 @@ namespace Elwig.Windows {
private async Task ModifiersFinishEditing(AppDbContext ctx) {
var year = (SeasonList.SelectedItem as Season)?.Year;
ControlUtils.RenewItemsSource(SeasonModifierList, await ctx.FetchModifiers(year ?? 0).ToListAsync());
ControlUtils.RenewItemsSource(SeasonModifierList, await ctx.Modifiers
.Where(m => m.Year == year)
.OrderBy(m => m.Ordering)
.ToListAsync());
_modList = null;
_mods = null;
_modIds = null;
+20 -6
View File
@@ -1,7 +1,6 @@
using Elwig.Dialogs;
using Elwig.Helpers;
using Elwig.Models.Entities;
using Elwig.Services;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
@@ -20,14 +19,22 @@ namespace Elwig.Windows {
private async Task SeasonsInitEditing(AppDbContext ctx) {
SeasonAddButton.IsEnabled = false;
SeasonRemoveButton.IsEnabled = false;
ControlUtils.RenewItemsSource(SeasonList, await ctx.FetchSeasons(includeModifiers: true).ToListAsync());
ControlUtils.RenewItemsSource(SeasonList, await ctx.Seasons
.OrderByDescending(s => s.Year)
.Include(s => s.Modifiers)
.Include(s => s.Currency)
.ToListAsync());
SeasonList_SelectionChanged(null, null);
}
private async Task SeasonsFinishEditing(AppDbContext ctx) {
SeasonAddButton.IsEnabled = true;
SeasonRemoveButton.IsEnabled = true;
ControlUtils.RenewItemsSource(SeasonList, await ctx.FetchSeasons(includeModifiers: true).ToListAsync());
ControlUtils.RenewItemsSource(SeasonList, await ctx.Seasons
.OrderByDescending(s => s.Year)
.Include(s => s.Modifiers)
.Include(s => s.Currency)
.ToListAsync());
_seasonChanged = false;
}
@@ -185,7 +192,9 @@ namespace Elwig.Windows {
}
await ctx.SaveChangesAsync();
} catch (Exception exc) {
InteractionService.ShowDbException("Saison anlegen", exc);
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Saison anlegen", MessageBoxButton.OK, MessageBoxImage.Error);
}
App.HintContextChange();
Mouse.OverrideCursor = null;
@@ -196,14 +205,19 @@ namespace Elwig.Windows {
private async void SeasonRemoveButton_Click(object sender, RoutedEventArgs evt) {
if (SeasonList.SelectedItem is not Season s)
return;
if (InteractionService.AskContinue("Saison löschen", $"Soll die Saison {s.Year} wirklich unwiderruflich gelöscht werden?")) {
var r = MessageBox.Show(
$"Soll die Saison {s.Year} wirklich unwiderruflich gelöscht werden?",
"Saison löschen", MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
if (r == MessageBoxResult.OK) {
Mouse.OverrideCursor = Cursors.Wait;
try {
using var ctx = new AppDbContext();
ctx.Remove(s);
await ctx.SaveChangesAsync();
} catch (Exception exc) {
InteractionService.ShowDbException("Saison löschen", exc);
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Saison löschen", MessageBoxButton.OK, MessageBoxImage.Error);
}
App.HintContextChange();
Mouse.OverrideCursor = null;
+10 -4
View File
@@ -19,7 +19,9 @@ namespace Elwig.Windows {
private bool _attrUpdate = false;
private async Task WineAttributesInitEditing(AppDbContext ctx) {
_attrList = new(await ctx.FetchWineAttributes().ToListAsync());
_attrList = new(await ctx.WineAttributes
.OrderBy(a => a.Name)
.ToListAsync());
_attrs = _attrList.ToDictionary(a => a.AttrId, a => (string?)a.AttrId);
_attrIds = _attrList.ToDictionary(a => a, a => a.AttrId);
ControlUtils.RenewItemsSource(WineAttributeList, _attrList);
@@ -27,7 +29,9 @@ namespace Elwig.Windows {
}
private async Task WineAttributesFinishEditing(AppDbContext ctx) {
ControlUtils.RenewItemsSource(WineAttributeList, await ctx.FetchWineAttributes().ToListAsync());
ControlUtils.RenewItemsSource(WineAttributeList, await ctx.WineAttributes
.OrderBy(a => a.Name)
.ToListAsync());
_attrList = null;
_attrs = null;
_attrIds = null;
@@ -41,8 +45,9 @@ namespace Elwig.Windows {
if (!_attrChanged || _attrList == null || _attrs == null || _attrIds == null)
return;
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 (attrid, _) in _attrs.Where(a => a.Value == null)) {
ctx.Remove(ctx.WineAttributes.Find(attrid)!);
}
foreach (var (attr, old) in _attrIds) {
attr.AttrId = old;
}
@@ -56,6 +61,7 @@ namespace Elwig.Windows {
await ctx.Database.ExecuteSqlAsync($"UPDATE area_commitment_type SET vtrgid = (sortid || COALESCE(attrid, '') || COALESCE(disc, '')) WHERE attrid = {attrid}");
await ctx.Database.ExecuteSqlRawAsync($"UPDATE payment_variant SET data = REPLACE(REPLACE(data, '/{old}\"', '/{attrid}\"'), '/{old}-', '/{attrid}-')");
}
await ctx.SaveChangesAsync();
foreach (var attr in _attrList.Where(a => !_attrIds.ContainsKey(a))) {
if (attr.AttrId == null) continue;
+10 -4
View File
@@ -19,7 +19,9 @@ namespace Elwig.Windows {
private bool _cultUpdate = false;
private async Task WineCultivationsInitEditing(AppDbContext ctx) {
_cultList = new(await ctx.FetchWineCultivations().ToListAsync());
_cultList = new(await ctx.WineCultivations
.OrderBy(c => c.Name)
.ToListAsync());
_cults = _cultList.ToDictionary(c => c.CultId, c => (string?)c.CultId);
_cultIds = _cultList.ToDictionary(c => c, c => c.CultId);
ControlUtils.RenewItemsSource(WineCultivationList, _cultList);
@@ -27,7 +29,9 @@ namespace Elwig.Windows {
}
private async Task WineCultivationsFinishEditing(AppDbContext ctx) {
ControlUtils.RenewItemsSource(WineCultivationList, await ctx.FetchWineCultivations().ToListAsync());
ControlUtils.RenewItemsSource(WineCultivationList, await ctx.WineCultivations
.OrderBy(c => c.Name)
.ToListAsync());
_cultList = null;
_cults = null;
_cultIds = null;
@@ -41,8 +45,9 @@ namespace Elwig.Windows {
if (!_cultChanged || _cultList == null || _cults == null || _cultIds == null)
return;
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 (cultid, _) in _cults.Where(c => c.Value == null)) {
ctx.Remove(ctx.WineCultivations.Find(cultid)!);
}
foreach (var (cult, old) in _cultIds) {
cult.CultId = old;
}
@@ -55,6 +60,7 @@ namespace Elwig.Windows {
await ctx.Database.ExecuteSqlAsync($"UPDATE wine_cultivation SET cultid = {cultid} WHERE cultid = {old}");
await ctx.Database.ExecuteSqlRawAsync($"UPDATE payment_variant SET data = REPLACE(data, '-{old}\"', '-{cultid}\"')");
}
await ctx.SaveChangesAsync();
foreach (var cult in _cultList.Where(c => !_cultIds.ContainsKey(c))) {
if (cult.CultId == null) continue;
+37 -14
View File
@@ -1,6 +1,5 @@
using Elwig.Helpers;
using Elwig.Models.Entities;
using Elwig.Services;
using Microsoft.EntityFrameworkCore;
using System;
using System.Linq;
@@ -154,22 +153,44 @@ namespace Elwig.Windows {
ParameterExportEbicsAddress.IsEnabled = true;
}
private void Window_Loaded(object sender, RoutedEventArgs evt) {
LockInputs();
}
protected override async Task OnRenewContext(AppDbContext ctx) {
await base.OnRenewContext(ctx);
FillInputs(App.Client, await ctx.FetchSeasons(Utils.CurrentLastSeason).SingleOrDefaultAsync());
ControlUtils.RenewItemsSource(SeasonList, await ctx.FetchSeasons(includeModifiers: true).ToListAsync(), null, ControlUtils.RenewSourceDefault.First);
FillInputs(App.Client, await ctx.Seasons.FindAsync(Utils.CurrentLastSeason));
ControlUtils.RenewItemsSource(SeasonList, await ctx.Seasons
.OrderByDescending(s => s.Year)
.Include(s => s.Modifiers)
.Include(s => s.Currency)
.ToListAsync(), null, ControlUtils.RenewSourceDefault.First);
var year = (SeasonList.SelectedItem as Season)?.Year;
ControlUtils.RenewItemsSource(BranchList, await ctx.FetchBranches().ToListAsync(), null, ControlUtils.RenewSourceDefault.First);
ControlUtils.RenewItemsSource(WineAttributeList, await ctx.FetchWineAttributes().ToListAsync(), null, ControlUtils.RenewSourceDefault.First);
ControlUtils.RenewItemsSource(AreaCommitmentTypeWineVariantInput, await ctx.FetchWineVarieties().ToListAsync());
var attrList = await ctx.FetchWineAttributes().Cast<object>().ToListAsync();
ControlUtils.RenewItemsSource(BranchList, await ctx.Branches
.OrderBy(b => b.Name)
.Include(b => b.PostalDest!.AtPlz)
.ToListAsync(), null, ControlUtils.RenewSourceDefault.First);
ControlUtils.RenewItemsSource(WineAttributeList, await ctx.WineAttributes
.OrderBy(a => a.Name)
.ToListAsync(), null, ControlUtils.RenewSourceDefault.First);
ControlUtils.RenewItemsSource(AreaCommitmentTypeWineVariantInput, await ctx.WineVarieties
.OrderBy(s => s.Name)
.ToListAsync());
var attrList = await ctx.WineAttributes.OrderBy(a => a.Name).Cast<object>().ToListAsync();
attrList.Insert(0, new NullItem(""));
ControlUtils.RenewItemsSource(AreaCommitmentTypeWineAttributeInput, attrList);
ControlUtils.RenewItemsSource(AreaCommitmentTypeList, await ctx.AreaCommitmentTypes
.OrderBy(t => t.VtrgId)
.Include(t => t.WineVar)
.Include(t => t.WineAttr)
.ToListAsync(), null, ControlUtils.RenewSourceDefault.First);
ControlUtils.RenewItemsSource(WineCultivationList, await ctx.WineCultivations
.OrderBy(c => c.Name)
.ToListAsync(), null, ControlUtils.RenewSourceDefault.First);
ControlUtils.RenewItemsSource(SeasonModifierList, await ctx.Modifiers
.Where(m => m.Year == year)
.OrderBy(m => m.Ordering)
.ToListAsync(), null, ControlUtils.RenewSourceDefault.First);
ControlUtils.RenewItemsSource(WineCultivationList, await ctx.FetchWineCultivations().ToListAsync(), null, ControlUtils.RenewSourceDefault.First);
ControlUtils.RenewItemsSource(SeasonModifierList, await ctx.FetchModifiers(year ?? 0).ToListAsync(), null, ControlUtils.RenewSourceDefault.First);
}
protected override void UpdateButtons() {
@@ -265,7 +286,7 @@ namespace Elwig.Windows {
using var ctx = new AppDbContext();
ClearInputStates();
FillInputs(App.Client, await ctx.FetchSeasons(Utils.CurrentLastSeason).SingleOrDefaultAsync());
FillInputs(App.Client, await ctx.Seasons.FindAsync(Utils.CurrentLastSeason));
LockInputs();
}
@@ -285,7 +306,7 @@ namespace Elwig.Windows {
using var ctx = new AppDbContext();
ClearInputStates();
FillInputs(App.Client, await ctx.FetchSeasons(Utils.CurrentLastSeason).SingleOrDefaultAsync());
FillInputs(App.Client, await ctx.Seasons.FindAsync(Utils.CurrentLastSeason));
UpdateButtons();
}
@@ -301,7 +322,9 @@ namespace Elwig.Windows {
try {
await Save();
} catch (Exception exc) {
InteractionService.ShowDbException("Stammdaten aktualisieren", exc);
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Stammdaten aktualisieren", MessageBoxButton.OK, MessageBoxImage.Error);
SaveButton.IsEnabled = true;
Mouse.OverrideCursor = null;
return;
@@ -319,7 +342,7 @@ namespace Elwig.Windows {
using (var ctx = new AppDbContext()) {
ClearInputStates();
FillInputs(App.Client, await ctx.FetchSeasons(Utils.CurrentLastSeason).SingleOrDefaultAsync());
FillInputs(App.Client, await ctx.Seasons.FindAsync(Utils.CurrentLastSeason));
LockInputs();
}
@@ -407,7 +430,7 @@ namespace Elwig.Windows {
private async Task UpdateParameters(int year) {
try {
using var ctx = new AppDbContext();
if (await ctx.FetchSeasons(year).SingleOrDefaultAsync() is not Season s)
if (await ctx.Seasons.FindAsync(year) is not Season s)
return;
s.Billing_AllowAttrsIntoLower = ParameterAllowAttrIntoLowerInput.IsChecked ?? false;
+1
View File
@@ -9,6 +9,7 @@
xmlns:ScottPlot="clr-namespace:ScottPlot.WPF;assembly=ScottPlot.WPF"
mc:Ignorable="d"
Title="Auszahlung - Elwig" Height="700" Width="1500" MinWidth="1000" MinHeight="500"
Loaded="Window_Loaded"
Closing="Window_Closing">
<Window.Resources>
+37 -24
View File
@@ -10,7 +10,6 @@ using Elwig.Helpers.Billing;
using Elwig.Models.Entities;
using ScottPlot.Plottables;
using ScottPlot;
using Elwig.Services;
namespace Elwig.Windows {
public partial class ChartWindow : ContextWindow {
@@ -81,9 +80,14 @@ namespace Elwig.Windows {
LockContext = true;
}
private void Window_Loaded(object sender, RoutedEventArgs evt) {
}
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) {
if (HasChanged) {
if (!InteractionService.AskConfirmation("Schließen bestätigen", "Soll das Fenster wirklich geschlossen werden? Nicht gespeicherte Änderungen werden NICHT übernommen!")) {
var r = MessageBox.Show("Soll das Fenster wirklich geschlossen werden? Nicht gespeicherte Änderungen werden NICHT übernommen!", "Schließen bestätigen",
MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No);
if (r != MessageBoxResult.Yes) {
e.Cancel = true;
return;
}
@@ -97,31 +101,32 @@ namespace Elwig.Windows {
private async Task RefreshGraphList(AppDbContext ctx) {
PaymentVar = await ctx.PaymentVariants.FindAsync(Year, AvNr) ?? throw new ArgumentException("PaymentVar not found");
Season = await ctx.FetchSeasons(Year).SingleOrDefaultAsync() ?? throw new ArgumentException("Season not found");
Season = await ctx.Seasons.FindAsync(Year) ?? throw new ArgumentException("Season not found");
CurrencySymbol = Season.Currency.Symbol ?? Season.Currency.Code;
PriceInput.Unit = $"{CurrencySymbol}/kg";
GebundenFlatBonus.Unit = $"{CurrencySymbol}/kg";
try {
var data = EditBillingData.FromJson(PaymentVar.Data, await Utils.GetVaributes(ctx, Year));
var paymentEntries = await data.GetPaymentGraphEntries(ctx, Season);
var data = EditBillingData.FromJson(PaymentVar.Data, Utils.GetVaributes(ctx, Year));
var paymentEntries = data.GetPaymentGraphEntries(ctx, Season);
GraphEntries = [
..paymentEntries,
..await data.GetQualityGraphEntries(ctx, Season, paymentEntries.Any() ? paymentEntries.Max(e => e.Id) : 0)
..data.GetQualityGraphEntries(ctx, Season, paymentEntries.Any() ? paymentEntries.Max(e => e.Id) : 0)
];
} catch (KeyNotFoundException exc) {
var key = exc.Message.Split('\'')[1].Split('\'')[0];
InteractionService.ShowError("Fehler",
$"Fehler beim Laden der Auszahlungsvariante:\n\n" +
$"Mit unbekanntem Attribut '{key}' kann nicht umgegangen werden.");
} catch (KeyNotFoundException ex) {
var key = ex.Message.Split('\'')[1].Split('\'')[0];
MessageBox.Show($"Fehler beim Laden der Auszahlungsvariante:\n\n" +
$"Mit unbekanntem Attribut '{key}' kann nicht umgegangen werden.", "Fehler",
MessageBoxButton.OK, MessageBoxImage.Error);
} catch (ArgumentException) {
InteractionService.ShowError("Fehler",
$"Fehler beim Laden der Auszahlungsvariante:\n\n" +
$"Die Daten der Auszahlungsvariante entsprechen nicht dem benötigtem Format.");
} catch (Exception exc) {
InteractionService.ShowException("Fehler", "Fehler beim Laden der Auszahlungsvariante", exc);
MessageBox.Show($"Fehler beim Laden der Auszahlungsvariante:\n\n" +
$"Die Daten der Auszahlungsvariante entsprechen nicht dem benötigtem Format.", "Fehler",
MessageBoxButton.OK, MessageBoxImage.Error);
} catch (Exception ex) {
MessageBox.Show("Fehler beim Laden der Auszahlungsvariante:\n\n" + ex.Message, "Fehler",
MessageBoxButton.OK, MessageBoxImage.Error);
}
Vaributes = await Utils.GetVaributeList(ctx, Year);
Vaributes = Utils.GetVaributeList(ctx, Year);
GraphEntries.ForEach(e => {
e.Vaributes.ForEach(v => {
var found = Vaributes.Find(a => a.Variety?.SortId == v.Variety?.SortId && a.Attribute?.AttrId == v.Attribute?.AttrId && a.Cultivation?.CultId == v.Cultivation?.CultId);
@@ -620,7 +625,11 @@ namespace Elwig.Windows {
private void DeleteButton_Click(object sender, RoutedEventArgs e) {
if (SelectedGraphEntry == null) return;
if (InteractionService.AskConfirmation("Kurve löschen", $"Soll die Kurve {SelectedGraphEntry.Id} (verwendet in folgenden Verträgen: {SelectedGraphEntry.VaributeStringSimple}) wirklich gelöscht werden?")) {
var r = MessageBox.Show(
$"Soll die Kurve {SelectedGraphEntry.Id} (verwendet in folgenden Verträgen: {SelectedGraphEntry.VaributeStringSimple}) wirklich gelöscht werden?",
"Kurve löschen", MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No);
if (r == MessageBoxResult.Yes) {
GraphEntries.Remove(SelectedGraphEntry);
SetHasChanged();
GraphList.Items.Refresh();
@@ -636,7 +645,7 @@ namespace Elwig.Windows {
await Task.Run(async () => {
using var ctx = new AppDbContext();
var origData = BillingData.FromJson(PaymentVar.Data);
var data = BillingData.FromGraphEntries(GraphEntries, origData, await Utils.GetVaributes(ctx, Year),
var data = BillingData.FromGraphEntries(GraphEntries, origData, Utils.GetVaributes(ctx, Year),
AllVaributesAssigned, AllVaributesAssignedAbgew);
PaymentVar.Data = data.ToJsonString();
@@ -645,20 +654,22 @@ namespace Elwig.Windows {
});
} catch (Exception exc) {
Mouse.OverrideCursor = null;
InteractionService.ShowDbException("Auszahlungsvariante speichern", exc);
var str = "Der Eintrag konnte nicht in der Datenbank gespeichert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Auszahlungsvariante speichern", MessageBoxButton.OK, MessageBoxImage.Error);
SaveButton.IsEnabled = true;
return;
}
try {
await Task.Run(async () => {
var b = await BillingVariant.Create(PaymentVar.Year, PaymentVar.AvNr);
var b = new BillingVariant(PaymentVar.Year, PaymentVar.AvNr);
await b.Calculate(false);
});
} catch (KeyNotFoundException exc) {
InteractionService.ShowInformation("Noch nicht alle Preise festgelegt", exc.Message);
MessageBox.Show(exc.Message, "Noch nicht alle Preise festgelegt", MessageBoxButton.OK, MessageBoxImage.Information);
} catch (Exception exc) {
InteractionService.ShowException("Berechnungsfehler", exc);
MessageBox.Show(exc.Message, "Berechnungsfehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
LockContext = false;
@@ -765,7 +776,9 @@ namespace Elwig.Windows {
if (ge != SelectedGraphEntry && ge.Abgewertet == SelectedGraphEntry?.Abgewertet) {
var toRemove = ge.Vaributes.Where(c => c.Listing.Equals(varibute)).ToList();
if (toRemove.Count == 0) continue;
if (!InteractionService.AskConfirmation("Entfernen bestätigen", $"Achtung: {string.Join(", ", toRemove)} ist bereits in Kurve {ge.Id} in Verwendung!\nSoll die Zuweisung dort entfernt werden?")) {
var r = MessageBox.Show($"Achtung: {string.Join(", ", toRemove)} ist bereits in Kurve {ge.Id} in Verwendung!\nSoll die Zuweisung dort entfernt werden?", "Entfernen bestätigen",
MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No);
if (r != MessageBoxResult.Yes) {
return false;
}
ge.Vaributes.RemoveAll(c => c.Listing.Equals(varibute));
+3 -19
View File
@@ -18,8 +18,6 @@ namespace Elwig.Windows {
}
}
protected bool HasContextLoaded { get; private set; }
private bool _renewPending = false;
private readonly RoutedCommand CtrlR = new("CtrlR", typeof(ContextWindow), [new KeyGesture(Key.R, ModifierKeys.Control)]);
@@ -32,41 +30,27 @@ namespace Elwig.Windows {
}
public async void ForceContextReload(object sender, EventArgs evt) {
await ForceContextReload();
await HintContextChange();
}
public async Task ForceContextReload() {
HintContextChange();
await TryContextReload();
}
public void HintContextChange() {
public async Task HintContextChange() {
_renewPending = true;
}
public async Task TryContextReload() {
if (LockContext) return;
await EnsureContextRenewed();
}
protected async void OnLoaded(object? sender, RoutedEventArgs? evt) {
Mouse.OverrideCursor = Cursors.AppStarting;
using var ctx = new AppDbContext();
await OnRenewContext(ctx);
HasContextLoaded = true;
await OnInit(ctx);
Mouse.OverrideCursor = null;
}
protected async Task EnsureContextRenewed() {
if (!_renewPending) return;
_renewPending = false;
using var ctx = new AppDbContext();
await OnRenewContext(ctx);
_renewPending = false;
}
virtual protected async Task OnInit(AppDbContext ctx) { }
abstract protected Task OnRenewContext(AppDbContext ctx);
}
}
+4 -3
View File
@@ -6,7 +6,8 @@
xmlns:local="clr-namespace:Elwig.Windows"
xmlns:vm="clr-namespace:Elwig.ViewModels"
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>
<vm:DeliveryAdminViewModel/>
</Window.DataContext>
@@ -529,12 +530,12 @@
</Grid.ColumnDefinitions>
<Label Content="Gradation:" Margin="10,10,10,10"/>
<ctrl:UnitTextBox x:Name="GradationOeInput" Unit="°Oe" Text="{Binding GradationOeString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
TextChanged="GradationOeInput_TextChanged" LostFocus="GradationOeInput_LostFocus" KeyUp="Input_KeyUp"
TextChanged="GradationOeInput_TextChanged" KeyUp="Input_KeyUp"
Grid.Column="1" Width="54" Margin="0,10,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<Label Content="=" Margin="60,10,10,10" Grid.Column="1"/>
<ctrl:UnitTextBox x:Name="GradationKmwInput" Unit="°KMW" Text="{Binding GradationKmwString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
TextChanged="GradationKmwInput_TextChanged" LostFocus="GradationKmwInput_LostFocus" KeyUp="Input_KeyUp"
TextChanged="GradationKmwInput_TextChanged" KeyUp="Input_KeyUp"
Grid.Column="1" Width="68" Margin="78,10,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<Label Content="Qualitätsstufe:" Margin="10,40,10,10"/>
+159 -118
View File
@@ -6,6 +6,7 @@ using Elwig.Models.Entities;
using Elwig.Services;
using Elwig.ViewModels;
using Microsoft.EntityFrameworkCore;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -36,7 +37,6 @@ namespace Elwig.Windows {
private readonly Button[] WeighingButtons;
private List<WineQualLevel> WineQualityLevels = [];
private Dictionary<int, List<Modifier>> Modifiers = [];
public DeliveryAdminWindow(bool receipt = false) {
InitializeComponent();
@@ -122,23 +122,22 @@ namespace Elwig.Windows {
Menu_Export_UploadSeason.IsEnabled = App.Config.SyncUrl != null;
}
public DeliveryAdminWindow(int mgnr) :
this() {
public DeliveryAdminWindow(int mgnr) : this() {
ViewModel.FilterMember = DeliveryService.GetMember(mgnr) ?? throw new ArgumentException("MgNr argument has invalid value");
ViewModel.Title = $"Lieferungen - {ViewModel.FilterMember.AdministrativeName} - Elwig";
ViewModel.EnableAllSeasons = true;
}
protected override async Task OnInit(AppDbContext ctx) {
await base.OnInit(ctx);
private void Window_Loaded(object sender, RoutedEventArgs evt) {
OnSecondPassed(null, null);
SecondsTimer.Start();
LockInputs();
if (ViewModel.IsReceipt) {
NewDeliveryButton_Click(null, null);
if (await ctx.FetchSeasons(Utils.CurrentYear).SingleOrDefaultAsync() == null) {
InteractionService.ShowWarning("Saison noch nicht erstellt",
"Die Saison für das aktuelle Jahr wurde noch nicht erstellt. Neue Lieferungen können nicht abgespeichert werden.\n\n" +
"(Stammdaten -> Saisons -> Neu anlegen...)");
using var ctx = new AppDbContext();
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...)",
"Saison noch nicht erstellt", MessageBoxButton.OK, MessageBoxImage.Warning);
}
}
}
@@ -164,7 +163,9 @@ namespace Elwig.Windows {
private async void Menu_DeliveryNote_Email_Click(object sender, RoutedEventArgs evt) {
if (DeliveryList.SelectedItem is not Delivery d)
return;
if (!InteractionService.AskQuestion("Lieferschein verschicken", "Soll eine E-Mail verschickt werden?", true))
var res = MessageBox.Show("Soll eine E-Mail verschickt werden?", "Lieferschein verschicken",
MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.Yes);
if (res != MessageBoxResult.Yes)
return;
await DeliveryService.GenerateDeliveryNote(d.Year, d.DId, ExportMode.Email);
}
@@ -172,11 +173,16 @@ namespace Elwig.Windows {
private async void Menu_Bki_SaveList_Click(object sender, RoutedEventArgs evt) {
if (sender is not MenuItem m) return;
var year = int.Parse(m.Header.ToString()?.Split(" ")[^1] ?? Utils.CurrentLastSeason.ToString());
var filename = InteractionService.SaveFile("Traubentransportscheinliste (BKI)", $"{App.Client.NameToken}-Traubentransportscheinliste-{year}", Bki.FileExtension);
if (filename != null) {
var d = new SaveFileDialog() {
FileName = $"{App.Client.NameToken}-Traubentransportscheinliste-{year}.{Bki.FileExtension}",
DefaultExt = Bki.FileExtension,
Filter = "CSV-Datei (*.csv)|*.csv",
Title = $"Traubentransportscheinliste (BKI) speichern unter - Elwig"
};
if (d.ShowDialog() == true) {
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
using var file = new Bki(filename);
using var file = new Bki(d.FileName);
await file.ExportAsync(year);
});
Mouse.OverrideCursor = null;
@@ -414,57 +420,45 @@ namespace Elwig.Windows {
}
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();
var (_, deliveryQuery, deliveryPartsQuery, predicate, filter) = await vm.GetFilters(ctx);
var deliveries = await deliveryQuery
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers).ThenInclude(m => m.Modifier)
.Include(d => d.Parts).ThenInclude(p => p.Variety)
.Include(d => d.Parts).ThenInclude(p => p.Attribute)
.Include(d => d.Parts).ThenInclude(p => p.Cultivation)
.IgnoreAutoIncludes()
.AsSplitQuery()
.ToListAsync();
deliveries.Reverse();
using var ctx = new AppDbContext();
var (_, deliveryQuery, deliveryPartsQuery, predicate, filter) = await ViewModel.GetFilters(ctx);
var deliveries = await deliveryQuery
.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.Member.EmailAddresses)
.AsSplitQuery()
.ToListAsync();
deliveries.Reverse();
if (filter.Count > 0 && deliveries.Count > 0) {
var dict = deliveries.AsParallel()
.ToDictionary(d => d, d => d.SearchScore(vm.TextFilter))
.OrderByDescending(a => a.Value)
.ThenBy(a => a.Key.DateTime);
var threshold = dict.Max(a => a.Value) * 3 / 4;
deliveries = [.. dict
.Where(a => a.Value > threshold)
.Select(a => a.Key)];
}
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;
if (filter.Count > 0 && deliveries.Count > 0) {
var dict = deliveries.AsParallel()
.ToDictionary(d => d, d => d.SearchScore(ViewModel.TextFilter))
.OrderByDescending(a => a.Value)
.ThenBy(a => a.Key.DateTime);
var threshold = dict.Select(a => a.Value).Max() * 3 / 4;
deliveries = dict
.Where(a => a.Value > threshold)
.Select(a => a.Key)
.ToList();
}
deliveries.ForEach(d => { d.PartFilter = predicate; });
ControlUtils.RenewItemsSource(DeliveryList, deliveries,
DeliveryList_SelectionChanged, ViewModel.TextFilter.Count > 0 ? ControlUtils.RenewSourceDefault.IfOnly : ControlUtils.RenewSourceDefault.None, !updateSort);
DeliveryList_SelectionChanged, filter.Count > 0 ? ControlUtils.RenewSourceDefault.IfOnly : ControlUtils.RenewSourceDefault.None, !updateSort);
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.StatusDeliveries = $"{deliveries.Count:N0}";
if (filter.Count == 0) {
ViewModel.StatusDeliveries = $"{deliveries.Count:N0} ({deliveryPartsNum:N0})";
var deliveryParts = deliveryPartsQuery;
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)})" : "");
var (wText, wData, gText, gData) = stat;
var (wText, wData, gText, gData) = await DeliveryService.GenerateToolTipData(deliveryParts);
ViewModel.StatusWeight = wText;
ViewModel.StatusGradation = gText;
(ViewModel.StatusWeightToolTip, ViewModel.StatusGradationToolTip) = DeliveryService.GenerateToolTip(wData, gData);
@@ -492,7 +486,7 @@ namespace Elwig.Windows {
int year = 0;
Menu_Bki_SaveList.Items.Clear();
foreach (var s in await ctx.FetchSeasons().ToListAsync()) {
foreach (var s in await ctx.Seasons.OrderByDescending(s => s.Year).ToListAsync()) {
if (s.Year > year) year = s.Year;
var i = new MenuItem {
Header = $"Saison {s.Year}",
@@ -501,9 +495,6 @@ namespace Elwig.Windows {
Menu_Bki_SaveList.Items.Add(i);
}
var attributes = await ctx.FetchWineAttributes(!IsCreating).ToListAsync();
Modifiers = await ctx.FetchModifiers(null).GroupBy(m => m.Year).ToDictionaryAsync(g => g.Key, g => g.ToList());
var font = new FontFamily("Segoe MDL2 Assets");
Menu_BulkAction_SetAttribute.Items.Clear();
var noAttr = new MenuItem {
@@ -512,7 +503,7 @@ namespace Elwig.Windows {
};
noAttr.Click += Menu_BulkAction_SetAttribute_Click;
Menu_BulkAction_SetAttribute.Items.Add(noAttr);
foreach (var attr in attributes) {
foreach (var attr in await ctx.WineAttributes.OrderBy(a => a.AttrId).ToListAsync()) {
var i = new MenuItem {
Header = attr.Name,
};
@@ -522,7 +513,7 @@ namespace Elwig.Windows {
Menu_BulkAction_AddModifier.Items.Clear();
Menu_BulkAction_RemoveModifier.Items.Clear();
foreach (var mod in Modifiers.GetValueOrDefault(ViewModel.SelectedDelivery?.Year ?? year, [])) {
foreach (var mod in await ctx.Modifiers.Where(m => m.Year == year).OrderBy(m => m.ModId).ToListAsync()) {
var i1 = new MenuItem {
Header = mod.Name,
};
@@ -536,34 +527,44 @@ namespace Elwig.Windows {
}
await RefreshList();
ControlUtils.RenewItemsSource(MemberInput, await ctx.FetchMembers(includeNotActive: !IsCreating, includeContactInfo: true).ToListAsync());
ControlUtils.RenewItemsSource(BranchInput, await ctx.FetchBranches().ToListAsync());
ControlUtils.RenewItemsSource(WineVarietyInput, await ctx.FetchWineVarieties().ToListAsync());
var attrList = attributes.Cast<object>().ToList();
var d = DeliveryList.SelectedItem as Delivery;
var y = d?.Year ?? ViewModel.FilterSeason;
ControlUtils.RenewItemsSource(MemberInput, await ctx.Members
.Where(m => m.IsActive || !IsCreating)
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.DefaultWbKg!.AtKg)
.OrderBy(m => m.Name)
.ThenBy(m => m.GivenName)
.ToListAsync());
ControlUtils.RenewItemsSource(BranchInput, await ctx.Branches.OrderBy(b => b.Name).ToListAsync());
ControlUtils.RenewItemsSource(WineVarietyInput, await ctx.WineVarieties.OrderBy(v => v.Name).ToListAsync());
var attrList = await ctx.WineAttributes.Where(a => !IsCreating || a.IsActive).OrderBy(a => a.Name).Cast<object>().ToListAsync();
attrList.Insert(0, new NullItem(""));
ControlUtils.RenewItemsSource(AttributeInput, attrList, null, ControlUtils.RenewSourceDefault.First);
var cultList = await ctx.FetchWineCultivations().Cast<object>().ToListAsync();
var cultList = await ctx.WineCultivations.OrderBy(a => a.Name).Cast<object>().ToListAsync();
cultList.Insert(0, new NullItem(""));
ControlUtils.RenewItemsSource(CultivationInput, cultList, null, ControlUtils.RenewSourceDefault.First);
WineQualityLevels = await ctx.FetchWineQualityLevels().ToListAsync();
WineQualityLevels = await ctx.WineQualityLevels.ToListAsync();
ControlUtils.RenewItemsSource(WineQualityLevelInput, WineQualityLevels);
ControlUtils.RenewItemsSource(ModifiersInput, Modifiers.GetValueOrDefault(year, []).Where(m => m.IsActive || !IsCreating).ToList());
var origins = await ctx.WineOrigins.ToListAsync();
origins.ForEach(o => { origins.FirstOrDefault(p => p.HkId == o.ParentHkId)?.Children.Add(o); });
origins = [.. origins.OrderByDescending(o => o.SortKey).ThenBy(o => o.HkId)];
ControlUtils.RenewItemsSource(WineOriginInput, origins);
ControlUtils.RenewItemsSource(ModifiersInput, await ctx.Modifiers
.Where(m => m.Year == y && (!IsCreating || m.IsActive))
.OrderBy(m => m.Ordering)
.Include(m => m.Season.Currency)
.ToListAsync());
ControlUtils.RenewItemsSource(WineOriginInput, (await ctx.WineOrigins.ToListAsync()).OrderByDescending(o => o.SortKey).ThenBy(o => o.HkId));
var kgList = (await ctx.Katastralgemeinden
.Where(k => k.WbKg != null)
.Include(k => k.WbKg)
.Include(k => k.Gem.WbGem)
.OrderBy(k => k.Name)
.AsSplitQuery()
.ToListAsync()).Cast<object>().ToList();
kgList.Insert(0, new NullItem());
ControlUtils.RenewItemsSource(WineKgInput, kgList);
UpdateRdInput();
if (IsCreating) await UpdateLsNr();
await RefreshDeliveryParts();
RefreshInputs();
}
@@ -575,28 +576,36 @@ namespace Elwig.Windows {
}
private async Task RefreshDeliveryParts() {
using var ctx = new AppDbContext();
if (DeliveryList.SelectedItem is Delivery d) {
ControlUtils.RenewItemsSource(ModifiersInput, Modifiers.GetValueOrDefault(d.Year, []).Where(m => m.IsActive || !IsCreating).ToList());
ControlUtils.RenewItemsSource(DeliveryPartList, d.Parts, DeliveryPartList_SelectionChanged, ControlUtils.RenewSourceDefault.First);
ControlUtils.RenewItemsSource(ModifiersInput, await ctx.Modifiers
.Where(m => m.Year == d.Year && (!IsCreating || m.IsActive))
.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 {
ControlUtils.RenewItemsSource(ModifiersInput, Modifiers.GetValueOrDefault(ViewModel.FilterSeason ?? 0, []).Where(m => m.IsActive || !IsCreating).ToList());
ControlUtils.RenewItemsSource(ModifiersInput, await ctx.Modifiers
.Where(m => m.Year == ViewModel.FilterSeason && (!IsCreating || m.IsActive))
.OrderBy(m => m.Ordering)
.Include(m => m.Season.Currency)
.ToListAsync());
DeliveryPartList.ItemsSource = null;
}
}
private void RefreshInputs(bool validate = false) {
ClearInputStates();
if (DeliveryList.SelectedItem is Delivery d) {
if (DeliveryPartList.SelectedItem is DeliveryPart p) {
FillInputs(p);
} else if (DeliveryList.SelectedItem is Delivery d) {
FillInputs(d);
if (DeliveryPartList.SelectedItem is DeliveryPart p) {
FillInputs(p);
}
} else {
ClearOriginalValues();
ClearDefaultValues();
ClearInputs(validate);
ClearInputStates();
}
}
GC.Collect();
}
@@ -608,6 +617,7 @@ namespace Elwig.Windows {
}
private void FillInputs(DeliveryPart p) {
FillInputs(p.Delivery);
ClearOriginalValues();
ClearDefaultValues();
ViewModel.FillInputs(p);
@@ -634,10 +644,11 @@ namespace Elwig.Windows {
try {
var res = await s.Weigh();
OnWeighingResult(s, res);
} catch (Exception exc) {
ViewModel.LastScaleError = exc.Message.Split(": ")[^1];
} catch (Exception ex) {
ViewModel.LastScaleError = ex.Message.Split(": ")[^1];
OnWeighingResult(s, new());
InteractionService.ShowException("Waagenfehler", "Beim Wiegen ist ein Fehler aufgetreten", exc);
MessageBox.Show($"Beim Wiegen ist ein Fehler aufgetreten:\n\n{ex.Message}", "Waagenfehler",
MessageBoxButton.OK, MessageBoxImage.Error);
}
ViewModel.ManualWeighingReason = null;
ManualWeighingInput.IsChecked = false;
@@ -670,19 +681,17 @@ namespace Elwig.Windows {
}
private async void SearchInput_TextChanged(object sender, RoutedEventArgs evt) {
if (!HasContextLoaded) return;
await RefreshList(true);
}
private async void SeasonInput_TextChanged(object sender, TextChangedEventArgs evt) {
if (!HasContextLoaded || ViewModel.FilterSeason == null || TodayOnlyInput == null || AllSeasonsInput == null) return;
if (ViewModel.FilterSeason == null || TodayOnlyInput == null || AllSeasonsInput == null) return;
TodayOnlyInput.IsChecked = false;
AllSeasonsInput.IsChecked = false;
await RefreshList();
}
private async void TodayOnlyInput_Changed(object sender, RoutedEventArgs evt) {
if (!HasContextLoaded) return;
if (TodayOnlyInput.IsChecked == true && AllSeasonsInput.IsChecked == false) {
ViewModel.FilterSeason = Utils.Today.Year;
ViewModel.FilterTodayOnly = true;
@@ -691,7 +700,6 @@ namespace Elwig.Windows {
}
private async void AllSeasonsInput_Changed(object sender, RoutedEventArgs evt) {
if (!HasContextLoaded) return;
if (AllSeasonsInput.IsChecked == true) {
SeasonInput.IsEnabled = false;
ViewModel.FilterSeason = null;
@@ -711,7 +719,7 @@ namespace Elwig.Windows {
Menu_DeliveryNote_Show.IsEnabled = !IsEditing && !IsCreating;
Menu_DeliveryNote_SavePdf.IsEnabled = !IsEditing && !IsCreating;
Menu_DeliveryNote_Print.IsEnabled = !IsEditing && !IsCreating;
Menu_DeliveryNote_Email.IsEnabled = !IsEditing && !IsCreating && App.Config.Smtp != null && ViewModel.Member?.EmailAddresses.Count > 0;
Menu_DeliveryNote_Email.IsEnabled = !IsEditing && !IsCreating && App.Config.Smtp != null && d.Member.EmailAddresses.Count > 0;
Menu_Export_ExportSelected.IsEnabled = !IsEditing && !IsCreating;
Menu_Export_UploadSelected.IsEnabled = !IsEditing && !IsCreating && App.Config.SyncUrl != null;
} else {
@@ -793,7 +801,9 @@ namespace Elwig.Windows {
);
App.HintContextChange();
} catch (Exception exc) {
InteractionService.ShowDbException("Lieferung aktualisieren", exc);
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Lieferung aktualisieren", MessageBoxButton.OK, MessageBoxImage.Error);
FinishButton.IsEnabled = true;
SaveButton.IsEnabled = true;
Mouse.OverrideCursor = null;
@@ -802,12 +812,11 @@ namespace Elwig.Windows {
}
EmptyScale();
await EnsureContextRenewed();
Mouse.OverrideCursor = null;
ControlUtils.SelectItemWithPk(DeliveryList, p?.Year, p?.DId);
ControlUtils.SelectItem(DeliveryList, p?.Delivery);
DeliveryPartList.SelectedItem = null;
DeliveryPartList.ScrollIntoView(DeliveryPartList.ItemsSource.Cast<object>().LastOrDefault());
DeliveryPartList.ScrollIntoView(DeliveryPartList.ItemsSource.Cast<object>().Last());
InitialInputs();
}
@@ -829,7 +838,9 @@ namespace Elwig.Windows {
);
App.HintContextChange();
} catch (Exception exc) {
InteractionService.ShowDbException("Lieferung aktualisieren", exc);
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Lieferung aktualisieren", MessageBoxButton.OK, MessageBoxImage.Error);
FinishButton.IsEnabled = true;
SaveButton.IsEnabled = true;
Mouse.OverrideCursor = null;
@@ -838,36 +849,46 @@ namespace Elwig.Windows {
}
EmptyScale();
Utils.RunBackground("Lieferschein drucken", async () => {
using var doc = await DeliveryNote.Initialize(p.Year, p.DId);
using (var ctx = new AppDbContext()) {
await doc.Generate(ctx);
}
if (App.Config.Debug) {
doc.Show();
} else {
await doc.Print(2);
}
});
await EnsureContextRenewed();
if (p?.Delivery != null) {
try {
using var ctx = new AppDbContext();
using var doc = new DeliveryNote((await ctx.Deliveries.FindAsync(p.Year, p.DId))!, ctx);
await doc.Generate();
if (App.Config.Debug) {
doc.Show();
} else {
await doc.Print(2);
}
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
Mouse.OverrideCursor = null;
DeliveryList.SelectedItem = null;
await EnsureContextRenewed();
InitInputs();
}
private async void CancelCreatingButton_Click(object sender, RoutedEventArgs evt) {
if (IsCreating && HasChanged) {
if (!InteractionService.AskConfirmation("Abbrechen bestätigen", "Soll der Vorgang wirklich abgebrochen werden?"))
return;
var r = MessageBox.Show("Soll der Vorgang wirklich abgebrochen werden?", "Abbrechen bestätigen",
MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No);
if (r != MessageBoxResult.Yes) return;
}
using var ctx = new AppDbContext();
var attrList = await ctx.FetchWineAttributes().Cast<object>().ToListAsync();
var attrList = await ctx.WineAttributes.OrderBy(a => a.Name).Cast<object>().ToListAsync();
attrList.Insert(0, new NullItem(""));
ControlUtils.RenewItemsSource(AttributeInput, attrList, null, ControlUtils.RenewSourceDefault.First);
ControlUtils.RenewItemsSource(MemberInput, await ctx.FetchMembers(includeNotActive: !ViewModel.IsReceipt, includeContactInfo: true).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());
if (DeliveryList.SelectedItem is not Delivery d) {
// switch away from creating mode
IsCreating = false;
@@ -899,11 +920,21 @@ namespace Elwig.Windows {
ViewModel.FilterTodayOnly = true;
ViewModel.SearchQuery = "";
using var ctx = new AppDbContext();
var attrList = await ctx.FetchWineAttributes(false).Cast<object>().ToListAsync();
var attrList = await ctx.WineAttributes.Where(a => a.IsActive).OrderBy(a => a.Name).Cast<object>().ToListAsync();
attrList.Insert(0, new NullItem(""));
ControlUtils.RenewItemsSource(AttributeInput, attrList, null, ControlUtils.RenewSourceDefault.First);
ControlUtils.RenewItemsSource(ModifiersInput, Modifiers.GetValueOrDefault(ViewModel.FilterSeason ?? 0, []).Where(m => m.IsActive).ToList());
ControlUtils.RenewItemsSource(MemberInput, await ctx.FetchMembers(includeNotActive: !ViewModel.IsReceipt, includeContactInfo: true).ToListAsync());
ControlUtils.RenewItemsSource(ModifiersInput, await ctx.Modifiers
.Where(m => m.Year == ViewModel.FilterSeason && m.IsActive)
.OrderBy(m => m.Ordering)
.Include(m => m.Season.Currency)
.ToListAsync());
ControlUtils.RenewItemsSource(MemberInput, await ctx.Members
.Where(m => m.IsActive || !ViewModel.IsReceipt)
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.DefaultWbKg!.AtKg)
.OrderBy(m => m.Name)
.ThenBy(m => m.GivenName)
.ToListAsync());
IsCreating = true;
DeliveryList.IsEnabled = false;
DeliveryPartList.IsEnabled = false;
@@ -941,7 +972,9 @@ namespace Elwig.Windows {
}
App.HintContextChange();
} catch (Exception exc) {
InteractionService.ShowDbException("Lieferung aktualisieren", exc);
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Lieferung aktualisieren", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = null;
}
@@ -988,13 +1021,18 @@ namespace Elwig.Windows {
if (DeliveryList.SelectedItem is not Delivery d)
return;
if (InteractionService.AskContinue("Lieferung löschen", $"Soll die Lieferung {d.LsNr} ({d.Member.AdministrativeName}, MgNr. {d.Member.MgNr}) wirklich unwiderruflich gelöscht werden?")) {
var r = MessageBox.Show(
$"Soll die Lieferung {d.LsNr} ({d.Member.AdministrativeName}, MgNr. {d.Member.MgNr}) wirklich unwiderruflich gelöscht werden?",
"Lieferung löschen", MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
if (r == MessageBoxResult.OK) {
Mouse.OverrideCursor = Cursors.Wait;
try {
await DeliveryService.DeleteDelivery(d.LsNr);
App.HintContextChange();
} catch (Exception exc) {
InteractionService.ShowDbException("Lieferung löschen", exc);
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Lieferung löschen", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = null;
}
@@ -1022,7 +1060,9 @@ namespace Elwig.Windows {
);
App.HintContextChange();
} catch (Exception exc) {
InteractionService.ShowDbException("Lieferung aktualisieren", exc);
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Lieferung aktualisieren", MessageBoxButton.OK, MessageBoxImage.Error);
SaveButton.IsEnabled = true;
Mouse.OverrideCursor = null;
return;
@@ -1259,7 +1299,8 @@ namespace Elwig.Windows {
UpdateWineQualityLevels();
if (!ViewModel.WineVar?.IsQuw ?? false) {
App.MainDispatcher.BeginInvoke(() => {
InteractionService.ShowWarning("Kein Qualitätswein", "Die eingegebene Sorte darf nicht als Qualitätswein\nübernommen werden!");
MessageBox.Show("Die eingegebene Sorte darf nicht als Qualitätswein\nübernommen werden!", "Kein Qualitätswein",
MessageBoxButton.OK, MessageBoxImage.Warning);
});
}
}
+2 -1
View File
@@ -8,7 +8,8 @@
xmlns:local="clr-namespace:Elwig.Windows"
xmlns:vm="clr-namespace:Elwig.ViewModels"
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>
<vm:DeliveryAncmtAdminViewModel/>
</Window.DataContext>
+72 -48
View File
@@ -36,7 +36,11 @@ namespace Elwig.Windows {
ControlUtils.InitializeDelayTimer(SearchInput, SearchInput_TextChanged);
SearchInput.TextChanged -= SearchInput_TextChanged;
ViewModel.FilterSeason = Utils.CurrentLastSeason;
}
private void Window_Loaded(object sender, RoutedEventArgs evt) {
ViewModel.FilterOnlyUpcoming = true;
LockInputs();
}
private void Input_KeyUp(object sender, KeyEventArgs evt) {
@@ -81,6 +85,7 @@ namespace Elwig.Windows {
using var ctx = new AppDbContext();
var list = await ctx.DeliverySchedules
.Where(s => s.Year == ViewModel.FilterSeason)
.Include(s => s.Branch)
.OrderBy(s => s.DateString)
.ThenBy(s => s.Branch.Name)
.ThenBy(s => s.Description)
@@ -98,41 +103,36 @@ namespace Elwig.Windows {
}
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();
var (_, deliveryAncmtQuery, filter) = await vm.GetFilters(ctx);
var deliveryAncmts = await deliveryAncmtQuery.ToListAsync();
using var ctx = new AppDbContext();
var (_, deliveryAncmtQuery, filter) = await ViewModel.GetFilters(ctx);
var deliveryAncmts = await deliveryAncmtQuery
.Include(a => a.Member.BillingAddress)
.Include(a => a.Schedule)
.Include(a => a.Variety)
.AsSplitQuery()
.ToListAsync();
if (filter.Count > 0 && deliveryAncmts.Count > 0) {
var dict = deliveryAncmts.AsParallel()
.ToDictionary(a => a, a => a.SearchScore(filter))
.OrderByDescending(a => a.Value)
.ThenBy(a => a.Key.Schedule.DateString)
.ThenBy(a => a.Key.Member.Name)
.ThenBy(a => a.Key.Member.GivenName)
.ThenBy(a => a.Key.Member.MgNr);
var threshold = dict.Max(a => a.Value) * 3 / 4;
deliveryAncmts = [.. dict
.Where(a => a.Value > threshold)
.Select(a => a.Key)];
} else {
deliveryAncmts = [.. deliveryAncmts
.OrderBy(a => a.Schedule.DateString)
.ThenBy(a => a.Member.Name)
.ThenBy(a => a.Member.GivenName)
.ThenBy(a => a.Member.MgNr)];
}
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;
if (filter.Count > 0 && deliveryAncmts.Count > 0) {
var dict = deliveryAncmts.AsParallel()
.ToDictionary(a => a, a => a.SearchScore(filter))
.OrderByDescending(a => a.Value)
.ThenBy(a => a.Key.Schedule.DateString)
.ThenBy(a => a.Key.Member.Name)
.ThenBy(a => a.Key.Member.GivenName)
.ThenBy(a => a.Key.Member.MgNr);
var threshold = dict.Select(a => a.Value).Max() * 3 / 4;
deliveryAncmts = dict
.Where(a => a.Value > threshold)
.Select(a => a.Key)
.ToList();
} else {
deliveryAncmts = deliveryAncmts
.OrderBy(a => a.Schedule.DateString)
.ThenBy(a => a.Member.Name)
.ThenBy(a => a.Member.GivenName)
.ThenBy(a => a.Member.MgNr)
.ToList();
}
ControlUtils.RenewItemsSource(DeliveryAncmtList, deliveryAncmts,
DeliveryAncmtList_SelectionChanged, ViewModel.TextFilter.Count > 0 ? ControlUtils.RenewSourceDefault.IfOnly : ControlUtils.RenewSourceDefault.None, !updateSort);
@@ -141,9 +141,9 @@ namespace Elwig.Windows {
ViewModel.StatusAncmts = $"{deliveryAncmts.Count:N0}";
if (filter.Count == 0) {
var (text, data) = stat;
var (text, grid) = await DeliveryAncmtService.GenerateToolTip(deliveryAncmtQuery);
ViewModel.StatusWeight = text;
ViewModel.StatusWeightToolTip = DeliveryAncmtService.GenerateToolTip(data);
ViewModel.StatusWeightToolTip = grid;
} else {
ViewModel.StatusWeight = $"{deliveryAncmts.Sum(a => a.Weight):N0} kg";
ViewModel.StatusWeightToolTip = null;
@@ -177,8 +177,15 @@ namespace Elwig.Windows {
protected override async Task OnRenewContext(AppDbContext ctx) {
await base.OnRenewContext(ctx);
ControlUtils.RenewItemsSource(MemberInput, await ctx.FetchMembers(includeNotActive: !IsCreating).ToListAsync());
ControlUtils.RenewItemsSource(WineVarietyInput, await ctx.FetchWineVarieties().ToListAsync());
ControlUtils.RenewItemsSource(MemberInput, await ctx.Members
.Where(m => m.IsActive || !IsCreating)
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.DefaultWbKg!.AtKg)
.OrderBy(m => m.Name)
.ThenBy(m => m.GivenName)
.ThenBy(m => m.MgNr)
.ToListAsync());
ControlUtils.RenewItemsSource(WineVarietyInput, await ctx.WineVarieties.OrderBy(v => v.Name).ToListAsync());
await RefreshDeliveryScheduleList();
await RefreshList();
@@ -189,7 +196,6 @@ namespace Elwig.Windows {
}
private async void DeliveryScheduleList_SelectionChanged(object sender, RoutedEventArgs evt) {
if (!HasContextLoaded) return;
await RefreshList();
if (DeliveryScheduleList.SelectedItem is DeliverySchedule s) {
Menu_DeliveryAncmtList_SaveSelected.IsEnabled = !IsEditing && !IsCreating;
@@ -211,13 +217,11 @@ namespace Elwig.Windows {
}
private async void OnlyUpcomingInput_Changed(object sender, RoutedEventArgs evt) {
if (!HasContextLoaded) return;
await RefreshDeliveryScheduleList();
await RefreshList(true);
}
private async void FromAllSchedulesInput_Changed(object sender, RoutedEventArgs evt) {
if (!HasContextLoaded) return;
if (ViewModel.FilterFromAllSchedules) {
DeliveryScheduleList.SelectedItem = null;
} else if (DeliveryScheduleList.SelectedItem == null) {
@@ -227,12 +231,11 @@ namespace Elwig.Windows {
}
private async void SearchInput_TextChanged(object sender, TextChangedEventArgs evt) {
if (!HasContextLoaded) return;
await RefreshList(true);
}
private async void SeasonInput_TextChanged(object sender, TextChangedEventArgs evt) {
if (!HasContextLoaded || ViewModel.FilterSeason == null) return;
if (ViewModel.FilterSeason == null) return;
ViewModel.FilterOnlyUpcoming = false;
await RefreshDeliveryScheduleList();
await RefreshList();
@@ -271,7 +274,14 @@ namespace Elwig.Windows {
ViewModel.SelectedDeliveryAncmt = null;
using var ctx = new AppDbContext();
ControlUtils.RenewItemsSource(MemberInput, await ctx.FetchMembers(includeNotActive: !IsCreating).ToListAsync());
ControlUtils.RenewItemsSource(MemberInput, await ctx.Members
.Where(m => m.IsActive || !IsCreating)
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.DefaultWbKg!.AtKg)
.OrderBy(m => m.Name)
.ThenBy(m => m.GivenName)
.ThenBy(m => m.MgNr)
.ToListAsync());
HideNewEditDeleteButtons();
ShowSaveResetCancelButtons();
@@ -309,7 +319,10 @@ namespace Elwig.Windows {
private async void DeleteDeliveryAncmtButton_Click(object? sender, RoutedEventArgs? evt) {
if (ViewModel.SelectedDeliveryAncmt is not DeliveryAncmt a)
return;
if (InteractionService.AskContinue("Anmeldung löschen", "Soll die Anmeldung wirklich unwiderruflich gelöscht werden?")) {
var r = MessageBox.Show(
$"Soll die Anmeldung wirklich unwiderruflich gelöscht werden?",
"Anmeldung löschen", MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
if (r == MessageBoxResult.OK) {
Mouse.OverrideCursor = Cursors.Wait;
try {
await Task.Run(async () => {
@@ -319,7 +332,9 @@ namespace Elwig.Windows {
});
App.HintContextChange();
} catch (Exception exc) {
InteractionService.ShowDbException("Anmeldung löschen", exc);
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Anmeldung löschen", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = null;
}
@@ -342,7 +357,9 @@ namespace Elwig.Windows {
(year, dsnr, mgnr, sortid) = await ViewModel.UpdateDeliveryAncmt(s?.Year, s?.DsNr, s?.MgNr, s?.SortId, s?.Type);
App.HintContextChange();
} catch (Exception exc) {
InteractionService.ShowDbException("Anmeldung aktualisieren", exc);
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Anmeldung aktualisieren", MessageBoxButton.OK, MessageBoxImage.Error);
SaveButton.IsEnabled = true;
return;
} finally {
@@ -386,7 +403,14 @@ namespace Elwig.Windows {
DeliveryAncmtList.IsEnabled = true;
using var ctx = new AppDbContext();
ControlUtils.RenewItemsSource(MemberInput, await ctx.FetchMembers(includeNotActive: !IsCreating).ToListAsync());
ControlUtils.RenewItemsSource(MemberInput, await ctx.Members
.Where(m => m.IsActive || !IsCreating)
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.DefaultWbKg!.AtKg)
.OrderBy(m => m.Name)
.ThenBy(m => m.GivenName)
.ThenBy(m => m.MgNr)
.ToListAsync());
HideSaveResetCancelButtons();
ShowNewEditDeleteButtons();
@@ -7,7 +7,8 @@
xmlns:local="clr-namespace:Elwig.Windows"
xmlns:vm="clr-namespace:Elwig.ViewModels"
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>
<vm:DeliveryScheduleAdminViewModel/>
</Window.DataContext>
@@ -30,43 +30,41 @@ namespace Elwig.Windows {
ControlUtils.InitializeDelayTimer(SearchInput, SearchInput_TextChanged);
SearchInput.TextChanged -= SearchInput_TextChanged;
ViewModel.FilterSeason = Utils.CurrentLastSeason;
}
private void Window_Loaded(object sender, RoutedEventArgs evt) {
ViewModel.FilterOnlyUpcoming = true;
LockInputs();
}
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();
var (_, deliveryScheduleQuery, filter) = await vm.GetFilters(ctx);
var deliverySchedules = await deliveryScheduleQuery
.Include(s => s.Varieties)
.ToListAsync();
using var ctx = new AppDbContext();
var (_, deliveryScheduleQuery, filter) = await ViewModel.GetFilters(ctx);
var deliverySchedules = await deliveryScheduleQuery
.Include(s => s.Varieties)
.Include(s => s.Branch)
.AsSplitQuery()
.ToListAsync();
if (filter.Count > 0 && deliverySchedules.Count > 0) {
var dict = deliverySchedules.AsParallel()
.ToDictionary(s => s, s => s.SearchScore(filter))
.OrderByDescending(a => a.Value)
.ThenBy(a => a.Key.DateString)
.ThenBy(a => a.Key.Branch.Name)
.ThenBy(a => a.Key.Description);
var threshold = dict.Max(a => a.Value) * 3 / 4;
deliverySchedules = [.. dict
.Where(a => a.Value > threshold)
.Select(a => a.Key)];
} else {
deliverySchedules = [.. deliverySchedules
.OrderBy(s => s.DateString)
.ThenBy(s => s.Branch.Name)
.ThenBy(s => s.Description)];
}
return deliverySchedules;
});
if (!cursor) Mouse.OverrideCursor = null;
if (query != ((ViewModel.SearchQuery, ViewModel.FilterSeason, ViewModel.FilterOnlyUpcoming))) return;
if (filter.Count > 0 && deliverySchedules.Count > 0) {
var dict = deliverySchedules.AsParallel()
.ToDictionary(s => s, s => s.SearchScore(filter))
.OrderByDescending(a => a.Value)
.ThenBy(a => a.Key.DateString)
.ThenBy(a => a.Key.Branch.Name)
.ThenBy(a => a.Key.Description);
var threshold = dict.Select(a => a.Value).Max() * 3 / 4;
deliverySchedules = dict
.Where(a => a.Value > threshold)
.Select(a => a.Key)
.ToList();
} else {
deliverySchedules = deliverySchedules
.OrderBy(s => s.DateString)
.ThenBy(s => s.Branch.Name)
.ThenBy(s => s.Description)
.ToList();
}
ControlUtils.RenewItemsSource(DeliveryScheduleList, deliverySchedules,
DeliveryScheduleList_SelectionChanged, ViewModel.TextFilter.Count > 0 ? ControlUtils.RenewSourceDefault.IfOnly : ControlUtils.RenewSourceDefault.None, !updateSort);
@@ -101,14 +99,14 @@ namespace Elwig.Windows {
protected override async Task OnRenewContext(AppDbContext ctx) {
await base.OnRenewContext(ctx);
ControlUtils.RenewItemsSource(BranchInput, await ctx.FetchBranches().ToListAsync());
var varieties = await ctx.FetchWineVarieties().ToListAsync();
ControlUtils.RenewItemsSource(BranchInput, await ctx.Branches.OrderBy(b => b.Name).ToListAsync());
var varieties = await ctx.WineVarieties.OrderBy(v => v.Name).ToListAsync();
ControlUtils.RenewItemsSource(MainWineVarietiesInput, varieties);
ControlUtils.RenewItemsSource(OtherWineVarietiesInput, varieties);
var attrList = await ctx.FetchWineAttributes().Cast<object>().ToListAsync();
var attrList = await ctx.WineAttributes.OrderBy(a => a.Name).Cast<object>().ToListAsync();
attrList.Insert(0, new NullItem("- Keine Angabe -"));
ControlUtils.RenewItemsSource(AttributeInput, attrList, null, ControlUtils.RenewSourceDefault.First);
var cultList = await ctx.FetchWineCultivations().Cast<object>().ToListAsync();
var cultList = await ctx.WineCultivations.OrderBy(a => a.Name).Cast<object>().ToListAsync();
cultList.Insert(0, new NullItem("- Kein Angabe -"));
ControlUtils.RenewItemsSource(CultivationInput, cultList, null, ControlUtils.RenewSourceDefault.First);
@@ -120,17 +118,15 @@ namespace Elwig.Windows {
}
private async void OnlyUpcomingInput_Changed(object sender, RoutedEventArgs evt) {
if (!HasContextLoaded) return;
await RefreshList();
}
private async void SearchInput_TextChanged(object sender, TextChangedEventArgs evt) {
if (!HasContextLoaded) return;
await RefreshList(true);
}
private async void SeasonInput_TextChanged(object sender, TextChangedEventArgs evt) {
if (!HasContextLoaded || ViewModel.FilterSeason == null) return;
if (ViewModel.FilterSeason == null) return;
ViewModel.FilterOnlyUpcoming = false;
await RefreshList();
}
@@ -177,7 +173,10 @@ namespace Elwig.Windows {
private async void DeleteDeliveryScheduleButton_Click(object? sender, RoutedEventArgs? evt) {
if (ViewModel.SelectedDeliverySchedule is not DeliverySchedule s)
return;
if (InteractionService.AskContinue("Leseplan löschen", $"Soll der Leseplan \"{s.Description}\" vom {s.Date:dd.MM.yyyy} wirklich unwiderruflich gelöscht werden?")) {
var r = MessageBox.Show(
$"Soll der Leseplan \"{s.Description}\" vom {s.Date:dd.MM.yyyy} wirklich unwiderruflich gelöscht werden?",
"Leseplan löschen", MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
if (r == MessageBoxResult.OK) {
Mouse.OverrideCursor = Cursors.Wait;
try {
await Task.Run(async () => {
@@ -187,7 +186,9 @@ namespace Elwig.Windows {
});
App.HintContextChange();
} catch (Exception exc) {
InteractionService.ShowDbException("Leseplan löschen", exc);
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Leseplan löschen", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = null;
}
@@ -207,7 +208,9 @@ namespace Elwig.Windows {
await ViewModel.UpdateDeliverySchedule(ViewModel.SelectedDeliverySchedule?.Year, ViewModel.SelectedDeliverySchedule?.DsNr);
App.HintContextChange();
} catch (Exception exc) {
InteractionService.ShowDbException("Leseplan aktualisieren", exc);
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Leseplan aktualisieren", MessageBoxButton.OK, MessageBoxImage.Error);
SaveButton.IsEnabled = true;
return;
} finally {
+46 -24
View File
@@ -3,7 +3,6 @@ using Elwig.Helpers;
using Elwig.Helpers.Billing;
using Elwig.Models.Dtos;
using Elwig.Models.Entities;
using Elwig.Services;
using MailKit.Net.Smtp;
using Microsoft.EntityFrameworkCore;
using Microsoft.Win32;
@@ -108,7 +107,7 @@ namespace Elwig.Windows {
public MailWindow(int? year = null) {
InitializeComponent();
using (var ctx = new AppDbContext()) {
Year = year ?? ctx.Seasons.OrderByDescending(s => s.Year).FirstOrDefault()?.Year ?? Utils.Today.Year;
Year = year ?? ctx.Seasons.OrderBy(s => s.Year).LastOrDefault()?.Year ?? Utils.Today.Year;
Title = $"Rundschreiben - Lese {Year} - Elwig";
}
@@ -156,7 +155,7 @@ namespace Elwig.Windows {
}
protected override async Task OnRenewContext(AppDbContext ctx) {
var season = await ctx.Seasons.Include(s => s.PaymentVariants).Where(s => s.Year == Year).SingleOrDefaultAsync();
var season = await ctx.Seasons.FindAsync(Year);
var l = new List<string> {
MemberDataSheet.Name
};
@@ -166,7 +165,10 @@ namespace Elwig.Windows {
}
AvaiableDocumentsList.ItemsSource = l;
ControlUtils.RenewItemsSource(MemberBranchInput, await ctx.FetchBranches(includeWithoutMembers: false).ToListAsync(), MemberInput_SelectionChanged);
ControlUtils.RenewItemsSource(MemberBranchInput, await ctx.Branches
.Where(b => b.Members.Count != 0)
.OrderBy(b => b.Name)
.ToListAsync(), MemberInput_SelectionChanged);
if (MemberBranchInput.SelectedItems.Count == 0) {
MemberBranchInput.SelectionChanged -= MemberInput_SelectionChanged;
MemberBranchInput.SelectAll();
@@ -205,8 +207,13 @@ namespace Elwig.Windows {
.OrderBy(m => m.Name)
.ThenBy(m => m.GivenName)
.Include(m => m.Branch)
.Include(m => m.DefaultWbKg!.AtKg)
.Include(m => m.EmailAddresses)
.Include(m => m.TelephoneNumbers)
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.PostalDest.AtPlz!.Country)
.Include(m => m.BillingAddress!.PostalDest.AtPlz!.Ort)
.Include(m => m.BillingAddress!.PostalDest.AtPlz!.Country)
.ToListAsync(), MemberInput_SelectionChanged);
if (MemberCustomInput.SelectedItems.Count == 0) {
MemberCustomInput.SelectionChanged -= MemberInput_SelectionChanged;
@@ -366,7 +373,7 @@ namespace Elwig.Windows {
RecipientsDeliveryMembersInput.IsChecked = true;
} else if (idx >= 2) {
var name = s.Split(" ")[^1];
var pv = await ctx.PaymentVariants.Where(v => v.Year == Year && v.Name == name).SingleAsync();
var pv = await ctx.PaymentVariants.SingleAsync(v => v.Year == Year && v.Name == name)!;
SelectedDocs.Add(new(DocType.CreditNote, s, (pv.Year, pv.AvNr)));
RecipientsCreditMembersInput.IsChecked = true;
}
@@ -485,8 +492,13 @@ namespace Elwig.Windows {
}
Recipients = await query
.Include(m => m.Branch)
.Include(m => m.DefaultWbKg!.AtKg)
.Include(m => m.EmailAddresses)
.Include(m => m.TelephoneNumbers)
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.PostalDest.AtPlz!.Country)
.Include(m => m.BillingAddress!.PostalDest.AtPlz!.Ort)
.Include(m => m.BillingAddress!.PostalDest.AtPlz!.Country)
.ToListAsync();
}
UpdatePostalEmailRecipients();
@@ -691,7 +703,7 @@ namespace Elwig.Windows {
PrintButton.IsEnabled = PrintDocument != null && !hasPreviewDocs;
EmailButton.IsEnabled = EmailDocuments != null && !hasPreviewDocs && App.Config.Smtp != null;
} catch (Exception exc) {
InteractionService.ShowException(exc);
MessageBox.Show(exc.ToString(), "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
} finally {
UnlockInputs();
GenerateButton.IsEnabled = true;
@@ -713,7 +725,7 @@ namespace Elwig.Windows {
foreach (var doc in docs) {
if (doc.Type == DocType.DeliveryConfirmation) {
var year = (int)doc.Details!;
var b = await Billing.Create(year);
var b = new Billing(year);
await b.FinishSeason();
await b.CalculateBuckets();
App.HintContextChange();
@@ -743,13 +755,10 @@ namespace Elwig.Windows {
Member = m,
Docs = docs.SelectMany<SelectedDoc, GeneratedDoc>(doc => {
try {
App.MainDispatcher.Invoke(() => {
ProgressBar.Value = offset + 100.0 * i / 2 / totalNum;
});
if (doc.Type == DocType.Custom) {
return [new GeneratedDoc((string)doc.Details!)];
} else if (doc.Type == DocType.MemberDataSheet) {
return [new GeneratedDoc(new MemberDataSheet(m) { Date = postalDate })];
return [new GeneratedDoc(new MemberDataSheet(m, ctx) { Date = postalDate })];
} else if (doc.Type == DocType.DeliveryConfirmation) {
var year = (int)doc.Details!;
DeliveryConfirmationDeliveryData data;
@@ -760,14 +769,21 @@ namespace Elwig.Windows {
} else {
return [];
}
return [new GeneratedDoc(new DeliveryConfirmation(year, m, postalDate, data) { Date = postalDate })];
return [new GeneratedDoc(new DeliveryConfirmation(ctx, year, m, data) { Date = postalDate })];
} else if (doc.Type == DocType.CreditNote) {
var details = ((int, int))doc.Details!;
var year = details.Item1;
var avnr = details.Item2;
var data = cnData[(year, avnr)];
try {
return [new GeneratedDoc(new CreditNote(data.Item2[m.MgNr], postalDate, data.Item3, data.Item1[m.MgNr]) { Date = postalDate })];
return [new GeneratedDoc(new CreditNote(
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) {
return [];
}
@@ -775,7 +791,7 @@ namespace Elwig.Windows {
throw new NotImplementedException("Invalid DocType");
}
} catch (Exception exc) {
InteractionService.ShowException(exc);
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
return [];
} finally {
App.MainDispatcher.Invoke(() => {
@@ -788,9 +804,9 @@ namespace Elwig.Windows {
var hasPreviewDocs = memberDocs.Any(m => m.Docs.Any(d => d.Doc.IsPreview));
if (hasPreviewDocs) {
if (!InteractionService.AskContinue("Vorläufige Dokumente",
"Einige der ausgewählten Dokumente sind nur als vorläufig zu betrachten und können daher nicht verschickt/ausgedruckt werden!\n\n" +
"Dies könnte an einer noch nicht festgesetzen Auszahlungsvariante liegen oder daran, dass nicht alle Adressaten/Empfänger eine Traubengutschrift erhalten\n(\"Empfänger von Gutschriften\").\n\nSoll mit dem Generieren fortgefahren werden?")) {
var res = MessageBox.Show("Einige der ausgewählten Dokumente sind nur als vorläufig zu betrachten und können daher nicht verschickt/ausgedruckt werden!\n\nDies könnte an einer noch nicht festgesetzen Auszahlungsvariante liegen oder daran, dass nicht alle Adressaten/Empfänger eine Traubengutschrift erhalten\n(\"Empfänger von Gutschriften\").\n\nSoll mit dem Generieren fortgefahren werden?",
"Vorläufige Dokumente", MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
if (res != MessageBoxResult.OK) {
throw new OperationCanceledException("Dokumentenerzeugung abgebrochen!");
}
}
@@ -811,7 +827,7 @@ namespace Elwig.Windows {
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 item2 in item1.Value.Select((d, i) => new { Index = i, Doc = d })) {
await item2.Doc.Generate(ctx, CancelGeneration?.Token, new Progress<double>(v => App.MainDispatcher.Invoke(() => {
await item2.Doc.Generate(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;
})));
}
@@ -845,7 +861,7 @@ namespace Elwig.Windows {
if (printDocs.Count > 0) {
var print = Document.Merge(printDocs);
await print.Generate(ctx, CancelGeneration?.Token, new Progress<double>(v => App.MainDispatcher.Invoke(() => {
await print.Generate(CancelGeneration?.Token, new Progress<double>(v => App.MainDispatcher.Invoke(() => {
ProgressBar.Value = offset + v * printNum / totalNum;
})));
PrintDocument = print;
@@ -893,7 +909,9 @@ namespace Elwig.Windows {
GenerateButton.IsEnabled = false;
LockInputs();
if (InteractionService.AskQuestion("Rundschreiben drucken", $"Sollen {PrintDocument.Pages} Blätter ({PrintDocument.TotalPages} Seiten) gedruckt werden?", false)) {
var res = MessageBox.Show($"Sollen {PrintDocument.Pages} Blätter ({PrintDocument.TotalPages} Seiten) gedruckt werden?",
"Rundschreiben drucken", MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No);
if (res == MessageBoxResult.Yes) {
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
if (App.Config.Debug) {
@@ -931,8 +949,11 @@ namespace Elwig.Windows {
client = await Task.Run(Utils.GetSmtpClient);
Mouse.OverrideCursor = null;
if (!InteractionService.AskQuestion("Rundschreiben verschicken", $"Sollen {EmailDocuments.Count:N0} E-Mails verschickt werden?", false))
var res = MessageBox.Show($"Sollen {EmailDocuments.Count:N0} E-Mails verschickt werden?",
"Rundschreiben verschicken", MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No);
if (res != MessageBoxResult.Yes) {
return;
}
Mouse.OverrideCursor = Cursors.Wait;
var subject = EmailSubjectInput.Text;
@@ -961,9 +982,10 @@ namespace Elwig.Windows {
}
});
InteractionService.ShowInformation("Rundschreiben verschicken", "Erfolgreich alle E-Mails verschickt!\n\nEs kann einige Minuten dauern, bis die E-Mails in den Posteingängen der Empfänger aufscheinen.");
MessageBox.Show("Erfolgreich alle E-Mails verschickt!\n\nEs kann einige Minuten dauern, bis die E-Mails in den Posteingängen der Empfänger aufscheinen.", "Rundschreiben verschicken",
MessageBoxButton.OK, MessageBoxImage.Information);
} catch (Exception exc) {
InteractionService.ShowException(exc);
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
} finally {
if (client != null)
await client.DisconnectAsync(true);
@@ -992,7 +1014,7 @@ namespace Elwig.Windows {
return;
var name = s.Split(" ")[^1];
using var ctx = new AppDbContext();
var pv = ctx.PaymentVariants.Where(v => v.Year == Year && v.Name == name).Single();
var pv = ctx.PaymentVariants.Single(v => v.Year == Year && v.Name == name)!;
SelectedDocs.Add(new(DocType.CreditNote, s, (pv.Year, pv.AvNr)));
SelectedDocumentsList.SelectedIndex = SelectedDocs.Count - 1;
RecipientsCreditMembersInput.IsChecked = true;
+1 -1
View File
@@ -5,7 +5,7 @@
xmlns:local="clr-namespace:Elwig.Windows"
xmlns:ctrl="clr-namespace:Elwig.Controls"
Title="Elwig" Height="390" Width="520" ResizeMode="CanMinimize"
Closing="Window_Closing">
Loaded="Window_Loaded" Closing="Window_Closing">
<Window.Resources>
<Style TargetType="Button">
<Setter Property="VerticalAlignment" Value="Top"/>
+89 -56
View File
@@ -37,11 +37,11 @@ namespace Elwig.Windows {
SyncButton.Visibility = App.Config.SyncUrl != null ? Visibility.Visible : Visibility.Hidden;
Menu_Database_Upload.IsEnabled = App.Config.SyncUrl != null;
Menu_Database_Download.IsEnabled = App.Config.SyncUrl != null;
SeasonInput.Value = Utils.CurrentLastSeason;
}
protected override async Task OnInit(AppDbContext ctx) {
await base.OnInit(ctx);
private void Window_Loaded(object sender, RoutedEventArgs evt) {
SeasonInput.Value = Utils.CurrentLastSeason;
if (Utils.HasInternetConnectivity()) {
CheckSync(200);
}
@@ -59,7 +59,9 @@ namespace Elwig.Windows {
}
Thread.Sleep(100);
if (App.NumWindows > 1 && !App.Current.Windows.Cast<Window>().Any(w => ((w as AdministrationWindow)?.IsEditing ?? false) || ((w as AdministrationWindow)?.IsCreating ?? false))) {
if (!InteractionService.AskConfirmation("Elwig beenden", "Es sind noch weitere Fenster geöffnet.\nSollen alle Fenster geschlossen werden?")) {
var res = MessageBox.Show("Es sind noch weitere Fenster geöffnet.\nSollen alle Fenster geschlossen werden?",
"Elwig beenden", MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No);
if (res != MessageBoxResult.Yes) {
evt.Cancel = true;
} else {
Application.Current.Shutdown();
@@ -82,9 +84,9 @@ namespace Elwig.Windows {
try {
using var client = await Utils.GetSmtpClient();
await client!.DisconnectAsync(true);
InteractionService.ShowInformation("Erfolg", "E -Mail-Einstellungen erfolgreich überprüft!");
MessageBox.Show("E-Mail-Einstellungen erfolgreich überprüft!", "Erfolg", MessageBoxButton.OK, MessageBoxImage.Information);
} catch (Exception exc) {
InteractionService.ShowException(exc);
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = null;
}
@@ -113,17 +115,17 @@ namespace Elwig.Windows {
private async void Menu_Scale_SetDateTime_Click(object sender, RoutedEventArgs evt) {
if (App.CommandScales.Count == 0) {
InteractionService.ShowError("Datum und Uhrzeit setzen", "Es sind keine geeigneten Waagen verfügbar!");
MessageBox.Show("Es sind keine geeigneten Waagen verfügbar!", "Datum und Uhrzeit setzen", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
foreach (var s in App.CommandScales) {
try {
await s.SetDateAndTime(DateTime.Now);
} catch (Exception exc) {
InteractionService.ShowException(exc);
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
InteractionService.ShowInformation("Datum und Uhrzeit setzen", "Datum und Uhrzeit auf entsprechenden Waagen gesetzt!");
MessageBox.Show("Datum und Uhrzeit auf entsprechenden Waagen gesetzt!", "Datum und Uhrzeit setzen", MessageBoxButton.OK, MessageBoxImage.Information);
}
private void Menu_Database_Query_Click(object sender, RoutedEventArgs evt) {
@@ -155,23 +157,29 @@ namespace Elwig.Windows {
});
}
} catch (Exception exc) {
InteractionService.ShowException(exc);
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = null;
}
private async void Menu_Database_Backup_Click(object sender, RoutedEventArgs evt) {
try {
var filename = InteractionService.SaveFile("Datenbank-Sicherung", $"database_{Utils.Today:yyyy-MM-dd}", "sql.zip");
if (filename != null) {
if (!filename.EndsWith(".sql.zip")) filename += ".sql.zip";
var d = new SaveFileDialog() {
Title = "Datenbank sichern - Elwig",
FileName = $"database_{Utils.Today:yyyy-MM-dd}.sql.zip",
DefaultExt = "sql.zip",
Filter = "Komprimierte SQL-Datei (*.sql.zip)|*.sql.zip",
AddExtension = false,
};
if (d.ShowDialog() == true) {
if (!d.FileName.EndsWith(".sql.zip")) d.FileName += ".sql.zip";
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
await Database.ExportSql(filename, true);
await Database.ExportSql(d.FileName, true);
});
}
} catch (Exception exc) {
InteractionService.ShowException(exc);
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = null;
}
@@ -184,13 +192,16 @@ namespace Elwig.Windows {
Filter = "SQLite-Datenbank (*.sqlite3, *.sqlite3.zip, *.sql, *.sql.zip)|*.sqlite3;*.sqlite3.zip;*.sql;*.sql.zip",
};
if (d.ShowDialog() == true) {
if (!InteractionService.AskContinue("Datenbank wiederherstellen", "Soll die Datenbank wirklich unwiederruflich durch die wiederhergestellte Version ersetzt werden?"))
var res = MessageBox.Show("Soll die Datenbank wirklich unwiederruflich durch die wiederhergestellte Version ersetzt werden?", "Datenbank wiederherstellen",
MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
if (res != MessageBoxResult.OK)
return;
Mouse.OverrideCursor = Cursors.Wait;
await App.ReplaceDatabase(d.FileName);
}
} catch (Exception exc) {
InteractionService.ShowException(exc);
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = null;
}
@@ -255,15 +266,15 @@ namespace Elwig.Windows {
.ToList();
if (files.Count == 0) {
InteractionService.ShowError("Datenbank herunterladen", "Die Datenbank wurde noch nicht vom Hauptgerät hochgeladen!");
MessageBox.Show("Die Datenbank wurde noch nicht vom Hauptgerät hochgeladen!", "Datenbank herunterladen",
MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
var file = files[0];
if (!InteractionService.AskContinue("Datenbank herunterladen",
$"Es wurde eine komprimierte Datenbank (ca. {file.Size / 1024 / 1024} MB) vom {file.Timestamp:dd.MM.yyyy, HH:mm} gefunden.\n\n" +
$"Wollen Sie wirklich die aktuelle Datenbank unwiederruflich\nlöschen und durch die gefundene ersetzen?\n\n" +
$"Das kann zu Datenverlust führen!"))
var res = MessageBox.Show($"Es wurde eine komprimierte Datenbank (ca. {file.Size / 1024 / 1024} MB) vom {file.Timestamp:dd.MM.yyyy, HH:mm} gefunden.\n\nWollen Sie wirklich die aktuelle Datenbank unwiederruflich\nlöschen und durch die gefundene ersetzen?\n\nDas kann zu Datenverlust führen!", "Datenbank herunterladen",
MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
if (res != MessageBoxResult.OK)
return;
var filename = Path.Combine(App.TempPath, file.Name);
@@ -272,21 +283,20 @@ namespace Elwig.Windows {
await client.DownloadAsync(file.Url, stream);
}
if (!InteractionService.AskContinue("Datenbank herunterladen",
"Die Datenbank wurde erfolgreich heruntergeladen!\n\n" +
"Soll die Datenbank wirklich unwiederruflich ersetzt werden?\n\n" +
"Wenn Sie unsicher sind sprechen Sie sich mit dem Benutzer des Hauptgerätes ab!"))
res = MessageBox.Show("Die Datenbank wurde erfolgreich heruntergeladen!\n\nSoll die Datenbank wirklich unwiederruflich ersetzt werden?\n\nWenn Sie unsicher sind sprechen Sie sich mit dem Benutzer des Hauptgerätes ab!", "Datenbank herunterladen",
MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
if (res != MessageBoxResult.OK)
return;
await App.MainDispatcher.BeginInvoke(async () => {
await App.ReplaceDatabase(filename);
});
} catch (HttpRequestException exc) {
InteractionService.ShowException("Datenbank herunterladen", "Eventuell Internetverbindung prüfen!", exc);
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Datenbank herunterladen", MessageBoxButton.OK, MessageBoxImage.Error);
} catch (TaskCanceledException exc) {
InteractionService.ShowException("Datenbank herunterladen", "Eventuell Internetverbindung prüfen!", exc);
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Datenbank herunterladen", MessageBoxButton.OK, MessageBoxImage.Error);
} catch (Exception exc) {
InteractionService.ShowException("Datenbank herunterladen", exc);
MessageBox.Show(exc.Message, "Datenbank herunterladen", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
@@ -296,7 +306,9 @@ namespace Elwig.Windows {
if (App.Config.SyncUrl == null)
return;
if (!InteractionService.AskContinue("Datenbank hochladen", "Sind Sie wirklich sicher, dass Sie die Datenbank dieses\nGerätes hochladen möchten? Das sollte nur vom Hauptgerät aus passieren!"))
var res = MessageBox.Show("Sind Sie wirklich sicher, dass Sie die Datenbank dieses\nGerätes hochladen möchten? Das sollte nur vom Hauptgerät aus passieren!", "Datenbank hochladen",
MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
if (res != MessageBoxResult.OK)
return;
Mouse.OverrideCursor = Cursors.Wait;
@@ -305,13 +317,14 @@ namespace Elwig.Windows {
var path = Path.Combine(App.TempPath, "database.sql.zip");
await Database.ExportSql(path, true);
await Utils.UploadExportData(path, App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
InteractionService.ShowInformation("Datenbank hochladen", $"Hochladen der gesamten Datenbank erfolgreich!");
MessageBox.Show($"Hochladen der gesamten Datenbank erfolgreich!", "Datenbank hochladen",
MessageBoxButton.OK, MessageBoxImage.Information);
} catch (HttpRequestException exc) {
InteractionService.ShowException("Datenbank hochladen", "Eventuell Internetverbindung prüfen!", exc);
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Datenbank hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
} catch (TaskCanceledException exc) {
InteractionService.ShowException("Datenbank hochladen", "Eventuell Internetverbindung prüfen!", exc);
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Datenbank hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
} catch (Exception exc) {
InteractionService.ShowException("Datenbank hochladen", exc);
MessageBox.Show(exc.Message, "Datenbank hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
@@ -392,7 +405,7 @@ namespace Elwig.Windows {
private async void SeasonInput_TextChanged(object? sender, TextChangedEventArgs? evt) {
using var ctx = new AppDbContext();
var year = SeasonInput.Value;
var s0 = await ctx.FetchSeasons(year).SingleOrDefaultAsync();
var s0 = await ctx.Seasons.FindAsync(year);
var valid = (s0 != null);
DeliveryConfirmationButton.IsEnabled = valid;
PaymentButton.IsEnabled = valid;
@@ -444,14 +457,19 @@ namespace Elwig.Windows {
private async void OverUnderDeliveryButton_Click(object sender, RoutedEventArgs evt) {
if (SeasonInput.Value is not int year)
return;
var filename = InteractionService.SaveFile($"Über-/Unterlieferungen {year}", $"Über-Unterlieferungen-{year}", "ods");
if (filename == null)
var d = new SaveFileDialog() {
FileName = $"Über-Unterlieferungen-{year}.ods",
DefaultExt = "ods",
Filter = "OpenDocument Format Spreadsheet (*.ods)|*.ods",
Title = $"Über-/Unterlieferungen {year} speichern unter - Elwig"
};
if (d.ShowDialog() == false)
return;
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
var b = await Billing.Create(year);
var b = new Billing(year);
await b.FinishSeason();
await b.CalculateBuckets();
App.HintContextChange();
@@ -459,11 +477,11 @@ namespace Elwig.Windows {
using var ctx = new AppDbContext();
var tbl1 = await OverUnderDeliveryData.ForSeason(ctx.OverUnderDeliveryRows, year);
var tbl2 = await AreaComUnderDeliveryData.ForSeason(ctx.AreaComUnderDeliveryRows, year);
using var ods = new OdsFile(filename);
using var ods = new OdsFile(d.FileName);
await ods.AddTable(tbl1);
await ods.AddTable(tbl2);
} catch (Exception exc) {
InteractionService.ShowException(exc);
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
@@ -472,28 +490,33 @@ namespace Elwig.Windows {
private async void BreakdownButton_Click(object sender, RoutedEventArgs evt) {
if (SeasonInput.Value is not int year)
return;
var filename = InteractionService.SaveFile($"Sorten-/Qualitätsaufschlüsselung {year}", $"Aufschlüsselung-{year}", "ods");
if (filename == null)
var d = new SaveFileDialog() {
FileName = $"Aufschlüsselung-{year}.ods",
DefaultExt = "ods",
Filter = "OpenDocument Format Spreadsheet (*.ods)|*.ods",
Title = $"Sorten-/Qualitätsaufschlüsselung {year} speichern unter - Elwig"
};
if (d.ShowDialog() == false)
return;
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
var b = await Billing.Create(year);
var b = new Billing(year);
await b.FinishSeason();
await b.CalculateBuckets();
App.HintContextChange();
using var ctx = new AppDbContext();
using var ods = new OdsFile(filename);
using var ods = new OdsFile(d.FileName);
var tblTotal = await WeightBreakdownData.ForSeason(ctx.WeightBreakDownRows, year);
await ods.AddTable(tblTotal);
foreach (var branch in await ctx.FetchBranches().ToListAsync()) {
foreach (var branch in await ctx.Branches.OrderBy(b => b.Name).ToListAsync()) {
var tbl = await WeightBreakdownData.ForSeason(ctx.WeightBreakDownRows, year, branch);
await ods.AddTable(tbl);
}
} catch (Exception exc) {
InteractionService.ShowException(exc);
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
@@ -502,24 +525,29 @@ namespace Elwig.Windows {
private async void AreaCommitmentsButton_Click(object sender, RoutedEventArgs evt) {
if (SeasonInput.Value is not int year)
return;
var filename = InteractionService.SaveFile($"Flächenbindungen {year}", $"Flächenbindungen-{year}", "ods");
if (filename == null)
var d = new SaveFileDialog() {
FileName = $"Flächenbindungen-{year}.ods",
DefaultExt = "ods",
Filter = "OpenDocument Format Spreadsheet (*.ods)|*.ods",
Title = $"Flächenbindungen {year} speichern unter - Elwig"
};
if (d.ShowDialog() == false)
return;
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
var b = await Billing.Create(year);
var b = new Billing(year);
await b.FinishSeason();
await b.CalculateBuckets();
App.HintContextChange();
using var ctx = new AppDbContext();
var tbl = await MemberAreaComsData.ForSeason(ctx.MemberAreaComsRows, year);
using var ods = new OdsFile(filename);
using var ods = new OdsFile(d.FileName);
await ods.AddTable(tbl);
} catch (Exception exc) {
InteractionService.ShowException(exc);
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
@@ -528,24 +556,29 @@ namespace Elwig.Windows {
private async void BreakdownMemberVarietyButton_Click(object sender, RoutedEventArgs evt) {
if (SeasonInput.Value is not int year)
return;
var filename = InteractionService.SaveFile($"Liefermengen/Ertrag {year}", $"Liefermengen-Ertrag-{year}", "ods");
if (filename == null)
var d = new SaveFileDialog() {
FileName = $"Liefermengen-Ertrag-{year}.ods",
DefaultExt = "ods",
Filter = "OpenDocument Format Spreadsheet (*.ods)|*.ods",
Title = $"Liefermengen/Ertrag {year} speichern unter - Elwig"
};
if (d.ShowDialog() == false)
return;
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
var b = await Billing.Create(year);
var b = new Billing(year);
await b.FinishSeason();
await b.CalculateBuckets();
App.HintContextChange();
using var ctx = new AppDbContext();
var tbl = await MemberDeliveryYieldsPerVarietyData.ForSeason(ctx.MemberDeliveryPerVariantRows, year);
using var ods = new OdsFile(filename);
using var ods = new OdsFile(d.FileName);
await ods.AddTable(tbl);
} catch (Exception exc) {
InteractionService.ShowException(exc);
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
+2 -1
View File
@@ -5,7 +5,8 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Elwig.Windows"
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>
<vm:MemberAdminViewModel/>
</Window.DataContext>
+61 -57
View File
@@ -82,9 +82,12 @@ namespace Elwig.Windows {
Menu_Export_UploadFilters.IsEnabled = App.Config.SyncUrl != null;
Menu_Export_UploadAll.IsEnabled = App.Config.SyncUrl != null;
ViewModel.ShowOnlyActiveMembers = true;
}
private void Window_Loaded(object sender, RoutedEventArgs evt) {
ViewModel.ShowOnlyActiveMembers = true;
UpdateContactInfoVisibility();
LockInputs();
}
public void FocusMember(int mgnr) {
@@ -110,52 +113,46 @@ namespace Elwig.Windows {
}
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();
var (_, memberQuery, filter) = await vm.GetFilters(ctx);
var members = await memberQuery
.Include(m => m.EmailAddresses)
.Include(m => m.TelephoneNumbers)
.AsSplitQuery()
.ToListAsync();
using var ctx = new AppDbContext();
var (_, memberQuery, filter) = await ViewModel.GetFilters(ctx);
var members = await memberQuery
.Include(m => m.Branch)
.Include(m => m.DefaultWbKg!.AtKg)
.Include(m => m.EmailAddresses)
.Include(m => m.TelephoneNumbers)
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.PostalDest.AtPlz!.Country)
.Include(m => m.BillingAddress!.PostalDest.AtPlz!.Ort)
.Include(m => m.BillingAddress!.PostalDest.AtPlz!.Country)
.ToListAsync();
if (filter.Count > 0 && members.Count > 0) {
var dict = members.AsParallel()
.ToDictionary(m => m, m => m.SearchScore(filter))
.OrderByDescending(a => a.Value)
.ThenBy(a => a.Key.Name)
.ThenBy(a => a.Key.GivenName)
.ThenBy(a => a.Key.MgNr);
var threshold = dict.Select(a => a.Value).Max() * 3 / 4;
members = [.. dict
.Where(a => a.Value > threshold)
.Select(a => a.Key)];
} else {
members = [.. members
.OrderBy(m => m.Name)
.ThenBy(m => m.GivenName)
.ThenBy(m => m.MgNr)];
}
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;
if (filter.Count > 0 && members.Count > 0) {
var dict = members.AsParallel()
.ToDictionary(m => m, m => m.SearchScore(filter))
.OrderByDescending(a => a.Value)
.ThenBy(a => a.Key.Name)
.ThenBy(a => a.Key.GivenName)
.ThenBy(a => a.Key.MgNr);
var threshold = dict.Select(a => a.Value).Max() * 3 / 4;
members = dict
.Where(a => a.Value > threshold)
.Select(a => a.Key)
.ToList();
} else {
members = members
.OrderBy(m => m.Name)
.ThenBy(m => m.GivenName)
.ThenBy(m => m.MgNr)
.ToList();
}
ControlUtils.RenewItemsSource(MemberList, members,
MemberList_SelectionChanged, ViewModel.TextFilter.Count > 0 ? ControlUtils.RenewSourceDefault.IfOnly : ControlUtils.RenewSourceDefault.None, !updateSort);
if (updateSort && MemberList.SelectedItem != null)
MemberList.ScrollIntoView(MemberList.SelectedItem);
ViewModel.StatusMembers = $"{members.Count:N0} ({totalMemberCount:N0})";
ViewModel.StatusBusinessShares = $"{members.Sum(m => m.BusinessShares):N0} ({totalBusinessShares:N0})";
ViewModel.StatusMembers = $"{members.Count:N0} ({await ctx.Members.CountAsync():N0})";
ViewModel.StatusBusinessShares = $"{members.Sum(m => m.BusinessShares):N0} ({await ctx.Members.SumAsync(m => m.BusinessShares):N0})";
}
private void RefreshInputs(bool validate = false) {
@@ -187,12 +184,12 @@ namespace Elwig.Windows {
protected override async Task OnRenewContext(AppDbContext ctx) {
await base.OnRenewContext(ctx);
ControlUtils.RenewItemsSource(BranchInput, await ctx.FetchBranches().ToListAsync());
ControlUtils.RenewItemsSource(BranchInput, await ctx.Branches.OrderBy(b => b.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");
MenuItem? temp = null;
var seasons = await ctx.Seasons.Include(s => s.PaymentVariants).OrderByDescending(s => s.Year).ToListAsync();
var seasons = await ctx.Seasons.OrderByDescending(s => s.Year).ToListAsync();
Menu_DeliveryConfirmation.Items.Clear();
foreach (var s in seasons) {
var i = new MenuItem {
@@ -331,7 +328,6 @@ namespace Elwig.Windows {
}
private async void ActiveMemberInput_Changed(object sender, RoutedEventArgs evt) {
if (!HasContextLoaded) return;
await RefreshList();
}
@@ -388,9 +384,10 @@ namespace Elwig.Windows {
int areaComs = 0, deliveries = 0, credits = 0;
using (var ctx = new AppDbContext()) {
areaComs = await ctx.AreaCommitments.Where(c => c.MgNr == m.MgNr).CountAsync();
deliveries = await ctx.Deliveries.Where(d => d.MgNr == m.MgNr).CountAsync();
credits = await ctx.Credits.Where(c => c.MgNr == m.MgNr).CountAsync();
var l = (await ctx.Members.FindAsync(m.MgNr))!;
areaComs = l.AreaCommitments.Count;
deliveries = l.Deliveries.Count;
credits = l.Credits.Count;
}
var d = new DeleteMemberDialog(m.MgNr, m.AdministrativeName, areaComs, deliveries, credits);
if (d.ShowDialog() == true) {
@@ -399,7 +396,9 @@ namespace Elwig.Windows {
await MemberService.DeleteMember(m.MgNr, d.DeletePaymentData, d.DeleteDeliveries, d.DeleteAreaComs);
App.HintContextChange();
} catch (Exception exc) {
InteractionService.ShowDbException("Mitglied löschen", exc);
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Mitglied löschen", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = null;
}
@@ -420,7 +419,9 @@ namespace Elwig.Windows {
mgnr = await ViewModel.UpdateMember(ViewModel.SelectedMember?.MgNr);
App.HintContextChange();
} catch (Exception exc) {
InteractionService.ShowDbException("Mitglied aktualisieren", exc);
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Mitglied aktualisieren", MessageBoxButton.OK, MessageBoxImage.Error);
SaveButton.IsEnabled = true;
Mouse.OverrideCursor = null;
return;
@@ -483,7 +484,6 @@ namespace Elwig.Windows {
}
private async void SearchInput_TextChanged(object sender, RoutedEventArgs evt) {
if (!HasContextLoaded) return;
await RefreshList(true);
}
@@ -498,9 +498,7 @@ namespace Elwig.Windows {
try {
await Task.Run(async () => {
using var doc = new Letterhead(m);
using (var ctx = new AppDbContext()) {
await doc.Generate(ctx);
}
await doc.Generate();
if (!App.Config.Debug) {
await doc.Print();
} else {
@@ -508,7 +506,7 @@ namespace Elwig.Windows {
}
});
} catch (Exception exc) {
InteractionService.ShowException(exc);
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = null;
}
@@ -530,7 +528,9 @@ namespace Elwig.Windows {
private async void Menu_MemberDataSheet_Email_Click(object sender, RoutedEventArgs evt) {
if (ViewModel.SelectedMember is not Member m) return;
if (!InteractionService.AskQuestion("Stammdatenblatt verschicken", "Soll eine E-Mail verschickt werden?", true))
var res = MessageBox.Show("Soll eine E-Mail verschickt werden?", "Stammdatenblatt verschicken",
MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.Yes);
if (res != MessageBoxResult.Yes)
return;
await MemberService.GenerateMemberDataSheet(m, ExportMode.Email);
}
@@ -560,7 +560,9 @@ namespace Elwig.Windows {
var year = (int?)((sender as MenuItem)?.Parent as MenuItem)?.Tag;
if (ViewModel.SelectedMember is not Member m || year == null)
return;
if (!InteractionService.AskQuestion("Anlieferungsbestätigung verschicken", "Soll eine E-Mail verschickt werden?", true))
var res = MessageBox.Show("Soll eine E-Mail verschickt werden?", "Anlieferungsbestätigung verschicken",
MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.Yes);
if (res != MessageBoxResult.Yes)
return;
await MemberService.GenerateDeliveryConfirmation(m, (int)year, ExportMode.Email);
}
@@ -594,7 +596,9 @@ namespace Elwig.Windows {
var avnr = (int?)((sender as MenuItem)?.Parent as MenuItem)?.Tag;
if (ViewModel.SelectedMember is not Member m || year == null || avnr == null)
return;
if (!InteractionService.AskQuestion("Traubengutschrift verschicken", "Soll eine E-Mail verschickt werden?", true))
var res = MessageBox.Show("Soll eine E-Mail verschickt werden?", "Traubengutschrift verschicken",
MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.Yes);
if (res != MessageBoxResult.Yes)
return;
await MemberService.GenerateCreditNote(m, (int)year, (int)avnr, ExportMode.Email);
}
@@ -783,7 +787,7 @@ namespace Elwig.Windows {
if (areaComs.Count == 0)
return;
var oldMember = await ctx.FetchMembers(mgnr).SingleAsync();
var oldMember = (await ctx.Members.FindAsync(mgnr))!;
var newName = $"{ViewModel.Name?.Replace('ß', 'ẞ').ToUpper()} " +
$"{ViewModel.Prefix}{(!string.IsNullOrEmpty(ViewModel.Prefix) ? " " : "")}" +
$"{ViewModel.GivenName}{(!string.IsNullOrEmpty(ViewModel.GivenName) ? " " : "")}" +
+19 -12
View File
@@ -1,6 +1,5 @@
using Elwig.Helpers;
using Elwig.Models.Entities;
using Elwig.Services;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
@@ -22,11 +21,12 @@ namespace Elwig.Windows {
}
protected override async Task OnRenewContext(AppDbContext ctx) {
var origins = await ctx.WineOrigins
.Include(o => o.Gems).ThenInclude(g => g.AtGem.Kgs).ThenInclude(k => k.WbKg!.Gl)
.ToListAsync();
origins.ForEach(o => { origins.FirstOrDefault(p => p.HkId == o.ParentHkId)?.Children.Add(o); });
origins = [.. origins.OrderByDescending(o => o.SortKey).ThenBy(o => o.HkId)];
var origins = (await ctx.WineOrigins
.Include("Gems.AtGem.Kgs.WbKg.Gl")
.AsSplitQuery()
.ToListAsync())
.OrderByDescending(o => o.SortKey)
.ThenBy(o => o.HkId);
ControlUtils.RenewItemsSource(WineOrigins, origins, WineOrigins_SelectionChanged);
if (WineOrigins.SelectedItem == null) {
var hkid = await ctx.WbKgs
@@ -39,7 +39,8 @@ namespace Elwig.Windows {
}
var gls = await ctx.WbGls
.OrderBy(g => g.GlNr)
.Include(g => g.Kgs).ThenInclude(k => k.Rds)
.Include("Kgs.Rds")
.AsSplitQuery()
.ToListAsync();
ControlUtils.RenewItemsSource(WbGls, gls, WbGls_SelectionChanged, ControlUtils.RenewSourceDefault.First);
UpdateWbGems();
@@ -193,14 +194,18 @@ namespace Elwig.Windows {
App.HintContextChange();
ControlUtils.SelectItemWithPk(WbGlKgs, k.KgNr);
} catch (Exception exc) {
InteractionService.ShowDbException("Katastralgemeinde aktivieren", exc);
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Katastralgemeinde aktivieren", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private async void DeactivateKgButton_Click(object sender, RoutedEventArgs e) {
if (WbGlKgs.SelectedItem is not AT_Kg k || k.WbKg == null) return;
if (!InteractionService.AskConfirmation("Katastralgemeinde deaktivieren", $"Sollen alle Riede und Stammgemeinden-Einträge von der KG {k.Name} wirklich unwiderruflich gelöscht werden?"))
return;
var r = MessageBox.Show(
$"Sollen alle Riede und Stammgemeinden-Einträge von der KG {k.Name} wirklich unwiderruflich gelöscht werden?",
"Katastralgemeinde deaktivieren", MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No);
if (r != MessageBoxResult.Yes) return;
try {
using (var ctx = new AppDbContext()) {
ctx.Remove(k.WbKg);
@@ -209,8 +214,10 @@ namespace Elwig.Windows {
App.HintContextChange();
ControlUtils.SelectItemWithPk(WbKgs, k.KgNr);
} catch (Exception exc) {
await ForceContextReload();
InteractionService.ShowDbException("Katastralgemeinde deaktivieren", exc);
await HintContextChange();
var str = "Der Eintrag konnte nicht aus der Datenbank gelöscht werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Katastralgemeinde deaktivieren", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
+21 -9
View File
@@ -2,7 +2,6 @@ using Elwig.Helpers;
using Elwig.Helpers.Billing;
using Elwig.Models.Dtos;
using Elwig.Models.Entities;
using Elwig.Services;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
@@ -41,7 +40,7 @@ namespace Elwig.Windows {
}
protected override async Task OnRenewContext(AppDbContext ctx) {
var members = await ctx.FetchMembers(includeNotActive: true)
var members = await ctx.Members
.Select(m => new {
m.MgNr,
m.Name,
@@ -49,8 +48,11 @@ namespace Elwig.Windows {
m.BusinessShares,
m.IsActive,
})
.OrderBy(m => m.Name)
.ThenBy(m => m.GivenName)
.ThenBy(m => m.MgNr)
.ToListAsync();
var season = await ctx.FetchSeasons(Year).SingleAsync();
var season = (await ctx.Seasons.FindAsync(Year))!;
var contracts = await ctx.AreaCommitmentTypes.ToDictionaryAsync(t => t.VtrgId, t => t);
var tbl1 = await OverUnderDeliveryData.ForSeason(ctx.OverUnderDeliveryRows, Year);
@@ -143,7 +145,11 @@ namespace Elwig.Windows {
TotalModifiers.Text = $"{list.Count(r => r.Total != 0)} Mg. / {list.Sum(r => r.Total):N2} {sym}";
NonDeliveries.Text = $"{list.Count(r => r.Weight == 0):N0}";
ControlUtils.RenewItemsSource(MemberInput, await ctx.FetchMembers(includeNotActive: true).ToListAsync());
ControlUtils.RenewItemsSource(MemberInput, await ctx.Members
.OrderBy(m => m.Name)
.ThenBy(m => m.GivenName)
.ThenBy(m => m.MgNr)
.ToListAsync());
CustomAmountInput.Unit = sym;
}
@@ -164,12 +170,14 @@ namespace Elwig.Windows {
await Task.Run(async () => {
await App.Client.UpdateValues();
var b = await Billing.Create(Year);
var b = new Billing(Year);
await b.AutoAdjustBusinessShares(new DateOnly(Year, 11, 30), kg ?? default, bs ?? default, kgPerBs ?? default, percent / 100.0 ?? default, minBs ?? default);
});
App.HintContextChange();
} catch (Exception exc) {
InteractionService.ShowDbException("GA Nachzeichnen", exc);
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "GA Nachzeichnen", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = null;
}
@@ -178,12 +186,14 @@ namespace Elwig.Windows {
Mouse.OverrideCursor = Cursors.Wait;
try {
await Task.Run(async () => {
var b = await Billing.Create(Year);
var b = new Billing(Year);
await b.UnAdjustBusinessShares();
});
App.HintContextChange();
} catch (Exception exc) {
InteractionService.ShowDbException("GA Nachzeichnen", exc);
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "GA Nachzeichnen", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = null;
}
@@ -300,7 +310,9 @@ namespace Elwig.Windows {
});
App.HintContextChange();
} catch (Exception exc) {
InteractionService.ShowDbException("Benutzerdefinierten Zu-/Abschlag speichern", exc);
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Benutzerdefinierten Zu-/Abschlag speichern", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = null;
}
+27 -13
View File
@@ -48,6 +48,7 @@ namespace Elwig.Windows {
ControlUtils.RenewItemsSource(PaymentVariantList, await ctx.PaymentVariants
.Where(v => v.Year == Year)
.OrderBy(v => v.AvNr)
.Include(v => v.Season.Currency)
.ToListAsync());
if (PaymentVariantList.SelectedItem == null && PaymentVariantList.Items.Count > 0) {
PaymentVariantList.SelectedIndex = PaymentVariantList.Items.Count - 1;
@@ -90,7 +91,9 @@ namespace Elwig.Windows {
App.HintContextChange();
ControlUtils.SelectItem(PaymentVariantList, v);
} catch (Exception exc) {
InteractionService.ShowDbException("Auszahlungsvariante erstellen", exc);
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Auszahlungsvariante erstellen", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = null;
}
@@ -104,7 +107,9 @@ namespace Elwig.Windows {
App.HintContextChange();
ControlUtils.SelectItem(PaymentVariantList, n);
} catch (Exception exc) {
InteractionService.ShowDbException("Auszahlungsvariante kopieren", exc);
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Auszahlungsvariante kopieren", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = null;
}
@@ -112,14 +117,19 @@ namespace Elwig.Windows {
private async void DeleteButton_Click(object sender, RoutedEventArgs evt) {
if (PaymentVariantList.SelectedItem is not PaymentVar v || !v.TestVariant)
return;
if (!InteractionService.AskContinue("Auszahlungsvariante löschen", $"Soll die Auszahlungsvariante \"{v.Name}\" wirklich unwiderruflich gelöscht werden?"))
var res = MessageBox.Show(
$"Soll die Auszahlungsvariante \"{v.Name}\" wirklich unwiderruflich gelöscht werden?",
"Auszahlungsvariante löschen", MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
if (res != MessageBoxResult.OK)
return;
Mouse.OverrideCursor = Cursors.Wait;
try {
await PaymentVariantService.DeletePaymentVariant(v.Year, v.AvNr);
App.HintContextChange();
} catch (Exception exc) {
InteractionService.ShowDbException("Auszahlungsvariante löschen", exc);
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Auszahlungsvariante löschen", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = null;
}
@@ -133,7 +143,7 @@ namespace Elwig.Windows {
await PaymentVariantService.Calculate(v.Year, v.AvNr);
App.HintContextChange();
} catch (Exception exc) {
InteractionService.ShowException("Berechnungsfehler", exc);
MessageBox.Show(exc.Message, "Berechnungsfehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = null;
ViewModel.CalculateIsEnabled = true;
@@ -195,7 +205,7 @@ namespace Elwig.Windows {
await PaymentVariantService.Commit(v.Year, v.AvNr);
App.HintContextChange();
} catch (Exception exc) {
InteractionService.ShowException(exc);
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = null;
ViewModel.RevertIsEnabled = true;
@@ -204,9 +214,11 @@ namespace Elwig.Windows {
private async void RevertButton_Click(object sender, RoutedEventArgs evt) {
if (PaymentVariantList.SelectedItem is not PaymentVar v)
return;
if (!InteractionService.AskConfirmation("Traubengutschriften löschen",
var res = MessageBox.Show(
"Sollen wirklich alle festgesetzten Traubengutschriften der ausgewählten Auszahlungsvariante unwiderruflich gelöscht werden?\n\n" +
"Dies ist im Allgemeinen nie empfohlen. Handelt es sich um die aktuellste Auszahlungsvariante könnte das eine Ausnahme sein."))
"Dies ist im Allgemeinen nie empfohlen. Handelt es sich um die aktuellste Auszahlungsvariante könnte das eine Ausnahme sein.",
"Traubengutschriften löschen", MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No);
if (res != MessageBoxResult.Yes)
return;
ViewModel.RevertIsEnabled = false;
Mouse.OverrideCursor = Cursors.Wait;
@@ -214,7 +226,7 @@ namespace Elwig.Windows {
await PaymentVariantService.Revert(v.Year, v.AvNr);
App.HintContextChange();
} catch (Exception exc) {
InteractionService.ShowException(exc);
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = null;
ViewModel.CommitIsEnabled = true;
@@ -224,7 +236,7 @@ namespace Elwig.Windows {
if (PaymentVariantList.SelectedItem is not PaymentVar v) {
return;
} else if (v.TransferDate == null) {
InteractionService.ShowError("Exportieren nicht möglich", "Überweisungsdatum muss gesetzt sein!");
MessageBox.Show("Überweisungsdatum muss gesetzt sein!", "Exportieren nicht möglich", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
await PaymentVariantService.GenerateEbics(v.Year, v.AvNr);
@@ -244,11 +256,13 @@ namespace Elwig.Windows {
await ViewModel.UpdatePaymentVariant(v.Year, v.AvNr);
App.HintContextChange();
} catch (Exception exc) {
await ForceContextReload();
InteractionService.ShowDbException("Auszahlungsvariante aktualisieren", exc);
await HintContextChange();
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Auszahlungsvariante aktualisieren", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = null;
await EnsureContextRenewed();
await HintContextChange();
CommentInput_TextChanged(null, null);
DateInput_TextChanged(null, null);
TransferDateInput_TextChanged(null, null);
+12 -7
View File
@@ -1,6 +1,6 @@
using Elwig.Helpers;
using Elwig.Helpers.Export;
using Elwig.Services;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Data.Common;
@@ -42,9 +42,9 @@ namespace Elwig.Windows {
Mouse.OverrideCursor = Cursors.Wait;
await DisplayQuery(QueryInput.Text);
Mouse.OverrideCursor = null;
} catch (Exception exc) {
} catch (Exception e) {
Mouse.OverrideCursor = null;
InteractionService.ShowException("Fehler beim Ausführen", exc);
MessageBox.Show(e.Message, "Fehler beim Ausführen", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
@@ -85,16 +85,21 @@ namespace Elwig.Windows {
}
private static async Task SaveQuery(string sqlQuery) {
var filename = InteractionService.SaveFile("Datenbank Abfrage", "Abfrage", "csv");
if (filename != null) {
var d = new SaveFileDialog() {
FileName = $"Abfrage.csv",
DefaultExt = "csv",
Filter = "CSV-Datei (*.csv)|*.csv",
Title = $"Datenbank Abfrage speichern unter - Elwig"
};
if (d.ShowDialog() == true) {
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
var (header, rows) = await ExecuteQuery(sqlQuery);
using var csv = new CsvSimple(filename, ';', Utils.UTF8BOM);
using var csv = new CsvSimple(d.FileName, ';', Utils.UTF8BOM);
await csv.ExportAsync(rows.Prepend([.. header.Select(h => h.ColumnName)]));
} catch (Exception exc) {
InteractionService.ShowException("Fehler beim Ausführen", exc);
MessageBox.Show(exc.Message, "Fehler beim Ausführen", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
-17
View File
@@ -1,17 +0,0 @@
Elwig
=====
Source code
C:\Program Files\Elwig\src\
https://git.necronda.net/winzer/elwig
Installation folder
C:\Program Files\Elwig\
Data and configuration folder
C:\ProgramData\Elwig\
- config.ini : main configuration file
- database.sqlite3 : stores all data
- imported.txt : list of all imported *.elwig.zip files to not automatically import them again
- mails\ : sent/outgoing email log
+1 -3
View File
@@ -3,9 +3,7 @@
<Fragment>
<!-- C:\Program Files (x86)\Elwig or C:\Program Files\Elwig -->
<StandardDirectory Id="ProgramFiles64Folder">
<Directory Id="InstallFolder" Name="!(bind.Property.ProductName)">
<Directory Id="SourceFolder" Name="src"/>
</Directory>
<Directory Id="InstallFolder" Name="!(bind.Property.ProductName)" />
</StandardDirectory>
<!-- C:\ProgramData\Elwig -->
+1 -6
View File
@@ -1,4 +1,4 @@
<Project Sdk="WixToolset.Sdk/7">
<Project Sdk="WixToolset.Sdk/6">
<PropertyGroup>
<HarvestFileSuppressUniqueIds>false</HarvestFileSuppressUniqueIds>
<HarvestFileGenerateGuidsNow>true</HarvestFileGenerateGuidsNow>
@@ -11,7 +11,6 @@
<BuildProjectReferences>False</BuildProjectReferences>
<OutputName>Elwig</OutputName>
<Cultures>de-AT</Cultures>
<AcceptEula>wix7</AcceptEula>
</PropertyGroup>
<UsingTask TaskName="GetFileVersion" TaskFactory="RoslynCodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll">
<ParameterGroup>
@@ -34,11 +33,7 @@
<DefineConstants>ProductVersion=$(ElwigFileVersion);BuildPath=..\Elwig\bin\Publish;ElwigProjectDir=..\Elwig</DefineConstants>
</PropertyGroup>
</Target>
<Target Name="CreateSourceArchive" BeforeTargets="BeforeBuild">
<Exec Command="git -C .. archive -o $(ProjectDir)\Files\elwig.zip HEAD" />
</Target>
<ItemGroup>
<None Include="Files\config.ini" />
<None Include="Files\README.txt" />
</ItemGroup>
</Project>
-6
View File
@@ -4,15 +4,9 @@
<Component Directory="InstallFolder">
<File Source="$(var.ElwigProjectDir)\bin\Publish\Elwig.exe" Id="Elwig.exe"/>
</Component>
<Component Directory="SourceFolder">
<File Source="$(ProjectDir)\Files\elwig.zip" Id="elwig.zip"/>
</Component>
<Component Directory="ConfigFolder" Permanent="true" NeverOverwrite="true">
<File Source="$(ProjectDir)\Files\config.ini" Id="config.ini"/>
</Component>
<Component Directory="ConfigFolder">
<File Source="$(ProjectDir)\Files\README.txt" Id="README.txt"/>
</Component>
</ComponentGroup>
</Fragment>
</Wix>
+2 -2
View File
@@ -13,7 +13,7 @@ About
**Product:** Elwig
**Description:** Electronic Management for Vintners' Cooperatives
**Type:** ERP system
**Version:** 1.0.5.6 ([Changelog](./CHANGELOG.md))
**Version:** 1.0.4.1 ([Changelog](./CHANGELOG.md))
**License:** [GNU General Public License 3.0 (GPLv3)](./LICENSE)
**Website:** https://elwig.at/
**Source code:** https://git.necronda.net/winzer/elwig
@@ -33,7 +33,7 @@ Packaging: [WiX Toolset](https://www.firegiant.com/wixtoolset/)
**Produkt:** Elwig
**Beschreibung:** Elektronische Winzergenossenschaftsverwaltung
**Typ:** Warenwirtschaftssystem (ERP-System)
**Version:** 1.0.5.6 ([Änderungsprotokoll](./CHANGELOG.md))
**Version:** 1.0.4.1 ([Änderungsprotokoll](./CHANGELOG.md))
**Lizenz:** [GNU General Public License 3.0 (GPLv3)](./LICENSE)
**Website:** https://elwig.at/
**Quellcode:** https://git.necronda.net/winzer/elwig
+3 -4
View File
@@ -1,9 +1,8 @@
<Project Sdk="WixToolset.Sdk/7">
<Project Sdk="WixToolset.Sdk/6">
<PropertyGroup>
<OutputType>Bundle</OutputType>
<OutputName>Elwig</OutputName>
<Cultures>de-AT</Cultures>
<AcceptEula>wix7</AcceptEula>
</PropertyGroup>
<Target Name="CustomBeforeBuild" BeforeTargets="BeforeBuild">
<Exec Command="curl --fail -s -L &quot;https://go.microsoft.com/fwlink/p/?LinkId=2124703&quot; -z &quot;$(ProjectDir)\Files\MicrosoftEdgeWebview2Setup.exe&quot; -o &quot;$(ProjectDir)\Files\MicrosoftEdgeWebview2Setup.exe&quot;" />
@@ -14,7 +13,7 @@
</Target>
<ItemGroup>
<ProjectReference Include="..\Installer\Installer.wixproj" />
<PackageReference Include="WixToolset.Bal.wixext" Version="7.0.0" />
<PackageReference Include="WixToolset.Util.wixext" Version="7.0.0" />
<PackageReference Include="WixToolset.Bal.wixext" Version="6.0.2" />
<PackageReference Include="WixToolset.Util.wixext" Version="6.0.2" />
</ItemGroup>
</Project>
+1 -2
View File
@@ -2,7 +2,6 @@ using Elwig;
using Elwig.Helpers;
using Elwig.Helpers.Billing;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using System.Reflection;
namespace Tests {
@@ -23,7 +22,7 @@ namespace Tests {
public void Setup_2_Client() {
using var ctx = new AppDbContext();
App.Client = new ClientParameters(ctx);
App.SetBranch(ctx.Branches.Include(b => b.PostalDest).Single());
App.SetBranch(ctx.Branches.Single());
}
[OneTimeSetUp]
-1
View File
@@ -80,7 +80,6 @@ namespace Tests.E2ETests {
Window.FindElement(By.WpfId("SaveButton")).Click();
Thread.Sleep(500);
Window.FindElement(By.WpfId("SearchInput")).SendKeys("9999");
Thread.Sleep(500);
var memberListRow = Window.FindElement(By.WpfId("MemberList")).FindElement(By.ClassName("DataGridRow"));
+1 -1
View File
@@ -3,7 +3,7 @@
DELETE FROM credit;
DELETE FROM payment_variant;
DELETE FROM delivery;
DELETE FROM area_commitment_contract;
DELETE FROM area_commitment;
DELETE FROM area_commitment_type;
DELETE FROM season;
DELETE FROM wine_attribute;
+4 -9
View File
@@ -22,15 +22,10 @@ INSERT INTO area_commitment_type (vtrgid, sortid, attrid, disc, min_kg_per_ha, p
('GVQ', 'GV', 'Q', NULL, 5000, 1000, 1000000, NULL),
('GVR', 'GV', 'R', NULL, 5000, 1000, 1000000, NULL);
INSERT INTO area_commitment_contract (fbnr, kgnr, rdnr) VALUES
( 1, 06109, NULL),
( 2, 06109, NULL),
( 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 area_commitment (fbnr, mgnr, vtrgid, cultid, area, kgnr, gstnr, rdnr, year_from, year_to) VALUES
( 1, 101, 'GV', 'KIP', 10000, 06109, '123/4', NULL, 2000, 2019),
( 2, 101, 'GV', 'KIP', 10000, 06109, '123/5', NULL, 2025, 2030),
( 3, 101, 'GV', 'KIP', 10000, 06109, '123/6', NULL, 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
(2020, 'EUR', 1000, 2000, NULL, NULL, NULL, NULL, NULL),
-4
View File
@@ -64,10 +64,6 @@ 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, 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
(2020, 1, 1, 0, '_', 3219),
(2020, 3, 1, 0, '_', 2561),
+1 -1
View File
@@ -4,7 +4,7 @@ DELETE FROM credit;
DELETE FROM payment_variant;
DELETE FROM delivery;
DELETE FROM season;
DELETE FROM area_commitment_contract;
DELETE FROM area_commitment;
DELETE FROM area_commitment_type;
DELETE FROM member WHERE mgnr >= 200;
DELETE FROM wine_cultivation;
+5 -11
View File
@@ -29,17 +29,11 @@ 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
('GV', 'GV', NULL, NULL, 5000, 500, NULL, NULL);
INSERT INTO area_commitment_contract (fbnr, kgnr, rdnr) VALUES
( 1, 15224, NULL),
( 2, 15224, NULL),
( 3, 15224, NULL),
( 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 area_commitment (fbnr, mgnr, vtrgid, cultid, area, kgnr, gstnr, rdnr, year_from, year_to) VALUES
( 1, 203, 'GV', NULL, 10000, 15224, '321/9', NULL, NULL, NULL),
( 2, 204, 'GV', NULL, 10000, 15224, '123/1', NULL, 2000, 2019),
( 3, 204, 'GV', NULL, 10000, 15224, '123/2', NULL, 2025, 2030),
( 4, 204, 'GV', NULL, 10000, 15224, '123/3', NULL, 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
+4 -4
View File
@@ -19,16 +19,16 @@
</Target>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.6.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.3.0" />
<PackageReference Include="Appium.WebDriver" Version="4.4.5" />
<PackageReference Include="NReco.PdfRenderer" Version="1.6.0" />
<PackageReference Include="NUnit" Version="4.6.1" />
<PackageReference Include="NUnit" Version="4.5.1" />
<PackageReference Include="NUnit3TestAdapter" Version="6.2.0" />
<PackageReference Include="NUnit.Analyzers" Version="4.14.0">
<PackageReference Include="NUnit.Analyzers" Version="4.12.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="10.0.1">
<PackageReference Include="coverlet.collector" Version="8.0.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
@@ -1,4 +1,7 @@
using Elwig.Documents;
using Elwig.Helpers;
using Elwig.Models.Dtos;
using Microsoft.EntityFrameworkCore;
namespace Tests.UnitTests.DocumentTests {
[TestFixture]
@@ -6,9 +9,14 @@ namespace Tests.UnitTests.DocumentTests {
[Test]
public async Task Test_01_VirtualCreditNote() {
using var doc = await CreditNote.Initialize(2020, 1, 101, null);
using var ctx = new AppDbContext();
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);
using (Assert.EnterMultipleScope()) {
Assert.Multiple(() => {
Assert.That(text, Contains.Substring("""
MUSTERMANN Max
Winzerstraße 1
@@ -32,7 +40,7 @@ namespace Tests.UnitTests.DocumentTests {
"""));
Assert.That(text, Contains.Substring("Gesamtbetrag: € 1 000,00"));
Assert.That(text, Contains.Substring("Auszahlungsbetrag: € 1 000,00"));
}
});
}
}
}
@@ -14,7 +14,7 @@ namespace Tests.UnitTests.DocumentTests {
using var doc = new DeliveryAncmtList(filter, data);
var text = await Utils.GeneratePdfText(doc, true);
var table = Utils.ExtractTable(text);
using (Assert.EnterMultipleScope()) {
Assert.Multiple(() => {
Assert.That(text, Contains.Substring("Anmeldeliste"));
Assert.That(text, Contains.Substring("01.10.2020 Matzen GV Kabinettaktion"));
Assert.That(table, Is.EqualTo(new string[][] {
@@ -24,7 +24,7 @@ namespace Tests.UnitTests.DocumentTests {
["01.10.2020", "104 WINZER Waltraud", "Wolkersdorf", "Grüner Veltliner", "-", "2 000"],
["Gesamt:", "Anmeldungen: 4", "25 000"],
}));
}
});
}
}
}
@@ -9,11 +9,11 @@ namespace Tests.UnitTests.DocumentTests {
[Test]
public async Task Test_01_SimpleDeliveryConfirmation() {
using var ctx = new AppDbContext();
var m = await ctx.FetchMembers(101).SingleAsync();
var m = await ctx.Members.FindAsync(101);
var data = await DeliveryConfirmationDeliveryData.ForMember(ctx.DeliveryParts, 2020, m!);
using var doc = new DeliveryConfirmation(2020, m!, null, data);
using var doc = new DeliveryConfirmation(ctx, 2020, m!, data);
var text = await Utils.GeneratePdfText(doc);
using (Assert.EnterMultipleScope()) {
Assert.Multiple(() => {
Assert.That(text, Contains.Substring("""
MUSTERMANN Max
Winzerstraße 1
@@ -39,7 +39,7 @@ namespace Tests.UnitTests.DocumentTests {
Welschriesling 5 382 - 5 382
12 442 3 129 15 571
"""));
}
});
}
}
}
@@ -13,7 +13,7 @@ namespace Tests.UnitTests.DocumentTests {
using var doc = new DeliveryDepreciationList("Saison 2020", data);
var text = await Utils.GeneratePdfText(doc, true);
var table = Utils.ExtractTable(text);
using (Assert.EnterMultipleScope()) {
Assert.Multiple(() => {
Assert.That(text, Contains.Substring("Abwertungsliste"));
Assert.That(text, Contains.Substring("Saison 2020"));
Assert.That(table, Is.EqualTo(new string[][] {
@@ -26,7 +26,7 @@ namespace Tests.UnitTests.DocumentTests {
["20201002X002 1 02.10.2020 09:28 Grüner Veltliner", "Bio", "78", "16,0", "2 901"],
["Gesamt:", "(Teil-)Lieferungen: 3 (5)", "80", "16,3", "13 069"],
}));
}
});
}
}
}
@@ -13,7 +13,7 @@ namespace Tests.UnitTests.DocumentTests {
using var doc = new DeliveryJournal("Saison 2020", data);
var text = await Utils.GeneratePdfText(doc, true);
var table = Utils.ExtractTable(text);
using (Assert.EnterMultipleScope()) {
Assert.Multiple(() => {
Assert.That(text, Contains.Substring("Lieferjournal"));
Assert.That(text, Contains.Substring("Saison 2020"));
Assert.That(table, Is.EqualTo(new string[][] {
@@ -42,7 +42,7 @@ namespace Tests.UnitTests.DocumentTests {
["20201003X003", "2", "03.10.2020 15:15", "104 WINZER Waltraud", "Blauer Portugieser", "89", "18,1", "2 313"],
["Gesamt:", "(Teil-)Lieferungen: 12 (23)", "82", "16,6", "58 886"],
}));
}
});
}
}
}
@@ -1,4 +1,5 @@
using Elwig.Documents;
using Elwig.Helpers;
namespace Tests.UnitTests.DocumentTests {
[TestFixture]
@@ -6,7 +7,9 @@ namespace Tests.UnitTests.DocumentTests {
[Test]
public async Task Test_01_OneDeliveryPart() {
using var doc = await DeliveryNote.Initialize(2020, 1);
using var ctx = new AppDbContext();
var d = await ctx.Deliveries.FindAsync(2020, 1);
using var doc = new DeliveryNote(d!, ctx);
var text = await Utils.GeneratePdfText(doc);
Assert.Multiple(() => {
Assert.That(text, Contains.Substring("""
@@ -16,7 +19,7 @@ namespace Tests.UnitTests.DocumentTests {
"""));
Assert.That(text, Contains.Substring("0123463")); // Betriebsnummer
Assert.That(text, Contains.Substring("pauschaliert"));
Assert.That(text, Contains.Substring($"Wolkersdorf, am {DateTime.Now:dd.MM.yyyy}"));
Assert.That(text, Contains.Substring($"Wolkersdorf, am {Elwig.Helpers.Utils.Today:dd.MM.yyyy}"));
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("""
@@ -31,7 +34,9 @@ namespace Tests.UnitTests.DocumentTests {
[Test]
public async Task Test_02_TwoDeliveryParts() {
using var doc = await DeliveryNote.Initialize(2020, 4);
using var ctx = new AppDbContext();
var d = await ctx.Deliveries.FindAsync(2020, 4);
using var doc = new DeliveryNote(d!, ctx);
var text = await Utils.GeneratePdfText(doc);
Assert.Multiple(() => {
Assert.That(text, Contains.Substring("""
@@ -42,7 +47,7 @@ namespace Tests.UnitTests.DocumentTests {
"""));
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($"Wolkersdorf, am {Elwig.Helpers.Utils.Today:dd.MM.yyyy}"));
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("""
@@ -63,7 +68,9 @@ namespace Tests.UnitTests.DocumentTests {
[Test]
public async Task Test_03_DeliveryPartsWithAttribute() {
using var doc = await DeliveryNote.Initialize(2020, 3);
using var ctx = new AppDbContext();
var d = await ctx.Deliveries.FindAsync(2020, 3);
using var doc = new DeliveryNote(d!, ctx);
var text = await Utils.GeneratePdfText(doc);
Assert.Multiple(() => {
Assert.That(text, Contains.Substring("""
@@ -73,7 +80,7 @@ namespace Tests.UnitTests.DocumentTests {
"""));
Assert.That(text, Contains.Substring("0123463")); // Betriebsnummer
Assert.That(text, Contains.Substring("pauschaliert"));
Assert.That(text, Contains.Substring($"Wolkersdorf, am {DateTime.Now:dd.MM.yyyy}"));
Assert.That(text, Contains.Substring($"Wolkersdorf, am {Elwig.Helpers.Utils.Today:dd.MM.yyyy}"));
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("""
@@ -100,7 +107,9 @@ namespace Tests.UnitTests.DocumentTests {
[Test]
public async Task Test_04_DeliveryPartsWithCultivation() {
using var doc = await DeliveryNote.Initialize(2020, 7);
using var ctx = new AppDbContext();
var d = await ctx.Deliveries.FindAsync(2020, 7);
using var doc = new DeliveryNote(d!, ctx);
var text = await Utils.GeneratePdfText(doc);
Assert.Multiple(() => {
Assert.That(text, Contains.Substring("""
@@ -110,7 +119,7 @@ namespace Tests.UnitTests.DocumentTests {
"""));
Assert.That(text, Contains.Substring("0123480")); // Betriebsnummer
Assert.That(text, Contains.Substring("pauschaliert"));
Assert.That(text, Contains.Substring($"Wolkersdorf, am {DateTime.Now:dd.MM.yyyy}"));
Assert.That(text, Contains.Substring($"Wolkersdorf, am {Elwig.Helpers.Utils.Today:dd.MM.yyyy}"));
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("""
@@ -130,37 +139,5 @@ namespace Tests.UnitTests.DocumentTests {
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);
using (Assert.EnterMultipleScope()) {
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
"""));
}
}
}
}
@@ -8,17 +8,17 @@ namespace Tests.UnitTests.DocumentTests {
[Test]
public async Task Test_01_SimpleLetterhead() {
using var ctx = new AppDbContext();
var m = await ctx.FetchMembers(104).SingleAsync();
var m = await ctx.Members.FindAsync(104);
using var doc = new Letterhead(m!);
var text = await Utils.GeneratePdfText(doc);
using (Assert.EnterMultipleScope()) {
Assert.Multiple(() => {
Assert.That(text, Contains.Substring("WG Test | Genossenschaftsstraße 1 | 2120 Wolkersdorf"));
Assert.That(text, Contains.Substring("""
WINZER Waltraud
Wiener Straße 15
2120 Wolkersdorf im Weinviertel
"""));
}
});
}
}
}
@@ -1,4 +1,5 @@
using Elwig.Documents;
using Elwig.Helpers;
namespace Tests.UnitTests.DocumentTests {
[TestFixture]
@@ -6,9 +7,11 @@ namespace Tests.UnitTests.DocumentTests {
[Test]
public async Task Test_01_SimpleMember() {
using var doc = await MemberDataSheet.Initialize(104);
using var ctx = new AppDbContext();
var m = await ctx.Members.FindAsync(104);
using var doc = new MemberDataSheet(m!, ctx);
var text = await Utils.GeneratePdfText(doc);
using (Assert.EnterMultipleScope()) {
Assert.Multiple(() => {
Assert.That(text, Contains.Substring("""
WINZER Waltraud
Wiener Straße 15
@@ -32,7 +35,7 @@ namespace Tests.UnitTests.DocumentTests {
Assert.That(text, Contains.Substring("IBAN: AT97 1234 5678 9012 3460"));
Assert.That(text, Contains.Substring("Betriebs-Nr.: 0123498"));
Assert.That(text, Contains.Substring("Stammgemeinde: Wolkersdorf"));
}
});
}
}
}

Some files were not shown because too many files have changed in this diff Show More