Compare commits
1 Commits
dev
..
f600609356
| Author | SHA1 | Date | |
|---|---|---|---|
| f600609356 |
@@ -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
|
||||
|
||||
@@ -7,4 +7,3 @@ Tests/Resources/Sql/Create.sql
|
||||
*.exe
|
||||
!WinziPrint.exe
|
||||
*.sqlite3
|
||||
*.zip
|
||||
|
||||
-119
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,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;
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"] ?? "");
|
||||
|
||||
@@ -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}",
|
||||
|
||||
@@ -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
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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:")) {
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)))),
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
@@ -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];
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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> 2022–2026<LineBreak/>
|
||||
<LineBreak/>
|
||||
<Bold>Verwendete Technologien:</Bold><LineBreak/>
|
||||
|
||||
@@ -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 });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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) ? " " : "")}" +
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -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,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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
@@ -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 "https://go.microsoft.com/fwlink/p/?LinkId=2124703" -z "$(ProjectDir)\Files\MicrosoftEdgeWebview2Setup.exe" -o "$(ProjectDir)\Files\MicrosoftEdgeWebview2Setup.exe"" />
|
||||
@@ -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>
|
||||
@@ -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]
|
||||
|
||||
@@ -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"));
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
Reference in New Issue
Block a user