Compare commits

...

63 Commits

Author SHA1 Message Date
lorenz.stechauner 0d8cdd5d6e Bump version to 1.1.0.0
Test / Run tests (push) Successful in 1m54s
Deploy / Build and Deploy (push) Successful in 1m42s
2026-07-09 01:43:38 +02:00
lorenz.stechauner 2350b55cea Tests: Update dependencies
Test / Run tests (push) Successful in 2m6s
2026-07-09 01:01:38 +02:00
lorenz.stechauner e8789aff37 Elwig: Update dependencies 2026-07-09 01:01:38 +02:00
lorenz.stechauner 918555f2b8 [#20] MemberAdminWindow: Add MemberBusinessSharesAdminWindow to manage member shares 2026-07-09 01:01:28 +02:00
lorenz.stechauner 1169ba5101 ChartWindow: Fix warnings and avoid null-forgiving operator
Test / Run tests (push) Successful in 2m10s
2026-07-06 19:11:39 +02:00
lorenz.stechauner 76da392f5f [#20][#80] MemberAdminWindow: Update business share status bar tool tip
Test / Run tests (push) Successful in 2m1s
2026-07-06 18:18:46 +02:00
lorenz.stechauner 000117dc67 CreditNoteData: Add AccountingNr of member
Test / Run tests (push) Successful in 3m6s
2026-07-06 11:03:38 +02:00
lorenz.stechauner 314a0d37a8 [#20] MemberDataSheet: Show members business share history 2026-07-03 12:02:44 +02:00
lorenz.stechauner 765edbdae6 [#20][#80] MemberAdminWindow: Add functionality to edit other business shares 2026-07-03 12:02:44 +02:00
lorenz.stechauner 9a0a422c8a [#20] Entities/MemberHistory: Add DeductYear to simplify billing 2026-07-03 12:02:37 +02:00
lorenz.stechauner a71c41af5c AppDbContext: Add Member.Branch AutoInclude to fix MemberDataSheet
Test / Run tests (push) Successful in 2m52s
2026-07-02 12:17:32 +02:00
lorenz.stechauner 62346a63a8 [#80] Elwig: Add client parameter to switch between simple and red/white business share mode
Test / Run tests (push) Successful in 2m20s
2026-07-01 17:09:55 +02:00
lorenz.stechauner feee6ad1ec [#20][#80] Elwig: Update member_history and add different types of shares
Test / Run tests (push) Successful in 2m0s
2026-07-01 16:22:01 +02:00
lorenz.stechauner 4ebe07f579 AppDbUpdater: Fix handling of foreign key errors
Test / Run tests (push) Successful in 3m4s
2026-07-01 00:36:04 +02:00
lorenz.stechauner beacba6bd9 Services: Add Utils.RunForeground() to factor Task.Run and try-catch-Blocks out
Test / Run tests (push) Successful in 2m2s
2026-06-30 02:32:24 +02:00
lorenz.stechauner 69efca1cc3 Tests: Use Assert.EnterMultipleScope instead of Assert.Multiple
Test / Run tests (push) Successful in 2m6s
2026-06-29 02:33:36 +02:00
lorenz.stechauner fcd0555e4d Elwig: Add InteractionService to centrally manage MessageBox and SaveFileDialogs
Test / Run tests (push) Successful in 2m50s
2026-06-29 02:28:34 +02:00
lorenz.stechauner b93e987685 Bump version to 1.0.5.6
Test / Run tests (push) Successful in 2m24s
Deploy / Build and Deploy (push) Successful in 1m58s
2026-06-25 13:07:10 +02:00
lorenz.stechauner 1ad97a78ff ClientParameters: Add client Seewinkel
Test / Run tests (push) Successful in 3m13s
2026-06-25 12:33:20 +02:00
lorenz.stechauner 1261be001c BaseDataWindow: Remove transactions inside *Save() functions to avoid nesting them 2026-06-25 12:32:46 +02:00
lorenz.stechauner 15de07a4c3 BillingData: Remove quality entry when using –FromGraphEntries
Test / Run tests (push) Successful in 2m34s
2026-06-24 15:51:37 +02:00
lorenz.stechauner 5cbad9a195 Bump version to 1.0.5.5
Test / Run tests (push) Successful in 6m43s
Deploy / Build and Deploy (push) Successful in 2m10s
2026-06-24 14:36:44 +02:00
lorenz.stechauner 4e027a9add Elwig: Update dependencies
Test / Run tests (push) Successful in 4m40s
2026-06-24 14:24:25 +02:00
lorenz.stechauner f32ff945ec BillingData: Preserve all settings when using FromGraphEntries() 2026-06-24 14:24:15 +02:00
lorenz.stechauner ba3f66591e BilllingVariant: Allow for credits with negative value 2026-06-24 13:20:46 +02:00
lorenz.stechauner 3f65b2350b PaymentVariantService: Fix crash in GenerateEbics()
Test / Run tests (push) Successful in 2m48s
2026-06-24 10:36:28 +02:00
lorenz.stechauner 7a6a77419b Bump version to 1.0.5.4
Test / Run tests (push) Successful in 2m17s
Deploy / Build and Deploy (push) Successful in 2m6s
2026-06-22 20:23:46 +02:00
lorenz.stechauner 7a993585c3 Elwig: Update dependencies
Test / Run tests (push) Successful in 2m3s
2026-06-22 20:08:18 +02:00
lorenz.stechauner d0ce377d92 AppDbContext: Fix FetchMembers when using for specific MgNr
Test / Run tests (push) Successful in 2m59s
2026-06-22 20:06:34 +02:00
lorenz.stechauner f8b3147c72 Tests: Update dependencies
Test / Run tests (push) Successful in 2m52s
2026-06-18 12:25:22 +02:00
lorenz.stechauner b4ab8349b4 Elwig: Update dependencies 2026-06-18 12:25:09 +02:00
lorenz.stechauner 5db5876905 Installer: Bundle and ship source code together with binaries
Test / Run tests (push) Successful in 3m14s
2026-05-01 15:10:19 +02:00
lorenz.stechauner 0617726139 Bump version to 1.0.5.3
Test / Run tests (push) Successful in 2m7s
Deploy / Build and Deploy (push) Successful in 2m13s
2026-04-29 11:42:05 +02:00
lorenz.stechauner 9dfe71d6d0 DeliveryConfirmation: Adapt spacing between rows to CreditNote
Test / Run tests (push) Successful in 2m52s
2026-04-29 11:37:09 +02:00
lorenz.stechauner 72155fc54e Documents: Fix error because of modifiers in CreditNote and DeliveryConfirmation 2026-04-29 11:29:16 +02:00
lorenz.stechauner 61bdb2f3b5 Bump version to 1.0.5.2
Test / Run tests (push) Successful in 2m15s
Deploy / Build and Deploy (push) Successful in 2m0s
2026-04-24 10:27:37 +02:00
lorenz.stechauner 2915f08a6b Elwig: Update dependencies
Test / Run tests (push) Successful in 3m7s
2026-04-24 09:49:06 +02:00
lorenz.stechauner 5c2fae1855 DeliveryAdminWindow: Fix attributes and cultivations in DeliveryPartList 2026-04-24 09:48:14 +02:00
lorenz.stechauner 95fabe3633 Bump version to 1.0.5.1
Test / Run tests (push) Successful in 2m25s
Deploy / Build and Deploy (push) Successful in 2m14s
2026-04-20 19:23:01 +02:00
lorenz.stechauner 7861a15e2e Test: Update dependencies
Test / Run tests (push) Successful in 2m20s
2026-04-20 15:12:29 +02:00
lorenz.stechauner 20fd5d5826 Elwig: Update dependencies 2026-04-20 15:12:29 +02:00
lorenz.stechauner 2b3c293730 Database: Adapt to changes for examples in WLNS 2026-04-20 15:12:22 +02:00
lorenz.stechauner a852dbb242 PaymentVariantSummary: Fix price display when null 2026-04-20 15:05:09 +02:00
lorenz.stechauner 7edf395497 CreditNote: Fix padding for Rbl. 2026-04-20 14:21:13 +02:00
lorenz.stechauner ea2b6db1fc Billing: Fix modifiers with absolute amounts 2026-04-20 14:20:43 +02:00
lorenz.stechauner cf48f005e2 DeliveryAdminWindow: Fix missing LostFocus for gradation inputs
Test / Run tests (push) Successful in 2m54s
2026-04-08 17:18:40 +02:00
lorenz.stechauner 4eac8cd629 DeliveryAdminWindow: Fix modifiers for bulk actions 2026-04-08 17:18:08 +02:00
lorenz.stechauner 360856585a Bump version to 1.0.5.0
Test / Run tests (push) Successful in 1m54s
Deploy / Build and Deploy (push) Successful in 2m14s
2026-04-08 00:47:15 +02:00
lorenz.stechauner cc6e31a006 Installer/Setup: Update to WiX 7 2026-04-08 00:31:00 +02:00
lorenz.stechauner ce1a55df86 Tests: Update dependencies
Test / Run tests (push) Successful in 2m1s
2026-04-07 23:57:52 +02:00
lorenz.stechauner 07d93dd384 Elwig: Update dependencies 2026-04-07 23:57:40 +02:00
lorenz.stechauner f6e9d429d5 [#77] Export/ElwigData: Fix import of AreaComContracts
Test / Run tests (push) Successful in 2m41s
2026-04-07 23:51:32 +02:00
lorenz.stechauner 7b78f9d6b9 [#79] Windows: Fix errors unconvered by E2E tests
Test / Run tests (push) Successful in 2m12s
2026-04-07 12:34:38 +02:00
lorenz.stechauner 22fbb0772f MailWindow: Fix MessageBox and ProgressBar
Test / Run tests (push) Successful in 2m11s
2026-04-07 12:16:50 +02:00
lorenz.stechauner 0a9c800116 BusinessDocument: Add DateFrom to be used for ShowDateAndLocation
Test / Run tests (push) Successful in 2m0s
2026-04-07 12:06:06 +02:00
lorenz.stechauner 278d79429b [#79] DeliveryAdminWindow: Cache modifiers 2026-04-07 11:15:56 +02:00
lorenz.stechauner e5e5e10cd7 ContextWindow: Add HasContextLoaded property 2026-04-07 11:15:34 +02:00
lorenz.stechauner d051a2bfcf [#79] AppDbContext: Use compiled queries 2026-04-07 11:15:14 +02:00
lorenz.stechauner 9c39a2f820 [#79] Entities: Remove EF proxies 2026-04-07 11:14:20 +02:00
lorenz.stechauner 4460de9975 [#77] Entities: Add AreaComContract to group area commitments together 2026-04-07 11:13:54 +02:00
lorenz.stechauner f96ebdcf60 DeliveryAdminWindow: Fix creation of new deliveries
Test / Run tests (push) Successful in 2m2s
2026-04-02 20:58:01 +02:00
lorenz.stechauner e593175e72 ContextWindow: Use Task.Run to load data outside main thread
Test / Run tests (push) Successful in 2m29s
2026-04-02 14:18:06 +02:00
lorenz.stechauner 1f4fe2129d Bump version to 1.0.4.1
Deploy / Build and Deploy (push) Successful in 1m49s
2026-03-27 12:29:28 +01:00
135 changed files with 5423 additions and 2868 deletions
+10
View File
@@ -23,6 +23,16 @@ jobs:
echo "No files with BOM found" echo "No files with BOM found"
exit 0 exit 0
} }
- name: Check for code smells
shell: powershell
run: |
git grep -IEn "\.(Single|First|Min|Max|Any)(OrDefault)?Async\([^)]|^using System.Data.Entity;"
if ( $lastexitcode -ne 1 ) {
exit 1
} else {
echo "No files with code smells found"
exit 0
}
- name: Setup MSBuild - name: Setup MSBuild
uses: microsoft/setup-msbuild@v1.1 uses: microsoft/setup-msbuild@v1.1
- name: Setup NuGet - name: Setup NuGet
+1
View File
@@ -7,3 +7,4 @@ Tests/Resources/Sql/Create.sql
*.exe *.exe
!WinziPrint.exe !WinziPrint.exe
*.sqlite3 *.sqlite3
*.zip
+166
View File
@@ -2,6 +2,172 @@
Changelog Changelog
========= =========
[v1.1.0.0][v1.1.0.0] (2026-07-09) {#v1.1.0.0}
---------------------------------------------
### Neue Funktionen {#v1.1.0.0-features}
* Per Opt-In Einstellung in den Stammdaten ist es nun möglich Mitgliederbewegungen und Verläufe von Geschäftsanteilen mit Elwig zu erfassen. ([#20][i20])
* Es wird nun unterstützt verschiedene Typen von Geschäftsanteilen pro Mitglied zu erfassen (normal, rot, weiß, ruhend). ([#80][i80])
### Behobene Fehler {#v1.1.0.0-bugfixes}
* Falls die Datenbank für die momentan verwndete Elwig-Version zu neu war kam es beim Überprüfen auf ein Update zu einem Fehler. (4ebe07f579)
* Im Stammdatenblatt (`MemberDataSheet`) wurde die Stamm-Zweigstelle nicht angeführt. (a71c41af5c)
### Sonstiges {#v1.1.0.0-misc}
* In der Buchungsliste (`CreditNoteData`) wird nun auch das Buchhaltungskonto der Mitglieder angeführt. (000117dc67)
* Viele kleine Verbesserungen der Code-Qualität. (u.a. fcd0555e4d, 69efca1cc3, beacba6bd9, 1169ba5101)
* Abhängigkeiten aktualisiert. (e8789aff37, 2350b55cea)
[v1.1.0.0]: https://git.necronda.net/winzer/elwig/releases/tag/v1.1.0.0
[i20]: https://git.necronda.net/winzer/elwig/issues/20
[i80]: https://git.necronda.net/winzer/elwig/issues/80
[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}
---------------------------------------------
### Behobene Fehler {#v1.0.4.1-bugfixes}
* In der Anlieferungsbestätigung (`DeliveryConfirmation`) war in einer Spalte der Text nicht rechtsbündig. (0aefab5d63)
* Die zweite Zeile des Absenders wurde nicht mehr abgedruckt und der Briefkopf (`Letterhead`) beinhaltete zu viele Informationen. (3c52156b7e)
### Sonstiges {#v1.0.4.1-misc}
* Evtl. wurden bei Änderungen in der Datenbank unnötigerweise einige Daten in Elwig doppelt angefordert. (cc018ded10)
* Massenaktionen im Lieferungen-Fenster (`DeliveryAdminWindow`) sind nun nicht mehr während dem Bearbeiten oder Erstellen möglich. (b1075d1e69)
* Das Datum auf Lieferscheinen (`DeliveryNote`) ist nun statt des heutigen, das Datum der letzten Änderung der Lieferung. (982a6616e1)
* Sollte es im Rundschreiben-Fenster (`MailWindow`) zu einem Fehler während dem Bereinigen der Dokumenten kommen wird dieser ignoriert. (ae0a082421)
* Abhängigkeiten aktualisiert. (ddfc86197d, cdb4b0a2bd)
[v1.0.4.1]: https://git.necronda.net/winzer/elwig/releases/tag/v1.0.4.1
[v1.0.4.0][v1.0.4.0] (2026-03-16) {#v1.0.4.0} [v1.0.4.0][v1.0.4.0] (2026-03-16) {#v1.0.4.0}
--------------------------------------------- ---------------------------------------------
+29 -23
View File
@@ -5,7 +5,9 @@ using Elwig.Helpers.Export;
using Elwig.Helpers.Printing; using Elwig.Helpers.Printing;
using Elwig.Helpers.Weighing; using Elwig.Helpers.Weighing;
using Elwig.Models.Entities; using Elwig.Models.Entities;
using Elwig.Services;
using Elwig.Windows; using Elwig.Windows;
using Microsoft.EntityFrameworkCore;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data; using System.Data;
@@ -90,11 +92,11 @@ namespace Elwig {
try { try {
await AppDbUpdater.CheckDb(); await AppDbUpdater.CheckDb();
} catch (Exception e) { } catch (Exception exc) {
if (Config.UpdateUrl != null && Utils.HasInternetConnectivity()) { if (Config.UpdateUrl != null && Utils.HasInternetConnectivity()) {
await CheckForUpdates(); await CheckForUpdates();
} }
MessageBox.Show($"Invalid Database:\n\n{e.Message}", "Invalid Database", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException("Fehlerhafte Datenbank", "Fehlerhafte Datenbank", exc);
Shutdown(); Shutdown();
return; return;
} }
@@ -104,11 +106,13 @@ namespace Elwig {
Dictionary<string, (string, string, int?, string?, string?, string?, string?, string?)> branches = []; Dictionary<string, (string, string, int?, string?, string?, string?, string?, string?)> branches = [];
using (var ctx = new AppDbContext()) { using (var ctx = new AppDbContext()) {
branches = ctx.Branches.ToDictionary(b => b.Name.ToLower(), b => (b.ZwstId, b.Name, b.PostalDest?.AtPlz?.Plz, b.PostalDest?.AtPlz?.Ort.Name, b.Address, b.PhoneNr, b.FaxNr, b.MobileNr)); branches = ctx.FetchBranches()
.ToDictionaryAsync(b => b.Name.ToLower(), b => (b.ZwstId, b.Name, b.PostalDest?.AtPlz?.Plz, b.PostalDest?.AtPlz?.Ort.Name, b.Address, b.PhoneNr, b.FaxNr, b.MobileNr))
.GetAwaiter().GetResult();
try { try {
Client = new(ctx); Client = new(ctx);
} catch (Exception e) { } catch (Exception exc) {
MessageBox.Show($"Fehler beim Laden der Mandantendaten:\n\n{e.Message}", "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException("Fehler", "Fehler beim Laden der Mandantendaten", exc);
Shutdown(); Shutdown();
return; return;
} }
@@ -142,18 +146,17 @@ namespace Elwig {
foreach (var s in Config.Scales) { foreach (var s in Config.Scales) {
try { try {
list.Add(Scale.FromConfig(s)); list.Add(Scale.FromConfig(s));
} catch (Exception e) { } catch (Exception exc) {
list.Add(new InvalidScale(s.Id)); list.Add(new InvalidScale(s.Id));
if (s.Required) if (s.Required)
MessageBox.Show($"Verbindung zu Waage {s.Id} konnte nicht hergestellt werden:\n\n{e.Message}", "Waagenfehler", InteractionService.ShowException("Waagenfehler", $"Verbindung zu Waage {s.Id} konnte nicht hergestellt werden", exc);
MessageBoxButton.OK, MessageBoxImage.Error);
} }
} }
Scales = list; Scales = list;
if (Config.Branch != null) { if (Config.Branch != null) {
if (!branches.ContainsKey(Config.Branch.ToLower())) { if (!branches.ContainsKey(Config.Branch.ToLower())) {
MessageBox.Show("Ungültige Zweigstelle in Konfigurationsdatei!", "Ungültige Zweigstelle", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowError("Ungültige Zweigstelle", "Ungültige Zweigstelle in Konfigurationsdatei!");
Shutdown(); Shutdown();
} else { } else {
SetBranch(branches[Config.Branch.ToLower()]); SetBranch(branches[Config.Branch.ToLower()]);
@@ -161,7 +164,7 @@ namespace Elwig {
} else if (branches.Count == 1) { } else if (branches.Count == 1) {
SetBranch(branches.First().Value); SetBranch(branches.First().Value);
} else { } else {
MessageBox.Show("Erkennen der lokalen Zweigstelle nicht möglich!", "Ungültige Zweigstelle", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowError("Ungültige Zweigstelle", "Erkennen der lokalen Zweigstelle nicht möglich!");
Shutdown(); Shutdown();
} }
@@ -198,6 +201,7 @@ namespace Elwig {
BranchName = entry.Item2; BranchName = entry.Item2;
BranchPlz = entry.Item3; BranchPlz = entry.Item3;
BranchLocation = entry.Item4? BranchLocation = entry.Item4?
.Split(",")[0]
.Split(" in ")[0] .Split(" in ")[0]
.Split(" im ")[0] .Split(" im ")[0]
.Split(" an ")[0] .Split(" an ")[0]
@@ -218,7 +222,8 @@ namespace Elwig {
MainDispatcher.Invoke(() => { MainDispatcher.Invoke(() => {
foreach (Window w in CurrentApp.Windows) { foreach (Window w in CurrentApp.Windows) {
if (w is not ContextWindow c) continue; if (w is not ContextWindow c) continue;
MainDispatcher.BeginInvoke(c.HintContextChange); MainDispatcher.Invoke(c.HintContextChange);
MainDispatcher.BeginInvoke(c.TryContextReload);
} }
}); });
} }
@@ -249,14 +254,13 @@ namespace Elwig {
if (Scales[i] is InvalidScale) { if (Scales[i] is InvalidScale) {
try { try {
Scales[i] = Scale.FromConfig(s); Scales[i] = Scale.FromConfig(s);
MessageBox.Show($"Verbindung zu Waage {s.Id} wieder hergestellt!", $"Waage {s.Id}", MessageBoxButton.OK, MessageBoxImage.Information); InteractionService.ShowInformation($"Waage {s.Id}", $"Verbindung zu Waage {s.Id} wieder hergestellt!");
} catch (Exception e) { } catch (Exception exc) {
Scales[i] = new InvalidScale(s.Id); Scales[i] = new InvalidScale(s.Id);
MessageBox.Show($"Verbindung zu Waage {s.Id} konnte nicht hergestellt werden:\n\n{e.Message}", "Waagenfehler", InteractionService.ShowException("Waagenfehler", $"Verbindung zu Waage {s.Id} konnte nicht hergestellt werden", exc);
MessageBoxButton.OK, MessageBoxImage.Error);
} }
} else if (Scales[i] is IEventScale) { } else if (Scales[i] is IEventScale) {
MessageBox.Show($"Verbindung zu Waage {s.Id} wieder hergestellt!", $"Waage {s.Id}", MessageBoxButton.OK, MessageBoxImage.Information); InteractionService.ShowInformation($"Waage {s.Id}", $"Verbindung zu Waage {s.Id} wieder hergestellt!");
} }
} }
} }
@@ -267,7 +271,7 @@ namespace Elwig {
for (var i = 0; i < Config.Scales.Count; i++) { for (var i = 0; i < Config.Scales.Count; i++) {
var s = Config.Scales[i]; var s = Config.Scales[i];
if ((s.Connection?.StartsWith($"serial://{name}:") ?? false) && Scales[i] is not InvalidScale) { if ((s.Connection?.StartsWith($"serial://{name}:") ?? false) && Scales[i] is not InvalidScale) {
MessageBox.Show($"Verbindung zu Waage {s.Id} unterbrochen!", $"Waagen {s.Id}", MessageBoxButton.OK, MessageBoxImage.Warning); InteractionService.ShowWarning($"Waagen {s.Id}", $"Verbindung zu Waage {s.Id} unterbrochen!");
if (Scales[i] is ICommandScale) { if (Scales[i] is ICommandScale) {
try { try {
Scales[i].Dispose(); Scales[i].Dispose();
@@ -302,11 +306,9 @@ namespace Elwig {
}); });
} else if (showAlert) { } else if (showAlert) {
if (latest == null) { if (latest == null) {
MessageBox.Show("Informationen konnten nicht abgerufen werden!", "Nach Updates suchen", InteractionService.ShowError("Nach Updates suchen", "Informationen konnten nicht abgerufen werden!");
MessageBoxButton.OK, MessageBoxImage.Error);
} else { } else {
MessageBox.Show($"Elwig ist auf dem aktuellsten Stand! (Version: {latest.Value.Version})", "Nach Updates suchen", InteractionService.ShowInformation("Nach Updates suchen", $"Elwig ist auf dem aktuellsten Stand! (Version: {latest.Value.Version})");
MessageBoxButton.OK, MessageBoxImage.Information);
} }
} }
} }
@@ -316,11 +318,11 @@ namespace Elwig {
await Task.Run(async () => { await Task.Run(async () => {
await Database.Import(filename); await Database.Import(filename);
}); });
MessageBox.Show("Das Ersetzen war erfolgreich!\n\nBitte starten Sie Elwig neu!", "Datenbank ersetzen", MessageBoxButton.OK, MessageBoxImage.Information); InteractionService.ShowInformation("Datenbank ersetzen", "Das Ersetzen war erfolgreich!\n\nBitte starten Sie Elwig neu!");
ForceShutdown = true; ForceShutdown = true;
Current.Shutdown(); Current.Shutdown();
} catch (Exception exc) { } catch (Exception exc) {
MessageBox.Show("Fehler beim Ersetzen:\n\n" + exc.Message, "Datenbank ersetzen", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException("Datenbank ersetzen", "Fehler beim Ersetzen", exc);
} }
} }
@@ -342,6 +344,10 @@ namespace Elwig {
return FocusWindow<DeliveryAdminWindow>(() => new(true), w => w.ViewModel.IsReceipt); return FocusWindow<DeliveryAdminWindow>(() => new(true), w => w.ViewModel.IsReceipt);
} }
public static MemberBusinessSharesAdminWindow FocusMemberBusinessSharesWindow(int mgnr) {
return FocusWindow<MemberBusinessSharesAdminWindow>(() => new(mgnr), w => w.ViewModel.FilterMember?.MgNr == mgnr);
}
public static DeliveryAdminWindow FocusMemberDeliveries(int mgnr) { public static DeliveryAdminWindow FocusMemberDeliveries(int mgnr) {
return FocusWindow<DeliveryAdminWindow>(() => new(mgnr), w => w.ViewModel.FilterMember?.MgNr == mgnr); return FocusWindow<DeliveryAdminWindow>(() => new(mgnr), w => w.ViewModel.FilterMember?.MgNr == mgnr);
} }
+1 -1
View File
@@ -122,7 +122,7 @@ namespace Elwig.Controls {
private void OnSelectionChanged(object sender, SelectionChangedEventArgs evt) { private void OnSelectionChanged(object sender, SelectionChangedEventArgs evt) {
SelectItemsReverse(); SelectItemsReverse();
var dmp = !string.IsNullOrEmpty(ListDisplayMemberPath) ? ListDisplayMemberPath : !string.IsNullOrEmpty(DisplayMemberPath) ? DisplayMemberPath : null; var dmp = !string.IsNullOrWhiteSpace(ListDisplayMemberPath) ? ListDisplayMemberPath : !string.IsNullOrWhiteSpace(DisplayMemberPath) ? DisplayMemberPath : null;
if (SelectedItems.Count == ItemsSource.Cast<object>().Count() && AllItemsSelectedContent != null) { if (SelectedItems.Count == ItemsSource.Cast<object>().Count() && AllItemsSelectedContent != null) {
AllItemsSelected = true; AllItemsSelected = true;
} else if (SelectedItems.Count == 0) { } else if (SelectedItems.Count == 0) {
+11 -2
View File
@@ -41,13 +41,21 @@ namespace Elwig.Controls {
incButton!.Click += IncrementButton_Click; incButton!.Click += IncrementButton_Click;
decButton!.Click += DecrementButton_Click; decButton!.Click += DecrementButton_Click;
base.OnApplyTemplate(); base.OnApplyTemplate();
UpdateButtons();
}
private void UpdateButtons() {
var incButton = GetTemplateChild("IncrementButton") as RepeatButton;
var decButton = GetTemplateChild("DecrementButton") as RepeatButton;
incButton?.IsEnabled = Maximum == null || Value < Maximum;
decButton?.IsEnabled = Minimum == null || Value > Minimum;
} }
private void IntegerUpDown_TextChanged(object sender, TextChangedEventArgs evt) { private void IntegerUpDown_TextChanged(object sender, TextChangedEventArgs evt) {
var idx = CaretIndex; var idx = CaretIndex;
Text = new string(Text.Where(char.IsAsciiDigit).Take(4).ToArray()); Text = new string([.. Text.Where(char.IsAsciiDigit).Take(4)]);
CaretIndex = idx; CaretIndex = idx;
evt.Handled = !(Value >= Minimum && Value <= Maximum); evt.Handled = !((!Minimum.HasValue || Value >= Minimum) && (!Maximum.HasValue || Value <= Maximum));
if (idx >= 4) { if (idx >= 4) {
if (Value < Minimum) { if (Value < Minimum) {
Value = Minimum; Value = Minimum;
@@ -56,6 +64,7 @@ namespace Elwig.Controls {
} }
CaretIndex = 4; CaretIndex = 4;
} }
UpdateButtons();
} }
private void IntegerUpDown_LostFocus(object sender, RoutedEventArgs evt) { private void IntegerUpDown_LostFocus(object sender, RoutedEventArgs evt) {
+9 -4
View File
@@ -1,4 +1,5 @@
using Elwig.Helpers; using Elwig.Helpers;
using System;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
@@ -12,23 +13,27 @@ namespace Elwig.Dialogs {
public string OrigYearTo { get; set; } public string OrigYearTo { get; set; }
public string Area { get; set; } public string Area { get; set; }
public AreaComModifyDialog(int? yearFrom, int? yearTo, int area, bool delete) { public AreaComModifyDialog(int? yearFrom, int? yearTo, int area, bool delete, bool forceRetroactive = false) {
Area = $"{area:N0}"; Area = $"{area:N0}";
OrigYearFrom = $"{yearFrom}"; OrigYearFrom = $"{yearFrom}";
OrigYearTo = $"{yearTo}"; OrigYearTo = $"{yearTo}";
InitializeComponent(); InitializeComponent();
Title = delete ? "Flächenbindung löschen" : "Flächenbindung bearbeiten"; Title = delete ? "Flächenbindung löschen" : "Flächenbindung bearbeiten";
RetroactiveInput.Content = delete ? "Rückwirkend löschen" : "Rückwirkend bearbeiten"; RetroactiveInput.Content = delete ? "Rückwirkend löschen" : "Rückwirkend bearbeiten";
forceRetroactive = forceRetroactive || yearFrom.HasValue && yearTo.HasValue && yearFrom.Value == yearTo.Value;
RetroactiveInput.IsEnabled = !forceRetroactive;
if (delete) { if (delete) {
QuestionBlock1.Visibility = Visibility.Hidden; QuestionBlock1.Visibility = Visibility.Hidden;
QuestionBlock2.Visibility = Visibility.Visible; QuestionBlock2.Visibility = Visibility.Visible;
DescBlock1.Visibility = Visibility.Hidden; DescBlock1.Visibility = Visibility.Hidden;
DescBlock2.Visibility = Visibility.Visible; DescBlock2.Visibility = Visibility.Visible;
} }
if ((yearTo.HasValue && yearTo < Utils.CurrentNextSeason) || (yearFrom.HasValue && yearFrom >= Utils.CurrentNextSeason)) { SeasonInput.Minimum = yearFrom.HasValue ? yearFrom + 1 : null;
SeasonInput.Maximum = yearTo.HasValue ? yearTo : null;
if (forceRetroactive || (yearTo.HasValue && yearTo < Utils.CurrentYear) || (yearFrom.HasValue && yearFrom >= Utils.CurrentYear)) {
RetroactiveInput.IsChecked = true; RetroactiveInput.IsChecked = true;
} else { } else {
SeasonInput.Text = $"{Utils.CurrentNextSeason}"; SeasonInput.Text = $"{Utils.CurrentYear}";
} }
} }
@@ -48,7 +53,7 @@ namespace Elwig.Dialogs {
DescBlock2.Visibility = Visibility.Hidden; DescBlock2.Visibility = Visibility.Hidden;
} else { } else {
SeasonInput.IsEnabled = true; SeasonInput.IsEnabled = true;
SeasonInput.Text = $"{Utils.CurrentNextSeason}"; SeasonInput.Text = $"{Math.Max(SeasonInput.Minimum ?? Utils.CurrentYear, Utils.CurrentYear)}";
DescBlock1.Visibility = QuestionBlock1.Visibility; DescBlock1.Visibility = QuestionBlock1.Visibility;
DescBlock2.Visibility = QuestionBlock2.Visibility; DescBlock2.Visibility = QuestionBlock2.Visibility;
} }
+2 -6
View File
@@ -8,7 +8,7 @@
ResizeMode="NoResize" ShowInTaskbar="False" Topmost="True" ResizeMode="NoResize" ShowInTaskbar="False" Topmost="True"
WindowStartupLocation="CenterOwner" WindowStartupLocation="CenterOwner"
DataContext="{Binding RelativeSource={RelativeSource Self}}" DataContext="{Binding RelativeSource={RelativeSource Self}}"
Title="Flächenbindungen übertragen" Height="260" Width="450"> Title="Flächenbindungen übertragen" Height="240" Width="450">
<Window.Resources> <Window.Resources>
<Style TargetType="Label"> <Style TargetType="Label">
<Setter Property="HorizontalAlignment" Value="Left"/> <Setter Property="HorizontalAlignment" Value="Left"/>
@@ -48,12 +48,8 @@
Minimum="1900" Maximum="9999" Minimum="1900" Maximum="9999"
HorizontalAlignment="Center" VerticalAlignment="Top" HorizontalAlignment="Center" VerticalAlignment="Top"
TextChanged="SeasonInput_TextChanged"/> TextChanged="SeasonInput_TextChanged"/>
<CheckBox x:Name="CopyYearToInput" Content="Beginn der Laufzeit von Vorgänger übernehmen" Margin="0,80,0,0"
HorizontalAlignment="Center" VerticalAlignment="Top"
Checked="CopyYearToInput_Changed" Unchecked="CopyYearToInput_Changed"
IsChecked="{Binding MaintainYearFrom}"/>
<TextBlock x:Name="DescBlock1" Margin="0,105,0,0" TextAlignment="Center" <TextBlock x:Name="DescBlock1" Margin="0,90,0,0" TextAlignment="Center"
HorizontalAlignment="Center" VerticalAlignment="Top"> HorizontalAlignment="Center" VerticalAlignment="Top">
Die Flächenbindungen beim <Bold>Vorgänger</Bold> sind bis inkl. Saison <Bold><Run x:Name="CancelSeason1"/></Bold> gültig,<LineBreak/> Die Flächenbindungen beim <Bold>Vorgänger</Bold> sind bis inkl. Saison <Bold><Run x:Name="CancelSeason1"/></Bold> gültig,<LineBreak/>
und werden beim <Bold>Nachfolger</Bold> ab <Run x:Name="DescBlock1Season" Text="inkl. Saison "/><Bold><Run x:Name="TransferSeason"/></Bold> übernommen. und werden beim <Bold>Nachfolger</Bold> ab <Run x:Name="DescBlock1Season" Text="inkl. Saison "/><Bold><Run x:Name="TransferSeason"/></Bold> übernommen.
+13 -13
View File
@@ -5,51 +5,51 @@ using System.Windows.Controls;
namespace Elwig.Dialogs { namespace Elwig.Dialogs {
public partial class AreaComTransferDialog : Window { public partial class AreaComTransferDialog : Window {
public int CancelSeason { get; set; } public int CancelSeason => SuccessorSeason - 1;
public int SuccessorSeason => CancelSeason + 1; public int SuccessorSeason { get; set; }
public bool MaintainYearFrom { get; set; }
public string AreaComNum { get; set; } public string AreaComNum { get; set; }
public string Area { get; set; } public string Area { get; set; }
public AreaComTransferDialog(string name, int areaComNum, int area) { public AreaComTransferDialog(string name, int areaComNum, int area) {
CancelSeason = Utils.FollowingSeason - 1; SuccessorSeason = Utils.FollowingSeason;
AreaComNum = $"{areaComNum:N0}"; AreaComNum = $"{areaComNum:N0}";
Area = $"{area:N0}"; Area = $"{area:N0}";
InitializeComponent(); InitializeComponent();
SeasonInput.Text = $"{CancelSeason}"; SeasonInput.Text = $"{SuccessorSeason}";
SeasonInput.Minimum = Utils.CurrentLastSeason;
Title = $"Aktive Flächenbindungen kündigen - {name}"; Title = $"Aktive Flächenbindungen kündigen - {name}";
QuestionBlock1.Visibility = Visibility.Hidden; QuestionBlock1.Visibility = Visibility.Hidden;
QuestionBlock2.Visibility = Visibility.Visible; QuestionBlock2.Visibility = Visibility.Visible;
DescBlock1.Visibility = Visibility.Hidden; DescBlock1.Visibility = Visibility.Hidden;
DescBlock2.Visibility = Visibility.Visible; DescBlock2.Visibility = Visibility.Visible;
CopyYearToInput.Visibility = Visibility.Hidden;
Height = 240; Height = 240;
SeasonInput.Margin = new(0, 40, 0, 0); SeasonInput.Margin = new(0, 40, 0, 0);
SeasonLabel.Margin = new(0, 40, 100, 0); SeasonLabel.Margin = new(0, 40, 100, 0);
} }
public AreaComTransferDialog(string name, string successorName, int areaComNum, int area) { public AreaComTransferDialog(string name, string successorName, int areaComNum, int area) {
CancelSeason = Utils.FollowingSeason - 1; SuccessorSeason = Utils.FollowingSeason;
AreaComNum = $"{areaComNum:N0}"; AreaComNum = $"{areaComNum:N0}";
Area = $"{area:N0}"; Area = $"{area:N0}";
InitializeComponent(); InitializeComponent();
SeasonInput.Text = $"{CancelSeason}"; SeasonInput.Text = $"{SuccessorSeason}";
SeasonInput.Minimum = Utils.CurrentLastSeason;
Title = $"Aktive Flächenbindungen übertragen - {name} - {successorName}"; Title = $"Aktive Flächenbindungen übertragen - {name} - {successorName}";
InfoBlock.Visibility = Visibility.Hidden; InfoBlock.Visibility = Visibility.Hidden;
} }
private void SeasonInput_TextChanged(object sender, TextChangedEventArgs evt) { private void SeasonInput_TextChanged(object sender, TextChangedEventArgs evt) {
CancelSeason = (int)SeasonInput.Value!; SuccessorSeason = (int)SeasonInput.Value!;
CancelSeason1.Text = $"{CancelSeason}"; CancelSeason1.Text = $"{CancelSeason}";
CancelSeason2.Text = $"{CancelSeason}"; CancelSeason2.Text = $"{CancelSeason}";
TransferSeason.Text = MaintainYearFrom ? "" : $"{SuccessorSeason}"; TransferSeason.Text = $"{SuccessorSeason}";
DescBlock1Season.Text = MaintainYearFrom ? "dem originalen Beginn der FB" : "inkl. Saison "; DescBlock1Season.Text = "inkl. Saison ";
} }
private void CopyYearToInput_Changed(object sender, RoutedEventArgs evt) { private void CopyYearToInput_Changed(object sender, RoutedEventArgs evt) {
TransferSeason.Text = MaintainYearFrom ? "" : $"{SuccessorSeason}"; TransferSeason.Text = $"{SuccessorSeason}";
DescBlock1Season.Text = MaintainYearFrom ? "dem originalen Beginn der FB" : "inkl. Saison "; DescBlock1Season.Text = "inkl. Saison ";
} }
private void ConfirmButton_Click(object sender, RoutedEventArgs evt) { private void ConfirmButton_Click(object sender, RoutedEventArgs evt) {
@@ -44,15 +44,10 @@ namespace Elwig.Dialogs {
} }
protected override async Task OnRenewContext(AppDbContext ctx) { protected override async Task OnRenewContext(AppDbContext ctx) {
ControlUtils.RenewItemsSource(MemberInput, await ctx.Members ControlUtils.RenewItemsSource(MemberInput, await ctx.FetchMembers().ToListAsync());
.Where(m => m.IsActive)
.OrderBy(m => m.Name)
.ThenBy(m => m.GivenName)
.ToListAsync());
ControlUtils.RenewItemsSource(DeliveryInput, await ctx.Deliveries ControlUtils.RenewItemsSource(DeliveryInput, await ctx.Deliveries
.Where(d => d.DateString == $"{_delivery.Date:yyyy-MM-dd}" && d.ZwstId == _delivery.ZwstId) .Where(d => d.DateString == $"{_delivery.Date:yyyy-MM-dd}" && d.ZwstId == _delivery.ZwstId)
.OrderBy(d => d.LsNr) .OrderBy(d => d.LsNr)
.Include(d => d.Member)
.Include(d => d.Parts) .Include(d => d.Parts)
.ToListAsync()); .ToListAsync());
if (DeliveryInput.SelectedItem == null) if (DeliveryInput.SelectedItem == null)
+2 -1
View File
@@ -1,4 +1,5 @@
using Elwig.Helpers; using Elwig.Helpers;
using Elwig.Services;
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
@@ -51,7 +52,7 @@ namespace Elwig.Dialogs {
File.Delete(fileName); File.Delete(fileName);
return; return;
} catch (Exception exc) { } catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException(exc);
} }
Process.Start(fileName); Process.Start(fileName);
DialogResult = true; DialogResult = true;
+21 -7
View File
@@ -18,10 +18,12 @@ namespace Elwig.Documents {
public class BusinessDocument : Document { public class BusinessDocument : Document {
public Member Member; public Member Member;
public MemberHistoryPoint MemberShares;
public string? Location; public string? Location;
public bool IncludeSender = false; public bool IncludeSender = false;
public bool UseBillingAddress = false; public bool UseBillingAddress = false;
public bool ShowDateAndLocation = false; public bool ShowDateAndLocation = false;
public DateOnly? DateFrom;
protected Table? Aside; protected Table? Aside;
public string Address { public string Address {
@@ -47,11 +49,13 @@ namespace Elwig.Documents {
return NewAsideCell(new KernedParagraph(text, 10), colspan, isName); return NewAsideCell(new KernedParagraph(text, 10), colspan, isName);
} }
public BusinessDocument(string title, Member m, bool includeSender = false) : public BusinessDocument(string title, Member m, DateOnly? dateFrom, bool includeSender = false) :
base(title) { base(title) {
Member = m; Member = m;
MemberShares = new(m.Shares, m.SharesRed, m.SharesWhite, m.SharesDormant);
Location = App.BranchLocation; Location = App.BranchLocation;
IncludeSender = includeSender; IncludeSender = includeSender;
DateFrom = dateFrom;
} }
protected override void BeforeRenderBody(iText.Layout.Document doc, PdfDocument pdf) { protected override void BeforeRenderBody(iText.Layout.Document doc, PdfDocument pdf) {
@@ -105,7 +109,7 @@ namespace Elwig.Documents {
} }
} }
doc.Add(new KernedParagraph(ShowDateAndLocation ? $"{Location}, am {Date:dd.MM.yyyy}" : "", 12).SetTextAlignment(TextAlignment.RIGHT).SetVerticalAlignment(VerticalAlignment.MIDDLE).SetHeight(24).SetMargin(0)); doc.Add(new KernedParagraph(ShowDateAndLocation ? $"{Location}, am {DateFrom ?? Date:dd.MM.yyyy}" : "", 12).SetTextAlignment(TextAlignment.RIGHT).SetVerticalAlignment(VerticalAlignment.MIDDLE).SetHeight(24).SetMargin(0));
doc.Add(new KernedParagraph(Title, 12).SetFont(BF).SetMargins(0, 0, 12, 0)); doc.Add(new KernedParagraph(Title, 12).SetFont(BF).SetMargins(0, 0, 12, 0));
} }
@@ -261,7 +265,7 @@ namespace Elwig.Documents {
} }
protected Table NewBucketTable( protected Table NewBucketTable(
Season season, Dictionary<string, MemberBucket> buckets, Season season, Dictionary<string, MemberBucket> buckets, int deliveredWeightRed, int deliveredWeightWhite,
bool includeDelivery = true, bool includePayment = false, bool includeDelivery = true, bool includePayment = false,
bool isTiny = false, IEnumerable<string>? filter = null bool isTiny = false, IEnumerable<string>? filter = null
) { ) {
@@ -314,11 +318,21 @@ namespace Elwig.Documents {
.Where(b => !fbVars.Contains(b.Key)) .Where(b => !fbVars.Contains(b.Key))
.OrderBy(b => b.Value.Name); .OrderBy(b => b.Value.Name);
if (MemberShares.Shares != 0 || (MemberShares.SharesRed == 0 && MemberShares.SharesWhite == 0)) {
tbl.AddCell(NewBucketTh("Gesamtlieferung lt. gez. GA", isTiny: isTiny)); tbl.AddCell(NewBucketTh("Gesamtlieferung lt. gez. GA", isTiny: isTiny));
tbl.AddCells(FormatRow(Member.BusinessShares * season.MinKgPerBusinessShare, tbl.AddCells(FormatRow(MemberShares.Shares * (season.MinKgPerShare ?? 0), MemberShares.Shares * (season.MaxKgPerShare ?? 0),
Member.BusinessShares * season.MaxKgPerBusinessShare, deliveredWeightRed + deliveredWeightWhite, isGa: true, showPayment: includePayment, showArea: !includeDelivery, isTiny: isTiny));
season.Deliveries.Where(d => d.MgNr == Member.MgNr).Sum(d => d.Weight), }
isGa: true, showPayment: includePayment, showArea: !includeDelivery, isTiny: isTiny));
if (MemberShares.SharesRed != 0 || MemberShares.SharesWhite != 0) {
tbl.AddCell(NewBucketTh("Gesamtlieferung lt. gez. GA (rot)", isTiny: isTiny));
tbl.AddCells(FormatRow(MemberShares.SharesRed * (season.MinKgPerShareRed ?? season.MinKgPerShare ?? 0), MemberShares.SharesRed * (season.MaxKgPerShareRed ?? season.MaxKgPerShare ?? 0),
deliveredWeightRed, isGa: true, showPayment: includePayment, showArea: !includeDelivery, isTiny: isTiny));
tbl.AddCell(NewBucketTh("Gesamtlieferung lt. gez. GA (weiß)", isTiny: isTiny));
tbl.AddCells(FormatRow(MemberShares.SharesWhite * (season.MinKgPerShareWhite ?? season.MinKgPerShare ?? 0), MemberShares.SharesWhite * (season.MaxKgPerShareWhite ?? season.MaxKgPerShare ?? 0),
deliveredWeightWhite, isGa: true, showPayment: includePayment, showArea: !includeDelivery, isTiny: isTiny));
}
if (fbs.Any()) { if (fbs.Any()) {
tbl.AddCell(NewBucketSubHdr("Flächenbindungen" + (vtr.Any() ? " (inkl. Verträge)" : "") + ":", includePayment ? 8 : 7, isTiny: isTiny)); tbl.AddCell(NewBucketSubHdr("Flächenbindungen" + (vtr.Any() ? " (inkl. Verträge)" : "") + ":", includePayment ? 8 : 7, isTiny: isTiny));
+80 -48
View File
@@ -1,55 +1,82 @@
using Elwig.Helpers; using Elwig.Helpers;
using Elwig.Helpers.Billing;
using Elwig.Models.Dtos; using Elwig.Models.Dtos;
using Elwig.Models.Entities; using Elwig.Models.Entities;
using iText.Kernel.Pdf; using iText.Kernel.Pdf;
using iText.Layout.Borders; using iText.Layout.Borders;
using iText.Layout.Element; using iText.Layout.Element;
using iText.Layout.Properties; using iText.Layout.Properties;
using Microsoft.EntityFrameworkCore;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
namespace Elwig.Documents { namespace Elwig.Documents {
public class CreditNote : BusinessDocument { public class CreditNote : BusinessDocument {
public new static string Name => "Traubengutschrift"; public new static string Name => "Traubengutschrift";
public PaymentMember? Payment; public PaymentMember Payment;
public Credit? Credit; public Credit? Credit;
public CreditNoteDeliveryData Data;
public string? Text; public string? Text;
public string CurrencySymbol; public string CurrencySymbol;
public int Precision; public int Precision;
public string MemberModifier; public string? MemberModifier;
public List<(string Name, int Kg, decimal Amount)>? MemberUnderDeliveries; public List<(string Name, int Kg, decimal Amount)>? MemberUnderDeliveries;
public decimal MemberTotalUnderDelivery; public decimal MemberTotalUnderDelivery;
public int MemberAutoBusinessShares; public int MemberAutoBusinessShares;
public decimal MemberAutoBusinessSharesAmount; public decimal MemberAutoBusinessSharesAmount;
public PaymentCustom? CustomPayment; public PaymentCustom? CustomPayment;
public CreditNote( protected bool ConsiderContractPenalties;
AppDbContext ctx, protected bool ConsiderTotalPenalty;
PaymentMember p, protected bool ConsiderAutoBusinessShares;
CreditNoteDeliveryData data, protected bool ConsiderCustomModifiers;
bool considerContractPenalties,
bool considerTotalPenalty, private CreditNoteDeliveryData? _data;
bool considerAutoBusinessShares, private Dictionary<string, UnderDelivery>? _underDeliveries;
bool considerCustomModifiers,
Dictionary<string, UnderDelivery>? underDeliveries = null public CreditNote(PaymentMember p, DateOnly? dateFrom, BillingData? billingData = null, CreditNoteDeliveryData? data = null, Dictionary<string, UnderDelivery>? underDeliveries = null) :
) : base($"{Name} {(p.Credit != null ? $"Nr. {p.Credit.Year}/{p.Credit.TgNr:000}" : p.Member.FullName)} {p.Variant.Name}", p.Member, dateFrom) {
base($"{Name} {(p.Credit != null ? $"Nr. {p.Credit.Year}/{p.Credit.TgNr:000}" : p.Member.FullName)} {p.Variant.Name}", p.Member) {
UseBillingAddress = true; UseBillingAddress = true;
ShowDateAndLocation = true; ShowDateAndLocation = true;
Data = data;
Payment = p; Payment = p;
Credit = p.Credit; Credit = p.Credit;
IsPreview = Payment == null || Credit == null; Text = App.Client.TextCreditNote;
var season = p.Variant.Season; DocumentId = $"Tr.-Gutschr. " + (Credit != null ? $"{Credit.Year}/{Credit.TgNr:000}" : Payment.MgNr);
if (considerCustomModifiers) { IsPreview = Credit == null;
CustomPayment = ctx.CustomPayments.Find(p.Year, p.MgNr); _data = data;
_underDeliveries = underDeliveries;
CurrencySymbol = Payment.Variant.Season.Currency.Symbol ?? Payment.Variant.Season.Currency.Code;
Precision = Payment.Variant.Season.Precision;
billingData ??= BillingData.FromJson(Payment.Variant.Data);
ConsiderContractPenalties = billingData.ConsiderContractPenalties;
ConsiderTotalPenalty = billingData.ConsiderTotalPenalty;
ConsiderAutoBusinessShares = billingData.ConsiderAutoBusinessShares;
ConsiderCustomModifiers = billingData.ConsiderCustomModifiers;
} }
var mod = App.Client.IsMatzen ? ctx.Modifiers.Where(m => m.Year == season.Year && m.Name.StartsWith("Treue")).FirstOrDefault() : null; public static async Task<CreditNote> Initialize(int year, int avnr, int mgnr, DateOnly? dateFrom, BillingData? billingData = null, CreditNoteDeliveryData? data = null, Dictionary<string, UnderDelivery>? underDeliveries = null) {
using var ctx = new AppDbContext();
var p = await ctx.MemberPayments
.Where(p => p.Year == year && p.AvNr == avnr && p.MgNr == mgnr)
.SingleAsync();
return new CreditNote(p, dateFrom, billingData, data, underDeliveries);
}
protected override async Task LoadData(AppDbContext ctx) {
await base.LoadData(ctx);
var season = Payment.Variant.Season;
if (ConsiderCustomModifiers) {
CustomPayment = await ctx.CustomPayments.FindAsync(Payment.Year, Payment.MgNr);
}
_data ??= (await CreditNoteDeliveryData.ForPaymentVariant(ctx.CreditNoteDeliveryRows, ctx.PaymentVariants, Payment.Year, Payment.AvNr))[Member.MgNr];
_underDeliveries ??= await ctx.GetMemberUnderDelivery(Payment.Year, Member.MgNr);
var mod = App.Client.IsMatzen ? await ctx.FetchModifiers(season.Year).Where(m => m.Name.StartsWith("Treue")).FirstOrDefaultAsync() : null;
if (CustomPayment?.ModComment != null) { if (CustomPayment?.ModComment != null) {
MemberModifier = CustomPayment.ModComment; MemberModifier = CustomPayment.ModComment;
} else if (mod != null) { } else if (mod != null) {
@@ -57,32 +84,33 @@ namespace Elwig.Documents {
} else { } else {
MemberModifier = "Sonstige Zu-/Abschläge"; MemberModifier = "Sonstige Zu-/Abschläge";
} }
Text = App.Client.TextCreditNote;
DocumentId = $"Tr.-Gutschr. " + (p.Credit != null ? $"{p.Credit.Year}/{p.Credit.TgNr:000}" : p.MgNr);
CurrencySymbol = season.Currency.Symbol ?? season.Currency.Code;
Precision = season.Precision;
if (considerTotalPenalty) { if (ConsiderTotalPenalty) {
var total = data.Rows.SelectMany(r => r.Buckets).Sum(b => b.Value); var weights = _data.Rows.Select(r => new {r.Type, Weight = r.Buckets.Sum(b => b.Value)}).GroupBy(r => r.Type).ToDictionary(r => r.Key, g => g.Sum(r => r.Weight));
var totalUnderDelivery = total - p.Member.BusinessShares * season.MinKgPerBusinessShare; var red = weights.GetValueOrDefault("R", 0);
MemberTotalUnderDelivery = totalUnderDelivery < 0 ? totalUnderDelivery * (season.PenaltyPerKg ?? 0) - (season.PenaltyAmount ?? 0) - (season.PenaltyPerBsAmount * Math.Floor(-(decimal)totalUnderDelivery / season.MinKgPerBusinessShare) ?? 0) : 0; var white = weights.GetValueOrDefault("W", 0);
var total = red + white;
var underDeliveryTotal = total - Member.Shares * (season.MinKgPerShare ?? 0);
var underDeliveryRed = red - Member.SharesRed * (season.MinKgPerShareRed ?? season.MinKgPerShare ?? 0);
var underDeliveryWhite = white - Member.SharesWhite * (season.MinKgPerShareWhite ?? season.MinKgPerShare ?? 0);
MemberTotalUnderDelivery =
(underDeliveryTotal < 0 ? underDeliveryTotal * (season.PenaltyPerKg ?? 0) - (season.PenaltyAmount ?? 0) - (season.PenaltyPerShareAmount * Math.Floor(-(decimal)underDeliveryTotal / (season.MinKgPerShare ?? 0)) ?? 0) : 0) +
(underDeliveryRed < 0 ? underDeliveryRed * (season.PenaltyPerKg ?? 0) - (season.PenaltyAmount ?? 0) - (season.PenaltyPerShareAmount * Math.Floor(-(decimal)underDeliveryRed / (season.MinKgPerShareRed ?? season.MinKgPerShare ?? 0)) ?? 0) : 0) +
(underDeliveryWhite < 0 ? underDeliveryWhite * (season.PenaltyPerKg ?? 0) - (season.PenaltyAmount ?? 0) - (season.PenaltyPerShareAmount * Math.Floor(-(decimal)underDeliveryWhite / (season.MinKgPerShareWhite ?? season.MinKgPerShare ?? 0)) ?? 0) : 0);
if (total == 0) if (total == 0)
MemberTotalUnderDelivery -= (season.PenaltyNone ?? 0) + (season.PenaltyPerBsNone * p.Member.BusinessShares ?? 0); MemberTotalUnderDelivery -= (season.PenaltyNone ?? 0) + (season.PenaltyPerShareNone * (Member.Shares + Member.SharesRed + Member.SharesWhite) ?? 0);
} }
if (considerAutoBusinessShares) { if (ConsiderAutoBusinessShares) {
var fromDate = $"{season.Year}-01-01"; MemberAutoBusinessShares = await ctx.MemberHistory
var toDate = $"{season.Year}-12-31"; .Where(h => h.ToMgNr == Member.MgNr && h.DeductYear == season.Year)
MemberAutoBusinessShares = ctx.MemberHistory .SumAsync(h => h.Shares);
.Where(h => h.MgNr == p.Member.MgNr && h.Type == "auto")
.Where(h => h.DateString.CompareTo(fromDate) >= 0 && h.DateString.CompareTo(toDate) <= 0)
.Sum(h => h.BusinessShares);
MemberAutoBusinessSharesAmount = MemberAutoBusinessShares * (-season.BusinessShareValue ?? 0); MemberAutoBusinessSharesAmount = MemberAutoBusinessShares * (-season.BusinessShareValue ?? 0);
} }
if (considerContractPenalties) { if (ConsiderContractPenalties) {
var varieties = ctx.WineVarieties.ToDictionary(v => v.SortId, v => v); var varieties = await ctx.FetchWineVarieties().ToDictionaryAsync(v => v.SortId, v => v);
var attributes = ctx.WineAttributes.ToDictionary(a => a.AttrId, a => a); var attributes = await ctx.FetchWineAttributes().ToDictionaryAsync(a => a.AttrId, a => a);
var comTypes = ctx.AreaCommitmentTypes.ToDictionary(t => t.VtrgId, t => t); var comTypes = await ctx.AreaCommitmentTypes.ToDictionaryAsync(t => t.VtrgId, t => t);
MemberUnderDeliveries = underDeliveries? MemberUnderDeliveries = _underDeliveries?
.OrderBy(u => u.Key) .OrderBy(u => u.Key)
.Select(u => ( .Select(u => (
varieties[u.Key[..2]].Name + (u.Key.Length > 2 ? " " + attributes[u.Key[2..]].Name : ""), varieties[u.Key[..2]].Name + (u.Key.Length > 2 ? " " + attributes[u.Key[2..]].Name : ""),
@@ -104,8 +132,9 @@ namespace Elwig.Documents {
} }
protected override void RenderBody(iText.Layout.Document doc, PdfDocument pdf) { protected override void RenderBody(iText.Layout.Document doc, PdfDocument pdf) {
if (_data == null) throw new Exception("Call LoadData before RenderBody");
base.RenderBody(doc, pdf); base.RenderBody(doc, pdf);
doc.Add(NewCreditTable(Data)); doc.Add(NewCreditTable(_data));
var div = new Table(ColsMM(60, 105)) var div = new Table(ColsMM(60, 105))
.SetWidth(UnitValue.CreatePercentValue(100)).SetFixedLayout() .SetWidth(UnitValue.CreatePercentValue(100)).SetFixedLayout()
@@ -131,7 +160,7 @@ namespace Elwig.Documents {
.SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE) .SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE)
.SetKeepTogether(true); .SetKeepTogether(true);
var sum = Data.Rows.Sum(p => p.Amount); var sum = _data.Rows.Sum(p => p.Amount);
if (Payment == null) { if (Payment == null) {
tbl1.AddCells(FormatRow("Gesamt", sum, bold: true, noTopBorder: true)); tbl1.AddCells(FormatRow("Gesamt", sum, bold: true, noTopBorder: true));
} else { } else {
@@ -139,7 +168,7 @@ namespace Elwig.Documents {
if (Payment.NetAmount != Payment.Amount) { if (Payment.NetAmount != Payment.Amount) {
tbl1.AddCells(FormatRow("Zwischensumme", Payment.NetAmount, noTopBorder: noBorder)); tbl1.AddCells(FormatRow("Zwischensumme", Payment.NetAmount, noTopBorder: noBorder));
noBorder = false; noBorder = false;
tbl1.AddCells(FormatRow(MemberModifier, Payment.Amount - Payment.NetAmount, add: true)); tbl1.AddCells(FormatRow(MemberModifier ?? "", Payment.Amount - Payment.NetAmount, add: true));
} }
if (Credit == null) { if (Credit == null) {
tbl1.AddCells(FormatRow("Gesamtbetrag", Payment.Amount, bold: true, noTopBorder: noBorder)); tbl1.AddCells(FormatRow("Gesamtbetrag", Payment.Amount, bold: true, noTopBorder: noBorder));
@@ -173,7 +202,7 @@ namespace Elwig.Documents {
penalty += MemberTotalUnderDelivery; penalty += MemberTotalUnderDelivery;
} }
if (MemberAutoBusinessSharesAmount != 0) { if (MemberAutoBusinessSharesAmount != 0) {
tbl2.AddCells(FormatRow($"Autom. Nachz. von GA ({MemberAutoBusinessShares})", MemberAutoBusinessSharesAmount, add: true)); tbl2.AddCells(FormatRow($"Nachzeichnung von GA ({MemberAutoBusinessShares})", MemberAutoBusinessSharesAmount, add: true));
penalty += MemberAutoBusinessSharesAmount; penalty += MemberAutoBusinessSharesAmount;
} }
if (CustomPayment?.Amount != null) { if (CustomPayment?.Amount != null) {
@@ -272,12 +301,15 @@ namespace Elwig.Documents {
if (p.QualId == "WEI") varibute.Add(Italic("abgew.")); if (p.QualId == "WEI") varibute.Add(Italic("abgew."));
sub.AddCell(NewCell(colspan: 2)) sub.AddCell(NewCell(colspan: 2))
.AddCell(NewTd(varibute, colspan: 3).SetPaddingTop(0)); .AddCell(NewTd(varibute, colspan: 3).SetPaddingTop(0));
} else if (i - (rows - p.Modifiers.Length) < p.Modifiers.Length) { } else {
var idx = i - (rows - p.Modifiers.Length);
if (idx >= 0 && idx < p.Modifiers.Length) {
sub.AddCell(NewCell(colspan: 2)) sub.AddCell(NewCell(colspan: 2))
.AddCell(NewTd(p.Modifiers[i - (rows - p.Modifiers.Length)], 8, colspan: 3).SetPaddingTop(0).SetPaddingLeftMM(5)); .AddCell(NewTd(p.Modifiers[idx], 8, colspan: 3).SetPaddingTop(0).SetPaddingLeftMM(5));
} else { } else {
sub.AddCell(NewCell(colspan: 5)); sub.AddCell(NewCell(colspan: 5));
} }
}
if (i < p.Buckets.Length) { if (i < p.Buckets.Length) {
var bucket = p.Buckets[i]; var bucket = p.Buckets[i];
@@ -297,7 +329,7 @@ namespace Elwig.Documents {
var totalMod = p.TotalModifiers ?? 0; var totalMod = p.TotalModifiers ?? 0;
var pad = i == 0 ? 0.5f : 0; var pad = i == 0 ? 0.5f : 0;
sub.AddCell(NewTd(rebelMod == 0 ? "-" : (Utils.GetSign(rebelMod) + $"{Math.Abs(rebelMod):0.0##}"), 6, center: true) sub.AddCell(NewTd(rebelMod == 0 ? "-" : (Utils.GetSign(rebelMod) + $"{Math.Abs(rebelMod):0.0##}"), 6, center: true)
.SetPaddingTopMM(pad)) .SetPaddingTopMM(pad).SetPaddingLeft(0).SetPaddingRight(0))
.AddCell(NewTd(totalMod == 0 ? "-" : Utils.GetSign(totalMod) + $"{Math.Abs(totalMod):N2}", center: totalMod == 0, right: true) .AddCell(NewTd(totalMod == 0 ? "-" : Utils.GetSign(totalMod) + $"{Math.Abs(totalMod):N2}", center: totalMod == 0, right: true)
.SetPaddingTopMM(pad)) .SetPaddingTopMM(pad))
.AddCell(NewTd($"{p.Amount:N2}", right: true) .AddCell(NewTd($"{p.Amount:N2}", right: true)
+41 -18
View File
@@ -5,33 +5,53 @@ using iText.Kernel.Pdf;
using iText.Layout.Borders; using iText.Layout.Borders;
using iText.Layout.Element; using iText.Layout.Element;
using iText.Layout.Properties; using iText.Layout.Properties;
using Microsoft.EntityFrameworkCore;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
namespace Elwig.Documents { namespace Elwig.Documents {
public class DeliveryConfirmation : BusinessDocument { public class DeliveryConfirmation : BusinessDocument {
public new static string Name => "Anlieferungsbestätigung"; public new static string Name => "Anlieferungsbestätigung";
public Season Season; private readonly int _year;
public DeliveryConfirmationDeliveryData Data; public Season? Season;
public int MemberDeliveredWeightRed;
public int MemberDeliveredWeightWhite;
public DeliveryConfirmationDeliveryData? Data;
public string? Text = App.Client.TextDeliveryConfirmation; public string? Text = App.Client.TextDeliveryConfirmation;
public Dictionary<string, MemberBucket> MemberBuckets; public Dictionary<string, MemberBucket> MemberBuckets = [];
public List<MemberStat> MemberStats; public List<MemberStat> MemberStats = [];
public DeliveryConfirmation(AppDbContext ctx, int year, Member m, DeliveryConfirmationDeliveryData data) : public DeliveryConfirmation(int year, Member m, DateOnly? dateFrom, DeliveryConfirmationDeliveryData? data = null) :
base($"{Name} {year}", m) { base($"{Name} {year}", m, dateFrom) {
Season = ctx.Seasons.Find(year) ?? throw new ArgumentException("invalid season"); _year = year;
ShowDateAndLocation = true; ShowDateAndLocation = true;
UseBillingAddress = true; UseBillingAddress = true;
DocumentId = $"Anl.-Best. {Season.Year}/{m.MgNr}"; DocumentId = $"Anl.-Best. {_year}/{m.MgNr}";
Data = data; Data = data;
MemberBuckets = ctx.GetMemberBuckets(Season.Year, m.MgNr).GetAwaiter().GetResult(); }
MemberStats = AppDbContext.GetMemberStats(Season.Year, m.MgNr).GetAwaiter().GetResult();
protected override async Task LoadData(AppDbContext ctx) {
await base.LoadData(ctx);
Season = await ctx.FetchSeasons(_year).SingleOrDefaultAsync() ?? throw new ArgumentException("Invalid season");
var weights = await ctx.Deliveries
.Where(d => d.Year == Season.Year && d.MgNr == Member.MgNr)
.SelectMany(d => d.Parts)
.GroupBy(p => p.Variety.Type)
.ToDictionaryAsync(g => g.Key, g => g.Sum(p => p.Weight));
MemberDeliveredWeightRed = weights.GetValueOrDefault("R", 0);
MemberDeliveredWeightWhite = weights.GetValueOrDefault("W", 0);
MemberShares = await ctx.GetMemberHistory(Season.Year, Member.MgNr);
MemberBuckets = await ctx.GetMemberBuckets(Season.Year, Member.MgNr);
MemberStats = await AppDbContext.GetMemberStats(Season.Year, Member.MgNr);
Data ??= await DeliveryConfirmationDeliveryData.ForMember(ctx.DeliveryParts, Season.Year, Member);
} }
protected override void BeforeRenderBody(iText.Layout.Document doc, PdfDocument pdf) { protected override void BeforeRenderBody(iText.Layout.Document doc, PdfDocument pdf) {
if (Data == null) throw new Exception("Call LoadData before BeforeRenderBody");
base.BeforeRenderBody(doc, pdf); base.BeforeRenderBody(doc, pdf);
var firstDay = Data.Rows.MinBy(r => r.Date)?.Date; var firstDay = Data.Rows.MinBy(r => r.Date)?.Date;
var lastDay = Data.Rows.MaxBy(r => r.Date)?.Date; var lastDay = Data.Rows.MaxBy(r => r.Date)?.Date;
@@ -42,12 +62,13 @@ namespace Elwig.Documents {
} }
protected override void RenderBody(iText.Layout.Document doc, PdfDocument pdf) { protected override void RenderBody(iText.Layout.Document doc, PdfDocument pdf) {
if (Season == null || Data == null) throw new Exception("Call LoadData before RenderBody");
base.RenderBody(doc, pdf); base.RenderBody(doc, pdf);
doc.Add(NewDeliveryListTable(Data)); doc.Add(NewDeliveryListTable(Data));
doc.Add(NewWeightsTable(MemberStats) doc.Add(NewWeightsTable(MemberStats)
.SetMarginTopMM(10).SetKeepTogether(true)); .SetMarginTopMM(10).SetKeepTogether(true));
doc.Add(NewBucketTable(Season, MemberBuckets, includePayment: true) doc.Add(NewBucketTable(Season, MemberBuckets, MemberDeliveredWeightRed, MemberDeliveredWeightWhite, includePayment: true)
.SetMarginTopMM(10).SetKeepTogether(true)); .SetMarginTopMM(10).SetKeepTogether(true));
if (Text != null) { if (Text != null) {
@@ -98,13 +119,14 @@ namespace Elwig.Documents {
} else if (i == 1 && attr) { } else if (i == 1 && attr) {
sub.AddCell(NewCell(colspan: 2)) sub.AddCell(NewCell(colspan: 2))
.AddCell(NewTd($"{p.Attribute}{(p.Attribute != null && p.Cultivation != null ? " / " : "")}{p.Cultivation}", 8, colspan: 2) .AddCell(NewTd($"{p.Attribute}{(p.Attribute != null && p.Cultivation != null ? " / " : "")}{p.Cultivation}", 8, colspan: 2)
.SetPaddingsMM(0.125f, 1, 0.125f, 1)) .SetPaddingTop(0))
.AddCell(NewCell(colspan: 2)); .AddCell(NewCell(colspan: 2));
} else { } else {
sub.AddCell(NewCell(colspan: 2)); sub.AddCell(NewCell(colspan: 2));
if (i - (rows - p.Modifiers.Length) < p.Modifiers.Length) { var idx = i - (rows - p.Modifiers.Length);
sub.AddCell(NewTd(p.Modifiers[i - (rows - p.Modifiers.Length)], 8, colspan: 2) if (idx >= 0 && idx < p.Modifiers.Length) {
.SetPaddingsMM(0.125f, 0, 0.125f, 5)); sub.AddCell(NewTd(p.Modifiers[idx], 8, colspan: 2)
.SetPaddingTop(0).SetPaddingLeftMM(5));
} else { } else {
sub.AddCell(NewCell(colspan: 2)); sub.AddCell(NewCell(colspan: 2));
} }
@@ -113,14 +135,15 @@ namespace Elwig.Documents {
if (i < p.Buckets.Length) { if (i < p.Buckets.Length) {
var bucket = p.Buckets[i]; var bucket = p.Buckets[i];
sub.AddCell(NewTd($"{bucket.Name}:", 8).SetHeight(10).SetPaddingsMM(0.125f, 0, 0.125f, 0)); var pad = i == 0 ? 0.5f : 0;
sub.AddCell(NewTd($"{bucket.Value:N0}", right: true)); sub.AddCell(NewTd($"{bucket.Name}:", 8).SetHeight(10).SetPaddingTopMM(pad));
sub.AddCell(NewTd($"{bucket.Value:N0}", right: true).SetPaddingTopMM(pad));
} else { } else {
sub.AddCell(NewCell(colspan: 2)); sub.AddCell(NewCell(colspan: 2));
} }
if (i == p.Buckets.Length - 1) { if (i == p.Buckets.Length - 1) {
sub.AddCell(NewTd($"{p.Weight:N0}", right: true)); sub.AddCell(NewTd($"{p.Weight:N0}", right: true).SetPaddingTop(0));
sub.AddCell(NewTd(p.IsNetWeight ? "\u2611" : "\u2610", 7, right: true).SetFont(SF).SetPadding(0)); sub.AddCell(NewTd(p.IsNetWeight ? "\u2611" : "\u2610", 7, right: true).SetFont(SF).SetPadding(0));
} else { } else {
sub.AddCell(NewCell(colspan: 2)); sub.AddCell(NewCell(colspan: 2));
+40 -7
View File
@@ -5,10 +5,12 @@ using iText.Layout.Borders;
using iText.Layout.Element; using iText.Layout.Element;
using iText.Layout.Layout; using iText.Layout.Layout;
using iText.Layout.Properties; using iText.Layout.Properties;
using Microsoft.EntityFrameworkCore;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace Elwig.Documents { namespace Elwig.Documents {
public class DeliveryNote : BusinessDocument { public class DeliveryNote : BusinessDocument {
@@ -17,7 +19,9 @@ namespace Elwig.Documents {
public Delivery Delivery; public Delivery Delivery;
public string? Text; public string? Text;
public Dictionary<string, MemberBucket> MemberBuckets; public int MemberDeliveredWeightRed;
public int MemberDeliveredWeightWhite;
public Dictionary<string, MemberBucket> MemberBuckets = [];
// 0 - none // 0 - none
// 1 - GA only // 1 - GA only
@@ -25,16 +29,45 @@ namespace Elwig.Documents {
// 3 - full // 3 - full
public int DisplayStats = App.Client.ModeDeliveryNoteStats; public int DisplayStats = App.Client.ModeDeliveryNoteStats;
public DeliveryNote(Delivery d, AppDbContext? ctx = null) : public DeliveryNote(Delivery d) :
base($"{Name} Nr. {d.LsNr}", d.Member) { base($"{Name} Nr. {d.LsNr}", d.Member, DateOnly.FromDateTime(d.ModifiedAt)) {
UseBillingAddress = true; UseBillingAddress = true;
ShowDateAndLocation = true; ShowDateAndLocation = true;
Delivery = d; Delivery = d;
Text = App.Client.TextDeliveryNote; Text = App.Client.TextDeliveryNote;
DocumentId = d.LsNr; DocumentId = d.LsNr;
Date = DateOnly.FromDateTime(d.ModifiedAt); }
IsDoublePaged = true;
MemberBuckets = ctx?.GetMemberBuckets(d.Year, d.Member.MgNr).GetAwaiter().GetResult() ?? []; public static async Task<DeliveryNote> Initialize(int year, int did) {
using var ctx = new AppDbContext();
await ctx.WineOrigins.LoadAsync();
var d = await ctx.Deliveries
.Where(d => d.Year == year && d.DId == did)
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers)
.SingleAsync();
return new DeliveryNote(d);
}
public static async Task<DeliveryNote> Initialize(string lsnr) {
using var ctx = new AppDbContext();
await ctx.WineOrigins.LoadAsync();
var d = await ctx.Deliveries
.Where(d => d.LsNr == lsnr)
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers)
.SingleAsync();
return new DeliveryNote(d);
}
protected override async Task LoadData(AppDbContext ctx) {
await base.LoadData(ctx);
var weights = await ctx.DeliveryParts
.Where(d => d.Year == Delivery.Year && d.Delivery.MgNr == Member.MgNr)
.GroupBy(p => p.Variety.Type)
.ToDictionaryAsync(g => g.Key, g => g.Sum(p => p.Weight));
MemberDeliveredWeightRed = weights.GetValueOrDefault("R", 0);
MemberDeliveredWeightWhite = weights.GetValueOrDefault("W", 0);
MemberShares = await ctx.GetMemberHistory(Delivery.Year, Member.MgNr);
MemberBuckets = await ctx.GetMemberBuckets(Delivery.Year, Member.MgNr) ?? [];
} }
protected override void BeforeRenderBody(iText.Layout.Document doc, PdfDocument pdf) { protected override void BeforeRenderBody(iText.Layout.Document doc, PdfDocument pdf) {
@@ -53,7 +86,7 @@ namespace Elwig.Documents {
doc.Add(new KernedParagraph($"Anmerkung zur Lieferung: {Delivery.Comment}", 10).SetMarginsMM(5, 0, 0, 0)); doc.Add(new KernedParagraph($"Anmerkung zur Lieferung: {Delivery.Comment}", 10).SetMarginsMM(5, 0, 0, 0));
} }
if (DisplayStats > 0) { if (DisplayStats > 0) {
doc.Add(NewBucketTable(Delivery.Season, MemberBuckets, isTiny: true, doc.Add(NewBucketTable(Delivery.Season, MemberBuckets, MemberDeliveredWeightRed, MemberDeliveredWeightWhite, isTiny: true,
filter: DisplayStats > 2 ? null : DisplayStats == 1 ? [] : Delivery.Parts.Select(p => p.SortId).Distinct().ToList()) filter: DisplayStats > 2 ? null : DisplayStats == 1 ? [] : Delivery.Parts.Select(p => p.SortId).Distinct().ToList())
.SetKeepTogether(true) .SetKeepTogether(true)
.SetMarginsMM(5, 0, 0, 0)); .SetMarginsMM(5, 0, 0, 0));
+5 -3
View File
@@ -49,14 +49,12 @@ namespace Elwig.Documents {
public bool IsPreview = false; public bool IsPreview = false;
private iText.Layout.Document? _doc; private iText.Layout.Document? _doc;
public int CurrentNextSeason;
public string? DocumentId; public string? DocumentId;
public string Title; public string Title;
public string Author; public string Author;
public DateOnly Date; public DateOnly Date;
public Document(string title) { public Document(string title) {
CurrentNextSeason = Utils.CurrentNextSeason;
Title = title; Title = title;
Author = App.Client.NameFull; Author = App.Client.NameFull;
Date = DateOnly.FromDateTime(Utils.Today); Date = DateOnly.FromDateTime(Utils.Today);
@@ -128,6 +126,8 @@ namespace Elwig.Documents {
} }
} }
protected virtual async Task LoadData(AppDbContext ctx) { }
protected virtual void BeforeRenderBody(iText.Layout.Document doc, PdfDocument pdf) { } protected virtual void BeforeRenderBody(iText.Layout.Document doc, PdfDocument pdf) { }
protected virtual void RenderBody(iText.Layout.Document doc, PdfDocument pdf) { } protected virtual void RenderBody(iText.Layout.Document doc, PdfDocument pdf) { }
@@ -136,7 +136,7 @@ namespace Elwig.Documents {
return new KernedParagraph(App.Client.NameFull, 10); return new KernedParagraph(App.Client.NameFull, 10);
} }
public async Task Generate(CancellationToken? cancelToken = null, IProgress<double>? progress = null) { public async Task Generate(AppDbContext ctx, CancellationToken? cancelToken = null, IProgress<double>? progress = null) {
if (_pdfFile != null) if (_pdfFile != null)
return; return;
progress?.Report(0.0); progress?.Report(0.0);
@@ -181,6 +181,7 @@ namespace Elwig.Documents {
merger.Merge(src, 1, src.GetNumberOfPages()); merger.Merge(src, 1, src.GetNumberOfPages());
p += src.GetNumberOfPages(); p += src.GetNumberOfPages();
} else { } else {
await doc.LoadData(ctx);
int pageNum = doc.Render(tmpPdf.FilePath); int pageNum = doc.Render(tmpPdf.FilePath);
if (IsDoublePaged && doc is Letterhead) { if (IsDoublePaged && doc is Letterhead) {
using var reader = new PdfReader(tmpPdf.FilePath); using var reader = new PdfReader(tmpPdf.FilePath);
@@ -233,6 +234,7 @@ namespace Elwig.Documents {
throw new OperationCanceledException("Dokumentenerzeugung abgebrochen!"); throw new OperationCanceledException("Dokumentenerzeugung abgebrochen!");
var pdf = new TempFile("pdf"); var pdf = new TempFile("pdf");
try { try {
await LoadData(ctx);
TotalPages = Render(pdf.FilePath); TotalPages = Render(pdf.FilePath);
} catch { } catch {
pdf.Dispose(); pdf.Dispose();
+1 -1
View File
@@ -6,7 +6,7 @@ using iText.Layout;
namespace Elwig.Documents { namespace Elwig.Documents {
public class Letterhead : BusinessDocument { public class Letterhead : BusinessDocument {
public Letterhead(Member m) : public Letterhead(Member m) :
base($"Briefkopf {m.FullName}", m, true) { base($"Briefkopf {m.FullName}", m, null, includeSender: true) {
} }
protected override void RenderBody(iText.Layout.Document doc, PdfDocument pdf) { protected override void RenderBody(iText.Layout.Document doc, PdfDocument pdf) {
+202 -21
View File
@@ -1,43 +1,83 @@
using Elwig.Helpers; using Elwig.Helpers;
using Elwig.Models;
using Elwig.Models.Entities; using Elwig.Models.Entities;
using iText.Kernel.Colors; using iText.Kernel.Colors;
using iText.Kernel.Pdf; using iText.Kernel.Pdf;
using iText.Layout.Borders; using iText.Layout.Borders;
using iText.Layout.Element; using iText.Layout.Element;
using iText.Layout.Properties; using iText.Layout.Properties;
using Microsoft.EntityFrameworkCore;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace Elwig.Documents { namespace Elwig.Documents {
public class MemberDataSheet : BusinessDocument { public class MemberDataSheet : BusinessDocument {
public new static string Name => "Stammdatenblatt"; public new static string Name => "Stammdatenblatt";
public Season Season; public Season? Season;
public Dictionary<string, MemberBucket> MemberBuckets; public int MemberDeliveredWeightRed;
public List<AreaCom> ActiveAreaCommitments; public int MemberDeliveredWeightWhite;
public List<MemberHistory> MemberHistory = [];
public Dictionary<string, MemberBucket> MemberBuckets = [];
public List<AreaCom> ActiveAreaCommitments = [];
public MemberDataSheet(Member m, AppDbContext ctx) : base($"{Name} {m.AdministrativeName}", m) { public MemberDataSheet(Member m) :
base($"{Name} {m.AdministrativeName}", m, DateOnly.FromDateTime(m.ModifiedAt)) {
ShowDateAndLocation = true;
DocumentId = $"{Name} {m.MgNr}"; DocumentId = $"{Name} {m.MgNr}";
Season = ctx.Seasons.ToList().MaxBy(s => s.Year) ?? throw new ArgumentException("invalid season"); }
MemberBuckets = ctx.GetMemberBuckets(Utils.CurrentYear, m.MgNr).GetAwaiter().GetResult();
ActiveAreaCommitments = [.. m.ActiveAreaCommitments(ctx)]; public static async Task<MemberDataSheet> Initialize(int mgnr) {
using var ctx = new AppDbContext();
return new MemberDataSheet(await ctx.FetchMembers(mgnr, includeContactInfo: true).SingleAsync());
}
protected override async Task LoadData(AppDbContext ctx) {
await base.LoadData(ctx);
Season = await ctx.FetchSeasons().FirstOrDefaultAsync() ?? throw new ArgumentException("Invalid season");
MemberHistory = await ctx.MemberHistory
.Where(h => h.FromMgNr == Member.MgNr || h.ToMgNr == Member.MgNr)
.OrderBy(h => h.DateNoticeString).ThenBy(h => h.HistNr)
.ToListAsync();
MemberBuckets = await ctx.GetMemberBuckets(Utils.CurrentYear, Member.MgNr);
ActiveAreaCommitments = await Member.ActiveAreaCommitments(ctx)
.Include(c => c.Contract).ThenInclude(c => c.Revisions)
.ToListAsync();
var weights = await ctx.Deliveries
.Where(d => d.Year == Season.Year && d.MgNr == Member.MgNr)
.SelectMany(d => d.Parts)
.GroupBy(p => p.Variety.Type)
.ToDictionaryAsync(g => g.Key, g => g.Sum(p => p.Weight));
MemberDeliveredWeightRed = weights.GetValueOrDefault("R", 0);
MemberDeliveredWeightWhite = weights.GetValueOrDefault("W", 0);
} }
protected override void RenderBody(iText.Layout.Document doc, PdfDocument pdf) { protected override void RenderBody(iText.Layout.Document doc, PdfDocument pdf) {
if (Season == null) throw new Exception("Call LoadData before RenderBody");
base.RenderBody(doc, pdf); base.RenderBody(doc, pdf);
doc.Add(NewMemberData().SetMarginBottomMM(5)); doc.Add(NewMemberData(Season).SetMarginBottomMM(5));
doc.Add(NewBucketTable(Season, MemberBuckets, includeDelivery: false)); doc.Add(NewBucketTable(Season, MemberBuckets, MemberDeliveredWeightRed, MemberDeliveredWeightWhite, includeDelivery: false));
if (ActiveAreaCommitments.Count != 0) { if (ActiveAreaCommitments.Count != 0) {
bool firstOnPage = false; bool firstOnPage = false;
if (pdf.GetNumberOfPages() == 1) { if (pdf.GetNumberOfPages() == 1) {
doc.Add(new AreaBreak(AreaBreakType.NEXT_PAGE)); doc.Add(new AreaBreak(AreaBreakType.NEXT_PAGE));
firstOnPage = true; firstOnPage = true;
} }
doc.Add(new KernedParagraph(12).Add(Bold($"Flächenbindungen per {Date:dd.MM.yyyy}")).SetMargins(firstOnPage ? 0 : 24, 0, 12, 0)); doc.Add(new KernedParagraph(12).Add(Bold($"Flächenbindungen per {Date:dd.MM.yyyy}")).SetMargins(firstOnPage ? 0 : 24, 0, 6, 0));
doc.Add(NewAreaComTable()); doc.Add(NewAreaComTable(ActiveAreaCommitments));
}
if (App.Client.EnableMemberHistory) {
bool firstOnPage = false;
if (pdf.GetNumberOfPages() == 1) {
doc.Add(new AreaBreak(AreaBreakType.NEXT_PAGE));
firstOnPage = true;
}
doc.Add(new KernedParagraph(12).Add(Bold($"Verlauf der Geschäftsanteile per {Date:dd.MM.yyyy}")).SetMargins(firstOnPage ? 0 : 24, 0, 6, 0));
doc.Add(NewMemberBusinessSharesTable(MemberHistory));
} }
} }
@@ -51,7 +91,7 @@ namespace Elwig.Documents {
.SetPaddingRightMM(0); .SetPaddingRightMM(0);
} }
protected Table NewMemberData() { protected Table NewMemberData(Season season) {
var tbl = new Table(ColsMM(30.0, 51.5, 20.0, 12.0, 18.0, 31.5)) var tbl = new Table(ColsMM(30.0, 51.5, 20.0, 12.0, 18.0, 31.5))
.SetWidth(UnitValue.CreatePercentValue(100)).SetFixedLayout() .SetWidth(UnitValue.CreatePercentValue(100)).SetFixedLayout()
.SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE) .SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE)
@@ -111,18 +151,21 @@ namespace Elwig.Documents {
.AddCell(NewTd(i < subTbl2.Count ? subTbl2[i][1] : "", colspan: 2)); .AddCell(NewTd(i < subTbl2.Count ? subTbl2[i][1] : "", colspan: 2));
} }
var shares = (Member.Shares != 0 || (Member.SharesRed == 0 && Member.SharesWhite == 0) ? $"{Member.Shares:N0}" : "") +
(Member.SharesRed != 0 || Member.SharesWhite != 0 ? (Member.Shares != 0 ? " / " : "") + $"{Member.SharesRed:N0} (rot) / {Member.SharesWhite:N0} (weiß)" : "") +
(Member.SharesDormant != 0 ? $" / {Member.SharesDormant:N0} (ruhend)" : "");
tbl.AddCell(NewDataHdr("Betrieb", colspan: 6)) tbl.AddCell(NewDataHdr("Betrieb", colspan: 6))
.AddCell(NewDataTh("Betriebs-Nr.:")).AddCell(NewTd(Member.LfbisNr)) .AddCell(NewDataTh("Betriebs-Nr.:")).AddCell(NewTd(Member.LfbisNr))
.AddCell(NewDataTh("UID:", colspan: 2)).AddCell(NewTd(Member.UstIdNr, colspan: 2)) .AddCell(NewDataTh("UID:", colspan: 2)).AddCell(NewTd(Member.UstIdNr, colspan: 2))
.AddCell(NewDataTh("Stammgemeinde:")).AddCell(NewTd(Member.DefaultKg?.Name)) .AddCell(NewDataTh("Stammgemeinde:")).AddCell(NewTd(Member.DefaultKg?.Name))
.AddCell(NewDataTh("Buchführend:", colspan: 2)).AddCell(NewTd(new KernedParagraph(Member.IsBuchführend ? "Ja " : "Nein ", 10) .AddCell(NewDataTh("Buchführend:", colspan: 2)).AddCell(NewTd(new KernedParagraph(Member.IsBuchführend ? "Ja " : "Nein ", 10)
.Add(Normal($"({(Member.IsBuchführend ? Season.VatNormal : Season.VatFlatrate) * 100:N0}% USt.)", 8)), colspan: 2)) .Add(Normal($"({(Member.IsBuchführend ? season.VatNormal : season.VatFlatrate) * 100:N0}% USt.)", 8)), colspan: 2))
.AddCell(NewDataTh("(Katastralgemeinde mit dem größten Anteil an Weinbauflächen)", 8, colspan: 2)) .AddCell(NewDataTh("(Katastralgemeinde mit dem größten Anteil an Weinbauflächen)", 8, colspan: 2))
.AddCell(NewDataTh("Bio:", colspan: 2)).AddCell(NewTd(Member.IsOrganic ? "Ja" : "Nein", colspan: 2)) .AddCell(NewDataTh("Bio:", colspan: 2)).AddCell(NewTd(Member.IsOrganic ? "Ja" : "Nein", colspan: 2))
.AddCell(NewDataHdr("Genossenschaft", colspan: 6)) .AddCell(NewDataHdr("Genossenschaft", colspan: 6))
.AddCell(NewDataTh("Status:")).AddCell(NewTd(new KernedParagraph(Member.IsActive ? "Aktiv " : "Nicht aktiv ", 10) .AddCell(NewDataTh("Status:")).AddCell(NewTd(new KernedParagraph(Member.IsActive ? "Aktiv " : "Nicht aktiv ", 10)
.Add(Normal("(" + (Member.ExitDate != null ? $"{Member.EntryDate:dd.MM.yyyy}\u2013{Member.ExitDate:dd.MM.yyyy}" : $"seit {Member.EntryDate:dd.MM.yyyy}") + ")", 8)))) .Add(Normal("(" + (Member.ExitDate != null ? $"{Member.EntryDate:dd.MM.yyyy}\u2013{Member.ExitDate:dd.MM.yyyy}" : $"seit {Member.EntryDate:dd.MM.yyyy}") + ")", 8))))
.AddCell(NewDataTh("Geschäftsanteile:", colspan: 2)).AddCell(NewTd($"{Member.BusinessShares:N0}", colspan: 2)) .AddCell(NewDataTh("Geschäftsanteile:", colspan: 2)).AddCell(NewTd(shares, colspan: 2))
.AddCell(NewDataTh("Stamm-Zweigstelle:")).AddCell(NewTd(Member.Branch?.Name)) .AddCell(NewDataTh("Stamm-Zweigstelle:")).AddCell(NewTd(Member.Branch?.Name))
.AddCell(NewDataTh("Volllieferant:", colspan: 2)).AddCell(NewTd(Member.IsVollLieferant ? "Ja" : "Nein", colspan: 2)) .AddCell(NewDataTh("Volllieferant:", colspan: 2)).AddCell(NewTd(Member.IsVollLieferant ? "Ja" : "Nein", colspan: 2))
.AddCell(NewDataTh("Zusendungen per\u2026")).AddCell(NewTd(new KernedParagraph(10) .AddCell(NewDataTh("Zusendungen per\u2026")).AddCell(NewTd(new KernedParagraph(10)
@@ -133,10 +176,10 @@ namespace Elwig.Documents {
return tbl; return tbl;
} }
protected Table NewAreaComTable() { protected Table NewAreaComTable(IEnumerable<AreaCom> activeAreaComs) {
var areaComs = ActiveAreaCommitments.GroupBy(a => a.AreaComType).Select(group => new { var areaComs = activeAreaComs.GroupBy(a => a.AreaComType).Select(group => new {
Type = group.Key, Type = group.Key,
AreaComs = group.OrderBy(c => c.Kg.AtKg.Name).ToList(), AreaComs = group.OrderBy(c => c.Contract.Kg.AtKg.Name).ToList(),
Size = group.Sum(c => c.Area) Size = group.Sum(c => c.Area)
}).OrderByDescending(a => a.Size).ToList(); }).OrderByDescending(a => a.Size).ToList();
@@ -164,21 +207,159 @@ namespace Elwig.Documents {
.SetBorderTop(contractType.Type.DisplayName != lastContract && lastContract != "" ? new SolidBorder(BorderThickness) : Border.NO_BORDER)); .SetBorderTop(contractType.Type.DisplayName != lastContract && lastContract != "" ? new SolidBorder(BorderThickness) : Border.NO_BORDER));
foreach (var areaCom in contractType.AreaComs) { foreach (var areaCom in contractType.AreaComs) {
tbl.AddCell(NewTd(new KernedParagraph(10).Add(Normal($"{areaCom.Kg.AtKg.Name} ")).Add(Normal($"({areaCom.Kg.AtKg.KgNr:00000})", 8)))) var c = areaCom.Contract;
.AddCell(NewTd(areaCom.Rd?.Name)) tbl.AddCell(NewTd(new KernedParagraph(10).Add(Normal($"{c.Kg.AtKg.Name} ")).Add(Normal($"({c.Kg.AtKg.KgNr:00000})", 8))))
.AddCell(NewTd(c.Rd?.Name))
.AddCell(NewTd(Regex.Replace(areaCom.GstNr.Replace(",", ", ").Replace("-", "\u2013"), @"\s+", " "), 10)) .AddCell(NewTd(Regex.Replace(areaCom.GstNr.Replace(",", ", ").Replace("-", "\u2013"), @"\s+", " "), 10))
.AddCell(NewTd($"{areaCom.Area:N0}", right: true)) .AddCell(NewTd($"{areaCom.Area:N0}", right: true))
.AddCell(NewTd(areaCom.WineCult?.Name, center: true)) .AddCell(NewTd(areaCom.WineCult?.Name, center: true))
.AddCell(NewTd(areaCom.YearTo == null ? (areaCom.YearFrom == null ? "unbefristet" : $"ab {areaCom.YearFrom}") : (areaCom.YearFrom == null ? $"bis {areaCom.YearTo}" : $"{areaCom.YearFrom}{areaCom.YearTo}"), center: true)); .AddCell(NewTd(c.YearTo == null ? (c.YearFrom == null ? "unbefristet" : $"ab {c.YearFrom}") : (c.YearFrom == null ? $"bis {c.YearTo}" : $"{c.YearFrom}{c.YearTo}"), center: true));
lastContract = contractType.Type.DisplayName; lastContract = contractType.Type.DisplayName;
} }
} }
tbl.AddCell(NewTd("Gesamt:", 12, colspan: 2, bold: true, borderTop: true).SetPaddingsMM(1, 1, 1, 1)); tbl.AddCell(NewTd("Gesamt:", 12, colspan: 2, bold: true, borderTop: true).SetPaddingsMM(1, 1, 1, 1));
tbl.AddCell(NewTd($"{ActiveAreaCommitments.Sum(a => a.Area):N0}", 12, colspan: 2, right: true, bold: true, borderTop: true).SetPaddingsMM(1, 1, 1, 1)); tbl.AddCell(NewTd($"{activeAreaComs.Sum(a => a.Area):N0}", 12, colspan: 2, right: true, bold: true, borderTop: true).SetPaddingsMM(1, 1, 1, 1));
tbl.AddCell(NewTd(colspan: 2, borderTop: true).SetPaddingsMM(1, 1, 1, 1)); tbl.AddCell(NewTd(colspan: 2, borderTop: true).SetPaddingsMM(1, 1, 1, 1));
return tbl; return tbl;
} }
protected Cell[] NewBusinessSharesCells(MemberHistoryPoint p, bool isDiff = true) {
if (App.Client.HasRedWhite) {
return [
NewTd(isDiff ? (p.SharesRed == 0 ? "" : p.SharesRed < 0 ? $"{-p.SharesRed:N0}" : $"+{p.SharesRed:N0}") : $"{p.SharesRed:N0}",
right: true, bold: !isDiff, borderTop: !isDiff),
NewTd(isDiff ? (p.SharesWhite == 0 ? "" : p.SharesWhite < 0 ? $"{-p.SharesWhite:N0}" : $"+{p.SharesWhite:N0}") : $"{p.SharesWhite:N0}",
right: true, bold: !isDiff, borderTop: !isDiff),
NewTd(isDiff ? (p.SharesDormant == 0 ? "" : p.SharesDormant < 0 ? $"{-p.SharesDormant:N0}" : $"+{p.SharesDormant:N0}") : $"{p.SharesDormant:N0}",
right: true, bold: !isDiff, borderTop: !isDiff),
];
} else {
return [
NewTd(isDiff ? (p.Shares == 0 ? "" : p.Shares < 0 ? $"{-p.Shares:N0}" : $"+{p.Shares:N0}") : $"{p.Shares:N0}",
right: true, bold: !isDiff, borderTop: !isDiff),
NewTd(isDiff ? (p.SharesDormant == 0 ? "" : p.SharesDormant < 0 ? $"{-p.SharesDormant:N0}" : $"+{p.SharesDormant:N0}") : $"{p.SharesDormant:N0}",
right : true, bold: !isDiff, borderTop: !isDiff),
];
}
}
protected Table NewMemberBusinessSharesTable(IEnumerable<MemberHistory> history) {
var tbl = new Table(ColsMM(18, 93, App.Client.HasRedWhite ? 18 : 12, App.Client.HasRedWhite ? 12 : 18, 12, 12), true)
.SetWidth(UnitValue.CreatePercentValue(100)).SetFixedLayout()
.SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE)
.SetBorder(Border.NO_BORDER)
.SetFontSize(10);
var tw = App.Client.HasRedWhite ? 1 : 2;
tbl.AddHeaderCell(NewTh("Meldung am", rowspan: 2))
.AddHeaderCell(NewTh("Text", rowspan: 2, colspan: tw, left: true))
.AddHeaderCell(NewTh("Wirksam ab", rowspan: 2))
.AddHeaderCell(NewTh("Geschäftsanteile", colspan: App.Client.HasRedWhite ? 3 : 2));
if (App.Client.HasRedWhite) {
tbl.AddHeaderCell(NewTh("rot"))
.AddHeaderCell(NewTh("weiß"))
.AddHeaderCell(NewTh("ruhend"));
} else {
tbl.AddHeaderCell(NewTh("normal"))
.AddHeaderCell(NewTh("ruhend"));
}
if (!history.Any() || Member.EntryDate <= history.First().DateNotice) {
tbl.AddCell(NewTd($"{Member.EntryDate:dd.MM.yyyy}"))
.AddCell(NewTd("Eintritt", colspan: tw, bold: true))
.AddCell(NewTd($"{Member.EntryDate:dd.MM.yyyy}"))
.AddCells(NewBusinessSharesCells(new()));
}
var recorded = history.Aggregate(new MemberHistoryPoint(), (s, h) => new(
s.Shares + (h.ToMgNr == Member.MgNr && h.ToType == BusinessShareType.Normal ? h.Shares : 0) - (h.FromMgNr == Member.MgNr && h.FromType == BusinessShareType.Normal ? h.Shares : 0),
s.SharesRed + (h.ToMgNr == Member.MgNr && h.ToType == BusinessShareType.Red ? h.Shares : 0) - (h.FromMgNr == Member.MgNr && h.FromType == BusinessShareType.Red ? h.Shares : 0),
s.SharesWhite + (h.ToMgNr == Member.MgNr && h.ToType == BusinessShareType.White ? h.Shares : 0) - (h.FromMgNr == Member.MgNr && h.FromType == BusinessShareType.White ? h.Shares : 0),
s.SharesDormant + (h.ToMgNr == Member.MgNr && h.ToType == BusinessShareType.Dormant ? h.Shares : 0) - (h.FromMgNr == Member.MgNr && h.FromType == BusinessShareType.Dormant ? h.Shares : 0)));
var cur = new MemberHistoryPoint(Member.Shares - recorded.Shares, Member.SharesRed - recorded.SharesRed, Member.SharesWhite - recorded.SharesWhite, Member.SharesDormant - recorded.SharesDormant);
if (cur.Shares != 0 || cur.SharesRed != 0 || cur.SharesWhite != 0 || cur.SharesDormant != 0) {
tbl.AddCell(NewTd())
.AddCell(NewTd("Nicht in Software erfasst", colspan: tw, italic: true))
.AddCell(NewTd())
.AddCells(NewBusinessSharesCells(cur));
if (history.Any()) {
tbl.AddCell(NewTd(borderTop: true))
.AddCell(NewTd($"Bis Lese {history.First().DateNotice.Year - 1}", borderTop: true, colspan: tw, bold: true))
.AddCell(NewTd(borderTop: true))
.AddCells(NewBusinessSharesCells(cur, isDiff: false));
}
}
DateOnly? lastDate = null;
foreach (var row in history) {
int s = 0, r = 0, w = 0, d = 0;
if (row.FromMgNr == Member.MgNr) {
switch (row.FromType) {
case BusinessShareType.Normal: s -= row.Shares; break;
case BusinessShareType.Red: r -= row.Shares; break;
case BusinessShareType.White: w -= row.Shares; break;
case BusinessShareType.Dormant: d -= row.Shares; break;
}
}
if (row.ToMgNr == Member.MgNr) {
switch (row.ToType) {
case BusinessShareType.Normal: s += row.Shares; break;
case BusinessShareType.Red: r += row.Shares; break;
case BusinessShareType.White: w += row.Shares; break;
case BusinessShareType.Dormant: d += row.Shares; break;
}
}
if (lastDate < Member.EntryDate && row.DateNotice <= Member.EntryDate) {
tbl.AddCell(NewTd($"{Member.EntryDate:dd.MM.yyyy}"))
.AddCell(NewTd("Eintritt", colspan: tw, bold: true))
.AddCell(NewTd($"{Member.EntryDate:dd.MM.yyyy}"))
.AddCells(NewBusinessSharesCells(new()));
}
if (lastDate != null && row.DateNotice.Year != lastDate?.Year) {
tbl.AddCell(NewTd(borderTop: true))
.AddCell(NewTd(lastDate?.Year == row.DateNotice.Year - 1 ? $"Lese {lastDate?.Year}" : $"Lese {lastDate?.Year}{row.DateNotice.Year - 1}", borderTop: true, colspan: tw, bold: true))
.AddCell(NewTd(borderTop: true))
.AddCells(NewBusinessSharesCells(cur, isDiff: false));
}
if (lastDate < Member.ExitDate && row.DateNotice <= Member.ExitDate) {
tbl.AddCell(NewTd($"{Member.ExitDate:dd.MM.yyyy}"))
.AddCell(NewTd("Austritt", colspan: tw, bold: true))
.AddCell(NewTd($"31.12.{Member.ExitDate.Value.Year + 1}")) // FIXME
.AddCells(NewBusinessSharesCells(new()));
}
cur = new(cur.Shares + s, cur.SharesRed + r, cur.SharesWhite + w, cur.SharesDormant + d);
tbl.AddCell(NewTd($"{row.DateNotice:dd.MM.yyyy}"))
.AddCell(NewTd(row.FormatReasonPhrase(Member.MgNr), colspan: tw))
.AddCell(NewTd($"{row.DateEffective:dd.MM.yyyy}"))
.AddCells(NewBusinessSharesCells(new(s, r, w, d)));
lastDate = row.DateNotice;
}
if (Member.EntryDate != null && history.Any() && Member.EntryDate > lastDate) {
tbl.AddCell(NewTd($"{Member.EntryDate:dd.MM.yyyy}"))
.AddCell(NewTd("Eintritt", colspan: tw, bold: true))
.AddCell(NewTd($"{Member.EntryDate:dd.MM.yyyy}"))
.AddCells(NewBusinessSharesCells(new()));
}
if (Member.ExitDate != null && (!history.Any() || Member.ExitDate > lastDate)) {
tbl.AddCell(NewTd($"{Member.ExitDate:dd.MM.yyyy}"))
.AddCell(NewTd("Austritt", colspan: tw, bold: true))
.AddCell(NewTd($"31.12.{Member.ExitDate.Value.Year + 1}")) // FIXME
.AddCells(NewBusinessSharesCells(new()));
}
tbl.AddCell(NewTd(borderTop: true))
.AddCell(NewTd(lastDate == null ? "Aktuell" : $"Ab Lese {lastDate?.Year}", borderTop: true, colspan: tw, bold: true))
.AddCell(NewTd(borderTop: true))
.AddCells(NewBusinessSharesCells(cur, isDiff: false));
return tbl;
}
} }
} }
+1 -1
View File
@@ -86,7 +86,7 @@ namespace Elwig.Documents {
.AddCell(NewTd($"{m.Plz}", 8)) .AddCell(NewTd($"{m.Plz}", 8))
.AddCell(NewTd(m.Locality, 6)) .AddCell(NewTd(m.Locality, 6))
.AddCell(NewTd(m.LfbisNr ?? "", 8)) .AddCell(NewTd(m.LfbisNr ?? "", 8))
.AddCell(NewTd($"{m.BusinessShares:N0}", 8, right: true).SetPaddingLeft(0).SetPaddingRight(0)) .AddCell(NewTd($"{m.SharesActive:N0}", 8, right: true).SetPaddingLeft(0).SetPaddingRight(0))
.AddCell(NewTd(m.DefaultKg ?? "", 6)); .AddCell(NewTd(m.DefaultKg ?? "", 6));
if (AreaComFilters.Length > 0) { if (AreaComFilters.Length > 0) {
foreach (var v in AreaComFilters) { foreach (var v in AreaComFilters) {
+61 -41
View File
@@ -7,40 +7,60 @@ using iText.Kernel.Pdf;
using iText.Layout.Borders; using iText.Layout.Borders;
using iText.Layout.Element; using iText.Layout.Element;
using iText.Layout.Properties; using iText.Layout.Properties;
using Microsoft.EntityFrameworkCore;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
namespace Elwig.Documents { namespace Elwig.Documents {
public class PaymentVariantSummary : Document { public class PaymentVariantSummary : Document {
public new static string Name => "Auszahlungsvariante"; public new static string Name => "Auszahlungsvariante";
public PaymentVariantSummaryData Data; public PaymentVariantSummaryData? Data;
public PaymentVar Variant; public PaymentVar Variant;
public BillingData BillingData; public BillingData BillingData;
public string CurrencySymbol; public string CurrencySymbol;
public int MemberNum; public int MemberNum;
public int DeliveryNum; public int DeliveryNum;
public int DeliveryPartNum; public int DeliveryPartNum;
public List<ModifierStat> ModifierStat; public List<ModifierStat>? ModifierStat;
public Dictionary<string, Modifier> Modifiers; public Dictionary<string, Modifier>? Modifiers;
public PaymentVariantSummary(PaymentVar v, PaymentVariantSummaryData data) : private List<Credit> _credits = [];
private List<PaymentDeliveryPart> _parts = [];
public PaymentVariantSummary(PaymentVar v, PaymentVariantSummaryData? data = null) :
base($"{Name} {v.Year} - {v.Name}") { base($"{Name} {v.Year} - {v.Name}") {
Variant = v; Variant = v;
BillingData = BillingData.FromJson(v.Data); BillingData = BillingData.FromJson(v.Data);
Data = data; Data = data;
CurrencySymbol = v.Season.Currency.Symbol ?? v.Season.Currency.Code; CurrencySymbol = v.Season.Currency.Symbol ?? v.Season.Currency.Code;
MemberNum = v.Credits.Count; }
public static async Task<PaymentVariantSummary> Initialize(int year, int avnr, PaymentVariantSummaryData? data = null) {
using var ctx = new AppDbContext();
var v = await ctx.PaymentVariants
.Where(v => v.Year == year && v.AvNr == avnr)
.SingleAsync();
return new PaymentVariantSummary(v, data);
}
protected override async Task LoadData(AppDbContext ctx) {
_credits = await ctx.Credits.Where(c => c.Year == Variant.Year && c.AvNr == Variant.AvNr).ToListAsync();
_parts = await ctx.PaymentDeliveryParts.Where(p => p.Year == Variant.Year && p.AvNr == Variant.AvNr).ToListAsync();
MemberNum = _credits.Count;
IsPreview = MemberNum == 0; IsPreview = MemberNum == 0;
DeliveryNum = v.DeliveryPartPayments.DistinctBy(p => p.DeliveryPart.Delivery).Count(); DeliveryNum = await ctx.Deliveries.Where(d => d.Year == Variant.Year).CountAsync();
DeliveryPartNum = v.DeliveryPartPayments.Count; DeliveryPartNum = await ctx.DeliveryParts.Where(d => d.Year == Variant.Year).CountAsync();
ModifierStat = AppDbContext.GetModifierStats(v.Year, v.AvNr).GetAwaiter().GetResult(); Data ??= await PaymentVariantSummaryData.ForPaymentVariant(Variant, ctx.PaymentVariantSummaryRows);
Modifiers = v.Season.Modifiers.ToDictionary(m => m.ModId); ModifierStat = await AppDbContext.GetModifierStats(Variant.Year, Variant.AvNr);
Modifiers = await ctx.FetchModifiers(Variant.Year).ToDictionaryAsync(m => m.ModId);
} }
protected override void RenderBody(iText.Layout.Document doc, PdfDocument pdf) { protected override void RenderBody(iText.Layout.Document doc, PdfDocument pdf) {
if (Data == null || Modifiers == null || ModifierStat == null) throw new Exception("Call LoadData before RenderBody");
base.RenderBody(doc, pdf); base.RenderBody(doc, pdf);
doc.Add(new KernedParagraph($"{Name} Lese {Variant.Year}", 24) doc.Add(new KernedParagraph($"{Name} Lese {Variant.Year}", 24)
.SetTextAlignment(TextAlignment.CENTER).SetFont(BF) .SetTextAlignment(TextAlignment.CENTER).SetFont(BF)
@@ -48,10 +68,10 @@ namespace Elwig.Documents {
doc.Add(new KernedParagraph(Variant.Name, 14) doc.Add(new KernedParagraph(Variant.Name, 14)
.SetTextAlignment(TextAlignment.CENTER).SetFont(BF) .SetTextAlignment(TextAlignment.CENTER).SetFont(BF)
.SetMarginsMM(0, 0, 10, 0)); .SetMarginsMM(0, 0, 10, 0));
doc.Add(NewVariantStatTable().SetMarginBottomMM(10)); doc.Add(NewVariantStatTable(Data).SetMarginBottomMM(10));
doc.Add(NewModifierStatTable()); doc.Add(NewModifierStatTable(Modifiers, ModifierStat));
doc.Add(new AreaBreak(AreaBreakType.NEXT_PAGE)); doc.Add(new AreaBreak(AreaBreakType.NEXT_PAGE));
doc.Add(NewPriceTable()); doc.Add(NewPriceTable(Data));
} }
protected Cell NewSectionHdr(string text, int colspan = 1, bool borderLeft = false) { protected Cell NewSectionHdr(string text, int colspan = 1, bool borderLeft = false) {
@@ -67,33 +87,33 @@ namespace Elwig.Documents {
.SetBorderLeft(borderLeft ? new SolidBorder(BorderThickness) : Border.NO_BORDER); .SetBorderLeft(borderLeft ? new SolidBorder(BorderThickness) : Border.NO_BORDER);
} }
protected Table NewVariantStatTable() { protected Table NewVariantStatTable(PaymentVariantSummaryData data) {
var tbl = new Table(ColsMM(20, 30, 4.5, 4.5, 23.5, 47.5, 15, 20)) var tbl = new Table(ColsMM(20, 30, 4.5, 4.5, 23.5, 47.5, 15, 20))
.SetWidth(UnitValue.CreatePercentValue(100)).SetFixedLayout() .SetWidth(UnitValue.CreatePercentValue(100)).SetFixedLayout()
.SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE) .SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE)
.SetBorder(new SolidBorder(BorderThickness)); .SetBorder(new SolidBorder(BorderThickness));
//var sum1 = Variant.DeliveryPartPayments.Sum(p => p.NetAmount); //var sum1 = _parts.Sum(p => p.NetAmount);
//var sum2 = Variant.Credits.Sum(p => p.); //Variant.MemberPayments.Sum(p => p.Amount); //var sum2 = _credits.Sum(p => p.); //Variant.MemberPayments.Sum(p => p.Amount);
var deliveryModifiers = Variant.DeliveryPartPayments.Sum(p => p.Amount - p.NetAmount); var deliveryModifiers = _parts.Sum(p => p.Amount - p.NetAmount);
var memberModifiers = Variant.Credits.Sum(c => c.Payment.Amount - c.Payment.NetAmount); var memberModifiers = _credits.Sum(c => c.Payment.Amount - c.Payment.NetAmount);
var sum2 = Variant.Credits.Sum(p => p.NetAmount); var sum2 = _credits.Sum(p => p.NetAmount);
var sum1 = sum2 - deliveryModifiers - memberModifiers; var sum1 = sum2 - deliveryModifiers - memberModifiers;
var payed = -Variant.Credits.Sum(p => p.PrevNetAmount ?? 0m); var payed = -_credits.Sum(p => p.PrevNetAmount ?? 0m);
var netSum = Variant.Credits.Sum(p => p.NetAmount) - Variant.Credits.Sum(p => p.PrevNetAmount ?? 0m); var netSum = _credits.Sum(p => p.NetAmount) - _credits.Sum(p => p.PrevNetAmount ?? 0m);
var vat = Variant.Credits.Sum(p => p.VatAmount); var vat = _credits.Sum(p => p.VatAmount);
var grossSum = Variant.Credits.Sum(p => p.GrossAmount); var grossSum = _credits.Sum(p => p.GrossAmount);
var totalMods = Variant.Credits.Sum(p => p.Modifiers ?? 0m); var totalMods = _credits.Sum(p => p.Modifiers ?? 0m);
var considered = -Variant.Credits.Sum(p => p.PrevModifiers ?? 0m); var considered = -_credits.Sum(p => p.PrevModifiers ?? 0m);
var totalSum = Variant.Credits.Sum(p => p.Amount); var totalSum = _credits.Sum(p => p.Amount);
var weiRows = Data.Rows.Where(r => r.QualityLevel == "Wein"); var weiRows = data.Rows.Where(r => r.QualityLevel == "Wein");
var minWei = weiRows.Min(r => r.Ungeb.MinPrice); var minWei = weiRows.Min(r => r.Ungeb.MinPrice);
var maxWei = weiRows.Max(r => r.Ungeb.MaxPrice); var maxWei = weiRows.Max(r => r.Ungeb.MaxPrice);
var quwRows = Data.Rows.Where(r => r.QualityLevel != "Wein"); var quwRows = data.Rows.Where(r => r.QualityLevel != "Wein");
var minPrice = quwRows.Min(r => r.Ungeb.MinPrice); var minPrice = quwRows.Min(r => r.Ungeb.MinPrice);
var maxPrice = quwRows.Max(r => r.Ungeb.MaxPrice); var maxPrice = quwRows.Max(r => r.Ungeb.MaxPrice);
var gebRows = Data.Rows var gebRows = data.Rows
.Where(r => r.Geb.MaxPrice != null && r.Ungeb.MinPrice != null) .Where(r => r.Geb.MaxPrice != null && r.Ungeb.MinPrice != null)
.Select(r => r.Geb.MaxPrice - r.Ungeb.MinPrice); .Select(r => r.Geb.MaxPrice - r.Ungeb.MinPrice);
var minGeb = gebRows.Min(); var minGeb = gebRows.Min();
@@ -119,7 +139,7 @@ namespace Elwig.Documents {
.AddCell(NewSectionTh("Datum/Überw.:", overflow: true)) .AddCell(NewSectionTh("Datum/Überw.:", overflow: true))
.AddCell(NewTd($"{Variant.Date:dd.MM.yyyy} / {Variant.TransferDate:dd.MM.yyyy}", colspan: 4, center: true)) .AddCell(NewTd($"{Variant.Date:dd.MM.yyyy} / {Variant.TransferDate:dd.MM.yyyy}", colspan: 4, center: true))
.AddCell(NewSectionTh("Automatische Nachzeichnung der GA:", colspan: 2, borderLeft: true)) .AddCell(NewSectionTh("(Automatische) Nachzeichnung von GA:", colspan: 2, borderLeft: true))
.AddCell(NewTd(BillingData.ConsiderAutoBusinessShares ? "Ja" : "Nein", center: true)) .AddCell(NewTd(BillingData.ConsiderAutoBusinessShares ? "Ja" : "Nein", center: true))
.AddCell(NewSectionTh("Berechnung:")) .AddCell(NewSectionTh("Berechnung:"))
@@ -163,21 +183,21 @@ namespace Elwig.Documents {
.AddCell(NewTd(CurrencySymbol)) .AddCell(NewTd(CurrencySymbol))
.AddCell(NewTd($"{Math.Abs(payed):N2}", right: true)) .AddCell(NewTd($"{Math.Abs(payed):N2}", right: true))
.AddCell(NewSectionTh("Preis (abgewertet):", borderTop: true, borderLeft: true)) .AddCell(NewSectionTh("Preis (abgewertet):", borderTop: true, borderLeft: true))
.AddCell(NewTd((minWei != maxWei ? $"{minWei:N4}\u2013{maxWei:N4}" : $"{minWei:N4}") + $" {CurrencySymbol}/kg", colspan: 2, center: true, borderTop: true)) .AddCell(NewTd(minWei == null && maxWei == null ? "-" : (minWei != maxWei ? $"{minWei:N4}\u2013{maxWei:N4}" : $"{minWei:N4}") + $" {CurrencySymbol}/kg", colspan: 2, center: true, borderTop: true))
.AddCell(NewSectionTh("Nettosumme:", colspan: 2)) .AddCell(NewSectionTh("Nettosumme:", colspan: 2))
.AddCell(NewTd(borderTop: true)) .AddCell(NewTd(borderTop: true))
.AddCell(NewTd(CurrencySymbol, borderTop: true)) .AddCell(NewTd(CurrencySymbol, borderTop: true))
.AddCell(NewTd($"{netSum:N2}", right: true, borderTop: true)) .AddCell(NewTd($"{netSum:N2}", right: true, borderTop: true))
.AddCell(NewSectionTh("Preis (ungeb., nicht abgew.):", borderLeft: true)) .AddCell(NewSectionTh("Preis (ungeb., nicht abgew.):", borderLeft: true))
.AddCell(NewTd((minPrice != maxPrice ? $"{minPrice:N4}{maxPrice:N4}" : $"{minPrice:N4}") + $" {CurrencySymbol}/kg", colspan: 2, center: true)) .AddCell(NewTd(minPrice == null && maxPrice == null ? "-" : (minPrice != maxPrice ? $"{minPrice:N4}{maxPrice:N4}" : $"{minPrice:N4}") + $" {CurrencySymbol}/kg", colspan: 2, center: true))
.AddCell(NewSectionTh("Mehrwertsteuer:", colspan: 2)) .AddCell(NewSectionTh("Mehrwertsteuer:", colspan: 2))
.AddCell(NewTd(Utils.GetSign(vat), right: true)) .AddCell(NewTd(Utils.GetSign(vat), right: true))
.AddCell(NewTd(CurrencySymbol)) .AddCell(NewTd(CurrencySymbol))
.AddCell(NewTd($"{Math.Abs(vat):N2}", right: true)) .AddCell(NewTd($"{Math.Abs(vat):N2}", right: true))
.AddCell(NewSectionTh("Gebunden-Zuschlag:", borderLeft: true)) .AddCell(NewSectionTh("Gebunden-Zuschlag:", borderLeft: true))
.AddCell(NewTd(minGeb != maxGeb ? $"{minGeb:N4}\u2013{maxGeb:N4} {CurrencySymbol}/kg" : minGeb == 0 ? "-" : $"{minGeb:N4} {CurrencySymbol}/kg", colspan: 2, center: true)) .AddCell(NewTd(minGeb == null && maxGeb == null ? "-" : minGeb != maxGeb ? $"{minGeb:N4}\u2013{maxGeb:N4} {CurrencySymbol}/kg" : minGeb == 0 ? "-" : $"{minGeb:N4} {CurrencySymbol}/kg", colspan: 2, center: true))
.AddCell(NewSectionTh("Bruttosumme:", colspan: 2)) .AddCell(NewSectionTh("Bruttosumme:", colspan: 2))
.AddCell(NewTd(borderTop: true)) .AddCell(NewTd(borderTop: true))
@@ -191,26 +211,26 @@ namespace Elwig.Documents {
.AddCell(NewTd(CurrencySymbol)) .AddCell(NewTd(CurrencySymbol))
.AddCell(NewTd($"{Math.Abs(totalMods):N2}", right: true)) .AddCell(NewTd($"{Math.Abs(totalMods):N2}", right: true))
.AddCell(NewSectionTh("Menge (ungebunden):", borderLeft: true, borderTop: true)) .AddCell(NewSectionTh("Menge (ungebunden):", borderLeft: true, borderTop: true))
.AddCell(NewTd($"{Data.Rows.Sum(r => r.Ungeb.Weight):N0} kg", colspan: 2, right: true, borderTop: true)) .AddCell(NewTd($"{data.Rows.Sum(r => r.Ungeb.Weight):N0} kg", colspan: 2, right: true, borderTop: true))
.AddCell(NewSectionTh("Bereits berücksichtigte Abzüge:", colspan: 2)) .AddCell(NewSectionTh("Bereits berücksichtigte Abzüge:", colspan: 2))
.AddCell(NewTd(Utils.GetSign(considered))) .AddCell(NewTd(Utils.GetSign(considered)))
.AddCell(NewTd(CurrencySymbol)) .AddCell(NewTd(CurrencySymbol))
.AddCell(NewTd($"{Math.Abs(considered):N2}", right: true)) .AddCell(NewTd($"{Math.Abs(considered):N2}", right: true))
.AddCell(NewSectionTh("Menge (gebunden):", borderLeft: true)) .AddCell(NewSectionTh("Menge (gebunden):", borderLeft: true))
.AddCell(NewTd($"{Data.Rows.Sum(r => r.Geb.Weight + r.LowGeb.Weight):N0} kg", colspan: 2, right: true)) .AddCell(NewTd($"{data.Rows.Sum(r => r.Geb.Weight + r.LowGeb.Weight):N0} kg", colspan: 2, right: true))
.AddCell(NewSectionTh("Auszahlungsbetrag:", colspan: 2)) .AddCell(NewSectionTh("Auszahlungsbetrag:", colspan: 2))
.AddCell(NewTd(borderTop: true)) .AddCell(NewTd(borderTop: true))
.AddCell(NewTd(CurrencySymbol, borderTop: true)) .AddCell(NewTd(CurrencySymbol, borderTop: true))
.AddCell(NewTd($"{totalSum:N2}", right: true, borderTop: true)) .AddCell(NewTd($"{totalSum:N2}", right: true, borderTop: true))
.AddCell(NewSectionTh("Gesamtmenge:", borderLeft: true)) .AddCell(NewSectionTh("Gesamtmenge:", borderLeft: true))
.AddCell(NewTd($"{Data.Rows.Sum(r => r.Ungeb.Weight + r.LowGeb.Weight + r.Geb.Weight):N0} kg", colspan: 2, right: true, borderTop: true)); .AddCell(NewTd($"{data.Rows.Sum(r => r.Ungeb.Weight + r.LowGeb.Weight + r.Geb.Weight):N0} kg", colspan: 2, right: true, borderTop: true));
return tbl; return tbl;
} }
protected Table NewModifierStatTable() { protected Table NewModifierStatTable(Dictionary<string, Modifier> modifiers, IEnumerable<ModifierStat> modStat) {
var tbl = new Table(ColsMM(35, 30, 25, 25, 25, 25)) var tbl = new Table(ColsMM(35, 30, 25, 25, 25, 25))
.SetWidth(UnitValue.CreatePercentValue(100)).SetFixedLayout() .SetWidth(UnitValue.CreatePercentValue(100)).SetFixedLayout()
.SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE) .SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE)
@@ -228,8 +248,8 @@ namespace Elwig.Documents {
.AddCell(NewTh($"[{CurrencySymbol}]")) .AddCell(NewTh($"[{CurrencySymbol}]"))
.AddCell(NewTh($"[{CurrencySymbol}]")); .AddCell(NewTh($"[{CurrencySymbol}]"));
foreach (var m in ModifierStat) { foreach (var m in modStat) {
var mod = Modifiers[m.ModId]; var mod = modifiers[m.ModId];
tbl.AddCell(NewTd(mod.Name, italic: true)) tbl.AddCell(NewTd(mod.Name, italic: true))
.AddCell(NewTd(mod.ValueStr, right: true)) .AddCell(NewTd(mod.ValueStr, right: true))
.AddCell(NewTd($"{m.Count:N0}", right: true)) .AddCell(NewTd($"{m.Count:N0}", right: true))
@@ -241,7 +261,7 @@ namespace Elwig.Documents {
return tbl; return tbl;
} }
protected Table NewPriceTable() { protected Table NewPriceTable(PaymentVariantSummaryData data) {
var tbl = new Table(ColsMM(25, 19, 18, 15, 18, 15, 18, 15, 22)) var tbl = new Table(ColsMM(25, 19, 18, 15, 18, 15, 18, 15, 22))
.SetWidth(UnitValue.CreatePercentValue(100)).SetFixedLayout() .SetWidth(UnitValue.CreatePercentValue(100)).SetFixedLayout()
.SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE); .SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE);
@@ -262,10 +282,10 @@ namespace Elwig.Documents {
.AddHeaderCell(NewTh($"[{CurrencySymbol}]")); .AddHeaderCell(NewTh($"[{CurrencySymbol}]"));
string? lastHdr = null; string? lastHdr = null;
foreach (var row in Data.Rows) { foreach (var row in data.Rows) {
var hdr = $"{row.Variety}{(row.Attribute != null ? " / " : "")}{row.Attribute}{(row.Cultivation != null ? " / " : "")}{row.Cultivation}"; var hdr = $"{row.Variety}{(row.Attribute != null ? " / " : "")}{row.Attribute}{(row.Cultivation != null ? " / " : "")}{row.Cultivation}";
if (lastHdr != hdr) { if (lastHdr != hdr) {
var rows = Data.Rows var rows = data.Rows
.Where(r => r.Variety == row.Variety && r.Attribute == row.Attribute && r.Cultivation == row.Cultivation) .Where(r => r.Variety == row.Variety && r.Attribute == row.Attribute && r.Cultivation == row.Cultivation)
.ToList(); .ToList();
var border = lastHdr != null; var border = lastHdr != null;
+14 -15
View File
@@ -9,7 +9,7 @@
<UseWindowsForms>true</UseWindowsForms> <UseWindowsForms>true</UseWindowsForms>
<PreserveCompilationContext>true</PreserveCompilationContext> <PreserveCompilationContext>true</PreserveCompilationContext>
<ApplicationIcon>Resources\Images\Elwig.ico</ApplicationIcon> <ApplicationIcon>Resources\Images\Elwig.ico</ApplicationIcon>
<Version>1.0.4.0</Version> <Version>1.1.0.0</Version>
<SatelliteResourceLanguages>de-AT</SatelliteResourceLanguages> <SatelliteResourceLanguages>de-AT</SatelliteResourceLanguages>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<ApplicationManifest>app.manifest</ApplicationManifest> <ApplicationManifest>app.manifest</ApplicationManifest>
@@ -23,22 +23,21 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="bblanchon.PDFium.Win32" Version="148.0.7749" /> <PackageReference Include="bblanchon.PDFium.Win32" Version="152.0.7934" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.2" /> <PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.2" />
<PackageReference Include="itext" Version="9.5.0" /> <PackageReference Include="itext" Version="9.7.0" />
<PackageReference Include="itext.bouncy-castle-adapter" Version="9.5.0" /> <PackageReference Include="itext.bouncy-castle-adapter" Version="9.7.0" />
<PackageReference Include="LinqKit" Version="1.3.11" /> <PackageReference Include="LinqKit" Version="1.3.11" />
<PackageReference Include="MailKit" Version="4.15.1" /> <PackageReference Include="MailKit" Version="4.17.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="10.0.5" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.9" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.5" /> <PackageReference Include="Microsoft.Extensions.Configuration.Ini" Version="10.0.9" />
<PackageReference Include="Microsoft.Extensions.Configuration.Ini" Version="10.0.5" /> <PackageReference Include="Microsoft.Web.WebView2" Version="1.0.4078.44" />
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.3856.49" /> <PackageReference Include="NJsonSchema" Version="11.6.1" />
<PackageReference Include="NJsonSchema" Version="11.5.2" /> <PackageReference Include="ScottPlot.WPF" Version="5.1.59" />
<PackageReference Include="ScottPlot.WPF" Version="5.1.57" /> <PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="3.0.3" />
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="3.0.2" /> <PackageReference Include="System.IO.Hashing" Version="10.0.9" />
<PackageReference Include="System.IO.Hashing" Version="10.0.5" /> <PackageReference Include="System.IO.Ports" Version="10.0.9" />
<PackageReference Include="System.IO.Ports" Version="10.0.5" /> <PackageReference Include="System.Management" Version="10.0.9" />
<PackageReference Include="System.Management" Version="10.0.5" />
</ItemGroup> </ItemGroup>
</Project> </Project>
+225 -56
View File
@@ -1,19 +1,20 @@
using Microsoft.EntityFrameworkCore;
using Elwig.Models.Entities;
using System.Linq;
using System.Threading.Tasks;
using System.IO;
using System;
using System.Windows;
using Microsoft.Extensions.Logging;
using Microsoft.Data.Sqlite;
using System.Text.RegularExpressions;
using System.Collections.Generic;
using Elwig.Models.Dtos; using Elwig.Models.Dtos;
using Elwig.Models.Entities;
using Elwig.Services;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Data; using System.Data;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace Elwig.Helpers { namespace Elwig.Helpers {
public record struct MemberHistoryPoint(int Shares, int SharesRed, int SharesWhite, int SharesDormant);
public record struct AreaComBucket(int Area, int Obligation, int Right); public record struct AreaComBucket(int Area, int Obligation, int Right);
public record struct UnderDelivery(int Weight, int Diff); public record struct UnderDelivery(int Weight, int Diff);
public record struct MemberBucket(string Name, int Area, int Obligation, int Right, int Delivery, int DeliveryStrict, int DeliveryTotal, int Payment); public record struct MemberBucket(string Name, int Area, int Obligation, int Right, int Delivery, int DeliveryStrict, int DeliveryTotal, int Payment);
@@ -48,6 +49,7 @@ namespace Elwig.Helpers {
public DbSet<MemberTelNr> MemberTelephoneNrs { get; private set; } public DbSet<MemberTelNr> MemberTelephoneNrs { get; private set; }
public DbSet<MemberEmailAddr> MemberEmailAddrs { get; private set; } public DbSet<MemberEmailAddr> MemberEmailAddrs { get; private set; }
public DbSet<MemberHistory> MemberHistory { get; private set; } public DbSet<MemberHistory> MemberHistory { get; private set; }
public DbSet<AreaComContract> AreaCommitmentContracts { get; private set; }
public DbSet<AreaCom> AreaCommitments { get; private set; } public DbSet<AreaCom> AreaCommitments { get; private set; }
public DbSet<Season> Seasons { get; private set; } public DbSet<Season> Seasons { get; private set; }
public DbSet<DeliverySchedule> DeliverySchedules { get; private set; } public DbSet<DeliverySchedule> DeliverySchedules { get; private set; }
@@ -81,6 +83,71 @@ namespace Elwig.Helpers {
public static string? ConnectionStringOverride { get; set; } = null; public static string? ConnectionStringOverride { get; set; } = null;
public static string ConnectionString => ConnectionStringOverride ?? $"Data Source=\"{App.Config.DatabaseFile}\"; Mode=ReadWrite; Foreign Keys=True; Cache=Default; Pooling=False"; public static string ConnectionString => ConnectionStringOverride ?? $"Data Source=\"{App.Config.DatabaseFile}\"; Mode=ReadWrite; Foreign Keys=True; Cache=Default; Pooling=False";
private static readonly Func<AppDbContext, string?, bool, IAsyncEnumerable<Branch>> _compiledQueryBranches =
EF.CompileAsyncQuery<AppDbContext, string?, bool, Branch>((ctx, zwstid, includeWithoutMembers) => ctx.Branches
.Where(b => includeWithoutMembers || b.Members.Count > 0)
.Where(b => zwstid == null || b.ZwstId == zwstid)
.Include(b => b.PostalDest)
.OrderBy(b => b.Name));
private static readonly Func<AppDbContext, string?, IAsyncEnumerable<WineVar>> _compiledQueryWineVarieties =
EF.CompileAsyncQuery<AppDbContext, string?, WineVar>((ctx, sortid) => ctx.WineVarieties
.Where(v => sortid == null || v.SortId == sortid)
.OrderBy(v => v.Name));
private static readonly Func<AppDbContext, string?, bool, IAsyncEnumerable<WineAttr>> _compiledQueryWineAttributes =
EF.CompileAsyncQuery<AppDbContext, string?, bool, WineAttr>((ctx, attrid, includeNotActive) => ctx.WineAttributes
.Where(a => includeNotActive || a.IsActive)
.Where(a => attrid == null || a.AttrId == attrid)
.OrderBy(a => a.Name));
private static readonly Func<AppDbContext, string?, IAsyncEnumerable<WineCult>> _compiledQueryWineCultivations =
EF.CompileAsyncQuery<AppDbContext, string?, WineCult>((ctx, cultid) => ctx.WineCultivations
.Where(c => cultid == null || c.CultId == cultid)
.OrderBy(v => v.Name));
private static readonly Func<AppDbContext, bool, IAsyncEnumerable<WineQualLevel>> _compiledQueryWineQualityLevels =
EF.CompileAsyncQuery<AppDbContext, bool, WineQualLevel>((ctx, includePredicate) => ctx.WineQualityLevels
.Where(l => includePredicate || !l.IsPredicate)
.OrderBy(l => l.MinKmw));
private static readonly Func<AppDbContext, int?, bool, IAsyncEnumerable<Modifier>> _compiledQueryModifiers =
EF.CompileAsyncQuery<AppDbContext, int?, bool, Modifier>((ctx, year, incudeNotActive) => ctx.Modifiers
.Where(m => (year == null || m.Year == year) && (incudeNotActive || m.IsActive))
.OrderBy(m => m.Year).ThenBy(m => m.Ordering).ThenBy(m => m.Name));
private static readonly Func<AppDbContext, int?, bool, IAsyncEnumerable<Member>> _compiledQueryMembers =
EF.CompileAsyncQuery<AppDbContext, int?, bool, Member>((ctx, mgnr, includeNotActive) => ctx.Members
.Where(m => includeNotActive || m.IsActive)
.Where(m => mgnr == null || m.MgNr == mgnr)
.OrderBy(m => m.Name).ThenBy(m => m.GivenName).ThenBy(m => m.MgNr));
private static readonly Func<AppDbContext, int?, bool, IAsyncEnumerable<Member>> _compiledQueryMembersContactInfo =
EF.CompileAsyncQuery<AppDbContext, int?, bool, Member>((ctx, mgnr, includeNotActive) => ctx.Members
.Where(m => includeNotActive || m.IsActive)
.Where(m => mgnr == null || m.MgNr == mgnr)
.Include(m => m.EmailAddresses)
.Include(m => m.TelephoneNumbers)
.OrderBy(m => m.Name).ThenBy(m => m.GivenName).ThenBy(m => m.MgNr)
.AsSplitQuery());
private static readonly Func<AppDbContext, int?, IAsyncEnumerable<AreaCom>> _compiledQueryAreaCommitments =
EF.CompileAsyncQuery<AppDbContext, int?, AreaCom>((ctx, fbnr) => ctx.AreaCommitments
.Where(c => fbnr == null || c.FbNr == fbnr)
.OrderBy(c => c.FbNr).ThenBy(c => c.RevNr));
private static readonly Func<AppDbContext, int?, IAsyncEnumerable<Season>> _compiledQuerySeasons =
EF.CompileAsyncQuery<AppDbContext, int?, Season>((ctx, year) => ctx.Seasons
.Where(s => year == null || s.Year == year)
.OrderByDescending(s => s.Year));
private static readonly Func<AppDbContext, int?, IAsyncEnumerable<Season>> _compiledQuerySeasonsModifiers =
EF.CompileAsyncQuery<AppDbContext, int?, Season>((ctx, year) => ctx.Seasons
.Where(s => year == null || s.Year == year)
.Include(s => s.Modifiers)
.OrderByDescending(s => s.Year));
private readonly Dictionary<int, Dictionary<int, MemberHistoryPoint>> _memberHistory = [];
private readonly Dictionary<int, Dictionary<int, Dictionary<string, AreaComBucket>>> _memberAreaCommitmentBuckets = []; private readonly Dictionary<int, Dictionary<int, Dictionary<string, AreaComBucket>>> _memberAreaCommitmentBuckets = [];
private readonly Dictionary<int, Dictionary<int, Dictionary<string, int>>> _memberDeliveryBuckets = []; private readonly Dictionary<int, Dictionary<int, Dictionary<string, int>>> _memberDeliveryBuckets = [];
private readonly Dictionary<int, Dictionary<int, Dictionary<string, int>>> _memberDeliveryBucketsStrict = []; private readonly Dictionary<int, Dictionary<int, Dictionary<string, int>>> _memberDeliveryBucketsStrict = [];
@@ -94,8 +161,8 @@ namespace Elwig.Helpers {
LogFile = new(file) { LogFile = new(file) {
AutoFlush = true AutoFlush = true
}; };
} catch (Exception e) { } catch (Exception exc) {
MessageBox.Show($"Unable to open database log file:\n\n{e.Message}", "Database Log", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException("Database Log", $"Unable to open database log file", exc);
} }
} }
SavedLastWriteTime = LastWriteTime; SavedLastWriteTime = LastWriteTime;
@@ -118,11 +185,59 @@ namespace Elwig.Helpers {
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
optionsBuilder.UseSqlite(ConnectionString); optionsBuilder.UseSqlite(ConnectionString);
optionsBuilder.UseLazyLoadingProxies();
optionsBuilder.LogTo(Log, LogLevel.Information); optionsBuilder.LogTo(Log, LogLevel.Information);
base.OnConfiguring(optionsBuilder); base.OnConfiguring(optionsBuilder);
} }
protected override void OnModelCreating(ModelBuilder modelBuilder) {
modelBuilder.Entity<WbKg>().Navigation(k => k.AtKg).AutoInclude();
modelBuilder.Entity<WbKg>().Navigation(k => k.Gl).AutoInclude();
modelBuilder.Entity<AT_Kg>().Navigation(k => k.Gem).AutoInclude();
modelBuilder.Entity<PostalDest>().Navigation(p => p.Country).AutoInclude();
modelBuilder.Entity<PostalDest>().Navigation(p => p.AtPlz).AutoInclude();
modelBuilder.Entity<AT_PlzDest>().Navigation(p => p.AtPlz).AutoInclude();
modelBuilder.Entity<AT_PlzDest>().Navigation(p => p.Ort).AutoInclude();
modelBuilder.Entity<Member>().Navigation(m => m.Branch).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();
modelBuilder.Entity<MemberHistory>().Navigation(s => s.FromMember).AutoInclude();
modelBuilder.Entity<MemberHistory>().Navigation(s => s.ToMember).AutoInclude();
modelBuilder.Entity<MemberHistory>().Navigation(s => s.Currency).AutoInclude();
}
public override void Dispose() { public override void Dispose() {
base.Dispose(); base.Dispose();
LogFile?.Dispose(); LogFile?.Dispose();
@@ -138,23 +253,23 @@ namespace Elwig.Helpers {
} }
public async Task<bool> MgNrExists(int mgnr) { public async Task<bool> MgNrExists(int mgnr) {
return await Members.FindAsync(mgnr) != null; return await _compiledQueryMembers.Invoke(this, mgnr, true).AnyAsync();
} }
public async Task<bool> FbNrExists(int fbnr) { public async Task<bool> FbNrExists(int fbnr) {
return await AreaCommitments.FindAsync(fbnr) != null; return await _compiledQueryAreaCommitments.Invoke(this, fbnr).AnyAsync();
} }
public async Task<bool> SortIdExists(string sortId) { public async Task<bool> SortIdExists(string sortId) {
return await WineVarieties.FindAsync(sortId) != null; return await _compiledQueryWineVarieties.Invoke(this, sortId).AnyAsync();
} }
public async Task<bool> AttrIdExists(string attrId) { public async Task<bool> AttrIdExists(string attrId) {
return await WineAttributes.FindAsync(attrId) != null; return await _compiledQueryWineAttributes.Invoke(this, attrId, true).AnyAsync();
} }
public async Task<bool> CultIdExists(string cultId) { public async Task<bool> CultIdExists(string cultId) {
return await WineCultivations.FindAsync(cultId) != null; return await _compiledQueryWineCultivations.Invoke(this, cultId).AnyAsync();
} }
public async Task<int> NextMgNr() { public async Task<int> NextMgNr() {
@@ -166,87 +281,117 @@ namespace Elwig.Helpers {
public async Task<int> NextFbNr() { public async Task<int> NextFbNr() {
int c = 0; int c = 0;
(await AreaCommitments.OrderBy(ac => ac.FbNr).Select(ac => ac.FbNr).ToListAsync()) (await AreaCommitmentContracts.OrderBy(ac => ac.FbNr).Select(ac => ac.FbNr).ToListAsync())
.ForEach(a => { if (a <= c + 10000) c = a; }); .ForEach(a => { if (a <= c + 10000) c = a; });
return c + 1; return c + 1;
} }
public async Task<int> NextRevNr(int fbnr) {
return (await AreaCommitments.Where(c => c.FbNr == fbnr).Select(c => (int?)c.RevNr).MaxAsync() ?? 0) + 1;
}
public async Task<int> NextLNr(DateOnly date, string zwstid) { public async Task<int> NextLNr(DateOnly date, string zwstid) {
var dateStr = date.ToString("yyyy-MM-dd"); var dateStr = date.ToString("yyyy-MM-dd");
int c = 0; return (await Deliveries.Where(d => d.DateString == dateStr && d.ZwstId == zwstid).Select(d => (int?)d.LNr).MaxAsync() ?? 0) + 1;
(await Deliveries.Where(d => d.DateString == dateStr && d.ZwstId == zwstid).Select(d => d.LNr).ToListAsync())
.ForEach(a => { if (a <= c + 100) c = a; });
return c + 1;
} }
public async Task<int> NextDId(int year) { public async Task<int> NextDId(int year) {
int c = 0; return (await Deliveries.Where(d => d.Year == year).Select(d => (int?)d.DId).MaxAsync() ?? 0) + 1;
(await Deliveries.Where(d => d.Year == year).Select(d => d.DId).ToListAsync())
.ForEach(a => { if (a <= c + 100) c = a; });
return c + 1;
} }
public async Task<int> NextDPNr(int year, int did) { public async Task<int> NextDPNr(int year, int did) {
int c = 0; return (await DeliveryParts.Where(p => p.Year == year && p.DId == did).Select(p => (int?)p.DPNr).MaxAsync() ?? 0) + 1;
(await DeliveryParts.Where(p => p.Year == year && p.DId == did).Select(d => d.DPNr).ToListAsync())
.ForEach(a => { if (a <= c + 100) c = a; });
return c + 1;
} }
public async Task<int> NextRdNr(int kgnr) { public async Task<int> NextRdNr(int kgnr) {
int c = 0; return (await WbRde.Where(r => r.KgNr == kgnr).Select(r => (int?)r.RdNr).MaxAsync() ?? 0) + 1;
(await WbRde.Where(r => r.KgNr == kgnr).Select(r => r.RdNr).ToListAsync())
.ForEach(a => { if (a <= c + 100) c = a; });
return c + 1;
} }
public async Task<int> NextAvNr(int year) { public async Task<int> NextAvNr(int year) {
int c = 0; return (await PaymentVariants.Where(v => v.Year == year).Select(v => (int?)v.AvNr).MaxAsync() ?? 0) + 1;
(await PaymentVariants.Where(v => v.Year == year).Select(v => v.AvNr).ToListAsync())
.ForEach(a => { if (a <= c + 100) c = a; });
return c + 1;
} }
public async Task<int> NextDsNr(int year) { public async Task<int> NextDsNr(int year) {
int c = 0; return (await DeliverySchedules.Where(s => s.Year == year).Select(v => (int?)v.DsNr).MaxAsync() ?? 0) + 1;
(await DeliverySchedules.Where(s => s.Year == year).Select(s => s.DsNr).ToListAsync())
.ForEach(a => { if (a <= c + 100) c = a; });
return c + 1;
} }
public void UpdateDeliveryPartModifiers(DeliveryPart part, IEnumerable<Modifier> oldModifiers, IEnumerable<Modifier> newModifiers) { public async Task<int> NextHistNr() {
foreach (var m in Modifiers.Where(m => m.Year == part.Year)) { return (await MemberHistory.Select(c => (int?)c.HistNr).MaxAsync() ?? 0) + 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()) {
var mod = new DeliveryPartModifier { var mod = new DeliveryPartModifier {
Year = part.Year, Year = part.Year,
DId = part.DId, DId = part.DId,
DPNr = part.DPNr, DPNr = part.DPNr,
ModId = m.ModId, ModId = m.ModId,
}; };
var old = oldModifiers.Where(pa => pa.ModId == m.ModId).FirstOrDefault(); var old = oldModIds.Contains(m.ModId);
if (newModifiers.Any(md => md.ModId == m.ModId)) { if (newModIds.Contains(m.ModId)) {
if (old == null) { if (!old) {
Add(mod); Add(mod);
} else { } else {
Update(mod); Update(mod);
} }
} else { } else {
if (old != null) { if (old) {
Remove(mod); Remove(mod);
} }
} }
} }
} }
public void UpdateDeliveryScheduleWineVarieties(DeliverySchedule schedule, IEnumerable<(WineVar, int)> oldVarieties, IEnumerable<(WineVar, int)> newVarieties) { public async Task UpdateDeliveryScheduleWineVarieties(DeliverySchedule schedule, IEnumerable<(string, int)> oldVarieties, IEnumerable<(string, int)> newVarieties) {
foreach (var v in WineVarieties) { foreach (var v in await FetchWineVarieties().ToArrayAsync()) {
var e = new DeliveryScheduleWineVar { var e = new DeliveryScheduleWineVar {
Year = schedule.Year, Year = schedule.Year,
DsNr = schedule.DsNr, DsNr = schedule.DsNr,
SortId = v.SortId, SortId = v.SortId,
Priority = 1, Priority = 1,
}; };
var o = oldVarieties.Where(x => x.Item1.SortId == e.SortId).Select(x => x.Item2).FirstOrDefault(-1); var o = oldVarieties.Where(x => x.Item1 == e.SortId).Select(x => x.Item2).FirstOrDefault(-1);
var n = newVarieties.Where(x => x.Item1.SortId == e.SortId).Select(x => x.Item2).FirstOrDefault(-1); var n = newVarieties.Where(x => x.Item1 == e.SortId).Select(x => x.Item2).FirstOrDefault(-1);
if (n != -1) { if (n != -1) {
e.Priority = n; e.Priority = n;
if (o == -1) { if (o == -1) {
@@ -262,6 +407,22 @@ namespace Elwig.Helpers {
} }
} }
private async Task FetchMemberHistory(int year, SqliteConnection? cnx = null) {
var ownCnx = cnx == null;
cnx ??= await ConnectAsync();
var history = new Dictionary<int, MemberHistoryPoint>();
using (var cmd = cnx.CreateCommand()) {
cmd.CommandText = $"SELECT mgnr, shares, shares_red, shares_white, shares_dormant FROM v_member_history WHERE year = {year}";
using var reader = await cmd.ExecuteReaderAsync();
while (await reader.ReadAsync()) {
var mgnr = reader.GetInt32(0);
history[mgnr] = new(reader.GetInt32(1), reader.GetInt32(2), reader.GetInt32(3), reader.GetInt32(4));
}
}
if (ownCnx) await cnx.DisposeAsync();
_memberHistory[year] = history;
}
private async Task FetchMemberAreaCommitmentBuckets(int year, SqliteConnection? cnx = null) { private async Task FetchMemberAreaCommitmentBuckets(int year, SqliteConnection? cnx = null) {
var ownCnx = cnx == null; var ownCnx = cnx == null;
cnx ??= await ConnectAsync(); cnx ??= await ConnectAsync();
@@ -352,6 +513,12 @@ namespace Elwig.Helpers {
_memberUnderDelivery[year] = buckets; _memberUnderDelivery[year] = buckets;
} }
public async Task<MemberHistoryPoint> GetMemberHistory(int year, int mgnr, SqliteConnection? cnx = null) {
if (!_memberHistory.ContainsKey(year))
await FetchMemberHistory(year, cnx);
return _memberHistory[year].GetValueOrDefault(mgnr, new());
}
public async Task<Dictionary<string, AreaComBucket>> GetMemberAreaCommitmentBuckets(int year, int mgnr, SqliteConnection? cnx = null) { public async Task<Dictionary<string, AreaComBucket>> GetMemberAreaCommitmentBuckets(int year, int mgnr, SqliteConnection? cnx = null) {
if (!_memberAreaCommitmentBuckets.ContainsKey(year)) if (!_memberAreaCommitmentBuckets.ContainsKey(year))
await FetchMemberAreaCommitmentBuckets(year, cnx); await FetchMemberAreaCommitmentBuckets(year, cnx);
@@ -391,10 +558,12 @@ namespace Elwig.Helpers {
var paymentBuckets = await GetMemberPaymentBuckets(year, mgnr, cnx); var paymentBuckets = await GetMemberPaymentBuckets(year, mgnr, cnx);
if (ownCnx) await cnx.DisposeAsync(); if (ownCnx) await cnx.DisposeAsync();
var varieties = await WineVarieties.ToDictionaryAsync(v => v.SortId);
var attributes = await WineAttributes.ToDictionaryAsync(a => a.AttrId);
var buckets = new Dictionary<string, MemberBucket>(); var buckets = new Dictionary<string, MemberBucket>();
foreach (var id in rightsAndObligations.Keys.Union(deliveryBuckets.Keys).Union(paymentBuckets.Keys)) { foreach (var id in rightsAndObligations.Keys.Union(deliveryBuckets.Keys).Union(paymentBuckets.Keys)) {
var variety = await WineVarieties.FindAsync(id[..2]); var variety = varieties.GetValueOrDefault(id[..2]);
var attribute = await WineAttributes.FindAsync(id[2..]); var attribute = attributes.GetValueOrDefault(id[2..]);
var name = (variety?.Name ?? "") + (id[2..] == "_" ? " (kein Qual.Wein)" : attribute != null ? $" ({attribute})" : ""); var name = (variety?.Name ?? "") + (id[2..] == "_" ? " (kein Qual.Wein)" : attribute != null ? $" ({attribute})" : "");
buckets[id] = new( buckets[id] = new(
name, name,
+32 -22
View File
@@ -1,6 +1,6 @@
using Microsoft.Data.Sqlite;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Threading.Tasks; using System.Threading.Tasks;
@@ -9,36 +9,41 @@ namespace Elwig.Helpers {
public static class AppDbUpdater { public static class AppDbUpdater {
// Don't forget to update value in Tests/fetch-resources.bat! // Don't forget to update value in Tests/fetch-resources.bat!
public static readonly int RequiredSchemaVersion = 37; public static readonly int RequiredSchemaVersion = 40;
private static int VersionOffset = 0; private static int VersionOffset = 0;
public static async Task<Version> CheckDb() { public static async Task<Version> CheckDb() {
using var cnx = AppDbContext.Connect(); long? applId, schemaVers;
using (var cnx = await AppDbContext.ConnectAsync()) {
var applId = (long?)await cnx.ExecuteScalar("PRAGMA application_id") ?? 0; applId = (long?)await cnx.ExecuteScalar("PRAGMA application_id") ?? 0;
if (applId != 0x454C5747) throw new Exception($"Invalid application_id in database (0x{applId:X08})"); if (applId != 0x454C5747) throw new Exception($"Invalid application_id in database (0x{applId:X08})");
var schemaVers = (long?)await cnx.ExecuteScalar("PRAGMA schema_version") ?? 0; schemaVers = (long?)await cnx.ExecuteScalar("PRAGMA schema_version") ?? 0;
VersionOffset = (int)(schemaVers % 100); VersionOffset = (int)(schemaVers % 100);
if (VersionOffset != 0) { if (VersionOffset != 0) {
// schema was modified manually/externally // schema was modified manually/externally
// TODO issue warning // TODO issue warning
} }
await UpdateDbSchema(cnx, (int)(schemaVers / 100), RequiredSchemaVersion); }
await UpdateDbSchema((int)(schemaVers / 100), RequiredSchemaVersion);
Version v;
using (var cnx = await AppDbContext.ConnectAsync()) {
var userVers = (long?)await cnx.ExecuteScalar("PRAGMA user_version") ?? 0; var userVers = (long?)await cnx.ExecuteScalar("PRAGMA user_version") ?? 0;
var v = new Version((int)(userVers >> 24), (int)((userVers >> 16) & 0xFF), (int)((userVers >> 8) & 0xFF), (int)(userVers & 0xFF)); v = new Version((int)(userVers >> 24), (int)((userVers >> 16) & 0xFF), (int)((userVers >> 8) & 0xFF), (int)(userVers & 0xFF));
if (App.Version > v) { if (App.Version > v) {
long vers = (App.Version.Major << 24) | (App.Version.Minor << 16) | (App.Version.Build << 8) | App.Version.Revision; long vers = (App.Version.Major << 24) | (App.Version.Minor << 16) | (App.Version.Build << 8) | App.Version.Revision;
await cnx.ExecuteBatch($"PRAGMA user_version = {vers}"); await cnx.ExecuteBatch($"PRAGMA user_version = {vers}");
} }
}
return v; return v;
} }
private static async Task UpdateDbSchema(SqliteConnection cnx, int fromVersion, int toVersion) { private static async Task UpdateDbSchema(int fromVersion, int toVersion) {
if (fromVersion == toVersion) { if (fromVersion == toVersion) {
return; return;
} else if (fromVersion > toVersion) { } else if (fromVersion > toVersion) {
@@ -48,43 +53,48 @@ namespace Elwig.Helpers {
} }
var asm = Assembly.GetExecutingAssembly(); var asm = Assembly.GetExecutingAssembly();
(int From, int To, string Name)[] scripts = asm.GetManifestResourceNames() (int From, int To, string Name)[] scripts = [.. asm.GetManifestResourceNames()
.Where(n => n.StartsWith("Elwig.Resources.Sql.")) .Where(n => n.StartsWith("Elwig.Resources.Sql."))
.Select(n => { .Select(n => {
var p = n.Split(".")[^2].Split("-"); var p = n.Split(".")[^2].Split("-");
return (int.Parse(p[0]), int.Parse(p[1]), n); return (int.Parse(p[0]), int.Parse(p[1]), n);
}) })
.OrderBy(s => s.Item1).ThenBy(s => s.Item2) .OrderBy(s => s.Item1).ThenBy(s => s.Item2)];
.ToArray();
List<string> toExecute = []; List<string> toExecute = [];
var vers = fromVersion; var vers = fromVersion;
while (vers < toVersion) { while (vers < toVersion) {
var (_, to, name) = scripts.Where(s => s.From == vers).Last(); var (_, to, name) = scripts.Last(s => s.From == vers);
toExecute.Add(name); toExecute.Add(name);
vers = to; vers = to;
} }
if (toExecute.Count == 0) if (toExecute.Count == 0)
return; return;
await cnx.ExecuteBatch(""" var backup = Path.ChangeExtension(App.Config.DatabaseFile, $".v{fromVersion}.sqlite3");
PRAGMA locking_mode = EXCLUSIVE; File.Copy(App.Config.DatabaseFile, backup, true);
BEGIN EXCLUSIVE; try {
"""); using var cnx = await AppDbContext.ConnectAsync();
await cnx.ExecuteBatch("PRAGMA locking_mode = EXCLUSIVE");
foreach (var script in toExecute) { foreach (var script in toExecute) {
await cnx.ExecuteEmbeddedScript(asm, script); await cnx.ExecuteEmbeddedScript(asm, script);
} }
var violations = await cnx.ForeignKeyCheck(); var violations = await cnx.ForeignKeyCheck();
if (violations.Length > 0) { if (violations.Length > 0) {
throw new Exception($"Foreign key violations ({violations.Length}):\n" + string.Join("\n", violations throw new Exception($"Foreign key violations ({violations.Length}):\n" + string.Join("\n", violations
.Take(50)
.Select(v => $"{v.Table} - {v.RowId} - {v.Parent} - {v.FkId}"))); .Select(v => $"{v.Table} - {v.RowId} - {v.Parent} - {v.FkId}")));
} }
await cnx.ExecuteBatch($""" await cnx.ExecuteBatch("VACUUM");
COMMIT; await cnx.ExecuteBatch($"PRAGMA schema_version = {toVersion * 100 + VersionOffset}");
VACUUM; } catch (Exception) {
PRAGMA schema_version = {toVersion * 100 + VersionOffset}; File.Move(backup, App.Config.DatabaseFile, true);
"""); throw;
} finally {
File.Delete(backup);
}
} }
} }
} }
+34 -34
View File
@@ -1,6 +1,5 @@
using Elwig.Models.Entities; using Elwig.Models.Entities;
using Microsoft.Data.Sqlite; using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
@@ -16,13 +15,30 @@ namespace Elwig.Helpers.Billing {
protected readonly Dictionary<string, (decimal?, decimal?)> Modifiers; protected readonly Dictionary<string, (decimal?, decimal?)> Modifiers;
protected readonly Dictionary<string, (string, string?, string?, int?, decimal?)> AreaComTypes; protected readonly Dictionary<string, (string, string?, string?, int?, decimal?)> AreaComTypes;
public Billing(int year) { protected Billing(int year, Season season,
Dictionary<string, string> attributes,
Dictionary<string, (decimal?, decimal?)> modifiers,
Dictionary<string, (string, string?, string?, int?, decimal?)> areaComTypes
) {
Year = year; Year = year;
Season = season;
Attributes = attributes;
Modifiers = modifiers;
AreaComTypes = areaComTypes;
}
protected static async Task<(Season, Dictionary<string, string>, Dictionary<string, (decimal?, decimal?)>, Dictionary<string, (string, string?, string?, int?, decimal?)>)> LoadData(AppDbContext ctx, int year) {
var season = await ctx.FetchSeasons(year).SingleOrDefaultAsync() ?? throw new ArgumentException("Invalid season");
var attributes = await ctx.FetchWineAttributes().ToDictionaryAsync(a => a.AttrId, a => a.Name);
var modifiers = await ctx.FetchModifiers(year).ToDictionaryAsync(m => m.ModId, m => (m.Abs, m.Rel));
var areaComTypes = ctx.AreaCommitmentTypes.ToDictionary(v => v.VtrgId, v => (v.SortId, v.AttrId, v.Discriminator, v.MinKgPerHa, v.PenaltyAmount));
return (season, attributes, modifiers, areaComTypes);
}
public static async Task<Billing> Create(int year) {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
Season = ctx.Seasons.Find(Year)!; var (season, attributes, modifiers, areaComTypes) = await LoadData(ctx, year);
Attributes = ctx.WineAttributes.ToDictionary(a => a.AttrId, a => a.Name); return new Billing(year, season, attributes, modifiers, areaComTypes);
Modifiers = ctx.Modifiers.Where(m => m.Year == Year).Include(m => m.Season).ToDictionary(m => m.ModId, m => (m.Abs, m.Rel));
AreaComTypes = ctx.AreaCommitmentTypes.ToDictionary(v => v.VtrgId, v => (v.SortId, v.AttrId, v.Discriminator, v.MinKgPerHa, v.PenaltyAmount));
} }
public async Task FinishSeason() { public async Task FinishSeason() {
@@ -34,45 +50,29 @@ namespace Elwig.Helpers.Billing {
"""); """);
} }
public async Task AutoAdjustBusinessShares(DateOnly date, int allowanceKg = 0, double allowanceBs = 0, int allowanceKgPerBs = 0, double allowanceRel = 0, int addMinBs = 1) { public async Task AutoAdjustBusinessShares(DateOnly date, int allowanceKg = 0, double allowanceShares = 0, int allowanceKgPerShare = 0, double allowanceRel = 0, int addMinShares = 1) {
if (addMinBs < 1) addMinBs = 1; if (addMinShares < 1) addMinShares = 1;
using var cnx = await AppDbContext.ConnectAsync(); using var cnx = await AppDbContext.ConnectAsync();
await cnx.ExecuteBatch($""" await cnx.ExecuteBatch($"""
UPDATE member DELETE FROM member_history WHERE source = 'elwig' AND reason = '{MemberHistory.REASON_PRESCRIPTION}' AND deduct_year = {Year};
SET business_shares = member.business_shares - h.business_shares INSERT INTO member_history (histnr, from_mgnr, from_type, to_mgnr, to_type, date_notice, date_effective, reason, source, deduct_year, shares, value_per_share, currency, comment)
FROM member_history h SELECT COALESCE((SELECT MAX(histnr) AS histnr FROM member_history), 0) + ROW_NUMBER() OVER(ORDER BY m.mgnr),
WHERE h.date = '{Year}-11-30' AND h.type = 'auto' AND h.mgnr = member.mgnr AND member.active; NULL, NULL, u.mgnr, 1, '{date:yyyy-MM-dd}', '{date:yyyy-MM-dd}', '{MemberHistory.REASON_PRESCRIPTION}', 'elwig', s.year,
CEIL((u.diff - {allowanceKg}.0 - {allowanceKgPerShare}.0 * u.shares) / s.max_kg_per_share
INSERT INTO member_history (mgnr, date, type, business_shares) - {allowanceShares.ToString(CultureInfo.InvariantCulture)}
SELECT u.mgnr, - {allowanceRel.ToString(CultureInfo.InvariantCulture)} * u.shares) AS adjust_shares,
'{date:yyyy-MM-dd}', s.share_value / POW(10, s.precision - 2), s.currency, 'durch automatische Nachzeichnung'
'auto',
CEIL((u.diff - {allowanceKg}.0 - {allowanceKgPerBs}.0 * u.business_shares) / s.max_kg_per_bs
- {allowanceBs.ToString(CultureInfo.InvariantCulture)}
- {allowanceRel.ToString(CultureInfo.InvariantCulture)} * u.business_shares) AS bs
FROM v_total_under_delivery u FROM v_total_under_delivery u
JOIN season s ON s.year = u.year JOIN season s ON s.year = u.year
JOIN member m ON m.mgnr = u.mgnr JOIN member m ON m.mgnr = u.mgnr
WHERE s.year = {Year} AND bs >= {addMinBs} AND m.active WHERE s.year = {Year} AND adjust_shares >= {addMinShares} AND m.active
ON CONFLICT DO UPDATE
SET business_shares = excluded.business_shares;
UPDATE member
SET business_shares = member.business_shares + h.business_shares
FROM member_history h
WHERE h.date = '{Year}-11-30' AND h.type = 'auto' AND h.mgnr = member.mgnr;
"""); """);
} }
public async Task UnAdjustBusinessShares() { public async Task UnAdjustBusinessShares() {
using var cnx = await AppDbContext.ConnectAsync(); using var cnx = await AppDbContext.ConnectAsync();
await cnx.ExecuteBatch($""" await cnx.ExecuteBatch($"""
UPDATE member DELETE FROM member_history WHERE source = 'elwig' AND reason = '{MemberHistory.REASON_PRESCRIPTION}' AND deduct_year = {Year};
SET business_shares = member.business_shares - h.business_shares
FROM member_history h
WHERE h.date = '{Year}-11-30' AND h.type = 'auto' AND h.mgnr = member.mgnr AND member.active;
DELETE FROM member_history WHERE date = '{Year}-11-30' AND type = 'auto';
"""); """);
} }
+25 -23
View File
@@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text.Json;
using System.Text.Json.Nodes; using System.Text.Json.Nodes;
using System.Threading.Tasks; using System.Threading.Tasks;
@@ -92,6 +93,14 @@ namespace Elwig.Helpers.Billing {
Mode = (mode == "elwig") ? CalculationMode.Elwig : CalculationMode.WgMaster; 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) { protected static JsonObject ParseJson(string json) {
if (Schema == null) throw new InvalidOperationException("Schema has to be initialized first"); if (Schema == null) throw new InvalidOperationException("Schema has to be initialized first");
try { try {
@@ -107,6 +116,10 @@ namespace Elwig.Helpers.Billing {
return new(ParseJson(json)); return new(ParseJson(json));
} }
public string ToJsonString(JsonSerializerOptions? options = null) {
return Data.ToJsonString(options);
}
protected JsonArray GetCurvesEntry() { protected JsonArray GetCurvesEntry() {
return Data[Mode == CalculationMode.Elwig ? "curves" : "Kurven"]?.AsArray() ?? throw new InvalidOperationException(); return Data[Mode == CalculationMode.Elwig ? "curves" : "Kurven"]?.AsArray() ?? throw new InvalidOperationException();
} }
@@ -412,7 +425,7 @@ namespace Elwig.Helpers.Billing {
} }
} }
public static JsonObject FromGraphEntries( public static BillingData FromGraphEntries(
IEnumerable<GraphEntry> graphEntries, IEnumerable<GraphEntry> graphEntries,
BillingData? origData = null, BillingData? origData = null,
IEnumerable<RawVaribute>? vaributes = null, IEnumerable<RawVaribute>? vaributes = null,
@@ -446,40 +459,29 @@ namespace Elwig.Helpers.Billing {
} }
} }
CollapsePaymentData(payment, payment.DeepClone().AsObject(), vaributes ?? payment.Select(e => new RawVaribute(e.Key)).ToList(), useDefaultPayment); 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)).ToList(), useDefaultQuality); CollapsePaymentData(qualityWei, qualityWei.DeepClone().AsObject(), vaributes ?? [.. qualityWei.Select(e => new RawVaribute(e.Key))], 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) { if (payment.Count == 0) {
data["payment"] = 0; data.Data["payment"] = 0;
} else if (payment.Count == 1 && payment.First().Key == "default") { } else if (payment.Count == 1 && payment.First().Key == "default") {
data["payment"] = payment.Single().Value?.DeepClone(); data.Data["payment"] = payment.Single().Value?.DeepClone();
} else { } else {
data["payment"] = payment; data.Data["payment"] = payment;
} }
if (qualityWei.Count == 1 && qualityWei.First().Key == "default") { if (qualityWei.Count == 1 && qualityWei.First().Key == "default") {
data["quality"] = new JsonObject() { data.Data["quality"] = new JsonObject() {
["WEI"] = qualityWei.Single().Value?.DeepClone() ["WEI"] = qualityWei.Single().Value?.DeepClone()
}; };
} else if (qualityWei.Count >= 1) { } else if (qualityWei.Count >= 1) {
data["quality"] = new JsonObject() { data.Data["quality"] = new JsonObject() {
["WEI"] = qualityWei ["WEI"] = qualityWei
}; };
} else {
data.Data.Remove("quality");
} }
data["curves"] = curves; data.Data["curves"] = curves;
return data; return data;
} }
+30 -12
View File
@@ -10,17 +10,35 @@ namespace Elwig.Helpers.Billing {
public class BillingVariant : Billing { public class BillingVariant : Billing {
protected readonly int AvNr; protected readonly int AvNr;
protected readonly PaymentVar PaymentVariant; protected PaymentVar PaymentVariant;
protected readonly PaymentBillingData Data; protected PaymentBillingData Data;
public BillingVariant(int year, int avnr) : base(year) { protected BillingVariant(int year, int avnr, Season season,
Dictionary<string, string> attributes,
Dictionary<string, (decimal?, decimal?)> modifiers,
Dictionary<string, (string, string?, string?, int?, decimal?)> areaComTypes,
PaymentVar paymentVar, PaymentBillingData data) :
base(year, season, attributes, modifiers, areaComTypes) {
AvNr = avnr; AvNr = avnr;
PaymentVariant = paymentVar;
Data = data;
}
protected static async Task<(PaymentVar, PaymentBillingData)> LoadData(AppDbContext ctx, int year, int avnr) {
var paymentVar = await ctx.PaymentVariants.Where(v => v.Year == year && v.AvNr == avnr).SingleAsync();
var data = PaymentBillingData.FromJson(paymentVar.Data, await Utils.GetVaributes(ctx, year, onlyDelivered: false));
return (paymentVar, data);
}
public static async Task<BillingVariant> Create(int year, int avnr) {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
PaymentVariant = ctx.PaymentVariants.Include(v => v.Season).Where(v => v.Year == Year && v.AvNr == AvNr).Single() ?? throw new ArgumentException("PaymentVar not found"); var (season, attributes, modifiers, areaComTypes) = await LoadData(ctx, year);
Data = PaymentBillingData.FromJson(PaymentVariant.Data, Utils.GetVaributes(ctx, Year, onlyDelivered: false)); var (paymentVar, data) = await LoadData(ctx, year, avnr);
return new BillingVariant(year, avnr, season, attributes, modifiers, areaComTypes, paymentVar, data);
} }
public async Task Calculate(bool strictPrices = true, bool? honorGebunden = null, bool? allowAttrsIntoLower = null, bool? avoidUnderDeliveries = null) { public async Task Calculate(bool strictPrices = true, bool? honorGebunden = null, bool? allowAttrsIntoLower = null, bool? avoidUnderDeliveries = null) {
if (PaymentVariant == null || Data == null) throw new Exception("Call Load before Calculate");
using var cnx = await AppDbContext.ConnectAsync(); using var cnx = await AppDbContext.ConnectAsync();
using var tx = await cnx.BeginTransactionAsync(); using var tx = await cnx.BeginTransactionAsync();
await CalculateBuckets(honorGebunden, allowAttrsIntoLower, avoidUnderDeliveries, cnx); await CalculateBuckets(honorGebunden, allowAttrsIntoLower, avoidUnderDeliveries, cnx);
@@ -58,7 +76,7 @@ namespace Elwig.Helpers.Billing {
IIF(m.buchführend, s.vat_normal, s.vat_flatrate) AS vat, IIF(m.buchführend, s.vat_normal, s.vat_flatrate) AS vat,
ROUND(IIF({Data.ConsiderTotalPenalty}, COALESCE(b.total_penalty, 0), 0) / POW(10, s.precision - 2)) + ROUND(IIF({Data.ConsiderTotalPenalty}, COALESCE(b.total_penalty, 0), 0) / POW(10, s.precision - 2)) +
ROUND(IIF({Data.ConsiderContractPenalties}, COALESCE(u.total_penalty, 0), 0) / POW(10, 4 - 2)) + ROUND(IIF({Data.ConsiderContractPenalties}, COALESCE(u.total_penalty, 0), 0) / POW(10, 4 - 2)) +
ROUND(IIF({Data.ConsiderAutoBusinessShares}, -COALESCE(a.total_amount, 0), 0) / POW(10, s.precision - 2)) + ROUND(IIF({Data.ConsiderAutoBusinessShares}, -COALESCE(a.total_amount, 0), 0)) +
IIF({Data.ConsiderCustomModifiers}, COALESCE(x.amount, 0), 0) IIF({Data.ConsiderCustomModifiers}, COALESCE(x.amount, 0), 0)
AS modifiers, AS modifiers,
IIF(lc.amount < 0, 0, lc.modifiers) AS prev_modifiers IIF(lc.amount < 0, 0, lc.modifiers) AS prev_modifiers
@@ -80,7 +98,7 @@ namespace Elwig.Helpers.Billing {
LEFT JOIN v_penalty_area_commitments u ON (u.year, u.mgnr) = (s.year, m.mgnr) 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 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) 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($""" await cnx.ExecuteBatch($"""
UPDATE payment_variant SET test_variant = FALSE WHERE (year, avnr) = ({Year}, {AvNr}); UPDATE payment_variant SET test_variant = FALSE WHERE (year, avnr) = ({Year}, {AvNr});
@@ -119,11 +137,11 @@ namespace Elwig.Helpers.Billing {
await cnx.ExecuteBatch($""" await cnx.ExecuteBatch($"""
INSERT INTO payment_member (year, avnr, mgnr, net_amount, mod_abs, mod_rel) INSERT INTO payment_member (year, avnr, mgnr, net_amount, mod_abs, mod_rel)
SELECT c.year, {AvNr}, s.mgnr, 0, SELECT c.year, {AvNr}, s.mgnr, 0,
ROUND(s.sum * COALESCE(m.abs, 0)), ROUND(s.weight_total * COALESCE(m.abs, 0)),
COALESCE(m.rel, 0) COALESCE(m.rel, 0)
FROM (SELECT {Year} AS year, m.mgnr, FROM (SELECT {Year} AS year, m.mgnr,
ROUND(AVG(COALESCE(a.sum, b.sum)) * {multiplier}) AS baseline, ROUND(AVG(COALESCE(a.weight_total, b.weight_total)) * {multiplier}) AS baseline,
COUNT(*) = {lastYears} AND MIN(COALESCE(a.sum, b.sum)) > 0 AS allowed COUNT(*) = {lastYears} AND MIN(COALESCE(a.weight_total, b.weight_total)) > 0 AS allowed
FROM member m FROM member m
LEFT JOIN v_stat_member a ON a.mgnr = m.mgnr LEFT JOIN v_stat_member a ON a.mgnr = m.mgnr
FULL OUTER JOIN v_stat_member b ON b.mgnr = m.predecessor_mgnr AND b.year = a.year AND {(includePredecessor ? "TRUE" : "FALSE")} FULL OUTER JOIN v_stat_member b ON b.mgnr = m.predecessor_mgnr AND b.year = a.year AND {(includePredecessor ? "TRUE" : "FALSE")}
@@ -132,7 +150,7 @@ namespace Elwig.Helpers.Billing {
HAVING allowed) c HAVING allowed) c
JOIN v_stat_member s ON (s.year, s.mgnr) = (c.year, c.mgnr) JOIN v_stat_member s ON (s.year, s.mgnr) = (c.year, c.mgnr)
LEFT JOIN modifier m ON m.year = c.year AND m.name LIKE '{modName}' LEFT JOIN modifier m ON m.year = c.year AND m.name LIKE '{modName}'
WHERE sum >= baseline WHERE weight_total >= baseline
ON CONFLICT DO UPDATE ON CONFLICT DO UPDATE
SET mod_abs = mod_abs + excluded.mod_abs, SET mod_abs = mod_abs + excluded.mod_abs,
mod_rel = mod_rel + excluded.mod_rel mod_rel = mod_rel + excluded.mod_rel
@@ -214,7 +232,7 @@ namespace Elwig.Helpers.Billing {
SET mod_rel = mod_rel + excluded.mod_rel; SET mod_rel = mod_rel + excluded.mod_rel;
INSERT INTO payment_delivery_part (year, did, dpnr, avnr, net_amount, mod_abs, mod_rel) INSERT INTO payment_delivery_part (year, did, dpnr, avnr, net_amount, mod_abs, mod_rel)
SELECT d.year, d.did, d.dpnr, {AvNr}, 0, COALESCE(m.abs, 0), COALESCE(m.rel, 0) SELECT d.year, d.did, d.dpnr, {AvNr}, 0, COALESCE(m.abs, 0) * d.weight, COALESCE(m.rel, 0)
FROM delivery_part d 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 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) LEFT JOIN modifier m ON (m.year, m.modid) = (d.year, p.modid)
+9 -8
View File
@@ -3,6 +3,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text.Json.Nodes; using System.Text.Json.Nodes;
using System.Threading.Tasks;
namespace Elwig.Helpers.Billing { namespace Elwig.Helpers.Billing {
public class EditBillingData : BillingData { public class EditBillingData : BillingData {
@@ -70,14 +71,14 @@ namespace Elwig.Helpers.Billing {
return (curves, dict3); return (curves, dict3);
} }
private static List<GraphEntry> CreateGraphEntries( private static async Task<List<GraphEntry>> CreateGraphEntries(
AppDbContext ctx, int precision, AppDbContext ctx, int precision,
Dictionary<int, Curve> curves, Dictionary<int, Curve> curves,
Dictionary<int, List<RawVaribute>> entries Dictionary<int, List<RawVaribute>> entries
) { ) {
var vars = ctx.WineVarieties.ToDictionary(v => v.SortId, v => v); var vars = await ctx.FetchWineVarieties().ToDictionaryAsync(v => v.SortId, v => v);
var attrs = ctx.WineAttributes.ToDictionary(a => a.AttrId, a => a); var attrs = await ctx.FetchWineAttributes().ToDictionaryAsync(a => a.AttrId, a => a);
var cults = ctx.WineCultivations.ToDictionary(c => c.CultId, c => c); var cults = await ctx.FetchWineCultivations().ToDictionaryAsync(c => c.CultId, c => c);
return entries return entries
.Select(e => new GraphEntry(e.Key, precision, curves[e.Key], e.Value .Select(e => new GraphEntry(e.Key, precision, curves[e.Key], e.Value
.Select(s => new Varibute(s, vars, attrs, cults)) .Select(s => new Varibute(s, vars, attrs, cults))
@@ -85,18 +86,18 @@ namespace Elwig.Helpers.Billing {
.ToList(); .ToList();
} }
public IEnumerable<GraphEntry> GetPaymentGraphEntries(AppDbContext ctx, Season season) { public async Task<IEnumerable<GraphEntry>> GetPaymentGraphEntries(AppDbContext ctx, Season season) {
var root = GetPaymentEntry(); var root = GetPaymentEntry();
var (curves, entries) = GetGraphEntries(root); var (curves, entries) = GetGraphEntries(root);
return CreateGraphEntries(ctx, season.Precision, curves, entries).Where(e => e.Vaributes.Count > 0); return (await CreateGraphEntries(ctx, season.Precision, curves, entries)).Where(e => e.Vaributes.Count > 0);
} }
public IEnumerable<GraphEntry> GetQualityGraphEntries(AppDbContext ctx, Season season, int idOffset = 0) { public async Task<IEnumerable<GraphEntry>> GetQualityGraphEntries(AppDbContext ctx, Season season, int idOffset = 0) {
var root = GetQualityEntry(); var root = GetQualityEntry();
if (root == null || root["WEI"] is not JsonNode qualityWei) if (root == null || root["WEI"] is not JsonNode qualityWei)
return []; return [];
var (curves, entries) = GetGraphEntries(qualityWei); var (curves, entries) = GetGraphEntries(qualityWei);
var list = CreateGraphEntries(ctx, season.Precision, curves, entries).Where(e => e.Vaributes.Count > 0); var list = (await CreateGraphEntries(ctx, season.Precision, curves, entries)).Where(e => e.Vaributes.Count > 0);
foreach (var e in list) { foreach (var e in list) {
e.Id += idOffset; e.Id += idOffset;
e.Abgewertet = true; e.Abgewertet = true;
+30 -6
View File
@@ -8,16 +8,18 @@ using System.Threading.Tasks;
namespace Elwig.Helpers { namespace Elwig.Helpers {
public class ClientParameters { public class ClientParameters {
public enum Type { Matzen, Winzerkeller, Weinland, Baden }; public enum Type { Matzen, Winzerkeller, Weinland, Baden, Seewinkel };
public bool IsMatzen => Client == Type.Matzen; public bool IsMatzen => Client == Type.Matzen;
public bool IsWinzerkeller => Client == Type.Winzerkeller; public bool IsWinzerkeller => Client == Type.Winzerkeller;
public bool IsWeinland => Client == Type.Weinland; public bool IsWeinland => Client == Type.Weinland;
public bool IsBaden => Client == Type.Baden; public bool IsBaden => Client == Type.Baden;
public bool IsSeewinkel => Client == Type.Seewinkel;
public bool IsWolkersdorf => IsWinzerkeller && App.ZwstId == "W"; public bool IsWolkersdorf => IsWinzerkeller && App.ZwstId == "W";
public bool IsHaugsdorf => IsWinzerkeller && App.ZwstId == "H"; public bool IsHaugsdorf => IsWinzerkeller && App.ZwstId == "H";
public bool IsSitzendorf => IsWinzerkeller && App.ZwstId == "S"; public bool IsSitzendorf => IsWinzerkeller && App.ZwstId == "S";
public bool IsGrInzersdorf => IsWeinland; public bool IsGrInzersdorf => IsWeinland;
public bool IsPamhagen => IsSeewinkel;
public string NameToken; public string NameToken;
public string NameShort; public string NameShort;
@@ -54,6 +56,10 @@ namespace Elwig.Helpers {
public string? EmailAddress; public string? EmailAddress;
public string? Website; public string? Website;
public bool EnableMemberHistory;
public int ModeBusinessShares;
public bool HasRedWhite => ModeBusinessShares == 1;
public int ModeDeliveryNoteStats; public int ModeDeliveryNoteStats;
public int ModeWineQualityStatistics; public int ModeWineQualityStatistics;
public int OrderingMemberList; public int OrderingMemberList;
@@ -73,7 +79,7 @@ namespace Elwig.Helpers {
public int ExportEbicsVersion; public int ExportEbicsVersion;
public int ExportEbicsAddress; public int ExportEbicsAddress;
public (int? AllowanceKg, double? AllowanceBs, int? AllowanceKgPerBs, double? AllowancePercent, int? MinBs) AutoAdjustBs; public (int? AllowanceKg, double? AllowanceShares, int? AllowanceKgPerShare, double? AllowancePercent, int? MinShares) AutoAdjustShares;
public ClientParameters(AppDbContext ctx) : this(ctx.ClientParameters.ToDictionary(e => e.Param, e => e.Value)) { } public ClientParameters(AppDbContext ctx) : this(ctx.ClientParameters.ToDictionary(e => e.Param, e => e.Value)) { }
@@ -93,6 +99,8 @@ namespace Elwig.Helpers {
Client = Type.Weinland; break; Client = Type.Weinland; break;
case "Winzergenossenschaft Baden - Bad Vöslau": case "Winzergenossenschaft Baden - Bad Vöslau":
Client = Type.Baden; break; Client = Type.Baden; break;
case "Winzerkeller Seewinkel":
Client = Type.Seewinkel; break;
}; };
Plz = int.Parse(parameters["CLIENT_PLZ"] ?? ""); Plz = int.Parse(parameters["CLIENT_PLZ"] ?? "");
@@ -108,6 +116,15 @@ namespace Elwig.Helpers {
Iban = parameters.GetValueOrDefault("CLIENT_IBAN"); Iban = parameters.GetValueOrDefault("CLIENT_IBAN");
OrganicAuthority = parameters.GetValueOrDefault("CLIENT_ORGANIC_AUTHORITY"); OrganicAuthority = parameters.GetValueOrDefault("CLIENT_ORGANIC_AUTHORITY");
EnableMemberHistory = (parameters.GetValueOrDefault("ENABLE_MEMBERHISTORY")?.ToUpper()) switch {
"1" or "TRUE" or "YES" or "JA" => true,
_ => false,
};
switch (parameters.GetValueOrDefault("MODE_BUSINESSSHARES", "SIMPLE")?.ToUpper()) {
case "SIMPLE": ModeBusinessShares = 0; break;
case "RED_WHITE": ModeBusinessShares = 1; break;
}
switch (parameters.GetValueOrDefault("MODE_DELIVERYNOTE_STATS", "SHORT")?.ToUpper()) { switch (parameters.GetValueOrDefault("MODE_DELIVERYNOTE_STATS", "SHORT")?.ToUpper()) {
case "NONE": ModeDeliveryNoteStats = 0; break; case "NONE": ModeDeliveryNoteStats = 0; break;
case "GA_ONLY": ModeDeliveryNoteStats = 1; break; case "GA_ONLY": ModeDeliveryNoteStats = 1; break;
@@ -172,7 +189,7 @@ namespace Elwig.Helpers {
} }
var autoAdjust = (parameters.GetValueOrDefault("AUTOADJUST_BUSINESSSHARES") ?? "").Split(';'); var autoAdjust = (parameters.GetValueOrDefault("AUTOADJUST_BUSINESSSHARES") ?? "").Split(';');
AutoAdjustBs = autoAdjust.Length == 5 ? ( AutoAdjustShares = autoAdjust.Length == 5 ? (
int.TryParse(autoAdjust[0], out var v1) ? v1 : null, int.TryParse(autoAdjust[0], out var v1) ? v1 : null,
double.TryParse(autoAdjust[1], out var v2) ? v2 : null, double.TryParse(autoAdjust[1], out var v2) ? v2 : null,
int.TryParse(autoAdjust[2], out var v3) ? v3 : null, int.TryParse(autoAdjust[2], out var v3) ? v3 : null,
@@ -185,6 +202,11 @@ namespace Elwig.Helpers {
} }
private IEnumerable<(string, string?)> GetParamValues() { private IEnumerable<(string, string?)> GetParamValues() {
string businessShares = "SIMPLE";
switch (ModeBusinessShares) {
case 0: businessShares = "SIMPLE"; break;
case 1: businessShares = "RED_WHITE"; break;
}
string deliveryNoteStats = "SHORT"; string deliveryNoteStats = "SHORT";
switch (ModeDeliveryNoteStats) { switch (ModeDeliveryNoteStats) {
case 0: deliveryNoteStats = "NONE"; break; case 0: deliveryNoteStats = "NONE"; break;
@@ -231,9 +253,9 @@ namespace Elwig.Helpers {
case 1: exportEbicsAddress = "LINES"; break; case 1: exportEbicsAddress = "LINES"; break;
case 2: exportEbicsAddress = "FULL"; break; case 2: exportEbicsAddress = "FULL"; break;
} }
string autoAdjust = $"{AutoAdjustBs.AllowanceKg};{AutoAdjustBs.AllowanceBs?.ToString(CultureInfo.InvariantCulture)};" + string autoAdjust = $"{AutoAdjustShares.AllowanceKg};{AutoAdjustShares.AllowanceShares?.ToString(CultureInfo.InvariantCulture)};" +
$"{AutoAdjustBs.AllowanceKgPerBs};{AutoAdjustBs.AllowancePercent?.ToString(CultureInfo.InvariantCulture)};" + $"{AutoAdjustShares.AllowanceKgPerShare};{AutoAdjustShares.AllowancePercent?.ToString(CultureInfo.InvariantCulture)};" +
$"{AutoAdjustBs.MinBs}"; $"{AutoAdjustShares.MinShares}";
return [ return [
("CLIENT_NAME_TOKEN", NameToken), ("CLIENT_NAME_TOKEN", NameToken),
("CLIENT_NAME_SHORT", NameShort), ("CLIENT_NAME_SHORT", NameShort),
@@ -252,6 +274,8 @@ namespace Elwig.Helpers {
("CLIENT_BIC", Bic), ("CLIENT_BIC", Bic),
("CLIENT_IBAN", Iban), ("CLIENT_IBAN", Iban),
("CLIENT_ORGANIC_AUTHORITY", OrganicAuthority), ("CLIENT_ORGANIC_AUTHORITY", OrganicAuthority),
("ENABLE_MEMBERHISTORY", EnableMemberHistory ? "YES" : "NO"),
("MODE_BUSINESSSHARES", businessShares),
("MODE_DELIVERYNOTE_STATS", deliveryNoteStats), ("MODE_DELIVERYNOTE_STATS", deliveryNoteStats),
("MODE_WINEQUALITYSTATISTICS", modeWineQualityStatistics), ("MODE_WINEQUALITYSTATISTICS", modeWineQualityStatistics),
("ORDERING_MEMBERLIST", orderingMemberList), ("ORDERING_MEMBERLIST", orderingMemberList),
+297 -95
View File
@@ -1,4 +1,6 @@
using Elwig.Models;
using Elwig.Models.Entities; using Elwig.Models.Entities;
using Elwig.Services;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -41,7 +43,7 @@ namespace Elwig.Helpers.Export {
List<WbGl> currentWbGls; List<WbGl> currentWbGls;
using (var ctx = new AppDbContext()) { using (var ctx = new AppDbContext()) {
branches = await ctx.Branches.ToDictionaryAsync(b => b.ZwstId); branches = await ctx.FetchBranches().ToDictionaryAsync(b => b.ZwstId);
currentDids = await ctx.Deliveries currentDids = await ctx.Deliveries
.GroupBy(d => d.Year) .GroupBy(d => d.Year)
.ToDictionaryAsync(g => g.Key, g => g.Max(d => d.DId)); .ToDictionaryAsync(g => g.Key, g => g.Max(d => d.DId));
@@ -59,14 +61,16 @@ namespace Elwig.Helpers.Export {
List<BillingAddr> BillingAddresses, List<BillingAddr> BillingAddresses,
List<MemberTelNr> TelephoneNumbers, List<MemberTelNr> TelephoneNumbers,
List<MemberEmailAddr> EmailAddresses, List<MemberEmailAddr> EmailAddresses,
List<MemberHistory> MemberHistory,
List<AreaCom> AreaCommitments, List<AreaCom> AreaCommitments,
List<AreaComContract> Contracts,
List<WbRd> Riede, List<WbRd> Riede,
List<WbKg> WbKgs, List<WbKg> WbKgs,
List<WbGl> WbGls, List<WbGl> WbGls,
List<Delivery> Deliveries, List<Delivery> Deliveries,
List<DeliveryPart> DeliveryParts, List<DeliveryPart> DeliveryParts,
List<DeliveryPartModifier> Modifiers, List<DeliveryPartModifier> Modifiers,
Dictionary<string, List<(int Id1, int Id2, DateTime CreatedAt, DateTime ModifiedAt)>> Timestamps)>(); Dictionary<string, List<(int Id1, int Id2, int Id3, DateTime CreatedAt, DateTime ModifiedAt)>> Timestamps)>();
var metaData = new List<(string FileName, string ZwstId, string Device, var metaData = new List<(string FileName, string ZwstId, string Device,
int? MemberNum, string? MemberFilters, int? MemberNum, string? MemberFilters,
@@ -75,10 +79,12 @@ namespace Elwig.Helpers.Export {
foreach (var filename in filenames) { foreach (var filename in filenames) {
try { try {
data.Add(new([], [], [], [], [], [], [], new([], [], [], [], new() { data.Add(new([], [], [], [], [], [], [], new([], [], [], [], [], [], new() {
["member"] = [], ["member"] = [],
["area_commitment_contract"] = [],
["area_commitment"] = [], ["area_commitment"] = [],
["delivery"] = [], ["delivery"] = [],
["delivery_part"] = [],
}))); })));
var r = data[^1]; var r = data[^1];
@@ -86,9 +92,11 @@ namespace Elwig.Helpers.Export {
using var zip = ZipFile.Open(filename, ZipArchiveMode.Read); using var zip = ZipFile.Open(filename, ZipArchiveMode.Read);
await zip.CheckIntegrity(); await zip.CheckIntegrity();
string[] acceptableVersions = ["1", "2"];
var version = zip.GetEntry("version"); var version = zip.GetEntry("version");
using (var reader = new StreamReader(version!.Open(), Utils.UTF8)) { using (var reader = new StreamReader(version!.Open(), Utils.UTF8)) {
if (await reader.ReadToEndAsync() != "elwig:1") var v = await reader.ReadToEndAsync();
if (!v.StartsWith("elwig:") || !acceptableVersions.Contains(v[6..]))
throw new FileFormatException($"Ungültige Elwig-Export-Datei ({filename})"); throw new FileFormatException($"Ungültige Elwig-Export-Datei ({filename})");
} }
@@ -96,8 +104,8 @@ namespace Elwig.Helpers.Export {
var meta = await JsonNode.ParseAsync(metaJson!.Open()); var meta = await JsonNode.ParseAsync(metaJson!.Open());
var memberCount = meta!["members"]?["count"]?.AsValue().GetValue<int>(); var memberCount = meta!["members"]?["count"]?.AsValue().GetValue<int>();
var memberFilters = meta!["members"]?["filters"]?.AsArray().Select(f => f!.AsValue().GetValue<string>()).ToArray(); var memberFilters = meta!["members"]?["filters"]?.AsArray().Select(f => f!.AsValue().GetValue<string>()).ToArray();
var areaComCount = meta!["area_commitments"]?["count"]?.AsValue().GetValue<int>(); var areaComCount = meta!["area_commitment_contracts"]?["count"]?.AsValue().GetValue<int>();
var areaComFilters = meta!["area_commitments"]?["filters"]?.AsArray().Select(f => f!.AsValue().GetValue<string>()).ToArray(); var areaComFilters = meta!["area_commitment_contracts"]?["filters"]?.AsArray().Select(f => f!.AsValue().GetValue<string>()).ToArray();
var deliveryCount = meta!["deliveries"]?["count"]?.AsValue().GetValue<int>(); var deliveryCount = meta!["deliveries"]?["count"]?.AsValue().GetValue<int>();
var deliveryFilters = meta!["deliveries"]?["filters"]?.AsArray().Select(f => f!.AsValue().GetValue<string>()).ToArray(); var deliveryFilters = meta!["deliveries"]?["filters"]?.AsArray().Select(f => f!.AsValue().GetValue<string>()).ToArray();
metaData.Add((Path.GetFileName(filename), metaData.Add((Path.GetFileName(filename),
@@ -133,23 +141,59 @@ namespace Elwig.Helpers.Export {
r.TelephoneNumbers.AddRange(telNrs); r.TelephoneNumbers.AddRange(telNrs);
r.EmailAddresses.AddRange(emailAddrs); r.EmailAddresses.AddRange(emailAddrs);
if (timestamps.HasValue) if (timestamps.HasValue)
r.Timestamps["member"].Add((m.MgNr, 0, timestamps.Value.CreatedAt, timestamps.Value.ModifiedAt)); r.Timestamps["member"].Add((m.MgNr, 0, 0, timestamps.Value.CreatedAt, timestamps.Value.ModifiedAt));
} }
} }
var historyJson = zip.GetEntry("member_history.json");
if (historyJson != null) {
using var reader = new StreamReader(historyJson.Open(), Utils.UTF8);
string? line;
while ((line = await reader.ReadLineAsync()) != null) {
var obj = JsonNode.Parse(line)!.AsObject();
var h = obj.ToMemberHistory();
r.MemberHistory.Add(h);
}
}
// legacy area commitments
var areaComsJson = zip.GetEntry("area_commitments.json"); var areaComsJson = zip.GetEntry("area_commitments.json");
if (areaComsJson != null) { if (areaComsJson != null) {
using var reader = new StreamReader(areaComsJson.Open(), Utils.UTF8); using var reader = new StreamReader(areaComsJson.Open(), Utils.UTF8);
string? line; string? line;
while ((line = await reader.ReadLineAsync()) != null) { while ((line = await reader.ReadLineAsync()) != null) {
var obj = JsonNode.Parse(line)!.AsObject(); var obj = JsonNode.Parse(line)!.AsObject();
var (areaCom, wbrd, timestamps) = obj.ToAreaCom(currentWbRde); var (contract, areaCom, wbrd, timestamps) = obj.ToAreaCom(currentWbRde);
r.Contracts.Add(contract);
r.AreaCommitments.Add(areaCom); r.AreaCommitments.Add(areaCom);
if (wbrd != null) { if (wbrd != null) {
r.Riede.Add(wbrd); r.Riede.Add(wbrd);
} }
if (timestamps.HasValue) {
r.Timestamps["area_commitment_contract"].Add((contract.FbNr, 0, 0, timestamps.Value.CreatedAt, timestamps.Value.ModifiedAt));
r.Timestamps["area_commitment"].Add((areaCom.FbNr, areaCom.RevNr, 0, timestamps.Value.CreatedAt, timestamps.Value.ModifiedAt));
}
}
}
var contractsJson = zip.GetEntry("area_commitment_contracts.json");
if (contractsJson != null) {
using var reader = new StreamReader(contractsJson.Open(), Utils.UTF8);
string? line;
while ((line = await reader.ReadLineAsync()) != null) {
var obj = JsonNode.Parse(line)!.AsObject();
var (contract, areaComs, wbrd, timestamps) = obj.ToAreaComContract(currentWbRde);
r.Contracts.Add(contract);
r.AreaCommitments.AddRange(areaComs.Select(v => v.Item1));
if (wbrd != null) {
r.Riede.Add(wbrd);
}
if (timestamps.HasValue) if (timestamps.HasValue)
r.Timestamps["area_commitment"].Add((areaCom.FbNr, 0, timestamps.Value.CreatedAt, timestamps.Value.ModifiedAt)); r.Timestamps["area_commitment_contract"].Add((contract.FbNr, 0, 0, timestamps.Value.CreatedAt, timestamps.Value.ModifiedAt));
foreach (var (areaCom, ts) in areaComs) {
if (!ts.HasValue) continue;
r.Timestamps["area_commitment"].Add((areaCom.FbNr, areaCom.RevNr, 0, ts.Value.CreatedAt, ts.Value.ModifiedAt));
}
} }
} }
@@ -161,11 +205,15 @@ namespace Elwig.Helpers.Export {
var obj = JsonNode.Parse(line)!.AsObject(); var obj = JsonNode.Parse(line)!.AsObject();
var (d, parts, mods, rde, timestamps) = obj.ToDelivery(currentLsNrs, currentDids, kgs, currentWbRde); var (d, parts, mods, rde, timestamps) = obj.ToDelivery(currentLsNrs, currentDids, kgs, currentWbRde);
r.Deliveries.Add(d); r.Deliveries.Add(d);
r.DeliveryParts.AddRange(parts); r.DeliveryParts.AddRange(parts.Select(p => p.Item1));
r.Modifiers.AddRange(mods); r.Modifiers.AddRange(mods);
r.Riede.AddRange(rde); r.Riede.AddRange(rde);
if (timestamps.HasValue) if (timestamps.HasValue)
r.Timestamps["delivery"].Add((d.Year, d.DId, timestamps.Value.CreatedAt, timestamps.Value.ModifiedAt)); r.Timestamps["delivery"].Add((d.Year, d.DId, 0, timestamps.Value.CreatedAt, timestamps.Value.ModifiedAt));
foreach (var (part, ts) in parts) {
if (!ts.HasValue) continue;
r.Timestamps["area_commitment"].Add((part.Year, part.DId, part.DPNr, ts.Value.CreatedAt, ts.Value.ModifiedAt));
}
} }
} }
} catch (Exception exc) when ( } catch (Exception exc) when (
@@ -174,30 +222,27 @@ namespace Elwig.Helpers.Export {
exc is FileNotFoundException || exc is FileNotFoundException ||
exc is IOException) { exc is IOException) {
data.RemoveAt(data.Count - 1); data.RemoveAt(data.Count - 1);
var str = $"Die Elwig-Export-Datei '{Path.GetFileName(filename)}' konnte nicht verarbeitet werden und wird übersprungen.\n\n" + exc.Message; InteractionService.ShowException("Fehler beim Importieren", $"Die Elwig-Export-Datei '{Path.GetFileName(filename)}' konnte nicht verarbeitet werden und wird übersprungen", exc);
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)); await AddImportedFiles(Path.GetFileName(filename));
} catch (Exception exc) { } catch (Exception exc) {
data.RemoveAt(data.Count - 1); data.RemoveAt(data.Count - 1);
var str = $"Die Elwig-Export-Datei '{Path.GetFileName(filename)}' konnte nicht verarbeitet werden. Soll sie in Zukunft übersprungen werden?\n\n" + exc.Message; if (InteractionService.AskException("Fehler beim Importieren", $"Die Elwig-Export-Datei '{Path.GetFileName(filename)}' konnte nicht verarbeitet werden. Soll sie in Zukunft übersprungen werden?", exc)) {
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)); await AddImportedFiles(Path.GetFileName(filename));
} }
} }
} }
var importedMembers = new List<(string FileName, string ZwstId, string Device, int New, int Overwritten, int NotImported, string Filters)>(); var importedMembers = new List<(string FileName, string ZwstId, string Device, int New, int Overwritten, int NotImported, string? Filters)>();
var importedAreaComs = new List<(string FileName, string ZwstId, string Device, int Imported, int NotImported, string Filters)>(); var importedAreaComs = new List<(string FileName, string ZwstId, string Device, int New, int Overwritten, int NotImported, string? Filters)>();
var importedDeliveries = new List<(string FileName, string ZwstId, string Device, int New, int Overwritten, int NotImported, string Filters)>(); var importedDeliveries = new List<(string FileName, string ZwstId, string Device, int New, int Overwritten, int NotImported, string? Filters)>();
foreach (var ((members, billingAddresses, telephoneNumbers, emailAddresses, areaCommitments, riede, wbKgs, wbGls, deliveries, deliveryParts, modifiers, timestamps), meta) in data.Zip(metaData)) { foreach (var ((members, billingAddresses, telephoneNumbers, emailAddresses, history, areaCommitments, contracts, riede, wbKgs, wbGls, deliveries, deliveryParts, modifiers, timestamps), meta) in data.Zip(metaData)) {
var branch = branches[meta.ZwstId]; var branch = branches[meta.ZwstId];
var device = meta.Device; var device = meta.Device;
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
var tx = await ctx.Database.BeginTransactionAsync();
await ctx.Database.ExecuteSqlAsync($"UPDATE client_parameter SET value = '0' WHERE param = 'ENABLE_MEMBER_HISTORY_TRIGGERS'");
var kgnrs = wbKgs.Select(k => k.KgNr).ToList(); var kgnrs = wbKgs.Select(k => k.KgNr).ToList();
var duplicateKgNrs = await ctx.WbKgs var duplicateKgNrs = await ctx.WbKgs
@@ -205,6 +250,12 @@ namespace Elwig.Helpers.Export {
.Select(k => k.KgNr) .Select(k => k.KgNr)
.ToListAsync(); .ToListAsync();
var histNrs = history.Select(h => h.HistNr).ToList();
var duplicateHistNrs = await ctx.MemberHistory
.Where(h => histNrs.Contains(h.HistNr))
.Select(h => h.HistNr)
.ToListAsync();
var mgnrs = members.Select(m => m.MgNr).ToList(); var mgnrs = members.Select(m => m.MgNr).ToList();
var duplicateMgNrs = await ctx.Members var duplicateMgNrs = await ctx.Members
.Where(m => mgnrs.Contains(m.MgNr)) .Where(m => mgnrs.Contains(m.MgNr))
@@ -220,11 +271,20 @@ namespace Elwig.Helpers.Export {
if (duplicateMgNrs.Count > 0) if (duplicateMgNrs.Count > 0)
importDuplicateMembers = ImportQuestion(branch.Name, device, "Mitglieder", true, duplicateMgNrs.Count); importDuplicateMembers = ImportQuestion(branch.Name, device, "Mitglieder", true, duplicateMgNrs.Count);
var fbnrs = areaCommitments.Select(c => c.FbNr).ToList(); var fbnrs = contracts.Select(c => c.FbNr).ToList();
var duplicateFbNrs = await ctx.AreaCommitments var duplicateFbNrs = await ctx.AreaCommitmentContracts
.Where(c => fbnrs.Contains(c.FbNr)) .Where(c => fbnrs.Contains(c.FbNr))
.Select(c => c.FbNr) .Select(c => c.FbNr)
.ToListAsync(); .ToListAsync();
bool importNewContracts = false, importDuplicateContracts = false;
if (mode == ImportMode.Interactively) {
if (fbnrs.Count - duplicateFbNrs.Count > 0)
importNewContracts = ImportQuestion(branch.Name, device, "Flächenbindungsverträge", false, fbnrs.Count - duplicateFbNrs.Count);
} else {
importNewContracts = true;
}
if (duplicateFbNrs.Count > 0)
importDuplicateContracts = ImportQuestion(branch.Name, device, "Flächenbindungsverträge", true, duplicateFbNrs.Count);
var lsnrs = deliveries.Select(d => d.LsNr).ToList(); var lsnrs = deliveries.Select(d => d.LsNr).ToList();
var duplicateLsNrs = await ctx.Deliveries var duplicateLsNrs = await ctx.Deliveries
@@ -258,40 +318,52 @@ namespace Elwig.Helpers.Export {
importDuplicateDeliveries = ImportQuestion(branch.Name, device, "Lieferungen", true, duplicateLsNrs.Count); importDuplicateDeliveries = ImportQuestion(branch.Name, device, "Lieferungen", true, duplicateLsNrs.Count);
} }
if (importDuplicateMembers || importNewMembers || importDuplicateDeliveries || importNewDeliveries) { if (importDuplicateMembers || importNewMembers || importDuplicateContracts || importNewContracts || importDuplicateDeliveries || importNewDeliveries) {
ctx.AddRange(wbGls); ctx.AddRange(wbGls);
ctx.UpdateRange(wbKgs.Where(k => duplicateKgNrs.Contains(k.KgNr))); ctx.UpdateRange(wbKgs.Where(k => duplicateKgNrs.Contains(k.KgNr)));
ctx.AddRange(wbKgs.Where(k => !duplicateKgNrs.Contains(k.KgNr))); ctx.AddRange(wbKgs.Where(k => !duplicateKgNrs.Contains(k.KgNr)));
} }
if (importDuplicateMembers) { if (importDuplicateMembers) {
ctx.RemoveRange(ctx.BillingAddresses.Where(a => duplicateMgNrs.Contains(a.MgNr))); ctx.RemoveRange(ctx.BillingAddresses.IgnoreAutoIncludes().Where(a => duplicateMgNrs.Contains(a.MgNr)));
ctx.RemoveRange(ctx.MemberTelephoneNrs.Where(n => duplicateMgNrs.Contains(n.MgNr))); ctx.RemoveRange(ctx.MemberTelephoneNrs.IgnoreAutoIncludes().Where(n => duplicateMgNrs.Contains(n.MgNr)));
ctx.RemoveRange(ctx.MemberEmailAddrs.Where(a => duplicateMgNrs.Contains(a.MgNr))); ctx.RemoveRange(ctx.MemberEmailAddrs.IgnoreAutoIncludes().Where(a => duplicateMgNrs.Contains(a.MgNr)));
ctx.UpdateRange(members.Where(m => duplicateMgNrs.Contains(m.MgNr))); ctx.UpdateRange(members.Where(m => duplicateMgNrs.Contains(m.MgNr)));
ctx.AddRange(billingAddresses.Where(a => duplicateMgNrs.Contains(a.MgNr))); ctx.AddRange(billingAddresses.Where(a => duplicateMgNrs.Contains(a.MgNr)));
ctx.AddRange(telephoneNumbers.Where(n => duplicateMgNrs.Contains(n.MgNr))); ctx.AddRange(telephoneNumbers.Where(n => duplicateMgNrs.Contains(n.MgNr)));
ctx.AddRange(emailAddresses.Where(a => duplicateMgNrs.Contains(a.MgNr))); ctx.AddRange(emailAddresses.Where(a => duplicateMgNrs.Contains(a.MgNr)));
ctx.UpdateRange(areaCommitments.Where(c => duplicateMgNrs.Contains(c.MgNr) && duplicateFbNrs.Contains(c.FbNr)));
ctx.AddRange(areaCommitments.Where(c => duplicateMgNrs.Contains(c.MgNr) && !duplicateFbNrs.Contains(c.FbNr)));
} }
if (importNewMembers) { if (importNewMembers) {
ctx.AddRange(members.Where(m => !duplicateMgNrs.Contains(m.MgNr))); ctx.AddRange(members.Where(m => !duplicateMgNrs.Contains(m.MgNr)));
ctx.AddRange(billingAddresses.Where(a => !duplicateMgNrs.Contains(a.MgNr))); ctx.AddRange(billingAddresses.Where(a => !duplicateMgNrs.Contains(a.MgNr)));
ctx.AddRange(telephoneNumbers.Where(n => !duplicateMgNrs.Contains(n.MgNr))); ctx.AddRange(telephoneNumbers.Where(n => !duplicateMgNrs.Contains(n.MgNr)));
ctx.AddRange(emailAddresses.Where(a => !duplicateMgNrs.Contains(a.MgNr))); ctx.AddRange(emailAddresses.Where(a => !duplicateMgNrs.Contains(a.MgNr)));
ctx.UpdateRange(areaCommitments.Where(c => !duplicateMgNrs.Contains(c.MgNr) && duplicateFbNrs.Contains(c.FbNr)));
ctx.AddRange(areaCommitments.Where(c => !duplicateMgNrs.Contains(c.MgNr) && !duplicateFbNrs.Contains(c.FbNr)));
} }
if (members.Count > 0) { if (members.Count > 0) {
var n = importNewMembers ? members.Count - duplicateMgNrs.Count : 0; var n = importNewMembers ? members.Count - duplicateMgNrs.Count : 0;
var o = importDuplicateMembers ? duplicateMgNrs.Count : 0; var o = importDuplicateMembers ? duplicateMgNrs.Count : 0;
importedMembers.Add((meta.FileName, meta.ZwstId, meta.Device, n, o, members.Count - n - o, meta.MemberFilters)); importedMembers.Add((meta.FileName, meta.ZwstId, meta.Device, n, o, members.Count - n - o, meta.MemberFilters));
} }
if (areaCommitments.Count > 0) {
if (importDuplicateMembers || importNewMembers) {
ctx.UpdateRange(history.Where(h => duplicateHistNrs.Contains(h.HistNr)));
ctx.AddRange(history.Where(h => !duplicateHistNrs.Contains(h.HistNr)));
}
if (importDuplicateContracts) {
ctx.RemoveRange(ctx.AreaCommitments.IgnoreAutoIncludes().Where(c => duplicateFbNrs.Contains(c.FbNr)));
ctx.UpdateRange(contracts.Where(c => duplicateFbNrs.Contains(c.FbNr)));
ctx.AddRange(areaCommitments.Where(c => duplicateFbNrs.Contains(c.FbNr)));
}
if (importNewContracts) {
ctx.AddRange(contracts.Where(c => !duplicateFbNrs.Contains(c.FbNr)));
ctx.AddRange(areaCommitments.Where(c => !duplicateFbNrs.Contains(c.FbNr)));
}
if (contracts.Count > 0) {
ctx.AddRange(riede); ctx.AddRange(riede);
var imported = areaCommitments.Where(c => (importNewMembers && !duplicateMgNrs.Contains(c.MgNr)) || (importDuplicateMembers && duplicateMgNrs.Contains(c.MgNr))).ToList(); var n = importNewContracts ? contracts.Count - duplicateFbNrs.Count : 0;
importedAreaComs.Add((meta.FileName, meta.ZwstId, meta.Device, imported.Count, areaCommitments.Count - imported.Count, meta.AreaComFilters)); var o = importDuplicateContracts ? duplicateFbNrs.Count : 0;
importedAreaComs.Add((meta.FileName, meta.ZwstId, meta.Device, n, o, contracts.Count - n - o, meta.AreaComFilters));
} }
if (allowedDuplicateLsNrs.Count > 0) { if (allowedDuplicateLsNrs.Count > 0) {
@@ -300,9 +372,10 @@ namespace Elwig.Helpers.Export {
.Select(d => (d.Year, d.DId)) .Select(d => (d.Year, d.DId))
.ToList(); .ToList();
ctx.RemoveRange(ctx.DeliveryParts ctx.RemoveRange(ctx.DeliveryParts
.IgnoreAutoIncludes()
.Where(p => allowedDuplicateLsNrs.Contains(p.Delivery.LsNr)) .Where(p => allowedDuplicateLsNrs.Contains(p.Delivery.LsNr))
.SelectMany(p => p.PartModifiers)); .SelectMany(p => p.PartModifiers));
ctx.RemoveRange(ctx.DeliveryParts.Where(p => allowedDuplicateLsNrs.Contains(p.Delivery.LsNr))); ctx.RemoveRange(ctx.DeliveryParts.IgnoreAutoIncludes().Where(p => allowedDuplicateLsNrs.Contains(p.Delivery.LsNr)));
ctx.UpdateRange(deliveries.Where(d => dids.Contains((d.Year, d.DId)))); ctx.UpdateRange(deliveries.Where(d => dids.Contains((d.Year, d.DId))));
ctx.AddRange(deliveryParts.Where(p => dids.Contains((p.Year, p.DId)))); ctx.AddRange(deliveryParts.Where(p => dids.Contains((p.Year, p.DId))));
ctx.AddRange(modifiers.Where(m => dids.Contains((m.Year, m.DId)))); ctx.AddRange(modifiers.Where(m => dids.Contains((m.Year, m.DId))));
@@ -314,9 +387,10 @@ namespace Elwig.Helpers.Export {
.Select(d => (d.Year, d.DId)) .Select(d => (d.Year, d.DId))
.ToList(); .ToList();
ctx.RemoveRange(ctx.DeliveryParts ctx.RemoveRange(ctx.DeliveryParts
.IgnoreAutoIncludes()
.Where(p => l.Contains(p.Delivery.LsNr)) .Where(p => l.Contains(p.Delivery.LsNr))
.SelectMany(p => p.PartModifiers)); .SelectMany(p => p.PartModifiers));
ctx.RemoveRange(ctx.DeliveryParts.Where(p => l.Contains(p.Delivery.LsNr))); ctx.RemoveRange(ctx.DeliveryParts.IgnoreAutoIncludes().Where(p => l.Contains(p.Delivery.LsNr)));
ctx.UpdateRange(deliveries.Where(d => dids.Contains((d.Year, d.DId)))); ctx.UpdateRange(deliveries.Where(d => dids.Contains((d.Year, d.DId))));
ctx.AddRange(deliveryParts.Where(p => dids.Contains((p.Year, p.DId)))); ctx.AddRange(deliveryParts.Where(p => dids.Contains((p.Year, p.DId))));
ctx.AddRange(modifiers.Where(m => dids.Contains((m.Year, m.DId)))); ctx.AddRange(modifiers.Where(m => dids.Contains((m.Year, m.DId))));
@@ -333,17 +407,21 @@ namespace Elwig.Helpers.Export {
} }
await ctx.SaveChangesAsync(); await ctx.SaveChangesAsync();
await ctx.Database.ExecuteSqlAsync($"UPDATE client_parameter SET value = '1' WHERE param = 'ENABLE_MEMBER_HISTORY_TRIGGERS'");
await tx.CommitAsync();
var primaryKeys = new Dictionary<string, string>() { var primaryKeys = new Dictionary<string, string>() {
["member"] = "mgnr, 0", ["member"] = "mgnr, 0, 0",
["area_commitment"] = "fbnr, 0", ["area_commitment_contract"] = "fbnr, 0, 0",
["delivery"] = "year, did", ["area_commitment"] = "fbnr, revnr, 0",
["delivery"] = "year, did, 0",
["delivery_part"] = "year, did, dpnr",
}; };
var updateStmts = timestamps var updateStmts = timestamps
.SelectMany(e => e.Value.Select(m => $"UPDATE {e.Key} " + .SelectMany(e => e.Value.Select(m => $"UPDATE {e.Key} " +
$"SET ctime = {((DateTimeOffset)m.CreatedAt.ToUniversalTime()).ToUnixTimeSeconds()}, " + $"SET ctime = {((DateTimeOffset)m.CreatedAt.ToUniversalTime()).ToUnixTimeSeconds()}, " +
$"mtime = {((DateTimeOffset)m.ModifiedAt.ToUniversalTime()).ToUnixTimeSeconds()} " + $"mtime = {((DateTimeOffset)m.ModifiedAt.ToUniversalTime()).ToUnixTimeSeconds()} " +
$"WHERE ({primaryKeys[e.Key]}) = ({m.Id1}, {m.Id2});")); $"WHERE ({primaryKeys[e.Key]}) = ({m.Id1}, {m.Id2}, {m.Id3});"));
using var cnx = AppDbContext.Connect(); using var cnx = AppDbContext.Connect();
await cnx.ExecuteBatch($""" await cnx.ExecuteBatch($"""
BEGIN; BEGIN;
@@ -357,7 +435,7 @@ namespace Elwig.Helpers.Export {
} }
App.HintContextChange(); App.HintContextChange();
MessageBox.Show( InteractionService.ShowInformation("Importieren erfolgreich",
$"Das importieren der Daten war erfolgreich!\n" + $"Das importieren der Daten war erfolgreich!\n" +
$"Folgendes wurde importiert:\n" + $"Folgendes wurde importiert:\n" +
string.Join("\n", [ string.Join("\n", [
@@ -367,10 +445,10 @@ namespace Elwig.Helpers.Export {
$" ({d.New} neu, {d.Overwritten} überschrieben, {d.NotImported} nicht importiert)\n" + $" ({d.New} neu, {d.Overwritten} überschrieben, {d.NotImported} nicht importiert)\n" +
$" Zweigstelle: {branches[d.ZwstId].Name} (Gerät {d.Device})\n" + $" Zweigstelle: {branches[d.ZwstId].Name} (Gerät {d.Device})\n" +
$" Filter: {d.Filters}"), $" Filter: {d.Filters}"),
$"Flächenbindungen: {importedAreaComs.Sum(d => d.Imported)}", $"Flächenbindungen: {importedAreaComs.Sum(d => d.New + d.Overwritten)}",
..importedAreaComs.Select(d => ..importedAreaComs.Select(d =>
$" {d.FileName} ({d.Imported})\n" + $" {d.FileName} ({d.New + d.Overwritten})\n" +
$" ({d.Imported} importiert, {d.NotImported} nicht importiert)\n" + $" ({d.New} importiert, {d.Overwritten} überschreiben, {d.NotImported} nicht importiert)\n" +
$" Zweigstelle: {branches[d.ZwstId].Name} (Gerät {d.Device})\n" + $" Zweigstelle: {branches[d.ZwstId].Name} (Gerät {d.Device})\n" +
$" Filter: {d.Filters}"), $" Filter: {d.Filters}"),
$"Lieferungen: {importedDeliveries.Sum(d => d.New + d.Overwritten)}", $"Lieferungen: {importedDeliveries.Sum(d => d.New + d.Overwritten)}",
@@ -379,37 +457,32 @@ namespace Elwig.Helpers.Export {
$" ({d.New} neu, {d.Overwritten} überschr., {d.NotImported} nicht importiert)\n" + $" ({d.New} neu, {d.Overwritten} überschr., {d.NotImported} nicht importiert)\n" +
$" Zwst.: {branches[d.ZwstId].Name} (Gerät {d.Device})\n" + $" Zwst.: {branches[d.ZwstId].Name} (Gerät {d.Device})\n" +
$" Filter: {d.Filters}") $" Filter: {d.Filters}")
]), ]));
"Importieren erfolgreich",
MessageBoxButton.OK, MessageBoxImage.Information);
} catch (Exception exc) { } catch (Exception 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; 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);
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Fehler beim Importieren", MessageBoxButton.OK, MessageBoxImage.Error);
} }
GC.Collect(); GC.Collect();
GC.WaitForPendingFinalizers(); GC.WaitForPendingFinalizers();
} }
private static bool ImportQuestion(string branch, string device, string subject, bool duplicate, int number) { private static bool ImportQuestion(string branch, string device, string subject, bool duplicate, int number) {
return MessageBox.Show( return InteractionService.AskQuestion($"{subject} importieren",
$"Sollen {number} {(duplicate ? "" : "neue ")}{subject} durch die Zweigstelle\n" + $"Sollen {number} {(duplicate ? "" : "neue ")}{subject} durch die Zweigstelle\n" +
$"{branch} (Gerät {device}) {(duplicate ? "überschrieben" : "importiert")} werden?", $"{branch} (Gerät {device}) {(duplicate ? "überschrieben" : "importiert")} werden?", true);
$"{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) { public static Task Export(string filename, IEnumerable<Member> members, IEnumerable<MemberHistory> history, IEnumerable<WbKg> wbKgs, IEnumerable<string> filters) {
return new ElwigExport { return new ElwigExport {
Members = (members, filters), Members = (members, filters),
History = (history, ["von exportierten Mitgliedern"]),
WbKgs = (wbKgs, ["von exportierten Mitgliedern"]), WbKgs = (wbKgs, ["von exportierten Mitgliedern"]),
}.Export(filename); }.Export(filename);
} }
public static Task Export(string filename, IEnumerable<Member> members, IEnumerable<AreaCom> areaComs, IEnumerable<WbKg> wbKgs, IEnumerable<string> filters) { public static Task Export(string filename, IEnumerable<Member> members, IEnumerable<MemberHistory> history, IEnumerable<AreaComContract> areaComs, IEnumerable<WbKg> wbKgs, IEnumerable<string> filters) {
return new ElwigExport { return new ElwigExport {
Members = (members, filters), Members = (members, filters),
History = (history, ["von exportierten Mitgliedern"]),
AreaComs = (areaComs, ["von exportierten Mitgliedern"]), AreaComs = (areaComs, ["von exportierten Mitgliedern"]),
WbKgs = (wbKgs, ["von exportierten Mitgliedern und Flächenbindungen"]), WbKgs = (wbKgs, ["von exportierten Mitgliedern und Flächenbindungen"]),
}.Export(filename); }.Export(filename);
@@ -425,7 +498,8 @@ namespace Elwig.Helpers.Export {
public class ElwigExport { public class ElwigExport {
public (IEnumerable<WbKg> WbKgs, IEnumerable<string> Filters)? WbKgs { get; set; } public (IEnumerable<WbKg> WbKgs, IEnumerable<string> Filters)? WbKgs { get; set; }
public (IEnumerable<Member> Members, IEnumerable<string> Filters)? Members { get; set; } public (IEnumerable<Member> Members, IEnumerable<string> Filters)? Members { get; set; }
public (IEnumerable<AreaCom> AreaComs, IEnumerable<string> Filters)? AreaComs { get; set; } public (IEnumerable<MemberHistory> History, IEnumerable<string> Filters)? History { get; set; }
public (IEnumerable<AreaComContract> AreaComs, IEnumerable<string> Filters)? AreaComs { get; set; }
public (IEnumerable<Delivery> Deliveries, IEnumerable<string> Filters)? Deliveries { get; set; } public (IEnumerable<Delivery> Deliveries, IEnumerable<string> Filters)? Deliveries { get; set; }
public async Task Export(string filename) { public async Task Export(string filename) {
@@ -434,7 +508,7 @@ namespace Elwig.Helpers.Export {
var version = zip.CreateEntry("version", CompressionLevel.NoCompression); var version = zip.CreateEntry("version", CompressionLevel.NoCompression);
using (var writer = new StreamWriter(version.Open(), Utils.UTF8)) { using (var writer = new StreamWriter(version.Open(), Utils.UTF8)) {
await writer.WriteAsync("elwig:1"); await writer.WriteAsync("elwig:2");
} }
var meta = zip.CreateEntry("meta.json", CompressionLevel.NoCompression); var meta = zip.CreateEntry("meta.json", CompressionLevel.NoCompression);
@@ -444,20 +518,25 @@ namespace Elwig.Helpers.Export {
["zwstid"] = App.ZwstId, ["zwstid"] = App.ZwstId,
["device"] = Environment.MachineName, ["device"] = Environment.MachineName,
}; };
if (WbKgs != null) { if (WbKgs != null)
obj["wb_kgs"] = new JsonObject { obj["wb_kgs"] = new JsonObject {
["count"] = WbKgs.Value.WbKgs.Count(), ["count"] = WbKgs.Value.WbKgs.Count(),
["filters"] = new JsonArray(WbKgs.Value.Filters.Select(f => (JsonNode)f).ToArray()), ["filters"] = new JsonArray(WbKgs.Value.Filters.Select(f => (JsonNode)f).ToArray()),
}; };
}
if (Members != null) if (Members != null)
obj["members"] = new JsonObject { obj["members"] = new JsonObject {
["count"] = Members.Value.Members.Count(), ["count"] = Members.Value.Members.Count(),
["filters"] = new JsonArray(Members.Value.Filters.Select(f => (JsonNode)f).ToArray()), ["filters"] = new JsonArray(Members.Value.Filters.Select(f => (JsonNode)f).ToArray()),
}; };
if (History != null)
obj["member_history"] = new JsonObject {
["count"] = History.Value.History.Count(),
["filters"] = new JsonArray(History.Value.Filters.Select(f => (JsonNode)f).ToArray()),
};
if (AreaComs != null) if (AreaComs != null)
obj["area_commitments"] = new JsonObject { obj["area_commitment_contracts"] = new JsonObject {
["count"] = AreaComs.Value.AreaComs.Count(), ["count"] = AreaComs.Value.AreaComs.Count(),
["revisions"] = AreaComs.Value.AreaComs.Sum(c => c.Revisions.Count),
["filters"] = new JsonArray(AreaComs.Value.Filters.Select(f => (JsonNode)f).ToArray()), ["filters"] = new JsonArray(AreaComs.Value.Filters.Select(f => (JsonNode)f).ToArray()),
}; };
if (Deliveries != null) if (Deliveries != null)
@@ -484,8 +563,15 @@ namespace Elwig.Helpers.Export {
await writer.WriteLineAsync(m.ToJson().ToJsonString(Utils.JsonOpts)); await writer.WriteLineAsync(m.ToJson().ToJsonString(Utils.JsonOpts));
} }
} }
if (History != null) {
var json = zip.CreateEntry("member_history.json", CompressionLevel.SmallestSize);
using var writer = new StreamWriter(json.Open(), Utils.UTF8);
foreach (var h in History.Value.History) {
await writer.WriteLineAsync(h.ToJson().ToJsonString(Utils.JsonOpts));
}
}
if (AreaComs != null) { if (AreaComs != null) {
var json = zip.CreateEntry("area_commitments.json", CompressionLevel.SmallestSize); var json = zip.CreateEntry("area_commitment_contracts.json", CompressionLevel.SmallestSize);
using var writer = new StreamWriter(json.Open(), Utils.UTF8); using var writer = new StreamWriter(json.Open(), Utils.UTF8);
foreach (var c in AreaComs.Value.AreaComs) { foreach (var c in AreaComs.Value.AreaComs) {
await writer.WriteLineAsync(c.ToJson().ToJsonString(Utils.JsonOpts)); await writer.WriteLineAsync(c.ToJson().ToJsonString(Utils.JsonOpts));
@@ -542,7 +628,10 @@ namespace Elwig.Helpers.Export {
["birthday"] = m.Birthday, ["birthday"] = m.Birthday,
["entry_date"] = m.EntryDate != null ? $"{m.EntryDate:yyyy-MM-dd}" : null, ["entry_date"] = m.EntryDate != null ? $"{m.EntryDate:yyyy-MM-dd}" : null,
["exit_date"] = m.ExitDate != null ? $"{m.ExitDate:yyyy-MM-dd}" : null, ["exit_date"] = m.ExitDate != null ? $"{m.ExitDate:yyyy-MM-dd}" : null,
["business_shares"] = m.BusinessShares, ["shares"] = m.Shares,
["shares_red"] = m.SharesRed,
["shares_white"] = m.SharesWhite,
["shares_dormant"] = m.SharesDormant,
["accounting_nr"] = m.AccountingNr, ["accounting_nr"] = m.AccountingNr,
["zwstid"] = m.ZwstId, ["zwstid"] = m.ZwstId,
["lfbis_nr"] = m.LfbisNr, ["lfbis_nr"] = m.LfbisNr,
@@ -611,7 +700,10 @@ namespace Elwig.Helpers.Export {
Birthday = json["birthday"]?.AsValue().GetValue<string>(), Birthday = json["birthday"]?.AsValue().GetValue<string>(),
EntryDateString = json["entry_date"]?.AsValue().GetValue<string>(), EntryDateString = json["entry_date"]?.AsValue().GetValue<string>(),
ExitDateString = json["exit_date"]?.AsValue().GetValue<string>(), ExitDateString = json["exit_date"]?.AsValue().GetValue<string>(),
BusinessShares = json["business_shares"]?.AsValue().GetValue<int>() ?? 0, Shares = json["shares"]?.AsValue().GetValue<int>() ?? json["business_shares"]?.AsValue().GetValue<int>() ?? 0,
SharesRed = json["shares_red"]?.AsValue().GetValue<int>() ?? 0,
SharesWhite = json["shares_white"]?.AsValue().GetValue<int>() ?? 0,
SharesDormant = json["shares_dormant"]?.AsValue().GetValue<int>() ?? 0,
AccountingNr = json["accounting_nr"]?.AsValue().GetValue<string>(), AccountingNr = json["accounting_nr"]?.AsValue().GetValue<string>(),
ZwstId = json["zwstid"]?.AsValue().GetValue<string>(), ZwstId = json["zwstid"]?.AsValue().GetValue<string>(),
LfbisNr = json["lfbis_nr"]?.AsValue().GetValue<string>(), LfbisNr = json["lfbis_nr"]?.AsValue().GetValue<string>(),
@@ -639,42 +731,142 @@ namespace Elwig.Helpers.Export {
CountryNum = a["country"]!.AsValue().GetValue<int>(), CountryNum = a["country"]!.AsValue().GetValue<int>(),
PostalDestId = a["postal_dest"]!.AsValue().GetValue<string>(), PostalDestId = a["postal_dest"]!.AsValue().GetValue<string>(),
Address = a["address"]!.AsValue().GetValue<string>(), Address = a["address"]!.AsValue().GetValue<string>(),
} : null, json["telephone_numbers"]!.AsArray().Select(n => n!.AsObject()).Select((n, i) => new MemberTelNr { } : null, [.. json["telephone_numbers"]!.AsArray().Select(n => n!.AsObject()).Select((n, i) => new MemberTelNr {
MgNr = mgnr, MgNr = mgnr,
Nr = i + 1, Nr = i + 1,
Type = n["type"]!.AsValue().GetValue<string>(), Type = n["type"]!.AsValue().GetValue<string>(),
Number = n["number"]!.AsValue().GetValue<string>(), Number = n["number"]!.AsValue().GetValue<string>(),
Comment = n["comment"]?.AsValue().GetValue<string>(), Comment = n["comment"]?.AsValue().GetValue<string>(),
}).ToList(), json["email_addresses"]!.AsArray().Select(a => a!.AsObject()).Select((a, i) => new MemberEmailAddr { })], [.. json["email_addresses"]!.AsArray().Select(a => a!.AsObject()).Select((a, i) => new MemberEmailAddr {
MgNr = mgnr, MgNr = mgnr,
Nr = i + 1, Nr = i + 1,
Address = a["address"]!.AsValue().GetValue<string>(), Address = a["address"]!.AsValue().GetValue<string>(),
Comment = a["comment"]?.AsValue().GetValue<string>(), Comment = a["comment"]?.AsValue().GetValue<string>(),
}).ToList(), })],
createdAt == null || modifiedAt == null ? null : createdAt == null || modifiedAt == null ? null :
(DateTime.ParseExact(createdAt, "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None), (DateTime.ParseExact(createdAt, "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None),
DateTime.ParseExact(modifiedAt, "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None))); DateTime.ParseExact(modifiedAt, "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None)));
} }
public static JsonObject ToJson(this AreaCom c) { public static JsonObject ToJson(this MemberHistory h) {
return new JsonObject {
["histnr"] = h.HistNr,
["from_mgnr"] = h.FromMgNr,
["from_type"] = h.FromType?.ToString().ToLower(),
["to_mgnr"] = h.ToMgNr,
["to_type"] = h.ToType?.ToString().ToLower(),
["date_notice"] = h.DateNoticeString,
["date_effective"] = h.DateEffectiveString,
["reason"] = h.Reason,
["source"] = h.Source,
["shares"] = h.Shares,
["signed"] = h.MemberHasSigned,
["value_per_share"] = h.ValuePerShare,
["currency"] = h.CurrencyCode,
["deduct_year"] = h.DeductYear,
["comment"] = h.Comment,
};
}
public static MemberHistory ToMemberHistory(this JsonNode json) {
return new MemberHistory {
HistNr = json["histnr"]!.AsValue().GetValue<int>(),
FromMgNr = json["from_mgnr"]?.AsValue().GetValue<int>(),
FromType = Enum.TryParse<BusinessShareType>(json["from_type"]?.AsValue().GetValue<string>(), true, out var from) ? from : null,
ToMgNr = json["to_mgnr"]?.AsValue().GetValue<int>(),
ToType = Enum.TryParse<BusinessShareType>(json["to_type"]?.AsValue().GetValue<string>(), true, out var to) ? to : null,
DateNoticeString = json["date_notice"]!.AsValue().GetValue<string>(),
DateEffectiveString = json["date_effective"]!.AsValue().GetValue<string>(),
Reason = json["reason"]!.AsValue().GetValue<string>(),
Source = json["source"]!.AsValue().GetValue<string>(),
Shares = json["shares"]!.AsValue().GetValue<int>(),
MemberHasSigned = json["signed"]?.AsValue().GetValue<bool>() ?? false,
ValuePerShare = json["value_per_share"]?.AsValue().GetValue<decimal>(),
CurrencyCode = json["currency"]?.AsValue().GetValue<string>(),
DeductYear = json["deduct_year"]?.AsValue().GetValue<int>(),
Comment = json["comment"]?.AsValue().GetValue<string>(),
};
}
public static JsonObject ToJson(this AreaComContract c) {
return new JsonObject { return new JsonObject {
["fbnr"] = c.FbNr, ["fbnr"] = c.FbNr,
["mgnr"] = c.MgNr,
["vtrgid"] = c.VtrgId,
["cultid"] = c.CultId,
["area"] = c.Area,
["kgnr"] = c.KgNr, ["kgnr"] = c.KgNr,
["gstnr"] = c.GstNr,
["ried"] = c.Rd?.Name, ["ried"] = c.Rd?.Name,
["year_from"] = c.YearFrom, ["revisions"] = new JsonArray(c.Revisions.OrderBy(r => r.RevNr).Select(r => r.ToJson()).ToArray()),
["year_to"] = c.YearTo,
["comment"] = c.Comment, ["comment"] = c.Comment,
["created_at"] = $"{c.CreatedAt:yyyy-MM-ddTHH:mm:ssK}", ["created_at"] = $"{c.CreatedAt:yyyy-MM-ddTHH:mm:ssK}",
["modified_at"] = $"{c.ModifiedAt:yyyy-MM-ddTHH:mm:ssK}", ["modified_at"] = $"{c.ModifiedAt:yyyy-MM-ddTHH:mm:ssK}",
}; };
} }
public static (AreaCom, WbRd?, (DateTime CreatedAt, DateTime ModifiedAt)?) ToAreaCom(this JsonNode json, Dictionary<int, List<WbRd>> riede) { private static JsonObject ToJson(this AreaCom c) {
return new JsonObject {
["revnr"] = c.RevNr,
["mgnr"] = c.MgNr,
["vtrgid"] = c.VtrgId,
["cultid"] = c.CultId,
["area"] = c.Area,
["gstnr"] = c.GstNr,
["year_from"] = c.YearFrom,
["year_to"] = c.YearTo,
["created_at"] = $"{c.CreatedAt:yyyy-MM-ddTHH:mm:ssK}",
["modified_at"] = $"{c.ModifiedAt:yyyy-MM-ddTHH:mm:ssK}",
};
}
public static (AreaComContract, List<(AreaCom, (DateTime CreatedAt, DateTime ModifiedAt)?)>, WbRd?, (DateTime CreatedAt, DateTime ModifiedAt)?) ToAreaComContract(this JsonNode json, Dictionary<int, List<WbRd>> riede) {
var kgnr = json["kgnr"]!.AsValue().GetValue<int>();
var ried = json["ried"]?.AsValue().GetValue<string>();
var fbnr = json["fbnr"]!.AsValue()!.GetValue<int>();
WbRd? rd = null;
bool newRd = false;
if (ried != null) {
var rde = riede.GetValueOrDefault(kgnr, []);
rd = rde.FirstOrDefault(r => r.Name == ried);
if (rd == null) {
newRd = true;
rd = new WbRd {
KgNr = kgnr,
RdNr = (rde.Count == 0 ? 1 : rde.Max(r => r.RdNr)) + 1,
Name = ried,
};
rde.Add(rd);
riede[rd.KgNr] = rde;
}
}
var createdAt = json["created_at"]?.AsValue().GetValue<string>();
var modifiedAt = json["modified_at"]?.AsValue().GetValue<string>();
return (new AreaComContract {
FbNr = fbnr,
KgNr = kgnr,
RdNr = rd?.RdNr ?? json["rdnr"]?.AsValue().GetValue<int>(),
Comment = json["comment"]?.AsValue().GetValue<string>(),
ImportedAt = DateTime.Now,
}, [.. json["revisions"]!.AsArray().Select(r => r!.AsObject()).Select<JsonObject, (AreaCom, (DateTime, DateTime)?)>(r => {
var createdAt = json["created_at"]?.AsValue().GetValue<string>();
var modifiedAt = json["modified_at"]?.AsValue().GetValue<string>();
return (new AreaCom {
FbNr = fbnr,
RevNr = r["revnr"]!.AsValue().GetValue<int>(),
MgNr = r["mgnr"]!.AsValue().GetValue<int>(),
VtrgId = r["vtrgid"]!.AsValue().GetValue<string>(),
CultId = r["cultid"]?.AsValue().GetValue<string>(),
Area = r["area"]!.AsValue().GetValue<int>(),
GstNr = r["gstnr"]?.AsValue().GetValue<string>() ?? "-",
YearFrom = r["year_from"]?.AsValue().GetValue<int>(),
YearTo = r["year_to"]?.AsValue().GetValue<int>(),
ImportedAt = DateTime.Now,
}, createdAt == null || modifiedAt == null ? null :
(DateTime.ParseExact(createdAt, "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None),
DateTime.ParseExact(modifiedAt, "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None)));
})], newRd ? rd : null,
createdAt == null || modifiedAt == null ? null :
(DateTime.ParseExact(createdAt, "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None),
DateTime.ParseExact(modifiedAt, "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None)));
}
public static (AreaComContract, AreaCom, WbRd?, (DateTime CreatedAt, DateTime ModifiedAt)?) ToAreaCom(this JsonNode json, Dictionary<int, List<WbRd>> riede) {
var kgnr = json["kgnr"]!.AsValue().GetValue<int>(); var kgnr = json["kgnr"]!.AsValue().GetValue<int>();
var ried = json["ried"]?.AsValue().GetValue<string>(); var ried = json["ried"]?.AsValue().GetValue<string>();
WbRd? rd = null; WbRd? rd = null;
@@ -695,18 +887,22 @@ namespace Elwig.Helpers.Export {
} }
var createdAt = json["created_at"]?.AsValue().GetValue<string>(); var createdAt = json["created_at"]?.AsValue().GetValue<string>();
var modifiedAt = json["modified_at"]?.AsValue().GetValue<string>(); var modifiedAt = json["modified_at"]?.AsValue().GetValue<string>();
return (new AreaCom { return (new AreaComContract {
FbNr = json["fbnr"]!.AsValue().GetValue<int>(), FbNr = json["fbnr"]!.AsValue().GetValue<int>(),
KgNr = kgnr,
RdNr = rd?.RdNr ?? json["rdnr"]?.AsValue().GetValue<int>(),
Comment = json["comment"]?.AsValue().GetValue<string>(),
ImportedAt = DateTime.Now,
}, new AreaCom {
FbNr = json["fbnr"]!.AsValue().GetValue<int>(),
RevNr = 1,
MgNr = json["mgnr"]!.AsValue().GetValue<int>(), MgNr = json["mgnr"]!.AsValue().GetValue<int>(),
VtrgId = json["vtrgid"]!.AsValue().GetValue<string>(), VtrgId = json["vtrgid"]!.AsValue().GetValue<string>(),
CultId = json["cultid"]?.AsValue().GetValue<string>(), CultId = json["cultid"]?.AsValue().GetValue<string>(),
Area = json["area"]!.AsValue().GetValue<int>(), Area = json["area"]!.AsValue().GetValue<int>(),
KgNr = kgnr,
GstNr = json["gstnr"]?.AsValue().GetValue<string>() ?? "-", GstNr = json["gstnr"]?.AsValue().GetValue<string>() ?? "-",
RdNr = rd?.RdNr ?? json["rdnr"]?.AsValue().GetValue<int>(),
YearFrom = json["year_from"]?.AsValue().GetValue<int>(), YearFrom = json["year_from"]?.AsValue().GetValue<int>(),
YearTo = json["year_to"]?.AsValue().GetValue<int>(), YearTo = json["year_to"]?.AsValue().GetValue<int>(),
Comment = json["comment"]?.AsValue().GetValue<string>(),
ImportedAt = DateTime.Now, ImportedAt = DateTime.Now,
}, newRd ? rd : null, }, newRd ? rd : null,
createdAt == null || modifiedAt == null ? null : createdAt == null || modifiedAt == null ? null :
@@ -723,7 +919,14 @@ namespace Elwig.Helpers.Export {
["lnr"] = d.LNr, ["lnr"] = d.LNr,
["time"] = d.Time != null ? $"{d.Time:HH:mm:ss}" : null, ["time"] = d.Time != null ? $"{d.Time:HH:mm:ss}" : null,
["mgnr"] = d.MgNr, ["mgnr"] = d.MgNr,
["parts"] = new JsonArray(d.Parts.OrderBy(p => p.DPNr).Select(p => { ["parts"] = new JsonArray(d.Parts.OrderBy(p => p.DPNr).Select(p => p.ToJson()).ToArray()),
["comment"] = d.Comment,
["created_at"] = $"{d.CreatedAt:yyyy-MM-ddTHH:mm:ssK}",
["modified_at"] = $"{d.ModifiedAt:yyyy-MM-ddTHH:mm:ssK}",
};
}
private static JsonObject ToJson(this DeliveryPart p) {
var obj = new JsonObject { var obj = new JsonObject {
["dpnr"] = p.DPNr, ["dpnr"] = p.DPNr,
["sortid"] = p.SortId, ["sortid"] = p.SortId,
@@ -737,7 +940,7 @@ namespace Elwig.Helpers.Export {
["ried"] = p.Rd?.Name, ["ried"] = p.Rd?.Name,
["net_weight"] = p.IsNetWeight, ["net_weight"] = p.IsNetWeight,
["manual_weighing"] = p.IsManualWeighing, ["manual_weighing"] = p.IsManualWeighing,
["modids"] = new JsonArray(p.Modifiers.Select(m => (JsonNode)m.ModId).ToArray()), ["modids"] = new JsonArray(p.PartModifiers.Select(m => (JsonNode)m.ModId).ToArray()),
["comment"] = p.Comment, ["comment"] = p.Comment,
["created_at"] = $"{p.CreatedAt:yyyy-MM-ddTHH:mm:ssK}", ["created_at"] = $"{p.CreatedAt:yyyy-MM-ddTHH:mm:ssK}",
["modified_at"] = $"{p.ModifiedAt:yyyy-MM-ddTHH:mm:ssK}", ["modified_at"] = $"{p.ModifiedAt:yyyy-MM-ddTHH:mm:ssK}",
@@ -752,14 +955,9 @@ namespace Elwig.Helpers.Export {
if (p.WeighingData != null) obj["weighing_data"] = JsonNode.Parse(p.WeighingData); if (p.WeighingData != null) obj["weighing_data"] = JsonNode.Parse(p.WeighingData);
if (p.WeighingReason != null) obj["weighing_reason"] = p.WeighingReason; if (p.WeighingReason != null) obj["weighing_reason"] = p.WeighingReason;
return obj; return obj;
}).ToArray()),
["comment"] = d.Comment,
["created_at"] = $"{d.CreatedAt:yyyy-MM-ddTHH:mm:ssK}",
["modified_at"] = $"{d.ModifiedAt:yyyy-MM-ddTHH:mm:ssK}",
};
} }
public static (Delivery, List<DeliveryPart>, List<DeliveryPartModifier>, List<WbRd>, (DateTime CreatedAt, DateTime ModifiedAt)?) ToDelivery(this JsonNode json, Dictionary<string, int> currentLsNrs, Dictionary<int, int> currentDids, Dictionary<int, AT_Kg> kgs, Dictionary<int, List<WbRd>> riede) { public static (Delivery, List<(DeliveryPart, (DateTime CreatedAt, DateTime ModifiedAt)?)>, List<DeliveryPartModifier>, List<WbRd>, (DateTime CreatedAt, DateTime ModifiedAt)?) ToDelivery(this JsonNode json, Dictionary<string, int> currentLsNrs, Dictionary<int, int> currentDids, Dictionary<int, AT_Kg> kgs, Dictionary<int, List<WbRd>> riede) {
var year = json["year"]!.AsValue().GetValue<int>(); var year = json["year"]!.AsValue().GetValue<int>();
var lsnr = json["lsnr"]!.AsValue().GetValue<string>(); var lsnr = json["lsnr"]!.AsValue().GetValue<string>();
var did = currentLsNrs.GetValueOrDefault(lsnr, -1); var did = currentLsNrs.GetValueOrDefault(lsnr, -1);
@@ -782,7 +980,7 @@ namespace Elwig.Helpers.Export {
MgNr = json["mgnr"]!.AsValue().GetValue<int>(), MgNr = json["mgnr"]!.AsValue().GetValue<int>(),
Comment = json["comment"]?.AsValue().GetValue<string>(), Comment = json["comment"]?.AsValue().GetValue<string>(),
ImportedAt = DateTime.Now, ImportedAt = DateTime.Now,
}, json["parts"]!.AsArray().Select(p => p!.AsObject()).Select(p => { }, [.. json["parts"]!.AsArray().Select(p => p!.AsObject()).Select<JsonObject, (DeliveryPart, (DateTime, DateTime)?)>(p => {
var kgnr = p["kgnr"]?.AsValue().GetValue<int>(); var kgnr = p["kgnr"]?.AsValue().GetValue<int>();
var ried = p["ried"]?.AsValue().GetValue<string>(); var ried = p["ried"]?.AsValue().GetValue<string>();
WbRd? rd = null; WbRd? rd = null;
@@ -800,7 +998,9 @@ namespace Elwig.Helpers.Export {
wbRde.Add(rd); wbRde.Add(rd);
} }
} }
return new DeliveryPart { var createdAt = p["created_at"]?.AsValue().GetValue<string>();
var modifiedAt = p["modified_at"]?.AsValue().GetValue<string>();
return (new DeliveryPart {
Year = year, Year = year,
DId = did, DId = did,
DPNr = p["dpnr"]!.AsValue().GetValue<int>(), DPNr = p["dpnr"]!.AsValue().GetValue<int>(),
@@ -825,13 +1025,15 @@ namespace Elwig.Helpers.Export {
ScaleId = p["scale_id"]?.AsValue().GetValue<string>(), ScaleId = p["scale_id"]?.AsValue().GetValue<string>(),
WeighingData = p["weighing_data"]?.AsObject().ToJsonString(Utils.JsonOpts), WeighingData = p["weighing_data"]?.AsObject().ToJsonString(Utils.JsonOpts),
WeighingReason = p["weighing_reason"]?.AsValue().GetValue<string>(), WeighingReason = p["weighing_reason"]?.AsValue().GetValue<string>(),
}; }, createdAt == null || modifiedAt == null ? null :
}).ToList(), json["parts"]!.AsArray().SelectMany(p => p!["modids"]!.AsArray().Select(m => new DeliveryPartModifier { (DateTime.ParseExact(createdAt, "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None),
DateTime.ParseExact(modifiedAt, "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None)));
})], [.. json["parts"]!.AsArray().SelectMany(p => p!["modids"]!.AsArray().Select(m => new DeliveryPartModifier {
Year = year, Year = year,
DId = did, DId = did,
DPNr = p["dpnr"]!.AsValue().GetValue<int>(), DPNr = p["dpnr"]!.AsValue().GetValue<int>(),
ModId = m!.AsValue().GetValue<string>(), ModId = m!.AsValue().GetValue<string>(),
})).ToList(), }))],
wbRde, wbRde,
createdAt == null || modifiedAt == null ? null : createdAt == null || modifiedAt == null ? null :
(DateTime.ParseExact(createdAt, "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None), (DateTime.ParseExact(createdAt, "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None),
+26
View File
@@ -4,11 +4,14 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.IO.Compression; using System.IO.Compression;
using System.IO.Hashing; using System.IO.Hashing;
using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Reflection; using System.Reflection;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
namespace Elwig.Helpers { namespace Elwig.Helpers {
public static partial class Extensions { public static partial class Extensions {
@@ -145,5 +148,28 @@ namespace Elwig.Helpers {
} }
return [.. list]; return [.. list];
} }
public static IEnumerable<T> Join<T>(this IEnumerable<T> src, Func<T> separatorFactory) {
var srcArr = src.ToArray();
for (int i = 0; i < srcArr.Length; i++) {
yield return srcArr[i];
if (i < srcArr.Length - 1) {
yield return separatorFactory();
}
}
}
public static void AddToolTipCell(this Grid grid, string text, int row, int col, int colSpan = 1, bool bold = false, bool alignRight = false, bool alignCenter = false) {
var tb = new TextBlock() {
Text = text,
TextAlignment = alignRight ? TextAlignment.Right : alignCenter ? TextAlignment.Center : TextAlignment.Left,
Margin = new(0, 12 * row, 0, 0),
FontWeight = bold ? FontWeights.Bold : FontWeights.Normal,
};
tb.SetValue(Grid.ColumnProperty, col);
tb.SetValue(Grid.ColumnSpanProperty, colSpan);
grid.Children.Add(tb);
}
} }
} }
+3 -3
View File
@@ -1,8 +1,8 @@
using Elwig.Services;
using Elwig.Windows; using Elwig.Windows;
using System; using System;
using System.Drawing.Printing; using System.Drawing.Printing;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows;
namespace Elwig.Helpers.Printing { namespace Elwig.Helpers.Printing {
public static class Pdf { public static class Pdf {
@@ -46,8 +46,8 @@ namespace Elwig.Helpers.Printing {
PrinterSettings = settings, PrinterSettings = settings,
}; };
printDoc.Print(); printDoc.Print();
} catch (Exception e) { } catch (Exception exc) {
MessageBox.Show("Beim Drucken ist ein Fehler aufgetreten:\n\n" + e.Message, "Fehler beim Drucken", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException("Fehler beim Drucken", "Beim Drucken ist ein Fehler aufgetreten", exc);
} }
return Task.CompletedTask; return Task.CompletedTask;
} }
+48 -37
View File
@@ -3,12 +3,12 @@ using Elwig.Documents;
using Elwig.Helpers.Billing; using Elwig.Helpers.Billing;
using Elwig.Models; using Elwig.Models;
using Elwig.Models.Entities; using Elwig.Models.Entities;
using Elwig.Services;
using iText.Layout.Element; using iText.Layout.Element;
using LinqKit; using LinqKit;
using MailKit.Net.Smtp; using MailKit.Net.Smtp;
using MailKit.Security; using MailKit.Security;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Win32;
using MimeKit; using MimeKit;
using System; using System;
using System.Collections; using System.Collections;
@@ -31,6 +31,7 @@ using System.Text.RegularExpressions;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows; using System.Windows;
using System.Windows.Input;
using System.Windows.Markup; using System.Windows.Markup;
namespace Elwig.Helpers { namespace Elwig.Helpers {
@@ -209,16 +210,29 @@ namespace Elwig.Helpers {
return Regex.Replace(iban.Trim(), ".{4}", "$0 ").Trim(); return Regex.Replace(iban.Trim(), ".{4}", "$0 ").Trim();
} }
public static void RunBackground(string title, Func<Task> a) { public static void RunBackground(string title, Func<Task> function) {
Task.Run(async () => { Task.Run(async () => {
try { try {
await a(); await function();
} catch (Exception e) { } catch (Exception exc) {
MessageBox.Show(e.ToString(), title, MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException(title, exc);
} }
}); });
} }
public static async Task RunForeground(Func<Task> function) {
var isSTA = Thread.CurrentThread.GetApartmentState() == ApartmentState.STA;
if (isSTA) Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
await function();
} catch (Exception exc) {
InteractionService.ShowException(exc);
}
});
if (isSTA) Mouse.OverrideCursor = null;
}
public static void MailTo(string emailAddress) { public static void MailTo(string emailAddress) {
MailTo([emailAddress]); MailTo([emailAddress]);
} }
@@ -413,8 +427,8 @@ namespace Elwig.Helpers {
return output.OrderByDescending(l => l.Count()); return output.OrderByDescending(l => l.Count());
} }
public static List<RawVaribute> GetVaributes(AppDbContext ctx, int year, bool onlyDelivered = true) { public static async Task<List<RawVaribute>> GetVaributes(AppDbContext ctx, int year, bool onlyDelivered = true) {
var varieties = ctx.WineVarieties.Select(v => new RawVaribute(v.SortId, "", null)).ToList(); var varieties = await ctx.FetchWineVarieties().Select(v => new RawVaribute(v.SortId, "", null)).ToListAsync();
var delivered = ctx.DeliveryParts var delivered = ctx.DeliveryParts
.Where(d => d.Year == year) .Where(d => d.Year == year)
.Select(d => new RawVaribute(d.SortId, d.AttrId ?? "", d.CultId ?? "")) .Select(d => new RawVaribute(d.SortId, d.AttrId ?? "", d.CultId ?? ""))
@@ -423,13 +437,11 @@ namespace Elwig.Helpers {
return [.. (onlyDelivered ? delivered : delivered.Union(varieties)).Order()]; return [.. (onlyDelivered ? delivered : delivered.Union(varieties)).Order()];
} }
public static List<Varibute> GetVaributeList(AppDbContext ctx, int year, bool onlyDelivered = true) { public static async Task<List<Varibute>> GetVaributeList(AppDbContext ctx, int year, bool onlyDelivered = true) {
var varieties = ctx.WineVarieties.ToDictionary(v => v.SortId, v => v); var varieties = await ctx.FetchWineVarieties().ToDictionaryAsync(v => v.SortId, v => v);
var attributes = ctx.WineAttributes.ToDictionary(a => a.AttrId, a => a); var attributes = await ctx.FetchWineAttributes().ToDictionaryAsync(a => a.AttrId, a => a);
var cultivations = ctx.WineCultivations.ToDictionary(c => c.CultId, c => c); var cultivations = await ctx.FetchWineCultivations().ToDictionaryAsync(c => c.CultId, c => c);
return GetVaributes(ctx, year, onlyDelivered) return [.. (await GetVaributes(ctx, year, onlyDelivered)).Select(s => new Varibute(s, varieties, attributes, cultivations))];
.Select(s => new Varibute(s, varieties, attributes, cultivations))
.ToList();
} }
[LibraryImport("wininet.dll")] [LibraryImport("wininet.dll")]
@@ -445,7 +457,7 @@ namespace Elwig.Helpers {
Timeout = TimeSpan.FromSeconds(5), Timeout = TimeSpan.FromSeconds(5),
}; };
client.DefaultRequestHeaders.UserAgent.Clear(); client.DefaultRequestHeaders.UserAgent.Clear();
client.DefaultRequestHeaders.UserAgent.ParseAdd($"Elwig/{App.Version} ({App.Client.NameToken}, {App.BranchName}, {Environment.MachineName}, {Environment.OSVersion})"); client.DefaultRequestHeaders.UserAgent.ParseAdd($"Elwig/{App.Version} ({App.Client?.NameToken}, {App.BranchName}, {Environment.MachineName}, {Environment.OSVersion})");
client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Clear();
if (accept != null) if (accept != null)
client.DefaultRequestHeaders.Accept.Add(new(accept)); client.DefaultRequestHeaders.Accept.Add(new(accept));
@@ -539,7 +551,7 @@ namespace Elwig.Helpers {
subject, docs.Select(d => d.Title).ToArray() subject, docs.Select(d => d.Title).ToArray()
)]); )]);
} catch (Exception exc) { } catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException(exc);
return false; return false;
} finally { } finally {
if (client != null) if (client != null)
@@ -553,41 +565,40 @@ namespace Elwig.Helpers {
public static async Task ExportDocument(Document doc, ExportMode mode, string? filename = null, (Member Member, string Subject, string Text)? emailData = null) { 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 (mode == ExportMode.Print && !App.Config.Debug) {
if (doc.IsPreview) { if (doc.IsPreview) {
MessageBox.Show("Dieses Dokument ist als vorläufig markiert und kann daher nicht ausgedruckt werden!", InteractionService.ShowError("Vorläufiges Dokument", "Dieses Dokument ist als vorläufig markiert und kann daher nicht ausgedruckt werden!");
"Vorläufiges Dokument", MessageBoxButton.OK, MessageBoxImage.Error);
return; return;
} }
await doc.Generate(); using (var ctx = new AppDbContext()) {
await doc.Generate(ctx);
}
await doc.Print(); await doc.Print();
} else if (mode == ExportMode.Email && emailData is (Member, string, string) e) { } else if (mode == ExportMode.Email && emailData is (Member, string, string) e) {
if (doc.IsPreview) { if (doc.IsPreview) {
MessageBox.Show("Dieses Dokument ist als vorläufig markiert und kann daher nicht verschickt werden!", InteractionService.ShowError("Vorläufiges Dokument", "Dieses Dokument ist als vorläufig markiert und kann daher nicht verschickt werden!");
"Vorläufiges Dokument", MessageBoxButton.OK, MessageBoxImage.Error);
return; return;
} }
await doc.Generate(); using (var ctx = new AppDbContext()) {
await doc.Generate(ctx);
}
var success = await SendEmail(e.Member, e.Subject, e.Text, [doc]); var success = await SendEmail(e.Member, e.Subject, e.Text, [doc]);
if (success) if (success)
MessageBox.Show("Die E-Mail wurde erfolgreich verschickt!\n\nEs kann einige Minuten dauern, bis die E-Mail im Posteingang des Empfängers aufscheint.", "E-Mail verschickt", 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.");
MessageBoxButton.OK, MessageBoxImage.Information);
} else if (mode == ExportMode.SavePdf) { } else if (mode == ExportMode.SavePdf) {
if (doc.IsPreview) { if (doc.IsPreview) {
MessageBox.Show("Dieses Dokument ist als vorläufig markiert und sollte daher nicht langfristig gespeichert werden!", InteractionService.ShowWarning("Vorläufiges Dokument", "Dieses Dokument ist als vorläufig markiert und sollte daher nicht langfristig gespeichert werden!");
"Vorläufiges Dokument", MessageBoxButton.OK, MessageBoxImage.Warning);
} }
var d = new SaveFileDialog() { filename = InteractionService.SaveFile(doc.Title, NormalizeFileName(filename ?? doc.Title), "pdf");
FileName = $"{NormalizeFileName(filename ?? doc.Title)}.pdf", if (filename != null) {
DefaultExt = "pdf", using (var ctx = new AppDbContext()) {
Filter = "PDF-Datei (*.pdf)|*.pdf", await doc.Generate(ctx);
Title = $"{doc.Title} speichern unter - Elwig" }
}; doc.SaveTo(filename);
if (d.ShowDialog() == true) { if (!App.Config.Debug) Process.Start("explorer.exe", filename);
await doc.Generate();
doc.SaveTo(d.FileName);
Process.Start("explorer.exe", d.FileName);
} }
} else { } else {
await doc.Generate(); using (var ctx = new AppDbContext()) {
await doc.Generate(ctx);
}
doc.Show(); doc.Show();
} }
} }
+9 -15
View File
@@ -136,8 +136,7 @@ namespace Elwig.Helpers {
return new(false, "PLZ zu kurz"); return new(false, "PLZ zu kurz");
} }
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
int plz = int.Parse(input.Text); if (!int.TryParse(input.Text, out var plz) || ctx.Postleitzahlen.Find(plz) == null) {
if (ctx.Postleitzahlen.Find(plz) == null) {
return new(false, "Ungültige PLZ"); return new(false, "Ungültige PLZ");
} }
return new(true, null); return new(true, null);
@@ -423,8 +422,7 @@ namespace Elwig.Helpers {
} }
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
int nr = int.Parse(input.Text); if (!int.TryParse(input.Text, out var nr) || !ctx.MgNrExists(nr).GetAwaiter().GetResult()) {
if (!ctx.MgNrExists(nr).GetAwaiter().GetResult()) {
return new(false, "Ungültige Mitgliedsnummer"); return new(false, "Ungültige Mitgliedsnummer");
} }
@@ -440,8 +438,7 @@ namespace Elwig.Helpers {
} }
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
int nr = int.Parse(input.Text); if (!int.TryParse(input.Text, out var nr) || nr != m?.MgNr && ctx.MgNrExists(nr).GetAwaiter().GetResult()) {
if (nr != m?.MgNr && ctx.MgNrExists(nr).GetAwaiter().GetResult()) {
return new(false, "Mitgliedsnummer wird bereits verwendet"); return new(false, "Mitgliedsnummer wird bereits verwendet");
} }
@@ -476,7 +473,7 @@ namespace Elwig.Helpers {
return res; return res;
} else if (!required && input.Text.Length == 0) { } else if (!required && input.Text.Length == 0) {
return new(true, null); return new(true, null);
} else if (!ctx.MgNrExists(int.Parse(input.Text)).GetAwaiter().GetResult()) { } else if (!int.TryParse(input.Text, out var nr) ||!ctx.MgNrExists(nr).GetAwaiter().GetResult()) {
return new(false, "Ein Mitglied mit dieser Mitgliedsnummer existiert nicht"); return new(false, "Ein Mitglied mit dieser Mitgliedsnummer existiert nicht");
} }
@@ -537,7 +534,7 @@ namespace Elwig.Helpers {
return (parts[0]?.Length == 4) ? new(true, null) : new(false, "Datum ist ungültig"); return (parts[0]?.Length == 4) ? new(true, null) : new(false, "Datum ist ungültig");
} else if (p == 1) { } else if (p == 1) {
// only month and year provided // only month and year provided
int m = parts[0] != null && parts[0] != "" ? int.Parse(parts[0] ?? "0") : 0; int m = parts[0] != null && parts[0] != "" && int.TryParse(parts[0], out var v) ? v : 0;
if (parts[1]?.Length != 4 || parts[0]?.Length != 2 || m < 1 || m > 12) if (parts[1]?.Length != 4 || parts[0]?.Length != 2 || m < 1 || m > 12)
return new(false, "Datum ist ungültig"); return new(false, "Datum ist ungültig");
return new(true, null); return new(true, null);
@@ -580,7 +577,7 @@ namespace Elwig.Helpers {
} }
} }
public static ValidationResult CheckFbNr(TextBox input, bool required, AreaCom? c) { public static ValidationResult CheckFbNr(TextBox input, bool required, AreaComContract? c) {
var res = CheckInteger(input, required); var res = CheckInteger(input, required);
if (!res.IsValid) { if (!res.IsValid) {
return res; return res;
@@ -589,8 +586,7 @@ namespace Elwig.Helpers {
} }
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
int nr = int.Parse(input.Text); if (!int.TryParse(input.Text, out var nr) || (nr != c?.FbNr && ctx.FbNrExists(nr).GetAwaiter().GetResult())) {
if (nr != c?.FbNr && ctx.FbNrExists(nr).GetAwaiter().GetResult()) {
return new(false, "Flächenbindungsnummer wird bereits verwendet"); return new(false, "Flächenbindungsnummer wird bereits verwendet");
} }
@@ -605,8 +601,7 @@ namespace Elwig.Helpers {
return new(true, null); return new(true, null);
} }
var oe = double.Parse(input.Text); if (!double.TryParse(input.Text, out var oe) || oe < 10 || oe >= 300) {
if (oe < 10 || oe >= 300) {
return new(false, "Ungültiger Oechsle-Wert"); return new(false, "Ungültiger Oechsle-Wert");
} }
@@ -621,8 +616,7 @@ namespace Elwig.Helpers {
return new(true, null); return new(true, null);
} }
var kmw = double.Parse(input.Text); if (!double.TryParse(input.Text, out var kmw) || kmw < 5 || kmw >= 50) {
if (kmw < 5 || kmw >= 50) {
return new(false, "Ungültiger KMW-Wert"); return new(false, "Ungültiger KMW-Wert");
} }
+3 -4
View File
@@ -1,9 +1,9 @@
using Elwig.Services;
using System; using System;
using System.IO; using System.IO;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows;
namespace Elwig.Helpers.Weighing { namespace Elwig.Helpers.Weighing {
public class AveryEventScale : Scale, IEventScale, IDisposable { public class AveryEventScale : Scale, IEventScale, IDisposable {
@@ -60,9 +60,8 @@ namespace Elwig.Helpers.Weighing {
} catch (TimeoutException) { } catch (TimeoutException) {
await Task.Delay(500); await Task.Delay(500);
await Reconnect(); await Reconnect();
} catch (Exception ex) { } catch (Exception exc) {
MessageBox.Show($"Beim Wiegen ist ein Fehler Aufgetreten:\n\n{ex.Message} ({ex.GetType().Name})", "Waagenfehler", InteractionService.ShowException("Waagenfehler", "Beim Wiegen ist ein Fehler Aufgetreten", exc, showExcType: true);
MessageBoxButton.OK, MessageBoxImage.Error);
} }
} }
} }
+3 -4
View File
@@ -1,9 +1,9 @@
using Elwig.Services;
using System; using System;
using System.IO; using System.IO;
using System.IO.Ports; using System.IO.Ports;
using System.Net.Sockets; using System.Net.Sockets;
using System.Text; using System.Text;
using System.Windows;
namespace Elwig.Helpers.Weighing { namespace Elwig.Helpers.Weighing {
public abstract class Scale : IDisposable { public abstract class Scale : IDisposable {
@@ -42,11 +42,10 @@ namespace Elwig.Helpers.Weighing {
if (cnx.StartsWith("serial:")) { if (cnx.StartsWith("serial:")) {
try { try {
Serial = Utils.OpenSerialConnection(cnx); Serial = Utils.OpenSerialConnection(cnx);
} catch (Exception e) { } catch (Exception exc) {
if (!softFail) throw; if (!softFail) throw;
if (!failSilent) if (!failSilent)
MessageBox.Show($"Verbindung zu Waage konnte nicht hergestellt werden:\n\n{e.Message}", "Waagenfehler", InteractionService.ShowException("Waagenfehler", "Verbindung zu Waage konnte nicht hergestellt werden", exc, isError: false);
MessageBoxButton.OK, MessageBoxImage.Warning);
} }
Stream = Serial?.BaseStream ?? Stream.Null; Stream = Serial?.BaseStream ?? Stream.Null;
} else if (cnx.StartsWith("tcp:")) { } else if (cnx.StartsWith("tcp:")) {
+5
View File
@@ -0,0 +1,5 @@
namespace Elwig.Models {
public enum BusinessShareType {
Normal = 1, Red = 2, White = 3, Dormant = 9,
}
}
+21 -16
View File
@@ -17,6 +17,7 @@ namespace Elwig.Models.Dtos {
("Address", "Adresse", null, 60), ("Address", "Adresse", null, 60),
("Plz", "PLZ", null, 10), ("Plz", "PLZ", null, 10),
("Locality", "Ort", null, 60), ("Locality", "Ort", null, 60),
("AccountingNr", "BH-Konto", null, 20),
("Iban", "IBAN", null, 45), ("Iban", "IBAN", null, 45),
("TgNr", "TG-Nr.", null, 20), ("TgNr", "TG-Nr.", null, 20),
("Sum", "Zwischens.", "€", 20), ("Sum", "Zwischens.", "€", 20),
@@ -29,7 +30,7 @@ namespace Elwig.Models.Dtos {
("Gross", "Brutto", "€", 20), ("Gross", "Brutto", "€", 20),
("Penalties", "Pönalen FB", "€", 20), ("Penalties", "Pönalen FB", "€", 20),
("Penalty", "Unterl. GA", "€", 20), ("Penalty", "Unterl. GA", "€", 20),
("AutoBs", "GA Nachz.", "€", 20), ("AutoShares", "GA Nachz.", "€", 20),
("Custom", "Weitere", "€", 20), ("Custom", "Weitere", "€", 20),
("Others", "Sonstige", "€", 20), ("Others", "Sonstige", "€", 20),
("Considered", "Berückstgt.", "€", 20), ("Considered", "Berückstgt.", "€", 20),
@@ -53,12 +54,12 @@ namespace Elwig.Models.Dtos {
SELECT m.mgnr, m.name AS name_1, SELECT m.mgnr, m.name AS name_1,
COALESCE(m.prefix || ' ', '') || m.given_name || COALESCE(m.prefix || ' ', '') || m.given_name ||
COALESCE(' ' || m.middle_names, '') || COALESCE(' ' || m.suffix, '') AS name_2, COALESCE(' ' || m.middle_names, '') || COALESCE(' ' || m.suffix, '') AS name_2,
p.plz, o.name AS ort, m.address, m.iban, c.tgnr, s.year, s.precision, p.plz, o.name AS ort, m.address, m.accounting_nr, m.iban, c.tgnr, s.year, s.precision,
p.amount - p.net_amount AS surcharge, p.amount - p.net_amount AS surcharge,
c.net_amount, c.prev_net_amount, c.vat, c.vat_amount, c.gross_amount, c.modifiers, c.prev_modifiers, c.amount, c.net_amount, c.prev_net_amount, c.vat, c.vat_amount, c.gross_amount, c.modifiers, c.prev_modifiers, c.amount,
ROUND(b.total_penalty / POW(10, s.precision - 2)) AS bs_penalty, ROUND(b.total_penalty / POW(10, s.precision - 2)) AS shares_penalty,
ROUND(u.total_penalty / POW(10, 4 - 2)) AS fb_penalty, ROUND(u.total_penalty / POW(10, 4 - 2)) AS ac_penalty,
ROUND(-a.total_amount / POW(10, s.precision - 2)) AS auto_bs, -a.total_amount AS auto_shares,
x.amount AS custom_mod x.amount AS custom_mod
FROM credit c FROM credit c
LEFT JOIN member m ON m.mgnr = c.mgnr LEFT JOIN member m ON m.mgnr = c.mgnr
@@ -83,6 +84,7 @@ namespace Elwig.Models.Dtos {
public string Address; public string Address;
public int Plz; public int Plz;
public string Locality; public string Locality;
public string? AccountingNr;
public string? Iban; public string? Iban;
public string TgNr; public string TgNr;
public decimal Sum; public decimal Sum;
@@ -94,7 +96,7 @@ namespace Elwig.Models.Dtos {
public decimal Gross; public decimal Gross;
public decimal? Penalties; public decimal? Penalties;
public decimal? Penalty; public decimal? Penalty;
public decimal? AutoBs; public decimal? AutoShares;
public decimal? Custom; public decimal? Custom;
public decimal? Others; public decimal? Others;
public decimal? Considered; public decimal? Considered;
@@ -108,6 +110,7 @@ namespace Elwig.Models.Dtos {
Address = row.Address; Address = row.Address;
Plz = row.Plz; Plz = row.Plz;
Locality = row.Locality; Locality = row.Locality;
AccountingNr = row.AccountingNr;
Iban = row.Iban != null ? Utils.FormatIban(row.Iban) : null; Iban = row.Iban != null ? Utils.FormatIban(row.Iban) : null;
TgNr = $"{row.Year}/{row.TgNr}"; TgNr = $"{row.Year}/{row.TgNr}";
Total = Utils.DecFromDb(row.NetAmount, prec1); Total = Utils.DecFromDb(row.NetAmount, prec1);
@@ -122,14 +125,14 @@ namespace Elwig.Models.Dtos {
} }
decimal mod = (row.Modifiers == null) ? 0 : Utils.DecFromDb((long)row.Modifiers, prec1); decimal mod = (row.Modifiers == null) ? 0 : Utils.DecFromDb((long)row.Modifiers, prec1);
if (data.ConsiderContractPenalties) if (data.ConsiderContractPenalties)
Penalties = (row.FbPenalty == null) ? null : Utils.DecFromDb((long)row.FbPenalty, prec1); Penalties = (row.AcPenalty == null) ? null : Utils.DecFromDb((long)row.AcPenalty, prec1);
if (data.ConsiderTotalPenalty) if (data.ConsiderTotalPenalty)
Penalty = (row.BsPenalty == null) ? null : Utils.DecFromDb((long)row.BsPenalty, prec1); Penalty = (row.SharesPenalty == null) ? null : Utils.DecFromDb((long)row.SharesPenalty, prec1);
if (data.ConsiderAutoBusinessShares) if (data.ConsiderAutoBusinessShares)
AutoBs = (row.AutoBs == null) ? null : Utils.DecFromDb((long)row.AutoBs, prec1); AutoShares = (row.AutoShares == null) ? null : Utils.DecFromDb((long)row.AutoShares, prec1);
if (data.ConsiderCustomModifiers) if (data.ConsiderCustomModifiers)
Custom = (row.CustomMod == null) ? null : Utils.DecFromDb((long)row.CustomMod, prec1); Custom = (row.CustomMod == null) ? null : Utils.DecFromDb((long)row.CustomMod, prec1);
mod -= (Penalties ?? 0) + (Penalty ?? 0) + (AutoBs ?? 0) + (Custom ?? 0); mod -= (Penalties ?? 0) + (Penalty ?? 0) + (AutoShares ?? 0) + (Custom ?? 0);
Others = (mod == 0) ? null : mod; Others = (mod == 0) ? null : mod;
Gross = Utils.DecFromDb(row.GrossAmount, prec1); Gross = Utils.DecFromDb(row.GrossAmount, prec1);
Considered = (row.PrevModifiers == null || row.PrevModifiers == 0) ? null : -Utils.DecFromDb((long)row.PrevModifiers, prec1); Considered = (row.PrevModifiers == null || row.PrevModifiers == 0) ? null : -Utils.DecFromDb((long)row.PrevModifiers, prec1);
@@ -153,6 +156,8 @@ namespace Elwig.Models.Dtos {
public required string LocalityFull { get; set; } public required string LocalityFull { get; set; }
[NotMapped] [NotMapped]
public string Locality => LocalityFull.Split(",")[0]; public string Locality => LocalityFull.Split(",")[0];
[Column("accounting_nr")]
public string? AccountingNr { get; set; }
[Column("iban")] [Column("iban")]
public string? Iban { get; set; } public string? Iban { get; set; }
[Column("year")] [Column("year")]
@@ -179,12 +184,12 @@ namespace Elwig.Models.Dtos {
public long? PrevModifiers { get; set; } public long? PrevModifiers { get; set; }
[Column("amount")] [Column("amount")]
public long Amount { get; set; } public long Amount { get; set; }
[Column("bs_penalty")] [Column("shares_penalty")]
public long? BsPenalty { get; set; } public long? SharesPenalty { get; set; }
[Column("fb_penalty")] [Column("ac_penalty")]
public long? FbPenalty { get; set; } public long? AcPenalty { get; set; }
[Column("auto_bs")] [Column("auto_shares")]
public long? AutoBs { get; set; } public long? AutoShares { get; set; }
[Column("custom_mod")] [Column("custom_mod")]
public long? CustomMod { get; set; } public long? CustomMod { get; set; }
} }
+13 -13
View File
@@ -28,9 +28,9 @@ namespace Elwig.Models.Dtos {
} }
public static async Task<IDictionary<int, CreditNoteDeliveryData>> ForPaymentVariant(DbSet<CreditNoteDeliveryRowSingle> table, DbSet<PaymentVar> paymentVariants, int year, int avnr) { public static async Task<IDictionary<int, CreditNoteDeliveryData>> ForPaymentVariant(DbSet<CreditNoteDeliveryRowSingle> table, DbSet<PaymentVar> paymentVariants, int year, int avnr) {
var variant = await paymentVariants.FindAsync(year, avnr); var variant = await paymentVariants.Include(v => v.Season.Modifiers).Where(v => v.Year == year && v.AvNr == avnr).SingleAsync();
BillingData? varData = null; BillingData? varData = null;
try { varData = variant != null ? BillingData.FromJson(variant.Data) : null; } catch { } try { varData = variant.Data != null ? BillingData.FromJson(variant.Data) : null; } catch { }
return (await FromDbSet(table, year, avnr)) return (await FromDbSet(table, year, avnr))
.GroupBy( .GroupBy(
r => new { r.Year, r.AvNr, r.MgNr, r.TgNr, r.DId, r.DPNr }, r => new { r.Year, r.AvNr, r.MgNr, r.TgNr, r.DId, r.DPNr },
@@ -42,13 +42,10 @@ namespace Elwig.Models.Dtos {
} }
private static async Task<IEnumerable<CreditNoteDeliveryRowSingle>> FromDbSet(DbSet<CreditNoteDeliveryRowSingle> table, int? year = null, int? avnr = null, int? mgnr = null) { private static async Task<IEnumerable<CreditNoteDeliveryRowSingle>> FromDbSet(DbSet<CreditNoteDeliveryRowSingle> table, int? year = null, int? avnr = null, int? mgnr = null) {
var y = year?.ToString() ?? "NULL"; return await table.FromSql($"""
var v = avnr?.ToString() ?? "NULL";
var m = mgnr?.ToString() ?? "NULL";
return await table.FromSqlRaw($"""
SELECT d.year, c.tgnr, v.avnr, d.mgnr, d.did, d.lsnr, d.dpnr, d.weight, d.modifiers, SELECT d.year, c.tgnr, v.avnr, d.mgnr, d.did, d.lsnr, d.dpnr, d.weight, d.modifiers,
b.bktnr, d.sortid, b.discr, b.value, pb.price, pb.amount, p.net_amount, p.amount AS total_amount, b.bktnr, d.sortid, b.discr, b.value, pb.price, pb.amount, p.net_amount, p.amount AS total_amount,
s.name AS variety, a.name AS attribute, c.name AS cultivation, q.qualid AS qualid, q.name AS quality_level, d.oe, d.kmw, d.net_weight s.name AS variety, s.type AS type, a.name AS attribute, c.name AS cultivation, q.qualid AS qualid, q.name AS quality_level, d.oe, d.kmw, d.net_weight
FROM v_delivery d FROM v_delivery d
JOIN wine_variety s ON s.sortid = d.sortid JOIN wine_variety s ON s.sortid = d.sortid
LEFT JOIN wine_attribute a ON a.attrid = d.attrid LEFT JOIN wine_attribute a ON a.attrid = d.attrid
@@ -59,7 +56,7 @@ namespace Elwig.Models.Dtos {
LEFT JOIN payment_delivery_part p ON (p.year, p.did, p.dpnr, p.avnr) = (d.year, d.did, d.dpnr, v.avnr) LEFT JOIN payment_delivery_part p ON (p.year, p.did, p.dpnr, p.avnr) = (d.year, d.did, d.dpnr, v.avnr)
LEFT JOIN payment_delivery_part_bucket pb ON (pb.year, pb.did, pb.dpnr, pb.bktnr, pb.avnr) = (b.year, b.did, b.dpnr, b.bktnr, v.avnr) LEFT JOIN payment_delivery_part_bucket pb ON (pb.year, pb.did, pb.dpnr, pb.bktnr, pb.avnr) = (b.year, b.did, b.dpnr, b.bktnr, v.avnr)
LEFT JOIN credit c ON (c.year, c.avnr, c.mgnr) = (d.year, v.avnr, d.mgnr) LEFT JOIN credit c ON (c.year, c.avnr, c.mgnr) = (d.year, v.avnr, d.mgnr)
WHERE b.value > 0 AND (d.year = {y} OR {y} IS NULL) AND (v.avnr = {v} OR {v} IS NULL) AND (d.mgnr = {m} OR {m} IS NULL) WHERE b.value > 0 AND (d.year = {year} OR {year} IS NULL) AND (v.avnr = {avnr} OR {avnr} IS NULL) AND (d.mgnr = {mgnr} OR {mgnr} IS NULL)
ORDER BY d.year, v.avnr, d.mgnr, d.lsnr, d.dpnr ORDER BY d.year, v.avnr, d.mgnr, d.lsnr, d.dpnr
""").ToListAsync(); """).ToListAsync();
} }
@@ -75,6 +72,7 @@ namespace Elwig.Models.Dtos {
public string LsNr; public string LsNr;
public int DPNr; public int DPNr;
public string Variety; public string Variety;
public string Type;
public string? Attribute; public string? Attribute;
public string? Cultivation; public string? Cultivation;
public string[] Modifiers; public string[] Modifiers;
@@ -97,24 +95,24 @@ namespace Elwig.Models.Dtos {
LsNr = f.LsNr; LsNr = f.LsNr;
DPNr = f.DPNr; DPNr = f.DPNr;
Variety = f.Variety; Variety = f.Variety;
Type = f.Type;
Attribute = f.Attribute; Attribute = f.Attribute;
Cultivation = f.Cultivation; Cultivation = f.Cultivation;
var modifiers = (IEnumerable<Modifier>)(f.Modifiers ?? "").Split(',') var modifiers = (IEnumerable<Modifier>)(f.Modifiers ?? "").Split(',')
.Select(m => season?.Modifiers.FirstOrDefault(s => s.ModId == m)) .Select(m => season?.Modifiers.FirstOrDefault(s => s.ModId == m))
.Where(m => m != null) .Where(m => m != null)
.OrderBy(m => m.Ordering) .OrderBy(m => m!.Ordering)
.ToList(); .ToList();
Modifiers = modifiers.Select(m => m.Name).ToArray(); Modifiers = [.. modifiers.Select(m => m.Name)];
QualId = f.QualId; QualId = f.QualId;
QualityLevel = f.QualityLevel; QualityLevel = f.QualityLevel;
Gradation = (f.Oe, f.Kmw); Gradation = (f.Oe, f.Kmw);
Buckets = rows Buckets = [.. rows
.Where(b => b.Value > 0) .Where(b => b.Value > 0)
.OrderByDescending(b => b.BktNr) .OrderByDescending(b => b.BktNr)
.Select(b => (b.Discr == "_" ? "ungeb." : $"geb. {f.SortId}{b.Discr}", b.Value, .Select(b => (b.Discr == "_" ? "ungeb." : $"geb. {f.SortId}{b.Discr}", b.Value,
b.Price != null ? season?.DecFromDb((long)b.Price) : null, b.Price != null ? season?.DecFromDb((long)b.Price) : null,
b.Amount != null ? season?.DecFromDb((long)b.Amount) : null)) b.Amount != null ? season?.DecFromDb((long)b.Amount) : null))];
.ToArray();
WeighingModifier = (varData == null || !varData.ConsiderDelieryModifiers) ? 0 : f.NetWeight ? varData.NetWeightModifier : varData.GrossWeightModifier; WeighingModifier = (varData == null || !varData.ConsiderDelieryModifiers) ? 0 : f.NetWeight ? varData.NetWeightModifier : varData.GrossWeightModifier;
Amount = f.TotalAmount != null ? season?.DecFromDb((long)f.TotalAmount) : null; Amount = f.TotalAmount != null ? season?.DecFromDb((long)f.TotalAmount) : null;
var netAmount = f.NetAmount != null ? season?.DecFromDb((long)f.NetAmount) : null; var netAmount = f.NetAmount != null ? season?.DecFromDb((long)f.NetAmount) : null;
@@ -161,6 +159,8 @@ namespace Elwig.Models.Dtos {
public long? TotalAmount { get; set; } public long? TotalAmount { get; set; }
[Column("variety")] [Column("variety")]
public required string Variety { get; set; } public required string Variety { get; set; }
[Column("type")]
public required string Type { get; set; }
[Column("attribute")] [Column("attribute")]
public string? Attribute { get; set; } public string? Attribute { get; set; }
[Column("cultivation")] [Column("cultivation")]
+1 -6
View File
@@ -28,12 +28,7 @@ namespace Elwig.Models.Dtos {
} }
public static async Task<DeliveryAncmtListData> FromQuery(IQueryable<DeliveryAncmt> query, List<string> filterNames) { public static async Task<DeliveryAncmtListData> FromQuery(IQueryable<DeliveryAncmt> query, List<string> filterNames) {
return new((await query return new((await query.ToListAsync()).Select(d => new DeliveryAncmtListRow(d)), filterNames);
.Include(a => a.Schedule.Branch)
.Include(a => a.Member)
.Include(a => a.Variety)
.AsSplitQuery()
.ToListAsync()).Select(d => new DeliveryAncmtListRow(d)), filterNames);
} }
} }
@@ -52,12 +52,8 @@ namespace Elwig.Models.Dtos {
if (mgnr != null) q = q.Where(p => p.Delivery.MgNr == mgnr); if (mgnr != null) q = q.Where(p => p.Delivery.MgNr == mgnr);
await q await q
.Include(p => p.Delivery) .Include(p => p.Delivery)
.Include(p => p.Variety)
.Include(p => p.Attribute)
.Include(p => p.Quality)
.Include(p => p.Buckets) .Include(p => p.Buckets)
.Include(p => p.PartModifiers) .Include(p => p.PartModifiers).ThenInclude(m => m.Modifier)
.ThenInclude(m => m.Modifier)
.LoadAsync(); .LoadAsync();
return await table.FromSqlRaw($""" return await table.FromSqlRaw($"""
SELECT p.* SELECT p.*
@@ -65,7 +61,7 @@ namespace Elwig.Models.Dtos {
JOIN delivery_part p ON (p.year, p.did, p.dpnr) = (v.year, v.did, v.dpnr) JOIN delivery_part p ON (p.year, p.did, p.dpnr) = (v.year, v.did, v.dpnr)
WHERE (p.year = {y} OR {y} IS NULL) AND (v.mgnr = {m} OR {m} IS NULL) WHERE (p.year = {y} OR {y} IS NULL) AND (v.mgnr = {m} OR {m} IS NULL)
ORDER BY p.year, v.mgnr, v.sortid, v.abgewertet ASC, v.attribute_prio DESC, COALESCE(v.attrid, '~'), v.kmw DESC, v.lsnr, v.dpnr ORDER BY p.year, v.mgnr, v.sortid, v.abgewertet ASC, v.attribute_prio DESC, COALESCE(v.attrid, '~'), v.kmw DESC, v.lsnr, v.dpnr
""").ToListAsync(); """).IgnoreAutoIncludes().ToListAsync();
} }
} }
-5
View File
@@ -40,12 +40,7 @@ namespace Elwig.Models.Dtos {
.Include(p => p.Delivery.Member.Branch) .Include(p => p.Delivery.Member.Branch)
.Include(p => p.Delivery.Branch) .Include(p => p.Delivery.Branch)
.Include(p => p.PartModifiers).ThenInclude(m => m.Modifier) .Include(p => p.PartModifiers).ThenInclude(m => m.Modifier)
.Include(p => p.Variety)
.Include(p => p.Attribute)
.Include(p => p.Cultivation)
.Include(p => p.Origin) .Include(p => p.Origin)
.Include(p => p.Quality)
.AsSplitQuery()
.ToListAsync()).Select(d => new DeliveryJournalRow(d)), filterNames); .ToListAsync()).Select(d => new DeliveryJournalRow(d)), filterNames);
} }
} }
+10 -8
View File
@@ -19,7 +19,7 @@ namespace Elwig.Models.Dtos {
("Locality", "Ort", null, 60), ("Locality", "Ort", null, 60),
("DefaultKg", "Stammgemeinde", null, 60), ("DefaultKg", "Stammgemeinde", null, 60),
("Branch", "Zweigstelle", null, 40), ("Branch", "Zweigstelle", null, 40),
("BusinessShares", "GA", null, 10), ("SharesActive", "GA", null, 10),
("BillingName", "Rechnungsname", null, 60), ("BillingName", "Rechnungsname", null, 60),
("BillingAddress", "Rechnungsadresse", null, 60), ("BillingAddress", "Rechnungsadresse", null, 60),
("BillingPlz", "PLZ", null, 10), ("BillingPlz", "PLZ", null, 10),
@@ -47,15 +47,11 @@ namespace Elwig.Models.Dtos {
} }
public static async Task<MemberListData> FromQuery(IQueryable<Member> query, List<string> filterNames, IEnumerable<string> filterAreaCom) { public static async Task<MemberListData> FromQuery(IQueryable<Member> query, List<string> filterNames, IEnumerable<string> filterAreaCom) {
var areaComs = await query.ToDictionaryAsync(m => m.MgNr, m => Utils.ActiveAreaCommitments(m.AreaCommitments)); var areaComs = await query.Include(m => m.AreaCommitments).ToDictionaryAsync(m => m.MgNr, m => Utils.ActiveAreaCommitments(m.AreaCommitments));
return new((await query return new((await query
.Include(m => m.DefaultWbKg!.AtKg)
.Include(m => m.Branch) .Include(m => m.Branch)
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.BillingAddress!.PostalDest.AtPlz!.Ort)
.Include(m => m.TelephoneNumbers) .Include(m => m.TelephoneNumbers)
.Include(m => m.EmailAddresses) .Include(m => m.EmailAddresses)
.AsSplitQuery()
.ToListAsync()).Select(m => new MemberListRow(m, .ToListAsync()).Select(m => new MemberListRow(m,
areaComs[m.MgNr].Sum(c => c.Area), areaComs[m.MgNr].Sum(c => c.Area),
areaComs[m.MgNr].Where(c => filterAreaCom.Contains(c.VtrgId)).GroupBy(c => c.VtrgId).ToDictionary(g => g.Key, g => g.Sum(c => c.Area)))), areaComs[m.MgNr].Where(c => filterAreaCom.Contains(c.VtrgId)).GroupBy(c => c.VtrgId).ToDictionary(g => g.Key, g => g.Sum(c => c.Area)))),
@@ -70,7 +66,10 @@ namespace Elwig.Models.Dtos {
public string? Name2; public string? Name2;
public string? DefaultKg; public string? DefaultKg;
public string? Branch; public string? Branch;
public int BusinessShares; public int Shares;
public int SharesRed;
public int SharesWhite;
public int SharesActive;
public string Address; public string Address;
public int Plz; public int Plz;
public string Locality; public string Locality;
@@ -102,7 +101,10 @@ namespace Elwig.Models.Dtos {
Name2 = m.AdministrativeName2; Name2 = m.AdministrativeName2;
DefaultKg = m.DefaultKg?.Name; DefaultKg = m.DefaultKg?.Name;
Branch = m.Branch?.Name; Branch = m.Branch?.Name;
BusinessShares = m.BusinessShares; Shares = m.Shares;
SharesRed = m.SharesRed;
SharesWhite = m.SharesWhite;
SharesActive = Shares + SharesRed + SharesWhite;
Address = m.Address; Address = m.Address;
Plz = m.PostalDest.AtPlz!.Plz; Plz = m.PostalDest.AtPlz!.Plz;
Locality = m.PostalDest.AtPlz!.Ort.Name; Locality = m.PostalDest.AtPlz!.Ort.Name;
+81 -18
View File
@@ -13,35 +13,74 @@ namespace Elwig.Models.Dtos {
("Address", "Adresse", null, 60), ("Address", "Adresse", null, 60),
("Plz", "PLZ", null, 10), ("Plz", "PLZ", null, 10),
("Locality", "Ort", null, 60), ("Locality", "Ort", null, 60),
("BusinessShares", "GA", null, 10), ("Shares", "GA", null, 10),
("DeliveryObligation", "Lieferpflicht", "kg", 22), ("DeliveryObligation", "Lieferpflicht", "kg", 22),
("DeliveryRight", "Lieferrecht", "kg", 22), ("DeliveryRight", "Lieferrecht", "kg", 22),
("Weight", "Geliefert", "kg", 22), ("WeightTotal", "Geliefert", "kg", 22),
("OverUnderDelivery", "Über-/Unterliefert", "kg|%", 34), ("OverUnderDelivery", "Über-/Unterliefert", "kg|%", 34),
]; ];
private static readonly (string, string, string?, int)[] FieldNamesRed = [
("MgNr", "MgNr.", null, 12),
("Name1", "Name", null, 40),
("Name2", "Vorname", null, 40),
("Address", "Adresse", null, 60),
("Plz", "PLZ", null, 10),
("Locality", "Ort", null, 60),
("SharesRed", "GA", null, 10),
("DeliveryObligationRed", "Lieferpflicht", "kg", 22),
("DeliveryRightRed", "Lieferrecht", "kg", 22),
("WeightRed", "Geliefert", "kg", 22),
("OverUnderDeliveryRed", "Über-/Unterliefert", "kg|%", 34),
];
private static readonly (string, string, string?, int)[] FieldNamesWhite = [
("MgNr", "MgNr.", null, 12),
("Name1", "Name", null, 40),
("Name2", "Vorname", null, 40),
("Address", "Adresse", null, 60),
("Plz", "PLZ", null, 10),
("Locality", "Ort", null, 60),
("SharesWhite", "GA", null, 10),
("DeliveryObligationWhite", "Lieferpflicht", "kg", 22),
("DeliveryRightWhite", "Lieferrecht", "kg", 22),
("WeightWhite", "Geliefert", "kg", 22),
("OverUnderDeliveryWhite", "Über-/Unterliefert", "kg|%", 34),
];
public OverUnderDeliveryData(IEnumerable<OverUnderDeliveryRow> rows, int year) : public OverUnderDeliveryData(IEnumerable<OverUnderDeliveryRow> rows, int year) :
base($"Über-Unterlieferungen", $"Über- und Unterlieferungen laut gezeichneten Geschäftsanteilen {year}", rows, FieldNames) { base($"Über-Unterlieferungen", $"Über- und Unterlieferungen laut gezeichneten Geschäftsanteilen {year}", rows, FieldNames) {
} }
public static async Task<OverUnderDeliveryData> ForSeason(DbSet<OverUnderDeliveryRow> table, int year) { public OverUnderDeliveryData(IEnumerable<OverUnderDeliveryRow> rows, int year, string mode) :
base($"Über-Unterlieferungen-{(mode == "R" ? "rot" : "weiß")}", $"Über- und Unterlieferungen laut gezeichneten Geschäftsanteilen {(mode == "R" ? "rot" : "weiß")} {year}", rows,
mode == "R" ? FieldNamesRed : FieldNamesWhite) {
}
public static async Task<(OverUnderDeliveryData Total, OverUnderDeliveryData Red, OverUnderDeliveryData White)> ForSeason(DbSet<OverUnderDeliveryRow> table, int year) {
var rows = await table.FromSql($""" var rows = await table.FromSql($"""
SELECT m.mgnr, m.name AS name_1, SELECT m.mgnr, m.name AS name_1,
COALESCE(m.prefix || ' ', '') || m.given_name || COALESCE(m.prefix || ' ', '') || m.given_name ||
COALESCE(' ' || m.middle_names, '') || COALESCE(' ' || m.suffix, '') AS name_2, COALESCE(' ' || m.middle_names, '') || COALESCE(' ' || m.suffix, '') AS name_2,
p.plz, o.name AS ort, m.address, m.business_shares, p.plz, o.name AS ort, m.address, h.shares, h.shares_red, h.shares_white,
m.business_shares * s.min_kg_per_bs AS min_kg, h.shares * COALESCE(s.min_kg_per_share, 0) AS min_kg,
m.business_shares * s.max_kg_per_bs AS max_kg, h.shares * COALESCE(s.max_kg_per_share, 0) AS max_kg,
COALESCE(SUM(d.weight), 0) AS sum h.shares_red * COALESCE(s.min_kg_per_share_red, s.min_kg_per_share, 0) AS min_kg_red,
h.shares_red * COALESCE(s.max_kg_per_share_red, s.max_kg_per_share, 0) AS max_kg_red,
h.shares_white * COALESCE(s.min_kg_per_share_white, s.min_kg_per_share, 0) AS min_kg_white,
h.shares_white * COALESCE(s.max_kg_per_share_white, s.max_kg_per_share, 0) AS max_kg_white,
COALESCE(d.weight_total, 0) AS weight_total,
COALESCE(d.weight_red, 0) AS weight_red,
COALESCE(d.weight_white, 0) AS weight_white
FROM season s, member m FROM season s, member m
LEFT JOIN AT_plz_dest p ON p.id = m.postal_dest LEFT JOIN AT_plz_dest p ON p.id = m.postal_dest
LEFT JOIN AT_ort o ON o.okz = p.okz LEFT JOIN AT_ort o ON o.okz = p.okz
LEFT JOIN v_delivery d ON (d.year, d.mgnr) = (s.year, m.mgnr) LEFT JOIN v_member_history h ON (h.year, h.mgnr) = (s.year, m.mgnr)
WHERE s.year = {year} AND (m.active = TRUE OR d.weight > 0) LEFT JOIN v_stat_member d ON (d.year, d.mgnr) = (s.year, m.mgnr)
GROUP BY s.year, m.mgnr WHERE s.year = {year} AND (m.active = TRUE OR d.weight_total > 0)
ORDER BY 100.0 * sum / max_kg, m.mgnr ORDER BY 100.0 * weight_total / (max_kg + max_kg_red + max_kg_white), m.mgnr
""").ToListAsync(); """).ToListAsync();
return new OverUnderDeliveryData(rows, year); return (new OverUnderDeliveryData(rows, year), new OverUnderDeliveryData(rows, year, "R"), new OverUnderDeliveryData(rows, year, "W"));
} }
} }
@@ -61,17 +100,41 @@ namespace Elwig.Models.Dtos {
public required string LocalityFull { get; set; } public required string LocalityFull { get; set; }
[NotMapped] [NotMapped]
public string Locality => LocalityFull.Split(",")[0]; public string Locality => LocalityFull.Split(",")[0];
[Column("business_shares")] [Column("shares")]
public int BusinessShares { get; set; } public int Shares { get; set; }
[Column("shares_red")]
public int SharesRed { get; set; }
[Column("shares_white")]
public int SharesWhite { get; set; }
[Column("min_kg")] [Column("min_kg")]
public int DeliveryObligation { get; set; } public int DeliveryObligation { get; set; }
[Column("max_kg")] [Column("max_kg")]
public int DeliveryRight { get; set; } public int DeliveryRight { get; set; }
[Column("sum")]
public int Weight { get; set; }
[NotMapped] [NotMapped]
public (int? Kg, double? Percent) OverUnderDelivery => public (int? Kg, double? Percent) OverUnderDelivery =>
Weight < DeliveryObligation ? (Weight - DeliveryObligation, Weight * 100.0 / DeliveryObligation - 100.0) : WeightTotal < DeliveryObligation ? (WeightTotal - DeliveryObligation, WeightTotal * 100.0 / DeliveryObligation - 100.0) :
Weight > DeliveryRight ? (Weight - DeliveryRight, Weight * 100.0 / DeliveryRight - 100.0) : (null, null); WeightTotal > DeliveryRight ? (WeightTotal - DeliveryRight, WeightTotal * 100.0 / DeliveryRight - 100.0) : (null, null);
[Column("min_kg_red")]
public int DeliveryObligationRed { get; set; }
[Column("max_kg_red")]
public int DeliveryRightRed { get; set; }
[NotMapped]
public (int? Kg, double? Percent) OverUnderDeliveryRed =>
WeightRed < DeliveryObligationRed ? (WeightRed - DeliveryObligationRed, WeightRed * 100.0 / DeliveryObligationRed - 100.0) :
WeightRed > DeliveryRightRed ? (WeightRed - DeliveryRightRed, WeightRed * 100.0 / DeliveryRightRed - 100.0) : (null, null);
[Column("min_kg_white")]
public int DeliveryObligationWhite { get; set; }
[Column("max_kg_white")]
public int DeliveryRightWhite { get; set; }
[NotMapped]
public (int? Kg, double? Percent) OverUnderDeliveryWhite =>
WeightWhite < DeliveryObligationWhite ? (WeightWhite - DeliveryObligationWhite, WeightWhite * 100.0 / DeliveryObligationWhite - 100.0) :
WeightWhite > DeliveryRightWhite ? (WeightWhite - DeliveryRightWhite, WeightWhite * 100.0 / DeliveryRightWhite - 100.0) : (null, null);
[Column("weight_total")]
public int WeightTotal { get; set; }
[Column("weight_red")]
public int WeightRed { get; set; }
[Column("weight_white")]
public int WeightWhite { get; set; }
} }
} }
+7 -24
View File
@@ -1,15 +1,16 @@
using Elwig.Helpers;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using System; using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
namespace Elwig.Models.Entities { namespace Elwig.Models.Entities {
[Table("area_commitment"), PrimaryKey("FbNr")] [Table("area_commitment"), PrimaryKey("FbNr", "RevNr")]
public class AreaCom { public class AreaCom {
[Column("fbnr")] [Column("fbnr")]
public int FbNr { get; set; } public int FbNr { get; set; }
[Column("revnr")]
public int RevNr { get; set; }
[Column("mgnr")] [Column("mgnr")]
public int MgNr { get; set; } public int MgNr { get; set; }
@@ -22,24 +23,15 @@ namespace Elwig.Models.Entities {
[Column("area")] [Column("area")]
public int Area { get; set; } public int Area { get; set; }
[Column("kgnr")]
public int KgNr { get; set; }
[Column("gstnr")] [Column("gstnr")]
public required string GstNr { get; set; } public required string GstNr { get; set; }
[Column("rdnr")]
public int? RdNr { get; set; }
[Column("year_from")] [Column("year_from")]
public int? YearFrom { get; set; } public int? YearFrom { get; set; }
[Column("year_to")] [Column("year_to")]
public int? YearTo { get; set; } public int? YearTo { get; set; }
[Column("comment")]
public string? Comment { get; set; }
[Column("ctime"), DatabaseGenerated(DatabaseGeneratedOption.Computed)] [Column("ctime"), DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public long CTime { get; set; } public long CTime { get; set; }
[NotMapped] [NotMapped]
@@ -72,6 +64,9 @@ namespace Elwig.Models.Entities {
set => ITime = value == null ? null : ((DateTimeOffset)value.Value.ToUniversalTime()).ToUnixTimeSeconds(); set => ITime = value == null ? null : ((DateTimeOffset)value.Value.ToUniversalTime()).ToUnixTimeSeconds();
} }
[ForeignKey("FbNr")]
public virtual AreaComContract Contract { get; private set; } = null!;
[ForeignKey("MgNr")] [ForeignKey("MgNr")]
public virtual Member Member { get; private set; } = null!; public virtual Member Member { get; private set; } = null!;
@@ -80,17 +75,5 @@ namespace Elwig.Models.Entities {
[ForeignKey("CultId")] [ForeignKey("CultId")]
public virtual WineCult? WineCult { get; private set; } public virtual WineCult? WineCult { get; private set; }
[ForeignKey("KgNr")]
public virtual WbKg Kg { get; private set; } = null!;
[ForeignKey("KgNr, RdNr")]
public virtual WbRd? Rd { get; private set; }
public int SearchScore(IEnumerable<string> keywords) {
return Utils.GetSearchScore([
WineCult?.Name, Kg.AtKg.Name, Rd?.Name, GstNr, Comment,
], keywords);
}
} }
} }
+78
View File
@@ -0,0 +1,78 @@
using Elwig.Helpers;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
namespace Elwig.Models.Entities {
[Table("area_commitment_contract"), PrimaryKey("FbNr")]
public class AreaComContract {
[Column("fbnr")]
public int FbNr { get; set; }
[Column("kgnr")]
public int KgNr { get; set; }
[Column("rdnr")]
public int? RdNr { get; set; }
[Column("comment")]
public string? Comment { get; set; }
[Column("ctime"), DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public long CTime { get; set; }
[NotMapped]
public DateTime CreatedAt {
get => DateTimeOffset.FromUnixTimeSeconds(CTime).LocalDateTime;
set => CTime = ((DateTimeOffset)value.ToUniversalTime()).ToUnixTimeSeconds();
}
[Column("mtime"), DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public long MTime { get; set; }
[NotMapped]
public DateTime ModifiedAt {
get => DateTimeOffset.FromUnixTimeSeconds(MTime).LocalDateTime;
set => MTime = ((DateTimeOffset)value.ToUniversalTime()).ToUnixTimeSeconds();
}
[Column("xtime")]
public long? XTime { get; set; }
[NotMapped]
public DateTime? ExportedAt {
get => XTime == null ? null : DateTimeOffset.FromUnixTimeSeconds(XTime.Value).LocalDateTime;
set => XTime = value == null ? null : ((DateTimeOffset)value.Value.ToUniversalTime()).ToUnixTimeSeconds();
}
[Column("itime")]
public long? ITime { get; set; }
[NotMapped]
public DateTime? ImportedAt {
get => ITime == null ? null : DateTimeOffset.FromUnixTimeSeconds(ITime.Value).LocalDateTime;
set => ITime = value == null ? null : ((DateTimeOffset)value.Value.ToUniversalTime()).ToUnixTimeSeconds();
}
[ForeignKey("KgNr")]
public virtual WbKg Kg { get; private set; } = null!;
[ForeignKey("KgNr, RdNr")]
public virtual WbRd? Rd { get; private set; }
[InverseProperty(nameof(AreaCom.Contract))]
public virtual ICollection<AreaCom> Revisions { get; private set; } = null!;
[NotMapped]
public AreaCom? Latest => Revisions.OrderBy(r => r.RevNr).LastOrDefault();
[NotMapped]
public int? YearFrom => Revisions.Any(r => r.YearFrom == null) ? null : Revisions.Min(r => r.YearFrom);
[NotMapped]
public int? YearTo => Revisions.Any(r => r.YearTo == null) ? null : Revisions.Max(r => r.YearTo);
public int SearchScore(IEnumerable<string> keywords) {
return Utils.GetSearchScore([
..Revisions.Select(r => r.WineCult?.Name), Kg.AtKg.Name, Rd?.Name, ..Revisions.Select(r => r.GstNr), Comment,
], keywords);
}
}
}
+5 -5
View File
@@ -111,16 +111,16 @@ namespace Elwig.Models.Entities {
[NotMapped] [NotMapped]
public Predicate<DeliveryPart>? PartFilter { get; set; } public Predicate<DeliveryPart>? PartFilter { get; set; }
public int Weight => Parts.Select(p => p.Weight).Sum(); public int Weight => Parts.Sum(p => p.Weight);
public int FilteredWeight => FilteredParts.Select(p => p.Weight).Sum(); public int FilteredWeight => FilteredParts.Sum(p => p.Weight);
public IEnumerable<RawVaribute> Vaributes => Parts public IEnumerable<RawVaribute> Vaributes => Parts
.GroupBy(p => (p.SortId, p.AttrId, p.CultId)) .GroupBy(p => (p.SortId, p.AttrId, p.CultId))
.OrderByDescending(g => g.Select(p => p.Weight).Sum()) .OrderByDescending(g => g.Sum(p => p.Weight))
.Select(g => new RawVaribute(g.Key.SortId, g.Key.AttrId, g.Key.CultId)); .Select(g => new RawVaribute(g.Key.SortId, g.Key.AttrId, g.Key.CultId));
public IEnumerable<RawVaribute> FilteredVaributes => FilteredParts public IEnumerable<RawVaribute> FilteredVaributes => FilteredParts
.GroupBy(p => (p.SortId, p.AttrId, p.CultId)) .GroupBy(p => (p.SortId, p.AttrId, p.CultId))
.OrderByDescending(g => g.Select(p => p.Weight).Sum()) .OrderByDescending(g => g.Sum(p => p.Weight))
.Select(g => new RawVaribute(g.Key.SortId, g.Key.AttrId, g.Key.CultId)); .Select(g => new RawVaribute(g.Key.SortId, g.Key.AttrId, g.Key.CultId));
public string VaributeString => string.Join(", ", Vaributes); public string VaributeString => string.Join(", ", Vaributes);
public string FilteredVaributeString => string.Join(", ", FilteredVaributes); public string FilteredVaributeString => string.Join(", ", FilteredVaributes);
@@ -153,7 +153,7 @@ namespace Elwig.Models.Entities {
Member.Name, Member.MiddleName, Member.GivenName, Member.BillingAddress?.FullName, Member.Name, Member.MiddleName, Member.GivenName, Member.BillingAddress?.FullName,
Comment Comment
}.ToList(); }.ToList();
list.AddRange(Parts.Select(p => p.Comment).Distinct()); list.AddRange(FilteredParts.Select(p => p.Comment).Distinct());
return Utils.GetSearchScore(list, keywords); return Utils.GetSearchScore(list, keywords);
} }
} }
+22 -3
View File
@@ -42,6 +42,8 @@ namespace Elwig.Models.Entities {
[NotMapped] [NotMapped]
public string ShortName => (!string.IsNullOrWhiteSpace(GivenName) ? $"{GivenName} " : "") + Name; public string ShortName => (!string.IsNullOrWhiteSpace(GivenName) ? $"{GivenName} " : "") + Name;
[NotMapped] [NotMapped]
public string FullAdministrativeName => $"{AdministrativeName} ({MgNr})";
[NotMapped]
public string AdministrativeName => AdministrativeName1 + (!string.IsNullOrWhiteSpace(AdministrativeName2) ? $" {AdministrativeName2}" : ""); public string AdministrativeName => AdministrativeName1 + (!string.IsNullOrWhiteSpace(AdministrativeName2) ? $" {AdministrativeName2}" : "");
[NotMapped] [NotMapped]
public string AdministrativeName1 => IsJuridicalPerson ? Name : Name.Replace('ß', 'ẞ').ToUpper(); public string AdministrativeName1 => IsJuridicalPerson ? Name : Name.Replace('ß', 'ẞ').ToUpper();
@@ -67,8 +69,20 @@ namespace Elwig.Models.Entities {
set => ExitDateString = value?.ToString("yyyy-MM-dd"); set => ExitDateString = value?.ToString("yyyy-MM-dd");
} }
[Column("business_shares")] [Column("shares")]
public int BusinessShares { get; set; } public int Shares { get; set; }
[Column("shares_red")]
public int SharesRed { get; set; }
[Column("shares_white")]
public int SharesWhite { get; set; }
[Column("shares_dormant")]
public int SharesDormant { get; set; }
[NotMapped]
public int SharesActive => Shares + SharesRed + SharesWhite;
[Column("accounting_nr")] [Column("accounting_nr")]
public string? AccountingNr { get; set; } public string? AccountingNr { get; set; }
@@ -189,9 +203,14 @@ namespace Elwig.Models.Entities {
[InverseProperty(nameof(BillingAddr.Member))] [InverseProperty(nameof(BillingAddr.Member))]
public virtual BillingAddr? BillingAddress { get; private set; } public virtual BillingAddr? BillingAddress { get; private set; }
[InverseProperty(nameof(Delivery.Member))] [InverseProperty(nameof(DeliveryAncmt.Member))]
public virtual ICollection<DeliveryAncmt> Announcements { get; private set; } = null!; public virtual ICollection<DeliveryAncmt> Announcements { get; private set; } = null!;
[InverseProperty(nameof(MemberHistory.FromMember))]
public virtual ICollection<MemberHistory> HistoryFrom { get; private set; } = null!;
[InverseProperty(nameof(MemberHistory.ToMember))]
public virtual ICollection<MemberHistory> HistoryTo { get; private set; } = null!;
[InverseProperty(nameof(Delivery.Member))] [InverseProperty(nameof(Delivery.Member))]
public virtual ICollection<Delivery> Deliveries { get; private set; } = null!; public virtual ICollection<Delivery> Deliveries { get; private set; } = null!;
+109 -13
View File
@@ -1,31 +1,127 @@
using Elwig.Helpers;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using System; using System;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
namespace Elwig.Models.Entities { namespace Elwig.Models.Entities {
[Table("member_history"), PrimaryKey("MgNr", "DateString", "Type")] [Table("member_history"), PrimaryKey("HistNr")]
public class MemberHistory { public class MemberHistory {
[Column("mgnr")]
public int MgNr { get; set; }
[Column("date")] public const string REASON_PURCHASE = "purchase"; // Kauf
public required string DateString { get; set; } public const string REASON_CONVERT = "convert"; // Änderung
public const string REASON_TRANSFER = "transfer"; // Übertragung
public const string REASON_PRESCRIPTION = "prescription"; // Vorschreibung
public const string REASON_EXCLUSION = "exclusion"; // Ausschluss
public const string REASON_DECEASED = "deceased"; // Tod
public const string REASON_RETIREMENT = "retirement"; // Kündigung/stilllegen
public const string REASON_PAYOUT = "payout"; // Auszahlung
[Column("histnr")]
public int HistNr { get; set; }
[Column("from_mgnr")]
public int? FromMgNr { get; set; }
[Column("from_type")]
public int? FromTypeValue { get; set; }
[NotMapped] [NotMapped]
public DateOnly Date { public BusinessShareType? FromType {
get => DateOnly.ParseExact(DateString, "yyyy-MM-dd"); get => (BusinessShareType?)FromTypeValue;
set => FromTypeValue = (int?)value;
}
[Column("to_mgnr")]
public int? ToMgNr { get; set; }
[Column("to_type")]
public int? ToTypeValue { get; set; }
[NotMapped]
public BusinessShareType? ToType {
get => (BusinessShareType?)ToTypeValue;
set => ToTypeValue = (int?)value;
}
[Column("date_notice")]
public required string DateNoticeString { get; set; }
[NotMapped]
public DateOnly DateNotice {
get => DateOnly.ParseExact(DateNoticeString, "yyyy-MM-dd");
set => value.ToString("yyyy-MM-dd"); set => value.ToString("yyyy-MM-dd");
} }
[Column("type")] [Column("date_effective")]
public required string Type { get; set; } public required string DateEffectiveString { get; set; }
[NotMapped]
public DateOnly DateEffective {
get => DateOnly.ParseExact(DateEffectiveString, "yyyy-MM-dd");
set => value.ToString("yyyy-MM-dd");
}
[Column("business_shares")] [Column("reason")]
public int BusinessShares { get; set; } public required string Reason { get; set; }
[NotMapped]
public string ReasonPretty => Reason switch {
REASON_PURCHASE => "Kauf",
REASON_CONVERT => "Änderung",
REASON_TRANSFER => "Übertragung",
REASON_PRESCRIPTION => "Vorschreibung",
REASON_EXCLUSION => "Ausschluss",
REASON_DECEASED => "Tod",
REASON_RETIREMENT => "Kündigung",
REASON_PAYOUT => "Auszahlung",
_ => Reason,
};
[Column("source")]
public required string Source { get; set; }
[Column("shares")]
public int Shares { get; set; }
[Column("signed")]
public bool MemberHasSigned { get; set; }
[Column("value_per_share")]
public long? ValuePerShareValue { get; set; }
[NotMapped]
public decimal? ValuePerShare {
get => ValuePerShareValue != null ? Utils.DecFromDb(ValuePerShareValue.Value, 2) : null;
set => ValuePerShareValue = value != null ? Utils.DecToDb(value.Value, 2) : null;
}
[NotMapped]
public decimal? TotalValue => Shares * ValuePerShare;
[Column("currency")]
public string? CurrencyCode { get; set; }
[Column("deduct_year")]
public int? DeductYear { get; set; }
[Column("comment")] [Column("comment")]
public string? Comment { get; set; } public string? Comment { get; set; }
[ForeignKey("MgNr")] public string FormatReasonPhrase(int mgnr) {
public virtual Member Member { get; private set; } = null!; if (Reason == REASON_TRANSFER) {
if (FromMgNr == mgnr) {
return $"{ReasonPretty} an {ToMember?.FullAdministrativeName ?? "Nachfolger"}" + (Comment != null ? $", {Comment}" : "");
} else if (ToMgNr == mgnr) {
return $"{ReasonPretty} von {FromMember?.FullAdministrativeName ?? "Vorgänger"}" + (Comment != null ? $", {Comment}" : "");
}
}
return ReasonPretty + (Comment != null ? $", {Comment}" : "");
}
[NotMapped]
public int? PoVMgNr { get; set; }
[NotMapped]
public string PoVReasonPhrase => FormatReasonPhrase(PoVMgNr ?? 0);
[ForeignKey("FromMgNr")]
public virtual Member? FromMember { get; private set; } = null!;
[ForeignKey("ToMgNr")]
public virtual Member? ToMember { get; private set; } = null!;
[ForeignKey("CurrencyCode")]
public virtual Currency Currency { get; private set; } = null!;
} }
} }
+24 -15
View File
@@ -25,11 +25,20 @@ namespace Elwig.Models.Entities {
[Column("vat_flatrate")] [Column("vat_flatrate")]
public double VatFlatrate { get; set; } public double VatFlatrate { get; set; }
[Column("min_kg_per_bs")] [Column("min_kg_per_share")]
public int MinKgPerBusinessShare { get; set; } public int? MinKgPerShare { get; set; }
[Column("max_kg_per_share")]
public int? MaxKgPerShare { get; set; }
[Column("max_kg_per_bs")] [Column("min_kg_per_share_red")]
public int MaxKgPerBusinessShare { get; set; } public int? MinKgPerShareRed { get; set; }
[Column("max_kg_per_share_red")]
public int? MaxKgPerShareRed { get; set; }
[Column("min_kg_per_share_white")]
public int? MinKgPerShareWhite { get; set; }
[Column("max_kg_per_share_white")]
public int? MaxKgPerShareWhite { get; set; }
[Column("penalty_per_kg")] [Column("penalty_per_kg")]
public long? PenaltyPerKgValue { get; set; } public long? PenaltyPerKgValue { get; set; }
@@ -55,23 +64,23 @@ namespace Elwig.Models.Entities {
set => PenaltyNoneValue = value != null ? DecToDb(value.Value) : null; set => PenaltyNoneValue = value != null ? DecToDb(value.Value) : null;
} }
[Column("penalty_per_bs_amount")] [Column("penalty_per_share_amount")]
public long? PenaltyPerBsAmountValue { get; set; } public long? PenaltyPerShareAmountValue { get; set; }
[NotMapped] [NotMapped]
public decimal? PenaltyPerBsAmount { public decimal? PenaltyPerShareAmount {
get => PenaltyPerBsAmountValue != null ? DecFromDb(PenaltyPerBsAmountValue.Value) : null; get => PenaltyPerShareAmountValue != null ? DecFromDb(PenaltyPerShareAmountValue.Value) : null;
set => PenaltyPerBsAmountValue = value != null ? DecToDb(value.Value) : null; set => PenaltyPerShareAmountValue = value != null ? DecToDb(value.Value) : null;
} }
[Column("penalty_per_bs_none")] [Column("penalty_per_share_none")]
public long? PenaltyPerBsNoneValue { get; set; } public long? PenaltyPerShareNoneValue { get; set; }
[NotMapped] [NotMapped]
public decimal? PenaltyPerBsNone { public decimal? PenaltyPerShareNone {
get => PenaltyPerBsNoneValue != null ? DecFromDb(PenaltyPerBsNoneValue.Value) : null; get => PenaltyPerShareNoneValue != null ? DecFromDb(PenaltyPerShareNoneValue.Value) : null;
set => PenaltyPerBsNoneValue = value != null ? DecToDb(value.Value) : null; set => PenaltyPerShareNoneValue = value != null ? DecToDb(value.Value) : null;
} }
[Column("bs_value")] [Column("share_value")]
public long? BusinessShareValueValue { get; set; } public long? BusinessShareValueValue { get; set; }
[NotMapped] [NotMapped]
public decimal? BusinessShareValue { public decimal? BusinessShareValue {
+4 -2
View File
@@ -27,13 +27,15 @@ namespace Elwig.Models.Entities {
public virtual ICollection<WbGem> Gems { get; private set; } = null!; public virtual ICollection<WbGem> Gems { get; private set; } = null!;
[InverseProperty(nameof(Parent))] [InverseProperty(nameof(Parent))]
public virtual ICollection<WineOrigin> Children { get; private set; } = null!; public virtual ICollection<WineOrigin> RealChildren { get; private set; } = null!;
[NotMapped]
public List<WineOrigin> Children { get; private set; } = [];
public int Level => (Parent?.Level + 1) ?? 0; public int Level => (Parent?.Level + 1) ?? 0;
public string HkIdLevel => $"{new string(' ', Level * 2)}{HkId}"; public string HkIdLevel => $"{new string(' ', Level * 2)}{HkId}";
public int TotalChildNum => 1 + Children.Select(c => c.TotalChildNum).Sum(); public int TotalChildNum => 1 + Children.Sum(c => c.TotalChildNum);
private int SortKey1 => (Parent?.SortKey1 ?? 0) | (TotalChildNum << ((3 - Level) * 8)); private int SortKey1 => (Parent?.SortKey1 ?? 0) | (TotalChildNum << ((3 - Level) * 8));
public int SortKey => SortKey1 | ((Level < 3) ? (-1 >>> (Level * 8 + 8)) : 0); public int SortKey => SortKey1 | ((Level < 3) ? (-1 >>> (Level * 8 + 8)) : 0);
+239
View File
@@ -0,0 +1,239 @@
-- schema version 37 to 38
UPDATE client_parameter SET value = '0' WHERE param = 'ENABLE_TIME_TRIGGERS';
DROP TRIGGER t_area_commitment_i_ctime;
DROP TRIGGER t_area_commitment_u_ctime;
DROP TRIGGER t_area_commitment_i_mtime;
DROP TRIGGER t_area_commitment_u_mtime;
CREATE TABLE area_commitment_contract (
fbnr INTEGER NOT NULL,
kgnr INTEGER NOT NULL,
rdnr INTEGER,
comment TEXT DEFAULT NULL,
ctime INTEGER NOT NULL DEFAULT (UNIXEPOCH()),
mtime INTEGER NOT NULL DEFAULT (UNIXEPOCH()),
xtime INTEGER DEFAULT NULL,
itime INTEGER DEFAULT NULL,
CONSTRAINT area_commitment_contract PRIMARY KEY (fbnr),
CONSTRAINT fk_area_commitment_contract_wb_kg FOREIGN KEY (kgnr) REFERENCES wb_kg (kgnr)
ON UPDATE CASCADE
ON DELETE RESTRICT,
CONSTRAINT fk_area_commitment_contract_wb_rd FOREIGN KEY (kgnr, rdnr) REFERENCES wb_rd (kgnr, rdnr)
ON UPDATE CASCADE
ON DELETE RESTRICT
) STRICT;
CREATE TABLE area_commitment_new (
fbnr INTEGER NOT NULL,
revnr INTEGER NOT NULL,
mgnr INTEGER NOT NULL,
vtrgid TEXT NOT NULL,
cultid TEXT DEFAULT NULL,
area INTEGER NOT NULL,
gstnr TEXT NOT NULL,
year_from INTEGER CHECK (year_from >= 1000 AND year_from <= 9999) DEFAULT NULL,
year_to INTEGER CHECK (year_to >= 1000 AND year_to <= 9999) DEFAULT NULL,
ctime INTEGER NOT NULL DEFAULT (UNIXEPOCH()),
mtime INTEGER NOT NULL DEFAULT (UNIXEPOCH()),
xtime INTEGER DEFAULT NULL,
itime INTEGER DEFAULT NULL,
CONSTRAINT pk_area_commitment PRIMARY KEY (fbnr, revnr),
CONSTRAINT fk_area_commitment_area_commitment_contract FOREIGN KEY (fbnr) REFERENCES area_commitment_contract (fbnr)
ON UPDATE CASCADE
ON DELETE CASCADE,
CONSTRAINT fk_area_commitment_member FOREIGN KEY (mgnr) REFERENCES member (mgnr)
ON UPDATE CASCADE
ON DELETE RESTRICT,
CONSTRAINT fk_area_commitment_area_commitment_type FOREIGN KEY (vtrgid) REFERENCES area_commitment_type (vtrgid)
ON UPDATE CASCADE
ON DELETE RESTRICT,
CONSTRAINT fk_area_commitment_wine_cultivation FOREIGN KEY (cultid) REFERENCES wine_cultivation (cultid)
ON UPDATE CASCADE
ON DELETE RESTRICT
) STRICT;
INSERT INTO area_commitment_contract (fbnr, kgnr, rdnr, comment, ctime, mtime, xtime, itime)
SELECT fbnr, kgnr, rdnr, comment, ctime, mtime, xtime, itime
FROM area_commitment;
INSERT INTO area_commitment_new (fbnr, revnr, mgnr, vtrgid, cultid, area, gstnr, year_from, year_to, ctime, mtime, xtime, itime)
SELECT fbnr, 1, mgnr, vtrgid, cultid, area, gstnr, year_from, year_to, ctime, mtime, xtime, itime
FROM area_commitment;
PRAGMA foreign_keys = OFF;
PRAGMA writable_schema = ON;
DROP TABLE area_commitment;
ALTER TABLE area_commitment_new RENAME TO area_commitment;
PRAGMA writable_schema = OFF;
PRAGMA foreign_keys = ON;
CREATE TRIGGER t_area_commitment_contract_i_ctime
AFTER INSERT ON area_commitment_contract FOR EACH ROW
WHEN (SELECT value FROM client_parameter WHERE param = 'ENABLE_TIME_TRIGGERS') = 1 AND NEW.ctime != UNIXEPOCH()
BEGIN
UPDATE area_commitment_contract SET ctime = UNIXEPOCH() WHERE fbnr = NEW.fbnr;
END;
CREATE TRIGGER t_area_commitment_contract_u_ctime
BEFORE UPDATE ON area_commitment_contract FOR EACH ROW
WHEN (SELECT value FROM client_parameter WHERE param = 'ENABLE_TIME_TRIGGERS') = 1 AND OLD.ctime != NEW.ctime
BEGIN
SELECT RAISE(ABORT, 'It is not allowed to change ctime');
END;
CREATE TRIGGER t_area_commitment_contract_i_mtime
AFTER INSERT ON area_commitment_contract FOR EACH ROW
WHEN (SELECT value FROM client_parameter WHERE param = 'ENABLE_TIME_TRIGGERS') = 1 AND NEW.mtime != UNIXEPOCH()
BEGIN
UPDATE area_commitment_contract SET mtime = UNIXEPOCH() WHERE fbnr = NEW.fbnr;
END;
CREATE TRIGGER t_area_commitment_contract_u_mtime
AFTER UPDATE ON area_commitment_contract FOR EACH ROW
WHEN (SELECT value FROM client_parameter WHERE param = 'ENABLE_TIME_TRIGGERS') = 1 AND NEW.mtime != UNIXEPOCH()
BEGIN
UPDATE area_commitment_contract SET mtime = UNIXEPOCH() WHERE fbnr = NEW.fbnr;
END;
CREATE TRIGGER t_area_commitment_i_ctime
AFTER INSERT ON area_commitment FOR EACH ROW
WHEN (SELECT value FROM client_parameter WHERE param = 'ENABLE_TIME_TRIGGERS') = 1 AND NEW.ctime != UNIXEPOCH()
BEGIN
UPDATE area_commitment SET ctime = UNIXEPOCH() WHERE (fbnr, revnr) = (NEW.fbnr, NEW.revnr);
END;
CREATE TRIGGER t_area_commitment_u_ctime
BEFORE UPDATE ON area_commitment FOR EACH ROW
WHEN (SELECT value FROM client_parameter WHERE param = 'ENABLE_TIME_TRIGGERS') = 1 AND OLD.ctime != NEW.ctime
BEGIN
SELECT RAISE(ABORT, 'It is not allowed to change ctime');
END;
CREATE TRIGGER t_area_commitment_i_mtime
AFTER INSERT ON area_commitment FOR EACH ROW
WHEN (SELECT value FROM client_parameter WHERE param = 'ENABLE_TIME_TRIGGERS') = 1 AND NEW.mtime != UNIXEPOCH()
BEGIN
UPDATE area_commitment SET mtime = UNIXEPOCH() WHERE (fbnr, revnr) = (NEW.fbnr, NEW.revnr);
END;
CREATE TRIGGER t_area_commitment_u_mtime
AFTER UPDATE ON area_commitment FOR EACH ROW
WHEN (SELECT value FROM client_parameter WHERE param = 'ENABLE_TIME_TRIGGERS') = 1 AND NEW.mtime != UNIXEPOCH()
BEGIN
UPDATE area_commitment SET mtime = UNIXEPOCH() WHERE (fbnr, revnr) = (NEW.fbnr, NEW.revnr);
END;
CREATE TRIGGER t_area_commitment_i_mtime_contract
AFTER INSERT ON area_commitment FOR EACH ROW
WHEN (SELECT value FROM client_parameter WHERE param = 'ENABLE_TIME_TRIGGERS') = 1
BEGIN
UPDATE area_commitment_contract SET mtime = UNIXEPOCH() WHERE fbnr = NEW.fbnr;
END;
CREATE TRIGGER t_area_commitment_u_mtime_contract
AFTER UPDATE ON area_commitment FOR EACH ROW
WHEN (SELECT value FROM client_parameter WHERE param = 'ENABLE_TIME_TRIGGERS') = 1
BEGIN
UPDATE area_commitment_contract SET mtime = UNIXEPOCH() WHERE fbnr = NEW.fbnr OR fbnr = OLD.fbnr;
END;
CREATE TRIGGER t_area_commitment_d_mtime_contract
AFTER DELETE ON area_commitment FOR EACH ROW
WHEN (SELECT value FROM client_parameter WHERE param = 'ENABLE_TIME_TRIGGERS') = 1
BEGIN
UPDATE area_commitment_contract SET mtime = UNIXEPOCH() WHERE fbnr = OLD.fbnr;
END;
CREATE TRIGGER t_area_commitment_i_mtime_member
AFTER INSERT ON area_commitment FOR EACH ROW
WHEN (SELECT value FROM client_parameter WHERE param = 'ENABLE_TIME_TRIGGERS') = 1
BEGIN
UPDATE member SET mtime = UNIXEPOCH() WHERE mgnr = NEW.mgnr;
END;
CREATE TRIGGER t_area_commitment_u_mtime_member
AFTER UPDATE ON area_commitment FOR EACH ROW
WHEN (SELECT value FROM client_parameter WHERE param = 'ENABLE_TIME_TRIGGERS') = 1
BEGIN
UPDATE member SET mtime = UNIXEPOCH() WHERE mgnr = NEW.mgnr OR mgnr = OLD.mgnr;
END;
CREATE TRIGGER t_area_commitment_d_mtime_member
AFTER DELETE ON area_commitment FOR EACH ROW
WHEN (SELECT value FROM client_parameter WHERE param = 'ENABLE_TIME_TRIGGERS') = 1
BEGIN
UPDATE member SET mtime = UNIXEPOCH() WHERE mgnr = OLD.mgnr;
END;
-- fix user fiddling - set actual year_from
UPDATE area_commitment AS b
SET fbnr = a.fbnr, revnr = b.fbnr, year_from = a.year_to + 1
FROM area_commitment AS a
WHERE a.fbnr < b.fbnr
AND COALESCE(a.year_from <= a.year_to, TRUE)
AND COALESCE(b.year_from <= b.year_to, TRUE)
AND SUBSTR(a.vtrgid, 0, 2) = SUBSTR(b.vtrgid, 0, 2)
AND (SELECT c.kgnr = d.kgnr AND COALESCE(c.rdnr = d.rdnr, TRUE) FROM area_commitment_contract c, area_commitment_contract d WHERE c.fbnr = a.fbnr AND d.fbnr = b.fbnr)
AND ((IIF(INSTR(a.gstnr, b.gstnr) > 0, 1, 0) + IIF(INSTR(b.gstnr, a.gstnr) > 0, 1, 0) + IIF(a.area = b.area, 2, 0) + (a.mgnr = b.mgnr)) > 1)
AND ((a.year_from = b.year_from AND b.year_to IS NULL AND a.year_to IS NOT NULL));
-- simple
UPDATE area_commitment AS b
SET fbnr = a.fbnr, revnr = b.fbnr
FROM area_commitment AS a
WHERE a.fbnr < b.fbnr
AND COALESCE(a.year_from <= a.year_to, TRUE)
AND COALESCE(b.year_from <= b.year_to, TRUE)
AND SUBSTR(a.vtrgid, 0, 2) = SUBSTR(b.vtrgid, 0, 2)
AND (SELECT c.kgnr = d.kgnr AND COALESCE(c.rdnr = d.rdnr, TRUE) FROM area_commitment_contract c, area_commitment_contract d WHERE c.fbnr = a.fbnr AND d.fbnr = b.fbnr)
AND (a.gstnr = b.gstnr OR a.gstnr IN ('offen', '', '-')) AND a.area = b.area
AND a.year_to + 1 = b.year_from;
-- copy comments
UPDATE area_commitment_contract AS b
SET comment = IIF(b.comment IS NULL, a.comment, CONCAT(b.comment, '; ', a.comment))
FROM area_commitment_contract AS a
WHERE a.comment IS NOT NULL AND a.fbnr IN (SELECT revnr FROM area_commitment WHERE revnr > 1 AND fbnr = b.fbnr);
-- fix revnr
UPDATE area_commitment AS b
SET revnr = a.revnr + 1
FROM area_commitment AS a
WHERE a.fbnr = b.fbnr AND a.revnr < b.revnr;
UPDATE area_commitment AS b
SET revnr = a.revnr + 1
FROM area_commitment AS a
WHERE a.fbnr = b.fbnr AND a.revnr < b.revnr;
UPDATE area_commitment AS b
SET revnr = a.revnr + 1
FROM area_commitment AS a
WHERE a.fbnr = b.fbnr AND a.revnr < b.revnr;
-- fix year_from
UPDATE area_commitment AS b
SET year_from = a.year_to + 1
FROM area_commitment AS a
WHERE a.fbnr = b.fbnr AND a.revnr = b.revnr - 1
AND a.year_to = b.year_from;
UPDATE area_commitment AS b
SET year_from = a.year_to + 1
FROM area_commitment AS a
WHERE a.fbnr = b.fbnr AND a.revnr = b.revnr - 1
AND a.year_to = b.year_from;
-- delete unreferenced contracts
DELETE FROM area_commitment_contract
WHERE fbnr IN (SELECT c.fbnr FROM area_commitment_contract c
LEFT JOIN area_commitment a ON a.fbnr = c.fbnr
WHERE a.fbnr IS NULL);
UPDATE client_parameter SET value = '1' WHERE param = 'ENABLE_TIME_TRIGGERS';
+8
View File
@@ -0,0 +1,8 @@
-- schema version 38 to 39
PRAGMA writable_schema = ON;
UPDATE sqlite_schema SET sql = REPLACE(sql, '{2,}', '{2,64}')
WHERE type = 'table' AND name = 'member_email_address';
PRAGMA writable_schema = OFF;
UPDATE wb_gem SET hkid = 'WLLB' WHERE gkz IN (10710, 10723);
+326
View File
@@ -0,0 +1,326 @@
-- schema version 39 to 40
PRAGMA writable_schema = ON;
ALTER TABLE member RENAME COLUMN business_shares TO shares;
ALTER TABLE member ADD COLUMN shares_red INTEGER NOT NULL DEFAULT 0 CHECK (shares_red >= 0);
ALTER TABLE member ADD COLUMN shares_white INTEGER NOT NULL DEFAULT 0 CHECK (shares_white >= 0);
ALTER TABLE member ADD COLUMN shares_dormant INTEGER NOT NULL DEFAULT 0 CHECK (shares_dormant >= 0);
UPDATE sqlite_schema SET sql = REPLACE(sql, 'shares INTEGER NOT NULL DEFAULT 0', 'shares INTEGER NOT NULL DEFAULT 0 CHECK (shares >= 0)')
WHERE type = 'table' AND name = 'member';
UPDATE client_parameter SET value = '0' WHERE param = 'ENABLE_TIME_TRIGGERS';
UPDATE member
SET shares_dormant = shares + shares_red + shares_white,
shares = 0, shares_red = 0, shares_white = 0
WHERE NOT active;
UPDATE client_parameter SET value = '1' WHERE param = 'ENABLE_TIME_TRIGGERS';
CREATE TABLE member_history_new (
histnr INTEGER NOT NULL,
from_mgnr INTEGER,
from_type INTEGER,
to_mgnr INTEGER,
to_type INTEGER,
date_notice TEXT NOT NULL CHECK (date_notice REGEXP '^[1-9][0-9]{3}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])$') DEFAULT CURRENT_DATE,
date_effective TEXT NOT NULL CHECK (date_effective REGEXP '^[1-9][0-9]{3}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])$') DEFAULT CURRENT_DATE,
reason TEXT NOT NULL CHECK (reason REGEXP '^[a-z_]+$'),
source TEXT NOT NULL CHECK (source REGEXP '^[a-z_]+$'),
shares INTEGER NOT NULL CHECK (shares > 0),
signed INTEGER NOT NULL CHECK (signed IN (TRUE, FALSE)) DEFAULT FALSE,
value_per_share INTEGER DEFAULT NULL,
currency TEXT DEFAULT NULL,
deduct_year INTEGER DEFAULT NULL,
comment TEXT DEFAULT NULL,
CONSTRAINT pk_member_history PRIMARY KEY (histnr),
CONSTRAINT fk_member_history_member_from FOREIGN KEY (from_mgnr) REFERENCES member (mgnr)
ON UPDATE CASCADE
ON DELETE RESTRICT,
CONSTRAINT fk_member_history_member_to FOREIGN KEY (to_mgnr) REFERENCES member (mgnr)
ON UPDATE CASCADE
ON DELETE RESTRICT,
CONSTRAINT fk_member_history_currency FOREIGN KEY (currency) REFERENCES currency (code)
ON UPDATE CASCADE
ON DELETE RESTRICT,
CONSTRAINT c_member_history CHECK ((from_mgnr IS NOT NULL OR to_mgnr IS NOT NULL) AND
((from_mgnr IS NULL AND from_type IS NULL) OR (from_mgnr IS NOT NULL AND from_type IS NOT NULL)) AND
((to_mgnr IS NULL AND to_type IS NULL) OR (to_mgnr IS NOT NULL AND to_type IS NOT NULL)))
) STRICT;
INSERT INTO member_history_new (histnr, from_mgnr, from_type, to_mgnr, to_type, date_notice, date_effective, reason, source, shares, value_per_share, currency, deduct_year, comment)
SELECT ROW_NUMBER() OVER(ORDER BY h.date, h.mgnr), NULL, NULL, h.mgnr, 1, h.date, h.date,
IIF(h.type = 'auto', 'prescription', h.type), 'elwig', h.business_shares, s.bs_value / POW(10, s.precision - 2), s.currency,
IIF(h.type = 'auto', s.year, NULL), 'automatische Nachzeichnung'
FROM member_history h
JOIN season s ON s.year = SUBSTR(h.date, 1, 4);
PRAGMA foreign_keys = OFF;
DROP TABLE member_history;
ALTER TABLE member_history_new RENAME TO member_history;
PRAGMA foreign_keys = ON;
CREATE TRIGGER t_member_history_i_member
AFTER INSERT ON member_history FOR EACH ROW
WHEN (SELECT value FROM client_parameter WHERE param = 'ENABLE_MEMBER_HISTORY_TRIGGERS') = 1
BEGIN
UPDATE member SET shares = shares - NEW.shares WHERE mgnr = NEW.from_mgnr AND NEW.from_type = 1;
UPDATE member SET shares_red = shares_red - NEW.shares WHERE mgnr = NEW.from_mgnr AND NEW.from_type = 2;
UPDATE member SET shares_white = shares_white - NEW.shares WHERE mgnr = NEW.from_mgnr AND NEW.from_type = 3;
UPDATE member SET shares_dormant = shares_dormant - NEW.shares WHERE mgnr = NEW.from_mgnr AND NEW.from_type = 9;
UPDATE member SET shares = shares + NEW.shares WHERE mgnr = NEW.to_mgnr AND NEW.to_type = 1;
UPDATE member SET shares_red = shares_red + NEW.shares WHERE mgnr = NEW.to_mgnr AND NEW.to_type = 2;
UPDATE member SET shares_white = shares_white + NEW.shares WHERE mgnr = NEW.to_mgnr AND NEW.to_type = 3;
UPDATE member SET shares_dormant = shares_dormant + NEW.shares WHERE mgnr = NEW.to_mgnr AND NEW.to_type = 9;
END;
CREATE TRIGGER t_member_history_u_member
AFTER UPDATE OF from_mgnr, from_type, to_mgnr, to_type, shares ON member_history FOR EACH ROW
WHEN (SELECT value FROM client_parameter WHERE param = 'ENABLE_MEMBER_HISTORY_TRIGGERS') = 1
BEGIN
UPDATE member SET shares = shares + OLD.shares WHERE mgnr = OLD.from_mgnr AND OLD.from_type = 1;
UPDATE member SET shares_red = shares_red + OLD.shares WHERE mgnr = OLD.from_mgnr AND OLD.from_type = 2;
UPDATE member SET shares_white = shares_white + OLD.shares WHERE mgnr = OLD.from_mgnr AND OLD.from_type = 3;
UPDATE member SET shares_dormant = shares_dormant + OLD.shares WHERE mgnr = OLD.from_mgnr AND OLD.from_type = 9;
UPDATE member SET shares = shares - OLD.shares WHERE mgnr = OLD.to_mgnr AND OLD.to_type = 1;
UPDATE member SET shares_red = shares_red - OLD.shares WHERE mgnr = OLD.to_mgnr AND OLD.to_type = 2;
UPDATE member SET shares_white = shares_white - OLD.shares WHERE mgnr = OLD.to_mgnr AND OLD.to_type = 3;
UPDATE member SET shares_dormant = shares_dormant - OLD.shares WHERE mgnr = OLD.to_mgnr AND OLD.to_type = 9;
UPDATE member SET shares = shares - NEW.shares WHERE mgnr = NEW.from_mgnr AND NEW.from_type = 1;
UPDATE member SET shares_red = shares_red - NEW.shares WHERE mgnr = NEW.from_mgnr AND NEW.from_type = 2;
UPDATE member SET shares_white = shares_white - NEW.shares WHERE mgnr = NEW.from_mgnr AND NEW.from_type = 3;
UPDATE member SET shares_dormant = shares_dormant - NEW.shares WHERE mgnr = NEW.from_mgnr AND NEW.from_type = 9;
UPDATE member SET shares = shares + NEW.shares WHERE mgnr = NEW.to_mgnr AND NEW.to_type = 1;
UPDATE member SET shares_red = shares_red + NEW.shares WHERE mgnr = NEW.to_mgnr AND NEW.to_type = 2;
UPDATE member SET shares_white = shares_white + NEW.shares WHERE mgnr = NEW.to_mgnr AND NEW.to_type = 3;
UPDATE member SET shares_dormant = shares_dormant + NEW.shares WHERE mgnr = NEW.to_mgnr AND NEW.to_type = 9;
END;
CREATE TRIGGER t_member_history_d_member
AFTER DELETE ON member_history FOR EACH ROW
WHEN (SELECT value FROM client_parameter WHERE param = 'ENABLE_MEMBER_HISTORY_TRIGGERS') = 1
BEGIN
UPDATE member SET shares = shares + OLD.shares WHERE mgnr = OLD.from_mgnr AND OLD.from_type = 1;
UPDATE member SET shares_red = shares_red + OLD.shares WHERE mgnr = OLD.from_mgnr AND OLD.from_type = 2;
UPDATE member SET shares_white = shares_white + OLD.shares WHERE mgnr = OLD.from_mgnr AND OLD.from_type = 3;
UPDATE member SET shares_dormant = shares_dormant + OLD.shares WHERE mgnr = OLD.from_mgnr AND OLD.from_type = 9;
UPDATE member SET shares = shares - OLD.shares WHERE mgnr = OLD.to_mgnr AND OLD.to_type = 1;
UPDATE member SET shares_red = shares_red - OLD.shares WHERE mgnr = OLD.to_mgnr AND OLD.to_type = 2;
UPDATE member SET shares_white = shares_white - OLD.shares WHERE mgnr = OLD.to_mgnr AND OLD.to_type = 3;
UPDATE member SET shares_dormant = shares_dormant - OLD.shares WHERE mgnr = OLD.to_mgnr AND OLD.to_type = 9;
END;
INSERT INTO client_parameter (param, value) VALUES ('ENABLE_MEMBER_HISTORY_TRIGGERS', '1');
CREATE TABLE season_new (
year INTEGER NOT NULL CHECK (year >= 1000 AND year <= 9999),
currency TEXT NOT NULL,
precision INTEGER NOT NULL DEFAULT 4,
max_kg_per_ha INTEGER NOT NULL DEFAULT 10000,
vat_normal REAL NOT NULL DEFAULT 0.10,
vat_flatrate REAL NOT NULL DEFAULT 0.13,
min_kg_per_share INTEGER DEFAULT NULL,
max_kg_per_share INTEGER DEFAULT NULL,
min_kg_per_share_red INTEGER DEFAULT NULL,
max_kg_per_share_red INTEGER DEFAULT NULL,
min_kg_per_share_white INTEGER DEFAULT NULL,
max_kg_per_share_white INTEGER DEFAULT NULL,
penalty_per_kg INTEGER DEFAULT NULL,
penalty_amount INTEGER DEFAULT NULL,
penalty_none INTEGER DEFAULT NULL,
penalty_per_share_amount INTEGER DEFAULT NULL,
penalty_per_share_none INTEGER DEFAULT NULL,
share_value INTEGER,
start_date TEXT CHECK (start_date REGEXP '^[1-9][0-9]{3}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])$'),
end_date TEXT CHECK (end_date REGEXP '^[1-9][0-9]{3}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])$'),
calc_mode INTEGER NOT NULL DEFAULT 0,
CONSTRAINT pk_season PRIMARY KEY (year),
CONSTRAINT fk_season_currency FOREIGN KEY (currency) REFERENCES currency (code)
ON UPDATE CASCADE
ON DELETE RESTRICT
) STRICT;
INSERT INTO season_new (year, currency, precision, max_kg_per_ha, vat_normal, vat_flatrate, min_kg_per_share, max_kg_per_share, penalty_per_kg, penalty_amount, penalty_none, penalty_per_share_amount, penalty_per_share_none, share_value, start_date, end_date, calc_mode)
SELECT year, currency, precision, max_kg_per_ha, vat_normal, vat_flatrate, min_kg_per_bs, max_kg_per_bs, penalty_per_kg, penalty_amount, penalty_none, penalty_per_bs_amount, penalty_per_bs_none, bs_value, start_date, end_date, calc_mode
FROM season;
PRAGMA foreign_keys = OFF;
DROP TABLE season;
ALTER TABLE season_new RENAME TO season;
PRAGMA foreign_keys = ON;
DROP VIEW v_delivery;
CREATE VIEW v_delivery AS
SELECT p.year, p.did, p.dpnr,
d.date, d.time, d.zwstid, d.lnr, d.lsnr,
m.mgnr, m.name, m.given_name,
v.sortid, v.type, a.attrid, p.cultid,
p.weight, p.kmw, ROUND(p.kmw * (4.54 + 0.022 * p.kmw), 0) AS oe, p.qualid,
p.hkid, p.kgnr, p.rdnr,
p.net_weight, p.gebunden,
p.qualid IN (SELECT l.qualid FROM wine_quality_level l WHERE NOT l.predicate AND (p.kmw >= l.min_kmw OR l.min_kmw IS NULL) ORDER BY l.min_kmw DESC LIMIT 1,100) AS abgewertet,
p.qualid NOT IN ('WEI', 'RSW', 'LDW') AS min_quw,
IIF(a.strict, COALESCE(a.fill_lower, 0), 0) AS attribute_prio,
GROUP_CONCAT(o.modid) AS modifiers,
d.comment, p.comment AS part_comment
FROM delivery_part p
JOIN delivery d ON (d.year, d.did) = (p.year, p.did)
JOIN member m ON m.mgnr = d.mgnr
LEFT JOIN wine_variety v ON v.sortid = p.sortid
LEFT JOIN wine_attribute a ON a.attrid = p.attrid
LEFT JOIN delivery_part_modifier o ON (o.year, o.did, o.dpnr) = (p.year, p.did, p.dpnr)
GROUP BY p.year, p.did, p.dpnr
ORDER BY p.year, p.did, p.dpnr, o.modid;
DROP VIEW v_stat_season;
CREATE VIEW v_stat_season AS
SELECT year,
SUM(weight) AS weight_total,
SUM(IIF(type = 'R', weight, 0)) AS weight_red,
SUM(IIF(type = 'W', weight, 0)) AS weight_white,
ROUND(SUM(kmw * weight) / SUM(weight), 2) AS kmw,
ROUND(SUM(oe * weight) / SUM(weight), 1) AS oe,
COUNT(DISTINCT did) AS lieferungen,
COUNT(DISTINCT mgnr) AS mitglieder
FROM v_delivery
GROUP BY year
ORDER BY year;
DROP VIEW v_stat_sort;
CREATE VIEW v_stat_variety AS
SELECT year, sortid,
SUM(weight) AS weight_total,
SUM(IIF(type = 'R', weight, 0)) AS weight_red,
SUM(IIF(type = 'W', weight, 0)) AS weight_white,
ROUND(SUM(kmw * weight) / SUM(weight), 2) AS kmw,
ROUND(SUM(oe * weight) / SUM(weight), 1) AS oe,
COUNT(DISTINCT did) AS lieferungen,
COUNT(DISTINCT mgnr) AS mitglieder
FROM v_delivery
GROUP BY year, sortid
ORDER BY year, sortid;
DROP VIEW v_stat_attr;
CREATE VIEW v_stat_attr AS
SELECT year, attrid,
SUM(weight) AS weight_total,
SUM(IIF(type = 'R', weight, 0)) AS weight_red,
SUM(IIF(type = 'W', weight, 0)) AS weight_white,
ROUND(SUM(kmw * weight) / SUM(weight), 2) AS kmw,
ROUND(SUM(oe * weight) / SUM(weight), 1) AS oe,
COUNT(DISTINCT did) AS lieferungen,
COUNT(DISTINCT mgnr) AS mitglieder
FROM v_delivery
GROUP BY year, attrid
ORDER BY year, attrid;
DROP VIEW v_stat_sort_attr;
CREATE VIEW v_stat_variety_attr AS
SELECT year, sortid, attrid,
SUM(weight) AS weight_total,
SUM(IIF(type = 'R', weight, 0)) AS weight_red,
SUM(IIF(type = 'W', weight, 0)) AS weight_white,
ROUND(SUM(kmw * weight) / SUM(weight), 2) AS kmw,
ROUND(SUM(oe * weight) / SUM(weight), 1) AS oe,
COUNT(DISTINCT did) AS lieferungen,
COUNT(DISTINCT mgnr) AS mitglieder
FROM v_delivery
GROUP BY year, sortid, attrid
ORDER BY year, sortid, attrid;
DROP VIEW v_stat_member;
CREATE VIEW v_stat_member AS
SELECT year, mgnr,
SUM(weight) AS weight_total,
SUM(IIF(type = 'R', weight, 0)) AS weight_red,
SUM(IIF(type = 'W', weight, 0)) AS weight_white,
ROUND(SUM(kmw * weight) / SUM(weight), 2) AS kmw,
ROUND(SUM(oe * weight) / SUM(weight), 1) AS oe,
COUNT(DISTINCT did) AS lieferungen
FROM v_delivery
GROUP BY year, mgnr
ORDER BY year, mgnr;
CREATE VIEW v_member_history AS
SELECT m.mgnr, s.year,
m.shares + SUM(IIF(h1.from_type = 1, h1.shares, 0)) - SUM(IIF(h2.to_type = 1, h2.shares, 0)) AS shares,
m.shares_red + SUM(IIF(h1.from_type = 2, h1.shares, 0)) - SUM(IIF(h2.to_type = 2, h2.shares, 0)) AS shares_red,
m.shares_white + SUM(IIF(h1.from_type = 3, h1.shares, 0)) - SUM(IIF(h2.to_type = 3, h2.shares, 0)) AS shares_white,
m.shares_dormant + SUM(IIF(h1.from_type = 9, h1.shares, 0)) - SUM(IIF(h2.to_type = 9, h2.shares, 0)) AS shares_dormant
FROM member m, v_virtual_season s
LEFT JOIN member_history h1 ON (SUBSTR(h1.date_notice, 1, 4) + 0) > s.year AND h1.from_mgnr = m.mgnr
LEFT JOIN member_history h2 ON (SUBSTR(h2.date_notice, 1, 4) + 0) > s.year AND h2.to_mgnr = m.mgnr
GROUP BY m.mgnr, s.year
ORDER BY m.mgnr, s.year;
DROP VIEW v_total_under_delivery;
CREATE VIEW v_total_under_delivery AS
SELECT s.year, m.mgnr,
h.shares,
h.shares * COALESCE(s.min_kg_per_share, 0) AS min_kg,
h.shares * COALESCE(s.max_kg_per_share, 0) AS max_kg,
COALESCE(d.weight_total, 0) AS weight_total,
IIF(COALESCE(d.weight_total, 0) < h.shares * COALESCE(s.min_kg_per_share, 0),
COALESCE(d.weight_total, 0) - h.shares * COALESCE(s.min_kg_per_share, 0),
IIF(COALESCE(d.weight_total, 0) > h.shares * COALESCE(s.max_kg_per_share, 0),
COALESCE(d.weight_total, 0) - h.shares * COALESCE(s.max_kg_per_share, 0),
0)) AS diff,
h.shares_red,
h.shares_red * COALESCE(s.min_kg_per_share_red, s.min_kg_per_share, 0) AS min_kg_red,
h.shares_red * COALESCE(s.max_kg_per_share_red, s.max_kg_per_share, 0) AS max_kg_red,
COALESCE(d.weight_red, 0) AS weight_red,
IIF(COALESCE(d.weight_red, 0) < h.shares_red * COALESCE(s.min_kg_per_share_red, s.min_kg_per_share, 0),
COALESCE(d.weight_red, 0) - h.shares_red * COALESCE(s.min_kg_per_share_red, s.min_kg_per_share, 0),
IIF(COALESCE(d.weight_red, 0) > h.shares_red * COALESCE(s.max_kg_per_share_red, s.max_kg_per_share, 0),
COALESCE(d.weight_red, 0) - h.shares_red * COALESCE(s.max_kg_per_share_red, s.max_kg_per_share, 0),
0)) AS diff_red,
h.shares_white,
h.shares_white * COALESCE(s.min_kg_per_share_white, s.min_kg_per_share, 0) AS min_kg_white,
h.shares_white * COALESCE(s.max_kg_per_share_white, s.max_kg_per_share, 0) AS max_kg_white,
COALESCE(d.weight_white, 0) AS weight_white,
IIF(COALESCE(d.weight_white, 0) < h.shares_white * COALESCE(s.min_kg_per_share_white, s.min_kg_per_share, 0),
COALESCE(d.weight_white, 0) - h.shares_white * COALESCE(s.min_kg_per_share_white, s.min_kg_per_share, 0),
IIF(COALESCE(d.weight_white, 0) > h.shares_white * COALESCE(s.max_kg_per_share_white, s.max_kg_per_share, 0),
COALESCE(d.weight_white, 0) - h.shares_white * COALESCE(s.max_kg_per_share_white, s.max_kg_per_share, 0),
0)) AS diff_white
FROM member m, season s
LEFT JOIN v_member_history h ON (h.year, h.mgnr) = (s.year, m.mgnr)
LEFT JOIN v_stat_member d ON (d.year, d.mgnr) = (s.year, m.mgnr)
ORDER BY s.year, m.mgnr;
DROP VIEW v_penalty_business_shares;
CREATE VIEW v_penalty_business_shares AS
SELECT u.year, u.mgnr,
SUM(IIF(u.weight_total = 0, COALESCE(-s.penalty_none, 0) + COALESCE(-(u.shares + u.shares_red + u.shares_white) * s.penalty_per_share_none, 0), 0) +
IIF(u.diff < 0 OR u.diff_red < 0 OR u.diff_white < 0, COALESCE(-s.penalty_amount, 0), 0) +
COALESCE((u.diff + u.diff_red + u.diff_white) * s.penalty_per_kg, 0) +
COALESCE(CEIL(CAST(u.diff AS REAL) / s.min_kg_per_share) * s.penalty_per_share_amount, 0) +
COALESCE(CEIL(CAST(u.diff_red AS REAL) / s.min_kg_per_share_red) * s.penalty_per_share_amount, 0) +
COALESCE(CEIL(CAST(u.diff_white AS REAL) / s.min_kg_per_share_white) * s.penalty_per_share_amount, 0)
) AS total_penalty
FROM v_total_under_delivery u
JOIN season s ON u.year = s.year
JOIN member m ON m.mgnr = u.mgnr
WHERE m.active
GROUP BY u.year, u.mgnr
HAVING total_penalty < 0
ORDER BY u.year, u.mgnr;
DROP VIEW v_auto_business_shares;
CREATE VIEW v_auto_business_shares AS
SELECT (SUBSTR(h.date_notice, 1, 4) + 0) AS year,
h.to_mgnr AS mgnr,
SUM(h.shares) AS shares,
SUM(h.shares * COALESCE(h.value_per_share, 0)) AS total_amount
FROM member_history h
WHERE h.reason = 'prescription' AND h.source = 'elwig'
GROUP BY year, h.to_mgnr
ORDER BY year, h.to_mgnr;
PRAGMA writable_schema = OFF;
+55 -47
View File
@@ -6,7 +6,6 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows;
namespace Elwig.Services { namespace Elwig.Services {
public static class AreaComService { public static class AreaComService {
@@ -20,41 +19,45 @@ namespace Elwig.Services {
} }
public static void ClearInputs(this AreaComAdminViewModel vm) { public static void ClearInputs(this AreaComAdminViewModel vm) {
vm.Period = null;
}
public static void FillInputs(this AreaComAdminViewModel vm, AreaComContract c) {
vm.FbNr = c.FbNr;
vm.Period = c.YearTo == null ? $"ab {c.YearFrom}" : $"{c.YearFrom}\u2013{c.YearTo}";
vm.Comment = c.Comment;
vm.Kg = ControlUtils.GetItemFromSourceWithPk(vm.KgSource, c.KgNr) as AT_Kg;
vm.Rd = ControlUtils.GetItemFromSourceWithPk(vm.RdSource, c.KgNr, c.RdNr) as WbRd;
} }
public static void FillInputs(this AreaComAdminViewModel vm, AreaCom a) { public static void FillInputs(this AreaComAdminViewModel vm, AreaCom a) {
vm.FbNr = a.FbNr;
vm.MgNr = a.MgNr; vm.MgNr = a.MgNr;
vm.YearFrom = a.YearFrom; vm.YearFrom = a.YearFrom;
vm.YearTo = a.YearTo; vm.YearTo = a.YearTo;
vm.AreaComType = ControlUtils.GetItemFromSourceWithPk(vm.AreaComTypeSource, a.VtrgId) as AreaComType; vm.AreaComType = ControlUtils.GetItemFromSourceWithPk(vm.AreaComTypeSource, a.VtrgId) as AreaComType;
vm.WineCult = ControlUtils.GetItemFromSourceWithPk(vm.WineCultSource, a.CultId) as WineCult; vm.WineCult = ControlUtils.GetItemFromSourceWithPk(vm.WineCultSource, a.CultId) as WineCult;
vm.Comment = a.Comment;
vm.Kg = ControlUtils.GetItemFromSourceWithPk(vm.KgSource, a.KgNr) as AT_Kg;
vm.Rd = ControlUtils.GetItemFromSourceWithPk(vm.RdSource, a.KgNr, a.RdNr) as WbRd;
vm.GstNr = a.GstNr; vm.GstNr = a.GstNr;
vm.Area = a.Area; vm.Area = a.Area;
} }
public static async Task<(List<string>, IQueryable<AreaCom>, List<string>)> GetFilters(this AreaComAdminViewModel vm, AppDbContext ctx) { public static async Task<(List<string>, IQueryable<AreaComContract>, IQueryable<AreaCom>, List<string>)> GetFilters(this AreaComAdminViewModel vm, AppDbContext ctx) {
List<string> filterNames = []; List<string> filterNames = [];
IQueryable<AreaCom> areaComQuery = ctx.AreaCommitments.Where(a => a.MgNr == vm.FilterMember.MgNr).OrderBy(a => a.FbNr); IQueryable<AreaCom> areaComQuery = ctx.AreaCommitments.Where(a => a.MgNr == vm.FilterMember.MgNr).OrderBy(a => a.FbNr);
if (vm.ShowOnlyActiveAreaComs) { if (vm.FilterSeason is int season) {
areaComQuery = Utils.ActiveAreaCommitments(areaComQuery, Utils.CurrentLastSeason); areaComQuery = Utils.ActiveAreaCommitments(areaComQuery, season);
filterNames.Add($"laufend {Utils.CurrentLastSeason}"); filterNames.Add($"laufend {season}");
} }
var filterVar = new List<string>(); var filterVar = new List<string>();
var filterNotVar = new List<string>(); var filterNotVar = new List<string>();
var filterAttr = new List<string>(); var filterAttr = new List<string>();
var filterNotAttr = new List<string>(); var filterNotAttr = new List<string>();
var filterSeasons = new List<int>();
var filter = vm.TextFilter; var filter = vm.TextFilter;
if (filter.Count > 0) { if (filter.Count > 0) {
var var = await ctx.WineVarieties.ToDictionaryAsync(v => v.SortId, v => v); var var = await ctx.FetchWineVarieties().ToDictionaryAsync(v => v.SortId, v => v);
var attr = await ctx.WineAttributes.ToDictionaryAsync(a => a.Name.ToLower().Split(" ")[0], a => a); var attrId = await ctx.FetchWineAttributes().ToDictionaryAsync(a => a.AttrId, a => a);
var attrId = await ctx.WineAttributes.ToDictionaryAsync(a => a.AttrId, a => a); var attr = attrId.Values.ToDictionary(a => a.Name.ToLower().Split(" ")[0], a => a);
for (int i = 0; i < filter.Count; i++) { for (int i = 0; i < filter.Count; i++) {
var e = filter[i]; var e = filter[i];
@@ -88,10 +91,6 @@ namespace Elwig.Services {
filter.RemoveAt(i--); filter.RemoveAt(i--);
filterNames.Add($"ohne {var[e[1..3].ToUpper()].Name}"); filterNames.Add($"ohne {var[e[1..3].ToUpper()].Name}");
filterNames.Add($"ohne Attribut {attrId[e[3..].ToUpper()].Name}"); filterNames.Add($"ohne Attribut {attrId[e[3..].ToUpper()].Name}");
} else if (e.Length == 4 && int.TryParse(e, out var year)) {
filterSeasons.Add(year);
filter.RemoveAt(i--);
filterNames.Add($"laufend {e}");
} }
} }
@@ -99,38 +98,50 @@ namespace Elwig.Services {
if (filterNotVar.Count > 0) areaComQuery = areaComQuery.Where(a => !filterNotVar.Contains(a.AreaComType.WineVar.SortId)); if (filterNotVar.Count > 0) areaComQuery = areaComQuery.Where(a => !filterNotVar.Contains(a.AreaComType.WineVar.SortId));
if (filterAttr.Count > 0) areaComQuery = areaComQuery.Where(a => a.AreaComType.WineAttr!.AttrId != null && filterAttr.Contains(a.AreaComType.WineAttr.AttrId)); if (filterAttr.Count > 0) areaComQuery = areaComQuery.Where(a => a.AreaComType.WineAttr!.AttrId != null && filterAttr.Contains(a.AreaComType.WineAttr.AttrId));
if (filterNotAttr.Count > 0) areaComQuery = areaComQuery.Where(a => a.AreaComType.WineAttr!.AttrId == null || !filterNotAttr.Contains(a.AreaComType.WineAttr.AttrId)); if (filterNotAttr.Count > 0) areaComQuery = areaComQuery.Where(a => a.AreaComType.WineAttr!.AttrId == null || !filterNotAttr.Contains(a.AreaComType.WineAttr.AttrId));
foreach (var year in filterSeasons) areaComQuery = Utils.ActiveAreaCommitments(areaComQuery, year);
} }
return (filterNames, areaComQuery, filter); IQueryable<AreaComContract> contracts = areaComQuery
.Select(c => c.Contract).Distinct()
.OrderBy(c => c.FbNr);
return (filterNames, contracts, areaComQuery, filter);
} }
public static async Task<int> UpdateAreaCommitment(this AreaComAdminViewModel vm, int? oldFbNr) { public static async Task<(int FbNr, int RevNr)> UpdateAreaCommitment(this AreaComAdminViewModel vm, int? oldFbNr, int? revNr) {
int newFbNr = vm.FbNr!.Value; int newFbNr = vm.FbNr!.Value;
return await Task.Run(async () => { return await Task.Run(async () => {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
var c = new AreaComContract {
FbNr = oldFbNr ?? newFbNr,
Comment = string.IsNullOrWhiteSpace(vm.Comment) ? null : vm.Comment,
KgNr = vm.Kg!.KgNr,
RdNr = vm.Rd?.RdNr,
};
var a = new AreaCom { var a = new AreaCom {
FbNr = oldFbNr ?? newFbNr, FbNr = oldFbNr ?? newFbNr,
RevNr = revNr ?? await ctx.NextRevNr(oldFbNr ?? newFbNr),
MgNr = vm.MgNr!.Value, MgNr = vm.MgNr!.Value,
YearFrom = vm.YearFrom, YearFrom = vm.YearFrom,
YearTo = vm.YearTo, YearTo = vm.YearTo,
VtrgId = vm.AreaComType!.VtrgId, VtrgId = vm.AreaComType!.VtrgId,
CultId = vm.WineCult?.CultId, CultId = vm.WineCult?.CultId,
Comment = string.IsNullOrEmpty(vm.Comment) ? null : vm.Comment,
KgNr = vm.Kg!.KgNr,
RdNr = vm.Rd?.RdNr,
GstNr = vm.GstNr?.Trim() ?? "-", GstNr = vm.GstNr?.Trim() ?? "-",
Area = vm.Area!.Value, Area = vm.Area!.Value,
}; };
if (vm.Rd?.RdNr == 0) { if (vm.Rd?.RdNr == 0) {
vm.Rd.RdNr = await ctx.NextRdNr(a.KgNr); vm.Rd.RdNr = await ctx.NextRdNr(c.KgNr);
a.RdNr = vm.Rd.RdNr; c.RdNr = vm.Rd.RdNr;
ctx.Add(vm.Rd); ctx.Add(vm.Rd);
} }
if (oldFbNr != null) { if (oldFbNr != null) {
ctx.Update(c);
} else {
ctx.Add(c);
}
if (revNr != null) {
ctx.Update(a); ctx.Update(a);
} else { } else {
ctx.Add(a); ctx.Add(a);
@@ -139,32 +150,20 @@ namespace Elwig.Services {
await ctx.SaveChangesAsync(); await ctx.SaveChangesAsync();
if (newFbNr != a.FbNr) { if (newFbNr != a.FbNr) {
await ctx.Database.ExecuteSqlAsync($"UPDATE area_commitment SET fbnr = {newFbNr} WHERE fbnr = {oldFbNr}"); await ctx.Database.ExecuteSqlAsync($"UPDATE area_commitment_contract SET fbnr = {newFbNr} WHERE fbnr = {oldFbNr}");
} }
return newFbNr; return (newFbNr, a.RevNr);
}); });
} }
private static void AddToolTipCell(Grid grid, string text, int row, int col, int colSpan = 1, bool bold = false, bool alignRight = false, bool alignCenter = false) {
var tb = new TextBlock() {
Text = text,
TextAlignment = alignRight ? TextAlignment.Right : alignCenter ? TextAlignment.Center : TextAlignment.Left,
Margin = new(0, 12 * row, 0, 0),
FontWeight = bold ? FontWeights.Bold : FontWeights.Normal,
};
tb.SetValue(Grid.ColumnProperty, col);
tb.SetValue(Grid.ColumnSpanProperty, colSpan);
grid.Children.Add(tb);
}
private static void AddToolTipRow(Grid grid, int row, string? h1, string? h2, int area, int? min, int? max) { private static void AddToolTipRow(Grid grid, int row, string? h1, string? h2, int area, int? min, int? max) {
var bold = h2 == null; var bold = h2 == null;
if (h1 != null) AddToolTipCell(grid, h1 + ":", row, 0, (h2 == null) ? 2 : 1, bold); if (h1 != null) grid.AddToolTipCell(h1 + ":", row, 0, (h2 == null) ? 2 : 1, bold);
if (h2 != null) AddToolTipCell(grid, h2 + ":", row, 1, 1, bold); if (h2 != null) grid.AddToolTipCell(h2 + ":", row, 1, bold: bold);
AddToolTipCell(grid, $"{area:N0} m²", row, 2, 1, bold, true); grid.AddToolTipCell($"{area:N0} m²", row, 2, bold: bold, alignRight: true);
AddToolTipCell(grid, min == null ? "" : $"{min:N0} kg", row, 3, 1, bold, true); grid.AddToolTipCell(min == null ? "" : $"{min:N0} kg", row, 3, bold: bold, alignRight: true);
AddToolTipCell(grid, max == null ? "" : $"{max:N0} kg", row, 4, 1, bold, true); grid.AddToolTipCell(max == null ? "" : $"{max:N0} kg", row, 4, bold: bold, alignRight: true);
} }
public static async Task<(string, (string?, string?, int, int?, int?)[])> GenerateToolTipData(IQueryable<AreaCom> areaComs, int maxKgPerHa) { public static async Task<(string, (string?, string?, int, int?, int?)[])> GenerateToolTipData(IQueryable<AreaCom> areaComs, int maxKgPerHa) {
@@ -243,8 +242,8 @@ namespace Elwig.Services {
grid.ColumnDefinitions.Add(new() { Width = new(80) }); grid.ColumnDefinitions.Add(new() { Width = new(80) });
grid.ColumnDefinitions.Add(new() { Width = new(80) }); grid.ColumnDefinitions.Add(new() { Width = new(80) });
grid.ColumnDefinitions.Add(new() { Width = new(80) }); grid.ColumnDefinitions.Add(new() { Width = new(80) });
AddToolTipCell(grid, "Lieferpflicht", 0, 3, 1, false, false, true); grid.AddToolTipCell("Lieferpflicht", 0, 3, alignCenter: true);
AddToolTipCell(grid, "Lieferrecht", 0, 4, 1, false, false, true); grid.AddToolTipCell("Lieferrecht", 0, 4, 1, alignCenter: true);
int rowNum = 1; int rowNum = 1;
foreach (var row in data) { foreach (var row in data) {
if (rowNum == 2 || (rowNum != 1 && row.Item1 != null)) rowNum++; if (rowNum == 2 || (rowNum != 1 && row.Item1 != null)) rowNum++;
@@ -256,7 +255,16 @@ namespace Elwig.Services {
public static async Task DeleteAreaCom(int fbnr) { public static async Task DeleteAreaCom(int fbnr) {
await Task.Run(async () => { await Task.Run(async () => {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
var l = (await ctx.AreaCommitments.FindAsync(fbnr))!; var l = (await ctx.AreaCommitmentContracts.FindAsync(fbnr))!;
ctx.Remove(l);
await ctx.SaveChangesAsync();
});
}
public static async Task DeleteAreaComRevision(int fbnr, int revnr) {
await Task.Run(async () => {
using var ctx = new AppDbContext();
var l = (await ctx.AreaCommitments.FindAsync(fbnr, revnr))!;
ctx.Remove(l); ctx.Remove(l);
await ctx.SaveChangesAsync(); await ctx.SaveChangesAsync();
}); });
+36 -60
View File
@@ -8,9 +8,6 @@ using Microsoft.EntityFrameworkCore;
using Elwig.Documents; using Elwig.Documents;
using Elwig.Helpers.Export; using Elwig.Helpers.Export;
using Elwig.Models.Dtos; using Elwig.Models.Dtos;
using Microsoft.Win32;
using System.Windows.Input;
using System.Windows;
using System; using System;
using LinqKit; using LinqKit;
using System.Windows.Controls; using System.Windows.Controls;
@@ -65,11 +62,11 @@ namespace Elwig.Services {
var filter = vm.TextFilter; var filter = vm.TextFilter;
if (filter.Count > 0) { if (filter.Count > 0) {
var var = await ctx.WineVarieties.ToDictionaryAsync(v => v.SortId, v => v); var var = await ctx.FetchWineVarieties().ToDictionaryAsync(v => v.SortId, v => v);
var mgnr = await ctx.Members.ToDictionaryAsync(m => m.MgNr.ToString(), m => m); var mgnr = await ctx.FetchMembers(includeNotActive: true).ToDictionaryAsync(m => m.MgNr.ToString(), m => m);
var zwst = await ctx.Branches.ToDictionaryAsync(b => b.Name.ToLower().Split(' ')[0], b => b); var zwst = await ctx.FetchBranches().ToDictionaryAsync(b => b.Name.ToLower().Split(' ')[0], b => b);
var attr = await ctx.WineAttributes.ToDictionaryAsync(a => a.Name.ToLower().Split(' ')[0], a => a); var attr = await ctx.FetchWineAttributes().ToDictionaryAsync(a => a.Name.ToLower().Split(' ')[0], a => a);
var cult = await ctx.WineCultivations.ToDictionaryAsync(c => c.Name.ToLower().Split(' ')[0], c => c); var cult = await ctx.FetchWineCultivations().ToDictionaryAsync(c => c.Name.ToLower().Split(' ')[0], c => c);
for (int i = 0; i < filter.Count; i++) { for (int i = 0; i < filter.Count; i++) {
var e = filter[i]; var e = filter[i];
@@ -261,75 +258,41 @@ namespace Elwig.Services {
.ThenBy(a => a.Member.MgNr); .ThenBy(a => a.Member.MgNr);
if (mode == ExportMode.SaveList) { if (mode == ExportMode.SaveList) {
var d = new SaveFileDialog() { var filename = InteractionService.SaveFile(DeliveryAncmtList.Name, DeliveryAncmtList.Name, "ods");
FileName = $"{DeliveryAncmtList.Name}.ods", if (filename != null) {
DefaultExt = "ods", await Utils.RunForeground(async () => {
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); var data = await DeliveryAncmtListData.FromQuery(query, filterNames);
using var ods = new OdsFile(d.FileName); using var ods = new OdsFile(filename);
await ods.AddTable(data); await ods.AddTable(data);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
}); });
Mouse.OverrideCursor = null;
} }
} else { } else {
Mouse.OverrideCursor = Cursors.Wait; await Utils.RunForeground(async () => {
await Task.Run(async () => {
try {
var data = await DeliveryAncmtListData.FromQuery(query, filterNames); var data = await DeliveryAncmtListData.FromQuery(query, filterNames);
using var doc = new DeliveryAncmtList(string.Join(" / ", filterNames), data); using var doc = new DeliveryAncmtList(string.Join(" / ", filterNames), data);
await Utils.ExportDocument(doc, mode); await Utils.ExportDocument(doc, mode);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
}); });
Mouse.OverrideCursor = null;
} }
} }
private static void AddToolTipCell(Grid grid, string text, int row, int col, int colSpan = 1, bool bold = false, bool alignRight = false, bool alignCenter = false) {
var tb = new TextBlock() {
Text = text,
TextAlignment = alignRight ? TextAlignment.Right : alignCenter ? TextAlignment.Center : TextAlignment.Left,
Margin = new(0, 12 * row, 0, 0),
FontWeight = bold ? FontWeights.Bold : FontWeights.Normal,
};
tb.SetValue(Grid.ColumnProperty, col);
tb.SetValue(Grid.ColumnSpanProperty, colSpan);
grid.Children.Add(tb);
}
private static void AddToolTipRow(Grid grid, int row, string? h1, string? h2, int weight, int? total1, int total2) { private static void AddToolTipRow(Grid grid, int row, string? h1, string? h2, int weight, int? total1, int total2) {
var bold = h2 == null; var bold = h2 == null;
if (h1 != null) AddToolTipCell(grid, h1 + ":", row, 0, (h2 == null) ? 2 : 1, bold); if (h1 != null) grid.AddToolTipCell(h1 + ":", row, 0, (h2 == null) ? 2 : 1, bold);
if (h2 != null) AddToolTipCell(grid, h2 + ":", row, 1, 1, bold); if (h2 != null) grid.AddToolTipCell(h2 + ":", row, 1, 1, bold);
AddToolTipCell(grid, $"{weight:N0} kg", row, 2, 1, bold, true); grid.AddToolTipCell($"{weight:N0} kg", row, 2, bold: bold, alignRight: true);
if (total1 != null && total1 != 0) if (total1 != null && total1 != 0)
AddToolTipCell(grid, $"{weight * 100.0 / total1:N1} %", row, 3, 1, bold, true); grid.AddToolTipCell($"{weight * 100.0 / total1:N1} %", row, 3, bold: bold, alignRight: true);
if (total2 != 0) if (total2 != 0)
AddToolTipCell(grid, $"{weight * 100.0 / total2:N1} %", row, 4, 1, bold, true); grid.AddToolTipCell($"{weight * 100.0 / total2:N1} %", row, 4, bold: bold, alignRight: true);
} }
public static async Task<(string, Grid)> GenerateToolTip(IQueryable<DeliveryAncmt> deliveryAncmts) { public static async Task<(string Text, (string?, string?, int, int?, int)[] Grid)> GenerateToolTipData(IQueryable<DeliveryAncmt> deliveryAncmts) {
var grid = new Grid(); var grid = new List<(string?, string?, int, int?, int)>();
grid.ColumnDefinitions.Add(new() { Width = new(10) });
grid.ColumnDefinitions.Add(new() { Width = new(60) });
grid.ColumnDefinitions.Add(new() { Width = new(80) });
grid.ColumnDefinitions.Add(new() { Width = new(50) });
grid.ColumnDefinitions.Add(new() { Width = new(50) });
var text = "-"; var text = "-";
var weight = await deliveryAncmts.SumAsync(p => p.Weight); var weight = await deliveryAncmts.SumAsync(p => p.Weight);
text = $"{weight:N0} kg"; text = $"{weight:N0} kg";
AddToolTipRow(grid, 0, "Menge", null, weight, null, weight); grid.Add(("Menge", null, weight, null, weight));
if (await deliveryAncmts.AnyAsync()) { if (await deliveryAncmts.AnyAsync()) {
var attrGroups = await deliveryAncmts var attrGroups = await deliveryAncmts
@@ -370,13 +333,11 @@ namespace Elwig.Services {
.ThenBy(g => g.SortId) .ThenBy(g => g.SortId)
.ToListAsync(); .ToListAsync();
int rowNum = 1;
foreach (var attrG in attrGroups) { foreach (var attrG in attrGroups) {
rowNum++;
var name = attrG.Attr == null && attrG.Cult == null ? null : attrG.Attr + (attrG.Attr != null && attrG.Cult != null ? " / " : "") + attrG.Cult; var name = attrG.Attr == null && attrG.Cult == null ? null : attrG.Attr + (attrG.Attr != null && attrG.Cult != null ? " / " : "") + attrG.Cult;
AddToolTipRow(grid, rowNum++, name, null, attrG.Weight, attrG.Weight, weight); grid.Add((name, null, attrG.Weight, attrG.Weight, weight));
foreach (var g in groups.Where(g => g.Attr == attrG.Attr && g.Cult == attrG.Cult).OrderByDescending(g => g.Weight).ThenBy(g => g.SortId)) { foreach (var g in groups.Where(g => g.Attr == attrG.Attr && g.Cult == attrG.Cult).OrderByDescending(g => g.Weight).ThenBy(g => g.SortId)) {
AddToolTipRow(grid, rowNum++, null, g.SortId, g.Weight, attrG.Weight, weight); grid.Add((null, g.SortId, g.Weight, attrG.Weight, weight));
} }
} }
@@ -395,7 +356,22 @@ namespace Elwig.Services {
} }
} }
return (text, grid); return (text, grid.ToArray());
}
public static Grid GenerateToolTip((string?, string?, int, int?, int)[] data) {
var grid = new Grid();
grid.ColumnDefinitions.Add(new() { Width = new(10) });
grid.ColumnDefinitions.Add(new() { Width = new(60) });
grid.ColumnDefinitions.Add(new() { Width = new(80) });
grid.ColumnDefinitions.Add(new() { Width = new(50) });
grid.ColumnDefinitions.Add(new() { Width = new(50) });
int rowNum = 0;
foreach (var row in data) {
if (rowNum != 0 && row.Item2 == null) rowNum++;
AddToolTipRow(grid, rowNum++, row.Item1, row.Item2, row.Item3, row.Item4, row.Item5);
}
return grid;
} }
} }
} }
+5 -5
View File
@@ -60,8 +60,8 @@ namespace Elwig.Services {
var filter = vm.TextFilter; var filter = vm.TextFilter;
if (filter.Count > 0) { if (filter.Count > 0) {
var var = await ctx.WineVarieties.ToDictionaryAsync(v => v.SortId, v => v); var var = await ctx.FetchWineVarieties().ToDictionaryAsync(v => v.SortId, v => v);
var zwst = await ctx.Branches.ToDictionaryAsync(b => b.Name.ToLower().Split(" ")[0], b => b); var zwst = await ctx.FetchBranches().ToDictionaryAsync(b => b.Name.ToLower().Split(" ")[0], b => b);
for (int i = 0; i < filter.Count; i++) { for (int i = 0; i < filter.Count; i++) {
var e = filter[i]; var e = filter[i];
@@ -174,12 +174,12 @@ namespace Elwig.Services {
ctx.Add(s); ctx.Add(s);
} }
ctx.UpdateDeliveryScheduleWineVarieties(s, (await ctx.DeliveryScheduleWineVarieties await ctx.UpdateDeliveryScheduleWineVarieties(s, (await ctx.DeliveryScheduleWineVarieties
.Where(v => v.Year == s.Year && v.DsNr == s.DsNr) .Where(v => v.Year == s.Year && v.DsNr == s.DsNr)
.Select(v => new { v.Variety, v.Priority }) .Select(v => new { v.Variety, v.Priority })
.ToListAsync()) .ToListAsync())
.Select(v => (v.Variety, v.Priority)) .Select(v => (v.Variety.SortId, v.Priority))
.ToList(), vm.MainVarieties.Select(v => (v, 1)).Union(vm.OtherVarieties.Select(v => (v, 2))).ToList()); .ToList(), vm.MainVarieties.Select(v => (v.SortId, 1)).Union(vm.OtherVarieties.Select(v => (v.SortId, 2))).ToList());
await ctx.SaveChangesAsync(); await ctx.SaveChangesAsync();
}); });
+124 -218
View File
@@ -3,12 +3,9 @@ using Elwig.Helpers.Export;
using Elwig.Helpers; using Elwig.Helpers;
using Elwig.Models.Dtos; using Elwig.Models.Dtos;
using Elwig.Models.Entities; using Elwig.Models.Entities;
using Microsoft.Win32;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Input;
using System.Windows;
using System; using System;
using Elwig.ViewModels; using Elwig.ViewModels;
using LinqKit; using LinqKit;
@@ -25,18 +22,6 @@ namespace Elwig.Services {
FromFilters, FromToday, FromSeason, FromSeasonAndBranch, Selected, FromFilters, FromToday, FromSeason, FromSeasonAndBranch, Selected,
}; };
public static async Task<Member?> GetMemberAsync(int mgnr) {
using var ctx = new AppDbContext();
return await ctx.Members
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.DefaultWbKg!.AtKg)
.FirstOrDefaultAsync(m => m.MgNr == mgnr);
}
public static Member? GetMember(int mgnr) {
return GetMemberAsync(mgnr).GetAwaiter().GetResult();
}
public static void ClearInputs(this DeliveryAdminViewModel vm) { public static void ClearInputs(this DeliveryAdminViewModel vm) {
} }
@@ -71,7 +56,7 @@ namespace Elwig.Services {
vm.IsNetWeight = p.IsNetWeight; vm.IsNetWeight = p.IsNetWeight;
vm.Modifiers.Clear(); vm.Modifiers.Clear();
foreach (var m in p.Modifiers) { foreach (var m in p.PartModifiers) {
vm.Modifiers.Add((Modifier)ControlUtils.GetItemFromSourceWithPk(vm.ModifiersSource, m.Year, m.ModId)!); vm.Modifiers.Add((Modifier)ControlUtils.GetItemFromSourceWithPk(vm.ModifiersSource, m.Year, m.ModId)!);
} }
@@ -129,12 +114,12 @@ namespace Elwig.Services {
var filter = vm.TextFilter; var filter = vm.TextFilter;
if (filter.Count > 0) { if (filter.Count > 0) {
var var = await ctx.WineVarieties.ToDictionaryAsync(v => v.SortId, v => v); var var = await ctx.FetchWineVarieties().ToDictionaryAsync(v => v.SortId, v => v);
var qual = await ctx.WineQualityLevels.Where(q => !q.IsPredicate).ToDictionaryAsync(q => q.QualId, q => q); var qual = await ctx.FetchWineQualityLevels(false).ToDictionaryAsync(q => q.QualId, q => q);
var mgnr = await ctx.Members.ToDictionaryAsync(m => m.MgNr.ToString(), m => m); var mgnr = await ctx.FetchMembers(includeNotActive: true).ToDictionaryAsync(m => m.MgNr.ToString(), m => m);
var zwst = await ctx.Branches.ToDictionaryAsync(b => b.Name.ToLower().Split(' ')[0], b => b); var zwst = await ctx.FetchBranches().ToDictionaryAsync(b => b.Name.ToLower().Split(' ')[0], b => b);
var attr = await ctx.WineAttributes.ToDictionaryAsync(a => a.Name.ToLower().Split(' ')[0], a => a); var attr = await ctx.FetchWineAttributes().ToDictionaryAsync(a => a.Name.ToLower().Split(' ')[0], a => a);
var cult = await ctx.WineCultivations.ToDictionaryAsync(c => c.Name.ToLower().Split(' ')[0], c => c); var cult = await ctx.FetchWineCultivations().ToDictionaryAsync(c => c.Name.ToLower().Split(' ')[0], c => c);
for (int i = 0; i < filter.Count; i++) { for (int i = 0; i < filter.Count; i++) {
var e = filter[i]; var e = filter[i];
@@ -472,6 +457,7 @@ namespace Elwig.Services {
DeliveryPart p; DeliveryPart p;
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
using var tx = await ctx.Database.BeginTransactionAsync();
int year = oldYear ?? Utils.CurrentYear; int year = oldYear ?? Utils.CurrentYear;
int did = oldDid ?? await ctx.NextDId(year); int did = oldDid ?? await ctx.NextDId(year);
int dpnr = oldDpnr ?? await ctx.NextDPNr(year, did); int dpnr = oldDpnr ?? await ctx.NextDPNr(year, did);
@@ -490,7 +476,7 @@ namespace Elwig.Services {
if (partNew && timeIsDefault) { if (partNew && timeIsDefault) {
newTimeString = DateTime.Now.ToString("HH:mm:ss"); newTimeString = DateTime.Now.ToString("HH:mm:ss");
} else if (partNew || timeHasChanged) { } else if (partNew || timeHasChanged) {
newTimeString = string.IsNullOrEmpty(vm.Time) ? null : vm.Time + ":00"; newTimeString = string.IsNullOrWhiteSpace(vm.Time) ? null : vm.Time + ":00";
} }
var d = new Delivery { var d = new Delivery {
@@ -502,7 +488,7 @@ namespace Elwig.Services {
ZwstId = vm.Branch!.ZwstId, ZwstId = vm.Branch!.ZwstId,
LsNr = newLsNr ?? vm.LsNr!, LsNr = newLsNr ?? vm.LsNr!,
MgNr = vm.MgNr!.Value, MgNr = vm.MgNr!.Value,
Comment = string.IsNullOrEmpty(vm.Comment) ? null : vm.Comment, Comment = string.IsNullOrWhiteSpace(vm.Comment) ? null : vm.Comment,
}; };
p = new DeliveryPart { p = new DeliveryPart {
@@ -525,7 +511,7 @@ namespace Elwig.Services {
Unloading = vm.Unloading, Unloading = vm.Unloading,
Temperature = vm.Temperature, Temperature = vm.Temperature,
Acid = vm.Acid, Acid = vm.Acid,
Comment = string.IsNullOrEmpty(vm.PartComment) ? null : vm.PartComment, Comment = string.IsNullOrWhiteSpace(vm.PartComment) ? null : vm.PartComment,
Weight = vm.Weight!.Value, Weight = vm.Weight!.Value,
IsManualWeighing = vm.IsManualWeighing, IsManualWeighing = vm.IsManualWeighing,
@@ -548,21 +534,21 @@ namespace Elwig.Services {
ctx.Add(p); ctx.Add(p);
} }
ctx.UpdateDeliveryPartModifiers(p, await ctx.DeliveryPartModifiers await ctx.UpdateDeliveryPartModifiers(p, await ctx.DeliveryPartModifiers
.Where(m => m.Year == p.Year && m.DId == p.DId && m.DPNr == p.DPNr) .Where(m => m.Year == p.Year && m.DId == p.DId && m.DPNr == p.DPNr)
.Select(m => m.Modifier) .Select(m => m.ModId)
.ToListAsync(), vm.Modifiers); .ToListAsync(), vm.Modifiers.Select(m => m.ModId).ToList());
if (originalMgNr != null && originalMgNr.Value != d.MgNr) { if (originalMgNr != null && originalMgNr.Value != d.MgNr) {
// update origin (KgNr), if default is selected // update origin (KgNr), if default is selected
var newKgNr = (await ctx.Members.FindAsync(d.MgNr))?.DefaultKgNr; var newKgNr = (await ctx.FetchMembers(d.MgNr).SingleOrDefaultAsync())?.DefaultKgNr;
foreach (var part in d.Parts.Where(part => part.DPNr != dpnr && part.KgNr == originalMemberKgNr)) { await ctx.DeliveryParts
part.KgNr = newKgNr; .Where(p => p.Year == d.Year && p.DId == d.DId && p.DPNr != dpnr && p.KgNr == originalMemberKgNr)
ctx.Update(part); .ExecuteUpdateAsync(u => u.SetProperty(p => p.KgNr, newKgNr));
}
} }
await ctx.SaveChangesAsync(); await ctx.SaveChangesAsync();
await tx.CommitAsync();
return p; return p;
}); });
@@ -574,7 +560,10 @@ namespace Elwig.Services {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
bool anyLeft = false; bool anyLeft = false;
var d = (await ctx.Deliveries.FindAsync(year, did))!; var d = await ctx.Deliveries
.Where(d => d.Year == year && d.DId == did)
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers)
.SingleAsync();
var lnr = await ctx.NextLNr(d.Date, d.ZwstId); var lnr = await ctx.NextLNr(d.Date, d.ZwstId);
n = new Delivery { n = new Delivery {
Year = year, Year = year,
@@ -601,7 +590,11 @@ namespace Elwig.Services {
anyLeft = true; anyLeft = true;
p.Weight -= w; p.Weight -= w;
ctx.Update(p); ctx.Update(p);
var s = ctx.CreateProxy<DeliveryPart>(); var s = new DeliveryPart {
SortId = null!,
QualId = null!,
HkId = null!,
};
var values = ctx.Entry(p).CurrentValues; var values = ctx.Entry(p).CurrentValues;
ctx.Entry(s).CurrentValues.SetValues(values); ctx.Entry(s).CurrentValues.SetValues(values);
s.Year = n.Year; s.Year = n.Year;
@@ -632,8 +625,11 @@ namespace Elwig.Services {
Delivery n; Delivery n;
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
var anyLeft = false; var anyLeft = false;
n = (await ctx.Deliveries.FirstAsync(d => d.LsNr == lsnr))!; n = (await ctx.Deliveries.Where(d => d.LsNr == lsnr).FirstAsync())!;
var d = (await ctx.Deliveries.FindAsync(year, did))!; var d = await ctx.Deliveries
.Where(d => d.Year == year && d.DId == did)
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers)
.SingleAsync();
var dpnr = await ctx.NextDPNr(n.Year, n.DId); var dpnr = await ctx.NextDPNr(n.Year, n.DId);
foreach (var (p, w) in d.Parts.ToList().Zip(weights)) { foreach (var (p, w) in d.Parts.ToList().Zip(weights)) {
if (w <= 0) { if (w <= 0) {
@@ -645,7 +641,11 @@ namespace Elwig.Services {
anyLeft = true; anyLeft = true;
p.Weight -= w; p.Weight -= w;
ctx.Update(p); ctx.Update(p);
var s = ctx.CreateProxy<DeliveryPart>(); var s = new DeliveryPart {
SortId = null!,
QualId = null!,
HkId = null!,
};
var values = ctx.Entry(p).CurrentValues; var values = ctx.Entry(p).CurrentValues;
ctx.Entry(s).CurrentValues.SetValues(values); ctx.Entry(s).CurrentValues.SetValues(values);
s.Year = n.Year; s.Year = n.Year;
@@ -674,7 +674,10 @@ namespace Elwig.Services {
public static async Task DepreciateDelivery(int year, int did, int[] weights) { public static async Task DepreciateDelivery(int year, int did, int[] weights) {
await Task.Run(async () => { await Task.Run(async () => {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
var d = (await ctx.Deliveries.FindAsync(year, did))!; var d = await ctx.Deliveries
.Where(d => d.Year == year && d.DId == did)
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers)
.SingleAsync();
var dpnr = await ctx.NextDPNr(year, did); var dpnr = await ctx.NextDPNr(year, did);
foreach (var (p, w) in d.Parts.ToList().Zip(weights)) { foreach (var (p, w) in d.Parts.ToList().Zip(weights)) {
if (w <= 0) { if (w <= 0) {
@@ -686,7 +689,11 @@ namespace Elwig.Services {
} else { } else {
p.Weight -= w; p.Weight -= w;
ctx.Update(p); ctx.Update(p);
var n = ctx.CreateProxy<DeliveryPart>(); var n = new DeliveryPart {
SortId = null!,
QualId = null!,
HkId = null!,
};
var values = ctx.Entry(p).CurrentValues; var values = ctx.Entry(p).CurrentValues;
ctx.Entry(n).CurrentValues.SetValues(values); ctx.Entry(n).CurrentValues.SetValues(values);
n.DPNr = dpnr++; n.DPNr = dpnr++;
@@ -708,18 +715,10 @@ namespace Elwig.Services {
} }
public static async Task GenerateDeliveryNote(int year, int did, ExportMode mode) { public static async Task GenerateDeliveryNote(int year, int did, ExportMode mode) {
Mouse.OverrideCursor = Cursors.Wait; await Utils.RunForeground(async () => {
await Task.Run(async () => { using var doc = await DeliveryNote.Initialize(year, did);
try { 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) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
}); });
Mouse.OverrideCursor = null;
} }
public static async Task GenerateDeliveryJournal(this DeliveryAdminViewModel vm, ExportSubject subject, ExportMode mode) { public static async Task GenerateDeliveryJournal(this DeliveryAdminViewModel vm, ExportSubject subject, ExportMode mode) {
@@ -756,45 +755,23 @@ namespace Elwig.Services {
.ThenBy(p => p.DPNr); .ThenBy(p => p.DPNr);
if (mode == ExportMode.SaveList) { if (mode == ExportMode.SaveList) {
var d = new SaveFileDialog() { var filename = InteractionService.SaveFile(DeliveryJournal.Name, DeliveryJournal.Name, "ods");
FileName = $"{DeliveryJournal.Name}.ods", if (filename != null) {
DefaultExt = "ods", await Utils.RunForeground(async () => {
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); var data = await DeliveryJournalData.FromQuery(query, filterNames);
using var ods = new OdsFile(d.FileName); using var ods = new OdsFile(filename);
await ods.AddTable(data); await ods.AddTable(data);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
}); });
Mouse.OverrideCursor = null;
} }
} else if (mode == ExportMode.Export) { } else if (mode == ExportMode.Export) {
var d = new SaveFileDialog() { 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");
FileName = subject == ExportSubject.Selected ? $"Lieferung_{vm.SelectedDelivery?.LsNr}.elwig.zip" : $"Lieferungen_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{App.ZwstId}.elwig.zip", if (filename != null) {
DefaultExt = "elwig.zip", if (!filename.EndsWith(".elwig.zip")) filename += ".elwig.zip";
Filter = "Elwig-Export-Datei (*.elwig.zip)|*.elwig.zip", await Utils.RunForeground(async () => {
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 {
var list = await query var list = await query
.Select(p => p.Delivery) .Select(p => p.Delivery)
.Distinct() .Distinct()
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers) .Include(d => d.Parts).ThenInclude(p => p.PartModifiers)
.Include(d => d.Parts).ThenInclude(p => p.Rd)
.Include(d => d.Parts).ThenInclude(p => p.Kg!.Gl)
.AsSplitQuery()
.ToListAsync(); .ToListAsync();
var wbKgs = list var wbKgs = list
.SelectMany(d => d.Parts) .SelectMany(d => d.Parts)
@@ -803,31 +780,19 @@ namespace Elwig.Services {
.DistinctBy(k => k.KgNr) .DistinctBy(k => k.KgNr)
.OrderBy(k => k.KgNr) .OrderBy(k => k.KgNr)
.ToList(); .ToList();
await ElwigData.Export(d.FileName, list, wbKgs, filterNames); await ElwigData.Export(filename, list, wbKgs, filterNames);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
}); });
Mouse.OverrideCursor = null;
} }
} else if (mode == ExportMode.Upload && App.Config.SyncUrl != null) { } else if (mode == ExportMode.Upload && App.Config.SyncUrl != null) {
Mouse.OverrideCursor = Cursors.Wait; await Utils.RunForeground(async () => {
await Task.Run(async () => {
await SyncService.Upload(App.Config.SyncUrl, App.Config.SyncUrl, App.Config.SyncPassword, query, filterNames); await SyncService.Upload(App.Config.SyncUrl, App.Config.SyncUrl, App.Config.SyncPassword, query, filterNames);
}); });
Mouse.OverrideCursor = null;
} else { } else {
Mouse.OverrideCursor = Cursors.Wait; await Utils.RunForeground(async () => {
await Task.Run(async () => {
try {
var data = await DeliveryJournalData.FromQuery(query, filterNames); var data = await DeliveryJournalData.FromQuery(query, filterNames);
using var doc = new DeliveryJournal(string.Join(" / ", filterNames), data); using var doc = new DeliveryJournal(string.Join(" / ", filterNames), data);
await Utils.ExportDocument(doc, mode); await Utils.ExportDocument(doc, mode);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
}); });
Mouse.OverrideCursor = null;
} }
} }
@@ -848,17 +813,11 @@ namespace Elwig.Services {
throw new ArgumentException("Invalid value for ExportSubject"); throw new ArgumentException("Invalid value for ExportSubject");
} }
Mouse.OverrideCursor = Cursors.Wait; await Utils.RunForeground(async () => {
await Task.Run(async () => {
try {
var data = await WineQualityStatisticsData.FromQuery(query, App.Client.OrderingMemberList); var data = await WineQualityStatisticsData.FromQuery(query, App.Client.OrderingMemberList);
using var doc = new WineQualityStatistics(string.Join(" / ", filterNames), data); using var doc = new WineQualityStatistics(string.Join(" / ", filterNames), data);
await Utils.ExportDocument(doc, mode); await Utils.ExportDocument(doc, mode);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
}); });
Mouse.OverrideCursor = null;
} }
public static async Task GenerateLocalityStatistics(this DeliveryAdminViewModel vm, ExportSubject subject) { public static async Task GenerateLocalityStatistics(this DeliveryAdminViewModel vm, ExportSubject subject) {
@@ -874,24 +833,13 @@ namespace Elwig.Services {
throw new ArgumentException("Invalid value for ExportSubject"); throw new ArgumentException("Invalid value for ExportSubject");
} }
var d = new SaveFileDialog() { var filename = InteractionService.SaveFile("Lieferstatistik pro Ort", $"Lieferstatistik-{vm.FilterSeason ?? Utils.CurrentLastSeason}", "ods");
FileName = $"Lieferstatistik-{vm.FilterSeason ?? Utils.CurrentLastSeason}.ods", if (filename != null) {
DefaultExt = "ods", await Utils.RunForeground(async () => {
Filter = "OpenDocument Format Spreadsheet (*.ods)|*.ods", using var ods = new OdsFile(filename);
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(d.FileName);
var tbl = await WineLocalityStatisticsData.FromQuery(query, filterNames); var tbl = await WineLocalityStatisticsData.FromQuery(query, filterNames);
await ods.AddTable(tbl); await ods.AddTable(tbl);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
}); });
Mouse.OverrideCursor = null;
} }
} }
@@ -922,45 +870,28 @@ namespace Elwig.Services {
filterNames.Remove("abgewertet"); filterNames.Remove("abgewertet");
if (mode == ExportMode.SaveList) { if (mode == ExportMode.SaveList) {
var d = new SaveFileDialog() { var filename = InteractionService.SaveFile(DeliveryDepreciationList.Name, $"{DeliveryDepreciationList.Name}-{vm.FilterSeason ?? Utils.CurrentLastSeason}", "ods");
FileName = $"{DeliveryDepreciationList.Name}-{vm.FilterSeason ?? Utils.CurrentLastSeason}.ods", if (filename != null) {
DefaultExt = "ods", await Utils.RunForeground(async () => {
Filter = "OpenDocument Format Spreadsheet (*.ods)|*.ods", using var ods = new OdsFile(filename);
Title = $"{DeliveryDepreciationList.Name} speichern unter - Elwig"
};
if (d.ShowDialog() == true) {
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
using var ods = new OdsFile(d.FileName);
var tblTotal = await DeliveryJournalData.FromQuery(query, filterNames); var tblTotal = await DeliveryJournalData.FromQuery(query, filterNames);
tblTotal.FullName = DeliveryDepreciationList.Name; tblTotal.FullName = DeliveryDepreciationList.Name;
tblTotal.Name = "Gesamt"; tblTotal.Name = "Gesamt";
await ods.AddTable(tblTotal); await ods.AddTable(tblTotal);
foreach (var branch in await ctx.Branches.OrderBy(b => b.Name).ToListAsync()) { foreach (var branch in await ctx.FetchBranches().ToListAsync()) {
var tbl = await DeliveryJournalData.FromQuery(query.Where(p => p.Delivery.ZwstId == branch.ZwstId), filterNames); var tbl = await DeliveryJournalData.FromQuery(query.Where(p => p.Delivery.ZwstId == branch.ZwstId), filterNames);
tbl.FullName = DeliveryDepreciationList.Name; tbl.FullName = DeliveryDepreciationList.Name;
tbl.Name = branch.Name; tbl.Name = branch.Name;
await ods.AddTable(tbl); await ods.AddTable(tbl);
} }
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
}); });
Mouse.OverrideCursor = null;
} }
} else { } else {
Mouse.OverrideCursor = Cursors.Wait; await Utils.RunForeground(async () => {
await Task.Run(async () => {
try {
var data = await DeliveryJournalData.FromQuery(query, filterNames); var data = await DeliveryJournalData.FromQuery(query, filterNames);
using var doc = new DeliveryDepreciationList(string.Join(" / ", filterNames), data); using var doc = new DeliveryDepreciationList(string.Join(" / ", filterNames), data);
await Utils.ExportDocument(doc, mode); await Utils.ExportDocument(doc, mode);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
}); });
Mouse.OverrideCursor = null;
} }
} }
@@ -987,59 +918,36 @@ namespace Elwig.Services {
.ThenBy(p => p.AttrId) .ThenBy(p => p.AttrId)
.ThenBy(p => p.CultId); .ThenBy(p => p.CultId);
var d = new SaveFileDialog() { var filename = InteractionService.SaveFile("Liefermengen", "Liefermengen", "ods");
FileName = $"Liefermengen.ods", if (filename != null) {
DefaultExt = "ods", await Utils.RunForeground(async () => {
Filter = "OpenDocument Format Spreadsheet (*.ods)|*.ods", using var ods = new OdsFile(filename);
Title = $"Liefermengen speichern unter - Elwig"
};
if (d.ShowDialog() == true) {
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
using var ods = new OdsFile(d.FileName);
var tblTotal = await MemberDeliveryData.FromQuery(query, filterNames); var tblTotal = await MemberDeliveryData.FromQuery(query, filterNames);
var tbl = await MemberDeliveryPerVarietyData.FromQuery(query, filterNames); var tbl = await MemberDeliveryPerVarietyData.FromQuery(query, filterNames);
await ods.AddTable(tblTotal); await ods.AddTable(tblTotal);
await ods.AddTable(tbl); await ods.AddTable(tbl);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
}); });
Mouse.OverrideCursor = null;
} }
} }
private static void AddToolTipCell(Grid grid, string text, int row, int col, int colSpan = 1, bool bold = false, bool alignRight = false, bool alignCenter = false) {
var tb = new TextBlock() {
Text = text,
TextAlignment = alignRight ? TextAlignment.Right : alignCenter ? TextAlignment.Center : TextAlignment.Left,
Margin = new(0, 12 * row, 0, 0),
FontWeight = bold ? FontWeights.Bold : FontWeights.Normal,
};
tb.SetValue(Grid.ColumnProperty, col);
tb.SetValue(Grid.ColumnSpanProperty, colSpan);
grid.Children.Add(tb);
}
private static void AddWeightToolTipRow(Grid grid, int row, string? h1, string? h2, int weight, int? total1, int total2) { private static void AddWeightToolTipRow(Grid grid, int row, string? h1, string? h2, int weight, int? total1, int total2) {
var bold = h2 == null; var bold = h2 == null;
if (h1 != null) AddToolTipCell(grid, h1 + ":", row, 0, (h2 == null) ? 2 : 1, bold); if (h1 != null) grid.AddToolTipCell(h1 + ":", row, 0, (h2 == null) ? 2 : 1, bold);
if (h2 != null) AddToolTipCell(grid, h2 + ":", row, 1, 1, bold); if (h2 != null) grid.AddToolTipCell(h2 + ":", row, 1, 1, bold);
AddToolTipCell(grid, $"{weight:N0} kg", row, 2, 1, bold, true); grid.AddToolTipCell($"{weight:N0} kg", row, 2, bold: bold, alignRight: true);
if (total1 != null && total1 != 0) if (total1 != null && total1 != 0)
AddToolTipCell(grid, $"{weight * 100.0 / total1:N1} %", row, 3, 1, bold, true); grid.AddToolTipCell($"{weight * 100.0 / total1:N1} %", row, 3, bold: bold, alignRight: true);
if (total2 != 0) if (total2 != 0)
AddToolTipCell(grid, $"{weight * 100.0 / total2:N1} %", row, 4, 1, bold, true); grid.AddToolTipCell($"{weight * 100.0 / total2:N1} %", row, 4, bold: bold, alignRight: true);
} }
private static void AddGradationToolTipRow(Grid grid, int row, string? h1, string? h2, double min, double avg, double max) { private static void AddGradationToolTipRow(Grid grid, int row, string? h1, string? h2, double min, double avg, double max) {
var bold = h2 == null; var bold = h2 == null;
if (h1 != null) AddToolTipCell(grid, h1 + ":", row, 0, (h2 == null) ? 2 : 1, bold); if (h1 != null) grid.AddToolTipCell(h1 + ":", row, 0, (h2 == null) ? 2 : 1, bold);
if (h2 != null) AddToolTipCell(grid, h2 + ":", row, 1, 1, bold); if (h2 != null) grid.AddToolTipCell(h2 + ":", row, 1, bold: bold);
AddToolTipCell(grid, $"{min:N1}°", row, 2, 1, bold, true); grid.AddToolTipCell($"{min:N1}°", row, 2, bold: bold, alignRight: true);
AddToolTipCell(grid, $"{avg:N1}°", row, 3, 1, bold, true); grid.AddToolTipCell($"{avg:N1}°", row, 3, bold: bold, alignRight: true);
AddToolTipCell(grid, $"{max:N1}°", row, 4, 1, bold, true); grid.AddToolTipCell($"{max:N1}°", row, 4, bold: bold, alignRight: true);
} }
public static async Task<(string WeightText, (string?, string?, int, int?, int)[] WeightGrid, string GradationText, (string?, string?, double, double, double)[] GradationGrid)> GenerateToolTipData(IQueryable<DeliveryPart> deliveryParts) { public static async Task<(string WeightText, (string?, string?, int, int?, int)[] WeightGrid, string GradationText, (string?, string?, double, double, double)[] GradationGrid)> GenerateToolTipData(IQueryable<DeliveryPart> deliveryParts) {
@@ -1048,16 +956,23 @@ namespace Elwig.Services {
var gGrid = new List<(string?, string?, double, double, double)>(); var gGrid = new List<(string?, string?, double, double, double)>();
var gText = "-"; var gText = "-";
var weight = await deliveryParts.SumAsync(p => p.Weight); var stat = (await deliveryParts.GroupBy(p => 0)
wText = $"{weight:N0} kg"; .Select(g => new {
wGrid.Add(("Menge", null, weight, null, weight)); Weight = g.Sum(p => p.Weight),
Min = g.Select(p => (double?)p.Kmw).DefaultIfEmpty().Min(),
Avg = g.Sum(p => p.Kmw * p.Weight) / g.Sum(p => p.Weight),
Max = g.Select(p => (double?)p.Kmw).DefaultIfEmpty().Max(),
})
.ToListAsync())
.DefaultIfEmpty(new { Weight = 0, Min = (double?)null, Avg = (double)0, Max = (double?)null })
.Single();
if (await deliveryParts.AnyAsync()) { wText = $"{stat.Weight:N0} kg";
var kmwMin = await deliveryParts.MinAsync(p => p.Kmw); wGrid.Add(("Menge", null, stat.Weight, null, stat.Weight));
var kmwAvg = Utils.AggregateDeliveryPartsKmw(deliveryParts);
var kmwMax = await deliveryParts.MaxAsync(p => p.Kmw); if (stat.Min != null && stat.Max != null) {
gText = $"{kmwMin:N1}° / {kmwAvg:N1}° / {kmwMax:N1}°"; gText = $"{stat.Min:N1}° / {stat.Avg:N1}° / {stat.Max:N1}°";
gGrid.Add(("Gradation", null, kmwMin, kmwAvg, kmwMax)); gGrid.Add(("Gradation", null, stat.Min.Value, stat.Avg, stat.Max.Value));
var attrGroups = await deliveryParts var attrGroups = await deliveryParts
.GroupBy(p => new { Attr = p.Attribute!.Name, Cult = p.Cultivation!.Name }) .GroupBy(p => new { Attr = p.Attribute!.Name, Cult = p.Cultivation!.Name })
@@ -1108,9 +1023,9 @@ namespace Elwig.Services {
foreach (var attrG in attrGroups) { foreach (var attrG in attrGroups) {
var name = attrG.Attr == null && attrG.Cult == null ? null : attrG.Attr + (attrG.Attr != null && attrG.Cult != null ? " / " : "") + attrG.Cult; var name = attrG.Attr == null && attrG.Cult == null ? null : attrG.Attr + (attrG.Attr != null && attrG.Cult != null ? " / " : "") + attrG.Cult;
wGrid.Add((name, null, attrG.Weight, attrG.Weight, weight)); wGrid.Add((name, null, attrG.Weight, attrG.Weight, stat.Weight));
foreach (var g in groups.Where(g => g.Attr == attrG.Attr && g.Cult == attrG.Cult).OrderByDescending(g => g.Weight).ThenBy(g => g.SortId)) { foreach (var g in groups.Where(g => g.Attr == attrG.Attr && g.Cult == attrG.Cult).OrderByDescending(g => g.Weight).ThenBy(g => g.SortId)) {
wGrid.Add((null, g.SortId, g.Weight, attrG.Weight, weight)); wGrid.Add((null, g.SortId, g.Weight, attrG.Weight, stat.Weight));
} }
} }
foreach (var attrG in attrGroups) { foreach (var attrG in attrGroups) {
@@ -1129,12 +1044,12 @@ namespace Elwig.Services {
gText += $" [{name}]"; gText += $" [{name}]";
} }
if (sortGroups.Count > 1 && sortGroups.Count <= 4) { if (sortGroups.Count > 1 && sortGroups.Count <= 4) {
wText += $" = {string.Join(" + ", sortGroups.Select(g => $"{g.Weight:N0} kg ({(double)g.Weight / weight:0%})" + (g.SortId == null ? "" : $" [{g.SortId}]")))}"; wText += $" = {string.Join(" + ", sortGroups.Select(g => $"{g.Weight:N0} kg ({(double)g.Weight / stat.Weight:0%})" + (g.SortId == null ? "" : $" [{g.SortId}]")))}";
gText += $" = {string.Join(" + ", sortGroups.Select(g => $"{g.Min:N1}/{g.Avg:N1}/{g.Max:N1}" + (g.SortId == null ? "" : $" [{g.SortId}]")))}"; gText += $" = {string.Join(" + ", sortGroups.Select(g => $"{g.Min:N1}/{g.Avg:N1}/{g.Max:N1}" + (g.SortId == null ? "" : $" [{g.SortId}]")))}";
} }
} else if (attrGroups.Count <= 4) { } else if (attrGroups.Count <= 4) {
wText += $" = {string.Join(" + ", attrGroups.Select(g => $"{g.Weight:N0} kg ({(double)g.Weight / weight:0%})" + (g.Attr == null && g.Cult == null ? "" : $" [{g.Attr}{(g.Attr != null && g.Cult != null ? " / " : "")}{g.Cult}]")))}"; wText += $" = {string.Join(" + ", attrGroups.Select(g => $"{g.Weight:N0} kg ({(double)g.Weight / stat.Weight:0%})" + (g.Attr == null && g.Cult == null ? "" : $" [{g.Attr}{(g.Attr != null && g.Cult != null ? " / " : "")}{g.Cult}]")))}";
gText += $" = {string.Join(" + ", attrGroups.Select(g => $"{g.Min:N1}/{g.Avg:N1}/{g.Max:N1}" + (g.Attr == null && g.Cult == null ? "" : $" [{g.Attr}{(g.Attr != null && g.Cult != null ? " / " : "")}{g.Cult}]")))}"; gText += $" = {string.Join(" + ", attrGroups.Select(g => $"{g.Min:N1}/{g.Avg:N1}/{g.Max:N1}" + (g.Attr == null && g.Cult == null ? "" : $" [{g.Attr}{(g.Attr != null && g.Cult != null ? " / " : "")}{g.Cult}]")))}";
} }
} }
@@ -1161,9 +1076,9 @@ namespace Elwig.Services {
gGrid.ColumnDefinitions.Add(new() { Width = new(35) }); gGrid.ColumnDefinitions.Add(new() { Width = new(35) });
gGrid.ColumnDefinitions.Add(new() { Width = new(35) }); gGrid.ColumnDefinitions.Add(new() { Width = new(35) });
gGrid.ColumnDefinitions.Add(new() { Width = new(35) }); gGrid.ColumnDefinitions.Add(new() { Width = new(35) });
AddToolTipCell(gGrid, "Min.", 0, 2, 1, false, false, true); gGrid.AddToolTipCell("Min.", 0, 2, alignCenter: true);
AddToolTipCell(gGrid, "⌀", 0, 3, 1, false, false, true); gGrid.AddToolTipCell("⌀", 0, 3, alignCenter: true);
AddToolTipCell(gGrid, "Max.", 0, 4, 1, false, false, true); gGrid.AddToolTipCell("Max.", 0, 4, alignCenter: true);
rowNum = 1; rowNum = 1;
foreach (var row in gradationData) { foreach (var row in gradationData) {
if (rowNum != 1 && row.Item2 == null) rowNum++; if (rowNum != 1 && row.Item2 == null) rowNum++;
@@ -1198,12 +1113,11 @@ namespace Elwig.Services {
attrid = $"'{attr.AttrId}'"; attrid = $"'{attr.AttrId}'";
} }
var dids = await vm.GetDidsFromFilters(); var dids = await vm.GetDidsFromFilters();
var res = MessageBox.Show($"Soll wirklich für {dids.Length:N0} Teillieferung(en) das Attribut\n'{attributeName}' gesetz werden?", if (!InteractionService.AskContinue("Massenaktion: Attribut setzen",
"Massenaktion: Attribut setzen", MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel); $"Soll wirklich für {dids.Length:N0} Teillieferung(en) das Attribut\n'{attributeName}' gesetz werden?"))
if (res != MessageBoxResult.OK) return; return;
Mouse.OverrideCursor = Cursors.Wait; await Utils.RunForeground(async () => {
await Task.Run(async () => {
using (var cnx = await AppDbContext.ConnectAsync()) { using (var cnx = await AppDbContext.ConnectAsync()) {
await cnx.ExecuteBatch($""" await cnx.ExecuteBatch($"""
UPDATE delivery_part SET attrid = {attrid} UPDATE delivery_part SET attrid = {attrid}
@@ -1213,9 +1127,7 @@ namespace Elwig.Services {
App.HintContextChange(); App.HintContextChange();
}); });
} catch (Exception exc) { } catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException(exc);
} finally {
Mouse.OverrideCursor = null;
} }
} }
@@ -1228,12 +1140,11 @@ namespace Elwig.Services {
} }
var dids = await vm.GetDidsFromFilters(); var dids = await vm.GetDidsFromFilters();
var res = MessageBox.Show($"Soll wirklich für {dids.Length:N0} Teillieferung(en) der Zu-/Abschlag\n'{modifierName}' hinzugefügt werden?", if (!InteractionService.AskContinue("Massenaktion: Zu-/Abschlag hinzufügen",
"Massenaktion: Zu-/Abschlag hinzufügen", MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel); $"Soll wirklich für {dids.Length:N0} Teillieferung(en) der Zu-/Abschlag\n'{modifierName}' hinzugefügt werden?"))
if (res != MessageBoxResult.OK) return; return;
Mouse.OverrideCursor = Cursors.Wait; await Utils.RunForeground(async () => {
await Task.Run(async () => {
using (var cnx = await AppDbContext.ConnectAsync()) { using (var cnx = await AppDbContext.ConnectAsync()) {
await cnx.ExecuteBatch($""" await cnx.ExecuteBatch($"""
INSERT INTO delivery_part_modifier (year, did, dpnr, modid) INSERT INTO delivery_part_modifier (year, did, dpnr, modid)
@@ -1244,9 +1155,7 @@ namespace Elwig.Services {
App.HintContextChange(); App.HintContextChange();
}); });
} catch (Exception exc) { } catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException(exc);
} finally {
Mouse.OverrideCursor = null;
} }
} }
@@ -1259,12 +1168,11 @@ namespace Elwig.Services {
} }
var dids = await vm.GetDidsFromFilters(); var dids = await vm.GetDidsFromFilters();
var res = MessageBox.Show($"Soll wirklich für {dids.Length:N0} Teillieferung(en) der Zu-/Abschlag\n'{modifierName}' entfernt werden?", if (!InteractionService.AskContinue("Massenaktion: Zu-/Abschlag entfernen",
"Massenaktion: Zu-/Abschlag entfernen", MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel); $"Soll wirklich für {dids.Length:N0} Teillieferung(en) der Zu-/Abschlag\n'{modifierName}' entfernt werden?"))
if (res != MessageBoxResult.OK) return; return;
Mouse.OverrideCursor = Cursors.Wait; await Utils.RunForeground(async () => {
await Task.Run(async () => {
using (var cnx = await AppDbContext.ConnectAsync()) { using (var cnx = await AppDbContext.ConnectAsync()) {
await cnx.ExecuteBatch($""" await cnx.ExecuteBatch($"""
DELETE FROM delivery_part_modifier DELETE FROM delivery_part_modifier
@@ -1274,9 +1182,7 @@ namespace Elwig.Services {
App.HintContextChange(); App.HintContextChange();
}); });
} catch (Exception exc) { } catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException(exc);
} finally {
Mouse.OverrideCursor = null;
} }
} }
} }
+163
View File
@@ -0,0 +1,163 @@
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 Action<string, string>? NextInformation;
public static Action<string, string>? NextWarning;
public static Action<string, string>? NextError;
public static Func<string, string, bool>? NextContinue;
public static Func<string, string, bool>? NextConfirmation;
public static Func<string, string, bool>? NextQuestion;
public static Func<string, string, string?>? NextSave;
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 (NextInformation != null) {
NextInformation(title, text);
NextInformation = null;
} else 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 (NextContinue != null) {
var r = NextContinue(title, text);
NextContinue = null;
return r;
} else 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? AskContinueYesNo(string title, string text) {
if (NextContinue != null) {
var r = NextContinue(title, text);
NextContinue = null;
return r;
} else if (Override != null) {
return Override("continue", title, text) != null;
} else {
var r = MessageBox.Show(text, title, MessageBoxButton.YesNoCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
return r == MessageBoxResult.Yes ? true : r == MessageBoxResult.No ? false : null;
}
}
public static bool AskConfirmation(string title, string text) {
if (NextConfirmation != null) {
var r = NextConfirmation(title, text);
NextConfirmation = null;
return r;
} else 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 (NextQuestion != null) {
var r = NextQuestion(title, text);
NextQuestion = null;
return r;
} else 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 (NextWarning != null) {
NextWarning(title, text);
NextWarning = null;
} else 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 (NextError != null) {
NextError(title, text);
NextError = null;
} else 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, null, 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 (NextSave != null) {
var r = NextSave(title, $"{defaultFileName}.{extension}");
NextSave = null;
return r;
} else 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;
}
}
}
}
@@ -0,0 +1,98 @@
using Elwig.Helpers;
using Elwig.Models;
using Elwig.Models.Entities;
using Elwig.ViewModels;
using Microsoft.EntityFrameworkCore;
using System.Linq;
using System.Threading.Tasks;
namespace Elwig.Services {
public static class MemberBusinessSharesService {
public static async Task InitInputs(this MemberBusinessSharesViewModel vm) {
using var ctx = new AppDbContext();
vm.DateNoticeString = $"{Utils.Today:dd.MM.yyyy}";
vm.ValuePerShare = (await ctx.Seasons.OrderBy(s => s.Year).LastOrDefaultAsync())?.BusinessShareValue;
}
public static void ClearInputs(this MemberBusinessSharesViewModel vm) {
}
public static void FillInputs(this MemberBusinessSharesViewModel vm, MemberHistory h) {
var mgnr = vm.FilterMember.MgNr;
vm.DateNotice = h.DateNotice;
vm.DateEffective = h.DateEffective;
vm.Reason = h.Reason + (h.Reason == MemberHistory.REASON_TRANSFER ? $"_{(h.ToMgNr == mgnr ? "from" : "to")}" : "");
vm.Shares = h.Shares;
vm.MemberHasSigned = h.MemberHasSigned;
vm.ValuePerShare = h.ValuePerShare;
vm.OtherMgNr = h.FromMgNr != null && h.FromMgNr != mgnr ? h.FromMgNr : h.ToMgNr != null && h.ToMgNr != mgnr ? h.ToMgNr : null;
vm.DeductYear = h.DeductYear ?? h.DateNotice.Year;
vm.Deduct = h.DeductYear != null;
vm.Comment = h.Comment;
}
public static async Task<int> UpdateMemberHistory(this MemberBusinessSharesViewModel vm, int? oldHistNr, bool enableTriggers) {
return await Task.Run(async () => {
using var ctx = new AppDbContext();
var tx = await ctx.Database.BeginTransactionAsync();
await ctx.Database.ExecuteSqlAsync($"UPDATE client_parameter SET value = {(enableTriggers ? "1" : "0")} WHERE param = 'ENABLE_MEMBER_HISTORY_TRIGGERS'");
var h = new MemberHistory {
HistNr = oldHistNr ?? await ctx.NextHistNr(),
FromMgNr =
vm.Reason == $"{MemberHistory.REASON_TRANSFER}_from" ? vm.OtherMgNr :
vm.Reason == MemberHistory.REASON_PURCHASE || vm.Reason == MemberHistory.REASON_PRESCRIPTION ? null :
vm.FilterMember.MgNr,
FromType =
vm.Reason == MemberHistory.REASON_PAYOUT ? BusinessShareType.Dormant :
vm.Reason == MemberHistory.REASON_PURCHASE || vm.Reason == MemberHistory.REASON_PRESCRIPTION ? null :
BusinessShareType.Normal,
ToMgNr =
vm.Reason == MemberHistory.REASON_PAYOUT || vm.Reason == MemberHistory.REASON_EXCLUSION ? null :
vm.Reason == $"{MemberHistory.REASON_TRANSFER}_to" ? vm.OtherMgNr :
vm.FilterMember.MgNr,
ToType =
vm.Reason == MemberHistory.REASON_PAYOUT || vm.Reason == MemberHistory.REASON_EXCLUSION ? null :
vm.Reason == MemberHistory.REASON_RETIREMENT || vm.Reason == MemberHistory.REASON_DECEASED ? BusinessShareType.Dormant :
BusinessShareType.Normal,
DateNoticeString = $"{vm.DateNotice:yyyy-MM-dd}",
DateEffectiveString = $"{vm.DateEffective:yyyy-MM-dd}",
Reason = vm.Reason?.Split("_")[0] ?? MemberHistory.REASON_CONVERT,
Source = "manual",
Shares = vm.Shares ?? 0,
MemberHasSigned = vm.MemberHasSigned,
ValuePerShare = vm.ValuePerShare,
CurrencyCode = vm.ValuePerShare != null ? "EUR" : null,
DeductYear = vm.Deduct ? vm.DeductYear : null,
Comment = string.IsNullOrWhiteSpace(vm.Comment) ? null : vm.Comment.Trim(),
};
if (oldHistNr != null) {
ctx.Update(h);
} else {
ctx.Add(h);
}
await ctx.SaveChangesAsync();
await ctx.Database.ExecuteSqlAsync($"UPDATE client_parameter SET value = '1' WHERE param = 'ENABLE_MEMBER_HISTORY_TRIGGERS'");
await tx.CommitAsync();
return h.HistNr;
});
}
public static async Task DeleteMemberHistory(int histnr, bool enableTriggers) {
await Task.Run(async () => {
using var ctx = new AppDbContext();
var tx = await ctx.Database.BeginTransactionAsync();
await ctx.Database.ExecuteSqlAsync($"UPDATE client_parameter SET value = {(enableTriggers ? "1" : "0")} WHERE param = 'ENABLE_MEMBER_HISTORY_TRIGGERS'");
await ctx.MemberHistory.Where(h => h.HistNr == histnr).ExecuteDeleteAsync();
await ctx.Database.ExecuteSqlAsync($"UPDATE client_parameter SET value = '1' WHERE param = 'ENABLE_MEMBER_HISTORY_TRIGGERS'");
await tx.CommitAsync();
});
}
}
}
+71 -129
View File
@@ -6,13 +6,10 @@ using Elwig.Models.Dtos;
using Elwig.Models.Entities; using Elwig.Models.Entities;
using Elwig.ViewModels; using Elwig.ViewModels;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Win32;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
namespace Elwig.Services { namespace Elwig.Services {
public static class MemberService { public static class MemberService {
@@ -129,7 +126,15 @@ namespace Elwig.Services {
vm.EntryDate = (m.EntryDateString != null) ? string.Join(".", m.EntryDateString.Split("-").Reverse()) : null; vm.EntryDate = (m.EntryDateString != null) ? string.Join(".", m.EntryDateString.Split("-").Reverse()) : null;
vm.ExitDate = (m.ExitDateString != null) ? string.Join(".", m.ExitDateString.Split("-").Reverse()) : null; vm.ExitDate = (m.ExitDateString != null) ? string.Join(".", m.ExitDateString.Split("-").Reverse()) : null;
vm.BusinessShares = m.BusinessShares; if (App.Client.HasRedWhite) {
vm.BusinessShares1 = m.SharesRed;
vm.BusinessShares2 = m.SharesWhite;
vm.BusinessShares3 = m.SharesDormant + m.Shares;
} else {
vm.BusinessShares1 = m.Shares;
vm.BusinessShares2 = m.SharesDormant + m.SharesRed + m.SharesWhite;
vm.BusinessShares3 = 0;
}
vm.AccountingNr = m.AccountingNr; vm.AccountingNr = m.AccountingNr;
vm.Branch = (Branch?)ControlUtils.GetItemFromSourceWithPk(vm.BranchSource, m.ZwstId); vm.Branch = (Branch?)ControlUtils.GetItemFromSourceWithPk(vm.BranchSource, m.ZwstId);
vm.DefaultKg = (AT_Kg?)ControlUtils.GetItemFromSourceWithPk(vm.DefaultKgSource, m.DefaultKgNr); vm.DefaultKg = (AT_Kg?)ControlUtils.GetItemFromSourceWithPk(vm.DefaultKgSource, m.DefaultKgNr);
@@ -172,7 +177,7 @@ namespace Elwig.Services {
var c = m.ActiveAreaCommitments(ctx, Utils.CurrentLastSeason); var c = m.ActiveAreaCommitments(ctx, Utils.CurrentLastSeason);
int maxKgPerHa = 10_000; int maxKgPerHa = 10_000;
try { try {
var s = await ctx.Seasons.FindAsync(await ctx.Seasons.MaxAsync(s => s.Year)); var s = await ctx.FetchSeasons().FirstOrDefaultAsync();
if (s != null) maxKgPerHa = s.MaxKgPerHa; if (s != null) maxKgPerHa = s.MaxKgPerHa;
} catch { } } catch { }
var (text, gridData) = await AreaComService.GenerateToolTipData(c, maxKgPerHa); var (text, gridData) = await AreaComService.GenerateToolTipData(c, maxKgPerHa);
@@ -225,8 +230,8 @@ namespace Elwig.Services {
var filter = vm.TextFilter; var filter = vm.TextFilter;
if (filter.Count > 0) { if (filter.Count > 0) {
var branches = await ctx.Branches.ToListAsync(); var branches = await ctx.FetchBranches().ToListAsync();
var mgnr = await ctx.Members.ToDictionaryAsync(m => m.MgNr.ToString(), m => m); var mgnr = await ctx.FetchMembers(includeNotActive: true).ToDictionaryAsync(m => m.MgNr.ToString(), m => m);
var kgs = await ctx.WbKgs.ToDictionaryAsync(k => k.AtKg.Name.ToLower(), k => k.AtKg); var kgs = await ctx.WbKgs.ToDictionaryAsync(k => k.AtKg.Name.ToLower(), k => k.AtKg);
var areaComs = await ctx.AreaCommitmentTypes.ToDictionaryAsync(t => $"{t.SortId}{t.AttrId}", t => t); var areaComs = await ctx.AreaCommitmentTypes.ToDictionaryAsync(t => $"{t.SortId}{t.AttrId}", t => t);
@@ -392,58 +397,29 @@ namespace Elwig.Services {
} }
public static async Task GenerateMemberDataSheet(Member m, ExportMode mode) { public static async Task GenerateMemberDataSheet(Member m, ExportMode mode) {
Mouse.OverrideCursor = Cursors.Wait; await Utils.RunForeground(async () => {
await Task.Run(async () => { using var doc = new MemberDataSheet(m);
try {
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")); await Utils.ExportDocument(doc, mode, emailData: (m, MemberDataSheet.Name, "Im Anhang finden Sie das aktuelle Stammdatenblatt"));
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
}); });
Mouse.OverrideCursor = null;
} }
public static async Task GenerateDeliveryConfirmation(Member m, int year, ExportMode mode) { public static async Task GenerateDeliveryConfirmation(Member m, int year, ExportMode mode) {
Mouse.OverrideCursor = Cursors.Wait; await Utils.RunForeground(async () => {
await Task.Run(async () => { var b = await Billing.Create(year);
try {
var b = new Billing(year);
await b.FinishSeason(); await b.FinishSeason();
await b.CalculateBuckets(); await b.CalculateBuckets();
App.HintContextChange(); App.HintContextChange();
using var ctx = new AppDbContext(); using var doc = new DeliveryConfirmation(year, m, null);
var data = await DeliveryConfirmationDeliveryData.ForMember(ctx.DeliveryParts, year, m);
using var doc = new DeliveryConfirmation(ctx, year, m, data);
await Utils.ExportDocument(doc, mode, emailData: (m, $"{DeliveryConfirmation.Name} {year}", $"Im Anhang finden Sie die Anlieferungsbestätigung {year}")); await Utils.ExportDocument(doc, mode, emailData: (m, $"{DeliveryConfirmation.Name} {year}", $"Im Anhang finden Sie die Anlieferungsbestätigung {year}"));
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
}); });
Mouse.OverrideCursor = null;
} }
public static async Task GenerateCreditNote(Member m, int year, int avnr, ExportMode mode) { public static async Task GenerateCreditNote(Member m, int year, int avnr, ExportMode mode) {
Mouse.OverrideCursor = Cursors.Wait; await Utils.RunForeground(async () => {
await Task.Run(async () => { using var doc = await CreditNote.Initialize(year, avnr, m.MgNr, null);
try { 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) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
}); });
Mouse.OverrideCursor = null;
} }
public static async Task GenerateMemberList(this MemberAdminViewModel vm, ExportSubject subject, ExportMode mode) { public static async Task GenerateMemberList(this MemberAdminViewModel vm, ExportSubject subject, ExportMode mode) {
@@ -488,76 +464,51 @@ namespace Elwig.Services {
} }
if (mode == ExportMode.SaveList) { if (mode == ExportMode.SaveList) {
var d = new SaveFileDialog() { var filename = InteractionService.SaveFile(MemberList.Name, MemberList.Name, "ods");
FileName = $"{MemberList.Name}.ods", if (filename != null) {
DefaultExt = "ods", await Utils.RunForeground(async () => {
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])); var data = await MemberListData.FromQuery(query, filterNames, filterNames.Where(f => f.StartsWith("Flächenbindung")).Select(f => f.Split(' ')[^1]));
using var ods = new OdsFile(d.FileName); using var ods = new OdsFile(filename);
await ods.AddTable(data); await ods.AddTable(data);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
}); });
Mouse.OverrideCursor = null;
} }
} else if (mode == ExportMode.Vcf) { } else if (mode == ExportMode.Vcf) {
var d = new SaveFileDialog() { var filename = InteractionService.SaveFile("Kontakte", "Mitglieder", "vcf");
FileName = "Mitglieder.vcf", if (filename != null) {
DefaultExt = "vcf", await Utils.RunForeground(async () => {
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 var members = await query
.OrderBy(m => m.MgNr) .OrderBy(m => m.MgNr)
.Include(m => m.BillingAddress)
.Include(m => m.TelephoneNumbers) .Include(m => m.TelephoneNumbers)
.Include(m => m.EmailAddresses) .Include(m => m.EmailAddresses)
.AsSplitQuery()
.ToListAsync(); .ToListAsync();
using var exporter = new VCard(d.FileName); using var exporter = new VCard(filename);
await exporter.ExportAsync(members); await exporter.ExportAsync(members);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
}); });
Mouse.OverrideCursor = null;
} }
} else if (mode == ExportMode.Export) { } else if (mode == ExportMode.Export) {
var d = new SaveFileDialog() { 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");
FileName = subject == ExportSubject.Selected ? $"Mitglied_{vm.SelectedMember?.MgNr}.elwig.zip" : $"Mitglieder_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{App.ZwstId}.elwig.zip", if (filename != null) {
DefaultExt = "elwig.zip", if (!filename.EndsWith(".elwig.zip")) filename += ".elwig.zip";
Filter = "Elwig-Export-Datei (*.elwig.zip)|*.elwig.zip", await Utils.RunForeground(async () => {
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 var members = await query
.OrderBy(m => m.MgNr) .OrderBy(m => m.MgNr)
.Include(m => m.BillingAddress)
.Include(m => m.TelephoneNumbers) .Include(m => m.TelephoneNumbers)
.Include(m => m.EmailAddresses) .Include(m => m.EmailAddresses)
.Include(m => m.DefaultWbKg!.Gl)
.AsSplitQuery()
.ToListAsync(); .ToListAsync();
var history1 = await query.IgnoreAutoIncludes()
.SelectMany(m => m.HistoryFrom)
.ToListAsync();
var history2 = await query.IgnoreAutoIncludes()
.SelectMany(m => m.HistoryTo)
.ToListAsync();
var history = history1.Union(history2)
.DistinctBy(h => h.HistNr)
.OrderBy(h => h.DateNotice).ThenBy(h => h.HistNr)
.ToList();
var areaComs = await query var areaComs = await query
.SelectMany(m => m.AreaCommitments) .SelectMany(m => m.AreaCommitments)
.Include(c => c.Rd) .Select(c => c.Contract).Distinct()
.Include(c => c.Kg.Gl) .Include(c => c.Revisions)
.ToListAsync(); .ToListAsync();
var wbKgs = members var wbKgs = members
.Where(m => m.DefaultWbKg != null) .Where(m => m.DefaultWbKg != null)
@@ -566,31 +517,19 @@ namespace Elwig.Services {
.Distinct() .Distinct()
.OrderBy(k => k.KgNr) .OrderBy(k => k.KgNr)
.ToList(); .ToList();
await ElwigData.Export(d.FileName, members, areaComs, wbKgs, filterNames); await ElwigData.Export(filename, members, history, areaComs, wbKgs, filterNames);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
}); });
Mouse.OverrideCursor = null;
} }
} else if (mode == ExportMode.Upload && App.Config.SyncUrl != null) { } else if (mode == ExportMode.Upload && App.Config.SyncUrl != null) {
Mouse.OverrideCursor = Cursors.Wait; await Utils.RunForeground(async () => {
await Task.Run(async () => {
await SyncService.Upload(App.Config.SyncUrl, App.Config.SyncUrl, App.Config.SyncPassword, query, filterNames); await SyncService.Upload(App.Config.SyncUrl, App.Config.SyncUrl, App.Config.SyncPassword, query, filterNames);
}); });
Mouse.OverrideCursor = null;
} else { } else {
Mouse.OverrideCursor = Cursors.Wait; await Utils.RunForeground(async () => {
await Task.Run(async () => {
try {
var data = await MemberListData.FromQuery(query, filterNames, filterNames.Where(f => f.StartsWith("Flächenbindung")).Select(f => f.Split(' ')[^1])); var data = await MemberListData.FromQuery(query, filterNames, filterNames.Where(f => f.StartsWith("Flächenbindung")).Select(f => f.Split(' ')[^1]));
using var doc = new MemberList(string.Join(" / ", filterNames), data); using var doc = new MemberList(string.Join(" / ", filterNames), data);
await Utils.ExportDocument(doc, mode); await Utils.ExportDocument(doc, mode);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
}); });
Mouse.OverrideCursor = null;
} }
} }
@@ -605,30 +544,33 @@ namespace Elwig.Services {
Name = vm.Name!, Name = vm.Name!,
Suffix = vm.IsJuridicalPerson || string.IsNullOrWhiteSpace(vm.Suffix) ? null : vm.Suffix, Suffix = vm.IsJuridicalPerson || string.IsNullOrWhiteSpace(vm.Suffix) ? null : vm.Suffix,
ForTheAttentionOf = !vm.IsJuridicalPerson || string.IsNullOrWhiteSpace(vm.ForTheAttentionOf) ? null : vm.ForTheAttentionOf, ForTheAttentionOf = !vm.IsJuridicalPerson || string.IsNullOrWhiteSpace(vm.ForTheAttentionOf) ? null : vm.ForTheAttentionOf,
Birthday = string.IsNullOrEmpty(vm.Birthday) ? null : string.Join("-", vm.Birthday!.Split(".").Reverse()), Birthday = string.IsNullOrWhiteSpace(vm.Birthday) ? null : string.Join("-", vm.Birthday!.Split(".").Reverse()),
IsDeceased = vm.IsDeceased, IsDeceased = vm.IsDeceased,
CountryNum = 40, // Austria AT AUT CountryNum = 40, // Austria AT AUT
PostalDestId = vm.Ort!.Id, PostalDestId = vm.Ort!.Id,
Address = vm.Address!, Address = vm.Address!,
Iban = string.IsNullOrEmpty(vm.Iban) ? null : vm.Iban?.Replace(" ", ""), Iban = string.IsNullOrWhiteSpace(vm.Iban) ? null : vm.Iban?.Replace(" ", ""),
Bic = string.IsNullOrEmpty(vm.Bic) ? null : vm.Bic, Bic = string.IsNullOrWhiteSpace(vm.Bic) ? null : vm.Bic,
UstIdNr = string.IsNullOrEmpty(vm.UstIdNr) ? null : vm.UstIdNr, UstIdNr = string.IsNullOrWhiteSpace(vm.UstIdNr) ? null : vm.UstIdNr,
LfbisNr = string.IsNullOrEmpty(vm.LfbisNr) ? null : vm.LfbisNr, LfbisNr = string.IsNullOrWhiteSpace(vm.LfbisNr) ? null : vm.LfbisNr,
IsBuchführend = vm.IsBuchführend, IsBuchführend = vm.IsBuchführend,
IsOrganic = vm.IsOrganic, IsOrganic = vm.IsOrganic,
EntryDateString = string.IsNullOrEmpty(vm.EntryDate) ? null : string.Join("-", vm.EntryDate.Split(".").Reverse()), EntryDateString = string.IsNullOrWhiteSpace(vm.EntryDate) ? null : string.Join("-", vm.EntryDate.Split(".").Reverse()),
ExitDateString = string.IsNullOrEmpty(vm.ExitDate) ? null : string.Join("-", vm.ExitDate.Split(".").Reverse()), ExitDateString = string.IsNullOrWhiteSpace(vm.ExitDate) ? null : string.Join("-", vm.ExitDate.Split(".").Reverse()),
BusinessShares = (int)vm.BusinessShares!, Shares = App.Client.HasRedWhite ? 0 : vm.BusinessShares1 ?? 0,
AccountingNr = string.IsNullOrEmpty(vm.AccountingNr) ? null : vm.AccountingNr, SharesRed = App.Client.HasRedWhite ? vm.BusinessShares1 ?? 0 : 0,
SharesWhite = App.Client.HasRedWhite ? vm.BusinessShares2 ?? 0 : 0,
SharesDormant = App.Client.HasRedWhite ? vm.BusinessShares3 ?? 0 : vm.BusinessShares2 ?? 0,
AccountingNr = string.IsNullOrWhiteSpace(vm.AccountingNr) ? null : vm.AccountingNr,
IsActive = vm.IsActive, IsActive = vm.IsActive,
IsVollLieferant = vm.IsVollLieferant, IsVollLieferant = vm.IsVollLieferant,
IsFunktionär = vm.IsFunktionär, IsFunktionär = vm.IsFunktionär,
ZwstId = vm.Branch?.ZwstId, ZwstId = vm.Branch?.ZwstId,
DefaultKgNr = vm.DefaultKg?.KgNr, DefaultKgNr = vm.DefaultKg?.KgNr,
Comment = string.IsNullOrEmpty(vm.Comment) ? null : vm.Comment, Comment = string.IsNullOrWhiteSpace(vm.Comment) ? null : vm.Comment,
ContactViaPost = vm.ContactViaPost, ContactViaPost = vm.ContactViaPost,
ContactViaEmail = vm.ContactViaEmail, ContactViaEmail = vm.ContactViaEmail,
}; };
@@ -681,19 +623,17 @@ namespace Elwig.Services {
.Where(c => c.MgNr == predecessor && (c.YearTo == null || c.YearTo >= year)) .Where(c => c.MgNr == predecessor && (c.YearTo == null || c.YearTo >= year))
.ToListAsync(); .ToListAsync();
var fbNr = await ctx.NextFbNr(); ctx.AddRange(await Task.WhenAll(areaComs.Select(async (c, i) => new AreaCom {
ctx.AddRange(areaComs.Select((c, i) => new AreaCom { FbNr = c.FbNr,
FbNr = fbNr + i, RevNr = await ctx.NextRevNr(c.FbNr),
MgNr = m.MgNr, MgNr = m.MgNr,
VtrgId = c.VtrgId, VtrgId = c.VtrgId,
CultId = c.CultId, CultId = c.CultId,
Area = c.Area, Area = c.Area,
KgNr = c.KgNr,
GstNr = c.GstNr, GstNr = c.GstNr,
RdNr = c.RdNr, YearFrom = year,
YearFrom = vm.MaintainAreaComYearFrom ? c.YearFrom : year,
YearTo = c.YearTo, YearTo = c.YearTo,
})); })));
foreach (var ac in areaComs) foreach (var ac in areaComs)
ac.YearTo = year - 1; ac.YearTo = year - 1;
@@ -725,18 +665,20 @@ namespace Elwig.Services {
public static async Task DeleteMember(int mgnr, bool deletePaymentData, bool deleteDeliveries, bool deleteAreaComs) { public static async Task DeleteMember(int mgnr, bool deletePaymentData, bool deleteDeliveries, bool deleteAreaComs) {
await Task.Run(async () => { await Task.Run(async () => {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
var l = (await ctx.Members.FindAsync(mgnr))!; using var tx = await ctx.Database.BeginTransactionAsync();
var l = await ctx.FetchMembers(mgnr).SingleAsync();
if (deletePaymentData) { if (deletePaymentData) {
ctx.RemoveRange(l.Credits); await ctx.Credits.Where(c => c.MgNr == mgnr).ExecuteDeleteAsync();
} }
if (deleteDeliveries) { if (deleteDeliveries) {
ctx.RemoveRange(l.Deliveries); await ctx.Deliveries.Where(c => c.MgNr == mgnr).ExecuteDeleteAsync();
} }
if (deleteAreaComs) { if (deleteAreaComs) {
ctx.RemoveRange(l.AreaCommitments); await ctx.AreaCommitments.Where(c => c.MgNr == mgnr).ExecuteDeleteAsync();
} }
ctx.Remove(l); ctx.Remove(l);
await ctx.SaveChangesAsync(); await ctx.SaveChangesAsync();
await tx.CommitAsync();
}); });
} }
} }
+60 -73
View File
@@ -6,13 +6,12 @@ using Elwig.Models.Dtos;
using Elwig.Models.Entities; using Elwig.Models.Entities;
using Elwig.ViewModels; using Elwig.ViewModels;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Win32;
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text.Json; using System.Text.Json;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows; using System.Windows;
using System.Windows.Input;
namespace Elwig.Services { namespace Elwig.Services {
public static class PaymentVariantService { public static class PaymentVariantService {
@@ -142,7 +141,7 @@ namespace Elwig.Services {
}); });
var credits = ctx.Credits.Where(c => c.Year == v.Year && c.AvNr == v.AvNr); var credits = ctx.Credits.Where(c => c.Year == v.Year && c.AvNr == v.AvNr);
if (!credits.Any()) { if (!(await credits.AnyAsync())) {
long lastTotalSum = 0; long lastTotalSum = 0;
decimal vatSum = 0; decimal vatSum = 0;
var currentPayments = await ctx.MemberPayments var currentPayments = await ctx.MemberPayments
@@ -150,8 +149,7 @@ namespace Elwig.Services {
.ToDictionaryAsync(p => p.MgNr); .ToDictionaryAsync(p => p.MgNr);
var lastV = await ctx.PaymentVariants var lastV = await ctx.PaymentVariants
.Where(l => l.Year == v.Year && !l.TestVariant) .Where(l => l.Year == v.Year && !l.TestVariant)
.OrderByDescending(l => l.TransferDateString ?? l.DateString) .OrderByDescending(l => l.TransferDateString ?? l.DateString).ThenByDescending(l => l.AvNr)
.ThenByDescending(l => l.AvNr)
.FirstOrDefaultAsync(); .FirstOrDefaultAsync();
if (lastV != null) { if (lastV != null) {
var lastPayments = await ctx.MemberPayments var lastPayments = await ctx.MemberPayments
@@ -160,8 +158,8 @@ namespace Elwig.Services {
lastTotalSum = lastPayments.Sum(e => e.Value.AmountValue); lastTotalSum = lastPayments.Sum(e => e.Value.AmountValue);
foreach (int mgnr in currentPayments.Keys) { foreach (int mgnr in currentPayments.Keys) {
var c = currentPayments[mgnr]; var c = currentPayments[mgnr];
var l = lastPayments[mgnr]; var l = lastPayments.GetValueOrDefault(mgnr);
vatSum += (c.Amount - l.Amount) * (decimal)(c.Member.IsBuchführend ? v.Season.VatNormal : v.Season.VatFlatrate); vatSum += (c.Amount - (l?.Amount ?? 0)) * (decimal)(c.Member.IsBuchführend ? v.Season.VatNormal : v.Season.VatFlatrate);
} }
} else { } else {
vatSum = currentPayments.Sum(e => e.Value.Amount * (decimal)(e.Value.Member.IsBuchführend ? v.Season.VatNormal : v.Season.VatFlatrate)); vatSum = currentPayments.Sum(e => e.Value.Amount * (decimal)(e.Value.Member.IsBuchführend ? v.Season.VatNormal : v.Season.VatFlatrate));
@@ -190,99 +188,58 @@ namespace Elwig.Services {
public static async Task GenerateSummary(PaymentVar v, ExportMode mode) { public static async Task GenerateSummary(PaymentVar v, ExportMode mode) {
if (mode == ExportMode.SaveList) { if (mode == ExportMode.SaveList) {
var d = new SaveFileDialog() { var filename = InteractionService.SaveFile($"Variantendaten {v.Name}", $"Variantendaten-{v.Name.Trim().Replace(' ', '-')}", "ods");
FileName = $"Variantendaten-{v.Name.Trim().Replace(' ', '-')}.ods", if (filename == null)
DefaultExt = "ods",
Filter = "OpenDocument Format Spreadsheet (*.ods)|*.ods",
Title = $"Variantendaten {v.Name} speichern unter - Elwig"
};
if (d.ShowDialog() == false)
return; return;
Mouse.OverrideCursor = Cursors.Wait; await Utils.RunForeground(async () => {
await Task.Run(async () => {
try {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
var data = await PaymentVariantSummaryData.ForPaymentVariant(v, ctx.PaymentVariantSummaryRows); var data = await PaymentVariantSummaryData.ForPaymentVariant(v, ctx.PaymentVariantSummaryRows);
using var ods = new OdsFile(d.FileName); using var ods = new OdsFile(filename);
await ods.AddTable(data); await ods.AddTable(data);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
}); });
Mouse.OverrideCursor = null;
} else { } else {
Mouse.OverrideCursor = Cursors.Wait; await Utils.RunForeground(async () => {
await Task.Run(async () => { using var doc = await PaymentVariantSummary.Initialize(v.Year, v.AvNr);
try {
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); await Utils.ExportDocument(doc, mode);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
}); });
Mouse.OverrideCursor = null;
} }
} }
public static async Task GenerateEbics(int year, int avnr) { public static async Task GenerateEbics(int year, int avnr) {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
var v = (await ctx.PaymentVariants.FindAsync(year, avnr))!; var v = await ctx.PaymentVariants.Include(v => v.Credits).Where(v => v.Year == year && v.AvNr == avnr).SingleAsync();
var withoutIban = v.Credits.Count(c => c.Member.Iban == null); var withoutIban = v.Credits.Count(c => c.Member.Iban == null);
if (withoutIban > 0) { if (withoutIban > 0) {
var r = MessageBox.Show($"Achtung: Für {withoutIban:N0} Mitglieder ist kein IBAN hinterlegt.\n\nDiese werden NICHT exportiert.", if (!InteractionService.AskContinue("Mitglieder ohne IBAN",
"Mitglieder ohne IBAN", MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel); $"Achtung: Für {withoutIban:N0} Mitglieder ist kein IBAN hinterlegt.\n\nDiese werden NICHT exportiert."))
if (r != MessageBoxResult.OK) return; return;
} }
var withNegAmount = v.Credits.Count(c => c.Amount <= 0); var withNegAmount = v.Credits.Count(c => c.Amount <= 0);
if (withNegAmount > 0) { if (withNegAmount > 0) {
var r = MessageBox.Show($"Achtung: Es gibt {withNegAmount:N0} Traubengutschriften mit negativem Betrag.\n\nDiese werden NICHT exportiert.", if (!InteractionService.AskContinue("Traubengutschriften mit negativem Betrag",
"Traubengutschriften mit negativem Betrag", MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.OK); $"Achtung: Es gibt {withNegAmount:N0} Traubengutschriften mit negativem Betrag.\n\nDiese werden NICHT exportiert."))
if (r != MessageBoxResult.OK) return; return;
} }
var d = new SaveFileDialog() { var filename = InteractionService.SaveFile("Überweisungsdaten", $"{App.Client.NameToken}-Überweisungsdaten-{v.Year}-{v.Name.Trim().Replace(' ', '-')}", Ebics.FileExtension);
FileName = $"{App.Client.NameToken}-Überweisungsdaten-{v.Year}-{v.Name.Trim().Replace(' ', '-')}.{Ebics.FileExtension}", if (filename != null) {
DefaultExt = Ebics.FileExtension, await Utils.RunForeground(async () => {
Filter = "EBICS-Datei (*.xml)|*.xml", using var e = new Ebics(v, filename, App.Client.ExportEbicsVersion, (Ebics.AddressMode)App.Client.ExportEbicsAddress);
Title = $"Überweisungsdaten speichern unter - Elwig",
};
if (d.ShowDialog() == true) {
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
using var e = new Ebics(v, d.FileName, App.Client.ExportEbicsVersion, (Ebics.AddressMode)App.Client.ExportEbicsAddress);
await e.ExportAsync(Transaction.FromPaymentVariant(v)); await e.ExportAsync(Transaction.FromPaymentVariant(v));
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
}); });
Mouse.OverrideCursor = null;
} }
} }
public static async Task GenerateAccountingList(int year, int avnr, string name) { public static async Task GenerateAccountingList(int year, int avnr, string name) {
var d = new SaveFileDialog() { var filename = InteractionService.SaveFile("Buchungsliste", $"{App.Client.NameToken}-Buchungsliste-{year}-{name.Trim().Replace(' ', '-')}", "ods");
FileName = $"{App.Client.NameToken}-Buchungsliste-{year}-{name.Trim().Replace(' ', '-')}.ods", if (filename != null) {
DefaultExt = "ods", await Utils.RunForeground(async () => {
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(); using var ctx = new AppDbContext();
var tbl = await CreditNoteData.ForPaymentVariant(ctx, year, avnr); var tbl = await CreditNoteData.ForPaymentVariant(ctx, year, avnr);
using var ods = new OdsFile(d.FileName); using var ods = new OdsFile(filename);
await ods.AddTable(tbl); await ods.AddTable(tbl);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
}); });
Mouse.OverrideCursor = null;
} }
} }
@@ -343,7 +300,7 @@ namespace Elwig.Services {
TransferDate = vm.TransferDate, TransferDate = vm.TransferDate,
TestVariant = vm.SelectedPaymentVariant?.TestVariant ?? true, TestVariant = vm.SelectedPaymentVariant?.TestVariant ?? true,
CalcTimeUnix = vm.SelectedPaymentVariant?.CalcTimeUnix, CalcTimeUnix = vm.SelectedPaymentVariant?.CalcTimeUnix,
Comment = string.IsNullOrEmpty(vm.Comment) ? null : vm.Comment, Comment = string.IsNullOrWhiteSpace(vm.Comment) ? null : vm.Comment,
Data = JsonSerializer.Serialize(d.Data), Data = JsonSerializer.Serialize(d.Data),
}; };
avnr = v.AvNr; avnr = v.AvNr;
@@ -365,21 +322,51 @@ namespace Elwig.Services {
public static async Task Calculate(int year, int avnr) { public static async Task Calculate(int year, int avnr) {
await Task.Run(async () => { await Task.Run(async () => {
var b = new BillingVariant(year, avnr); var b = await BillingVariant.Create(year, avnr);
await b.Calculate(); await b.Calculate();
}); });
} }
public static async Task Commit(int year, int avnr) { public static async Task Commit(int year, int avnr) {
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 () => { await Task.Run(async () => {
var b = new BillingVariant(year, avnr); var b = await BillingVariant.Create(year, avnr);
await b.Commit(); 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) { public static async Task Revert(int year, int avnr) {
await Task.Run(async () => { await Task.Run(async () => {
var b = new BillingVariant(year, avnr); var b = await BillingVariant.Create(year, avnr);
await b.Revert(); await b.Revert();
}); });
} }
+56 -69
View File
@@ -10,12 +10,12 @@ using System.Linq;
using System.Linq.Expressions; using System.Linq.Expressions;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows;
namespace Elwig.Services { namespace Elwig.Services {
public static class SyncService { public static class SyncService {
public static readonly Expression<Func<Member, bool>> ChangedMembers = (m) => ((m.XTime == null && m.MTime > 1751328000) || m.MTime > m.XTime) && (m.ITime == null || m.MTime > m.ITime); public static readonly Expression<Func<Member, bool>> ChangedMembers = (m) => ((m.XTime == null && m.MTime > 1751328000) || m.MTime > m.XTime) && (m.ITime == null || m.MTime > m.ITime);
public static readonly Expression<Func<AreaComContract, bool>> ChangedAreaComContracts = (c) => ((c.XTime == null && c.MTime > 1751328000) || c.MTime > c.XTime) && (c.ITime == null || c.MTime > c.ITime);
public static readonly Expression<Func<Delivery, bool>> ChangedDeliveries = (d) => ((d.XTime == null && d.MTime > 1751328000) || d.MTime > d.XTime) && (d.ITime == null || d.MTime > d.ITime); public static readonly Expression<Func<Delivery, bool>> ChangedDeliveries = (d) => ((d.XTime == null && d.MTime > 1751328000) || d.MTime > d.XTime) && (d.ITime == null || d.MTime > d.ITime);
public static async Task Upload(string url, string username, string password, IQueryable<Member> query, IEnumerable<string> filterNames) { public static async Task Upload(string url, string username, string password, IQueryable<Member> query, IEnumerable<string> filterNames) {
@@ -24,17 +24,24 @@ namespace Elwig.Services {
var path = Path.Combine(App.TempPath, filename); var path = Path.Combine(App.TempPath, filename);
var members = await query var members = await query
.OrderBy(m => m.MgNr) .OrderBy(m => m.MgNr)
.Include(m => m.BillingAddress)
.Include(m => m.TelephoneNumbers) .Include(m => m.TelephoneNumbers)
.Include(m => m.EmailAddresses) .Include(m => m.EmailAddresses)
.Include(m => m.DefaultWbKg!.Gl)
.AsSplitQuery()
.ToListAsync(); .ToListAsync();
var history1 = await query.IgnoreAutoIncludes()
.SelectMany(m => m.HistoryFrom)
.ToListAsync();
var history2 = await query.IgnoreAutoIncludes()
.SelectMany(m => m.HistoryTo)
.ToListAsync();
var history = history1.Union(history2)
.DistinctBy(h => h.HistNr)
.OrderBy(h => h.DateNotice).ThenBy(h => h.HistNr)
.ToList();
var areaComs = await query var areaComs = await query
.SelectMany(m => m.AreaCommitments) .SelectMany(m => m.AreaCommitments)
.OrderBy(c => c.MgNr).ThenBy(c => c.FbNr) .Select(c => c.Contract).Distinct()
.Include(c => c.Rd) .OrderBy(c => c.FbNr)
.Include(c => c.Kg.Gl) .Include(c => c.Revisions)
.ToListAsync(); .ToListAsync();
var wbKgs = members var wbKgs = members
.Where(m => m.DefaultWbKg != null) .Where(m => m.DefaultWbKg != null)
@@ -44,22 +51,20 @@ namespace Elwig.Services {
.OrderBy(k => k.KgNr) .OrderBy(k => k.KgNr)
.ToList(); .ToList();
if (members.Count == 0) { if (members.Count == 0) {
MessageBox.Show("Es wurden keine Mitglieder zum Hochladen ausgewählt!", "Mitglieder hochladen", InteractionService.ShowError("Mitglieder hochladen", "Es wurden keine Mitglieder zum Hochladen ausgewählt!");
MessageBoxButton.OK, MessageBoxImage.Error);
} else { } else {
var exportedAt = DateTime.Now; var exportedAt = DateTime.Now;
await ElwigData.Export(path, members, areaComs, wbKgs, filterNames); await ElwigData.Export(path, members, history, areaComs, wbKgs, filterNames);
await Utils.UploadExportData(path, url, username, password); await Utils.UploadExportData(path, url, username, password);
await UpdateExportedAt(members, [], exportedAt); await UpdateExportedAt(members, areaComs, [], exportedAt);
MessageBox.Show($"Hochladen von {members.Count:N0} Mitgliedern erfolgreich!", "Mitglieder hochgeladen", InteractionService.ShowInformation("Mitglieder hochgeladen", $"Hochladen von {members.Count:N0} Mitgliedern erfolgreich!");
MessageBoxButton.OK, MessageBoxImage.Information);
} }
} catch (HttpRequestException exc) { } catch (HttpRequestException exc) {
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Mitglieder hochladen", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException("Mitglieder hochladen", "Eventuell Internetverbindung prüfen!", exc);
} catch (TaskCanceledException exc) { } catch (TaskCanceledException exc) {
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Mitglieder hochladen", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException("Mitglieder hochladen", "Eventuell Internetverbindung prüfen!", exc);
} catch (Exception exc) { } catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException("Mitglieder hochladen", exc);
} }
} }
@@ -70,10 +75,7 @@ namespace Elwig.Services {
var list = await query var list = await query
.Select(p => p.Delivery) .Select(p => p.Delivery)
.Distinct() .Distinct()
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers).ThenInclude(m => m.Modifier) .Include(d => d.Parts).ThenInclude(p => p.PartModifiers)
.Include(d => d.Parts).ThenInclude(p => p.Rd)
.Include(d => d.Parts).ThenInclude(p => p.Kg!.Gl)
.AsSplitQuery()
.ToListAsync(); .ToListAsync();
var wbKgs = list var wbKgs = list
.SelectMany(d => d.Parts) .SelectMany(d => d.Parts)
@@ -83,22 +85,20 @@ namespace Elwig.Services {
.OrderBy(k => k.KgNr) .OrderBy(k => k.KgNr)
.ToList(); .ToList();
if (list.Count == 0) { if (list.Count == 0) {
MessageBox.Show("Es wurden keine Lieferungen zum Hochladen ausgewählt!", "Lieferungen hochladen", InteractionService.ShowError("Lieferungen hochladen", "Es wurden keine Lieferungen zum Hochladen ausgewählt!");
MessageBoxButton.OK, MessageBoxImage.Error);
} else { } else {
var exportedAt = DateTime.Now; var exportedAt = DateTime.Now;
await ElwigData.Export(path, list, wbKgs, filterNames); await ElwigData.Export(path, list, wbKgs, filterNames);
await Utils.UploadExportData(path, url, username, password); await Utils.UploadExportData(path, url, username, password);
await UpdateExportedAt([], list, exportedAt); await UpdateExportedAt([], [], list, exportedAt);
MessageBox.Show($"Hochladen von {list.Count:N0} Lieferungen erfolgreich!", "Lieferungen hochgeladen", InteractionService.ShowInformation("Lieferungen hochgeladen", $"Hochladen von {list.Count:N0} Lieferungen erfolgreich!");
MessageBoxButton.OK, MessageBoxImage.Information);
} }
} catch (HttpRequestException exc) { } catch (HttpRequestException exc) {
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Lieferungen hochladen", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException("Lieferungen hochladen", "Eventuell Internetverbindung prüfen!", exc);
} catch (TaskCanceledException exc) { } catch (TaskCanceledException exc) {
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException("Lieferungen hochladen", "Eventuell Internetverbindung prüfen!", exc);
} catch (Exception exc) { } catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException("Lieferungen hochladen", exc);
} }
} }
@@ -106,32 +106,24 @@ namespace Elwig.Services {
try { try {
var path = Path.Combine(App.TempPath, $"{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{App.ZwstId}.elwig.zip"); var path = Path.Combine(App.TempPath, $"{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{App.ZwstId}.elwig.zip");
List<Member> members; List<Member> members;
List<AreaCom> areaComs; List<AreaComContract> areaComs;
List<Delivery> deliveries; List<Delivery> deliveries;
using (var ctx = new AppDbContext()) { using (var ctx = new AppDbContext()) {
members = await ctx.Members members = await ctx.Members
.Where(ChangedMembers) .Where(ChangedMembers)
.Include(m => m.BillingAddress)
.Include(m => m.TelephoneNumbers) .Include(m => m.TelephoneNumbers)
.Include(m => m.EmailAddresses) .Include(m => m.EmailAddresses)
.Include(m => m.DefaultWbKg!.Gl)
.OrderBy(m => m.MgNr) .OrderBy(m => m.MgNr)
.AsSplitQuery()
.ToListAsync(); .ToListAsync();
areaComs = await ctx.Members areaComs = await ctx.AreaCommitmentContracts
.Where(ChangedMembers) .Where(ChangedAreaComContracts)
.SelectMany(m => m.AreaCommitments) .Include(c => c.Revisions)
.Include(c => c.Rd) .OrderBy(c => c.FbNr)
.Include(c => c.Kg.Gl)
.OrderBy(c => c.MgNr).ThenBy(c => c.FbNr)
.ToListAsync(); .ToListAsync();
deliveries = await ctx.Deliveries deliveries = await ctx.Deliveries
.Where(ChangedDeliveries) .Where(ChangedDeliveries)
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers).ThenInclude(m => m.Modifier) .Include(d => d.Parts).ThenInclude(p => p.PartModifiers)
.Include(d => d.Parts).ThenInclude(p => p.Rd)
.Include(d => d.Parts).ThenInclude(p => p.Kg).ThenInclude(k => k!.Gl)
.OrderBy(d => d.DateString).ThenBy(d => d.TimeString).ThenBy(d => d.LsNr) .OrderBy(d => d.DateString).ThenBy(d => d.TimeString).ThenBy(d => d.LsNr)
.AsSplitQuery()
.ToListAsync(); .ToListAsync();
} }
var wbKgs = members var wbKgs = members
@@ -145,27 +137,25 @@ namespace Elwig.Services {
.OrderBy(k => k.KgNr) .OrderBy(k => k.KgNr)
.ToList(); .ToList();
if (members.Count == 0 && deliveries.Count == 0) { if (members.Count == 0 && deliveries.Count == 0) {
MessageBox.Show("Es gibt keine geänderten Mitglieder oder Lieferungen, die hochgeladen werden könnten!", "Mitglieder und Lieferungen hochladen", InteractionService.ShowInformation("Mitglieder und Lieferungen hochladen", "Es gibt keine geänderten Mitglieder oder Lieferungen, die hochgeladen werden könnten!");
MessageBoxButton.OK, MessageBoxImage.Information);
} else { } else {
var exportedAt = DateTime.Now; var exportedAt = DateTime.Now;
await (new ElwigData.ElwigExport { await (new ElwigData.ElwigExport {
Members = (members, ["geändert seit letztem Export"]), Members = (members, ["geändert seit letztem Export"]),
AreaComs = (areaComs, ["von exportierten Mitgliedern"]), AreaComs = (areaComs, ["geändert seit letztem Export"]),
Deliveries = (deliveries, ["geändert seit letzem Export"]), Deliveries = (deliveries, ["geändert seit letzem Export"]),
WbKgs = (wbKgs, ["von exportierten Mitgliedern, Flächenbindungen und Lieferungen"]), WbKgs = (wbKgs, ["von exportierten Mitgliedern, Flächenbindungen und Lieferungen"]),
}).Export(path); }).Export(path);
await Utils.UploadExportData(path, url, username, password); await Utils.UploadExportData(path, url, username, password);
await UpdateExportedAt(members, deliveries, exportedAt); await UpdateExportedAt(members, areaComs, deliveries, exportedAt);
MessageBox.Show($"Hochladen von {members.Count:N0} Mitgliedern und {deliveries.Count:N0} Lieferungen erfolgreich!", "Mitglieder und Lieferungen hochladen", InteractionService.ShowInformation("Mitglieder und Lieferungen hochladen", $"Hochladen von {members.Count:N0} Mitgliedern, {areaComs.Count:N0} Flächenbindungsverträgen, und {deliveries.Count:N0} Lieferungen erfolgreich!");
MessageBoxButton.OK, MessageBoxImage.Information);
} }
} catch (HttpRequestException exc) { } catch (HttpRequestException exc) {
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Mitglieder und Lieferungen hochladen", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException("Mitglieder und Lieferungen hochladen", "Eventuell Internetverbindung prüfen!", exc);
} catch (TaskCanceledException exc) { } catch (TaskCanceledException exc) {
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Mitglieder und Lieferungen hochladen", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException("Mitglieder und Lieferungen hochladen", "Eventuell Internetverbindung prüfen!", exc);
} catch (Exception exc) { } catch (Exception exc) {
MessageBox.Show(exc.Message, "Mitglieder und Lieferungen hochladen", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException("Mitglieder und Lieferungen hochladen", exc);
} }
} }
@@ -176,11 +166,8 @@ namespace Elwig.Services {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
var deliveries = await ctx.Deliveries var deliveries = await ctx.Deliveries
.Where(d => d.Year == year && d.ZwstId == App.ZwstId) .Where(d => d.Year == year && d.ZwstId == App.ZwstId)
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers).ThenInclude(m => m.Modifier) .Include(d => d.Parts).ThenInclude(p => p.PartModifiers)
.Include(d => d.Parts).ThenInclude(p => p.Rd)
.Include(d => d.Parts).ThenInclude(p => p.Kg).ThenInclude(k => k!.Gl)
.OrderBy(d => d.DateString).ThenBy(d => d.TimeString).ThenBy(d => d.LsNr) .OrderBy(d => d.DateString).ThenBy(d => d.TimeString).ThenBy(d => d.LsNr)
.AsSplitQuery()
.ToListAsync(); .ToListAsync();
var wbKgs = deliveries var wbKgs = deliveries
.SelectMany(d => d.Parts) .SelectMany(d => d.Parts)
@@ -189,22 +176,20 @@ namespace Elwig.Services {
.DistinctBy(k => k.KgNr) .DistinctBy(k => k.KgNr)
.ToList(); .ToList();
if (deliveries.Count == 0) { if (deliveries.Count == 0) {
MessageBox.Show("Es gibt keine Lieferungen, die hochgeladen werden können!", "Lieferungen hochladen", InteractionService.ShowError("Lieferungen hochladen", "Es gibt keine Lieferungen, die hochgeladen werden können!");
MessageBoxButton.OK, MessageBoxImage.Error);
} else { } else {
var exportedAt = DateTime.Now; var exportedAt = DateTime.Now;
await ElwigData.Export(path, deliveries, wbKgs, [$"{year}", $"Zweigstelle {App.BranchName}"]); await ElwigData.Export(path, deliveries, wbKgs, [$"{year}", $"Zweigstelle {App.BranchName}"]);
await Utils.UploadExportData(path, url, username, password); await Utils.UploadExportData(path, url, username, password);
await UpdateExportedAt([], deliveries, exportedAt); await UpdateExportedAt([], [], deliveries, exportedAt);
MessageBox.Show($"Hochladen von {deliveries.Count:N0} Lieferungen erfolgreich!", "Lieferungen hochladen", InteractionService.ShowInformation("Lieferungen hochladen", $"Hochladen von {deliveries.Count:N0} Lieferungen erfolgreich!");
MessageBoxButton.OK, MessageBoxImage.Information);
} }
} catch (HttpRequestException exc) { } catch (HttpRequestException exc) {
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Lieferungen hochladen", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException("Lieferungen hochladen", "Eventuell Internetverbindung prüfen!", exc);
} catch (TaskCanceledException exc) { } catch (TaskCanceledException exc) {
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Lieferungen hochladen", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException("Lieferungen hochladen", "Eventuell Internetverbindung prüfen!", exc);
} catch (Exception exc) { } catch (Exception exc) {
MessageBox.Show(exc.Message, "Lieferungen hochladen", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException("Lieferungen hochladen", exc);
} }
} }
@@ -243,24 +228,26 @@ namespace Elwig.Services {
} }
await ElwigData.Import(paths, ElwigData.ImportMode.FromBranches); await ElwigData.Import(paths, ElwigData.ImportMode.FromBranches);
} catch (HttpRequestException exc) { } catch (HttpRequestException exc) {
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Daten herunterladen", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException("Daten herunterladen", "Eventuell Internetverbindung prüfen!", exc);
} catch (TaskCanceledException exc) { } catch (TaskCanceledException exc) {
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Daten herunterladen", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException("Daten herunterladen", "Eventuell Internetverbindung prüfen!", exc);
} catch (Exception exc) { } catch (Exception exc) {
MessageBox.Show(exc.Message, "Daten herunterladen", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException("Daten herunterladen", exc);
} }
} }
private static async Task UpdateExportedAt(IEnumerable<Member> member, IEnumerable<Delivery> deliveries, DateTime dateTime) { private static async Task UpdateExportedAt(IEnumerable<Member> member, IEnumerable<AreaComContract> contracts, IEnumerable<Delivery> deliveries, DateTime dateTime) {
var timestamp = ((DateTimeOffset)dateTime.ToUniversalTime()).ToUnixTimeSeconds(); var timestamp = ((DateTimeOffset)dateTime.ToUniversalTime()).ToUnixTimeSeconds();
var mgnrs = string.Join(",", member.Select(m => $"{m.MgNr}").Append("0")); var mgnrs = string.Join(",", member.Select(m => $"{m.MgNr}").Append("0"));
var fbnrs = string.Join(",", contracts.Select(c => $"{c.FbNr}").Append("0"));
var dids = string.Join(",", deliveries.Select(d => $"({d.Year},{d.DId})").Append("(0,0)")); var dids = string.Join(",", deliveries.Select(d => $"({d.Year},{d.DId})").Append("(0,0)"));
using (var cnx = await AppDbContext.ConnectAsync()) { using (var cnx = await AppDbContext.ConnectAsync()) {
await cnx.ExecuteBatch($""" await cnx.ExecuteBatch($"""
BEGIN; BEGIN;
UPDATE client_parameter SET value = '0' WHERE param = 'ENABLE_TIME_TRIGGERS'; UPDATE client_parameter SET value = '0' WHERE param = 'ENABLE_TIME_TRIGGERS';
UPDATE member SET xtime = {timestamp} WHERE mgnr IN ({mgnrs}); UPDATE member SET xtime = {timestamp} WHERE mgnr IN ({mgnrs});
UPDATE area_commitment SET xtime = {timestamp} WHERE mgnr IN ({mgnrs}); UPDATE area_commitment_contract SET xtime = {timestamp} WHERE fbnr IN ({fbnrs});
UPDATE area_commitment SET xtime = {timestamp} WHERE fbnr IN ({fbnrs});
UPDATE delivery SET xtime = {timestamp} WHERE (year, did) IN ({dids}); UPDATE delivery SET xtime = {timestamp} WHERE (year, did) IN ({dids});
UPDATE delivery_part SET xtime = {timestamp} WHERE (year, did) IN ({dids}); UPDATE delivery_part SET xtime = {timestamp} WHERE (year, did) IN ({dids});
UPDATE client_parameter SET value = '1' WHERE param = 'ENABLE_TIME_TRIGGERS'; UPDATE client_parameter SET value = '1' WHERE param = 'ENABLE_TIME_TRIGGERS';
@@ -272,7 +259,7 @@ namespace Elwig.Services {
public static async Task<bool> ChangesAvailable(AppDbContext ctx, string url, string username, string password) { public static async Task<bool> ChangesAvailable(AppDbContext ctx, string url, string username, string password) {
try { try {
return await ctx.Members.AnyAsync(ChangedMembers) || await ctx.Deliveries.AnyAsync(ChangedDeliveries) || (Utils.HasInternetConnectivity() && (await GetFilesToImport(url, username, password)).Count > 0); return await ctx.Members.Where(ChangedMembers).AnyAsync() || await ctx.AreaCommitmentContracts.Where(ChangedAreaComContracts).AnyAsync() || await ctx.Deliveries.Where(ChangedDeliveries).AnyAsync() || (Utils.HasInternetConnectivity() && (await GetFilesToImport(url, username, password)).Count > 0);
} catch { } catch {
return false; return false;
} }
+7 -1
View File
@@ -20,7 +20,11 @@ namespace Elwig.ViewModels {
} }
[ObservableProperty] [ObservableProperty]
private bool _showOnlyActiveAreaComs; private string? _filterSeasonString;
public int? FilterSeason {
get => int.TryParse(FilterSeasonString, out var year) ? year : null;
set => FilterSeasonString = $"{value}";
}
[ObservableProperty] [ObservableProperty]
private string? _fbNrString; private string? _fbNrString;
@@ -46,6 +50,8 @@ namespace Elwig.ViewModels {
get => int.TryParse(YearToString, out var year) ? year : null; get => int.TryParse(YearToString, out var year) ? year : null;
set => YearToString = $"{value}"; set => YearToString = $"{value}";
} }
[ObservableProperty]
private string? _period;
[ObservableProperty] [ObservableProperty]
private AreaComType? _areaComType; private AreaComType? _areaComType;
+19 -9
View File
@@ -6,12 +6,12 @@ using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Documents;
namespace Elwig.ViewModels { namespace Elwig.ViewModels {
public partial class MemberAdminViewModel : ObservableObject { public partial class MemberAdminViewModel : ObservableObject {
public int? TransferPredecessorAreaComs = null; public int? TransferPredecessorAreaComs = null;
public bool MaintainAreaComYearFrom = false;
public int? CancelAreaComs = null; public int? CancelAreaComs = null;
public ObservableCollection<KeyValuePair<string, string>> PhoneNrTypes { get; set; } = new(Utils.PhoneNrTypes); public ObservableCollection<KeyValuePair<string, string>> PhoneNrTypes { get; set; } = new(Utils.PhoneNrTypes);
@@ -21,7 +21,7 @@ namespace Elwig.ViewModels {
public List<string> TextFilter => [.. SearchQuery?.ToLower().Split(' ').ToList().FindAll(e => e.Length > 0) ?? []]; public List<string> TextFilter => [.. SearchQuery?.ToLower().Split(' ').ToList().FindAll(e => e.Length > 0) ?? []];
[ObservableProperty] [ObservableProperty]
private bool _showOnlyActiveMembers; private bool _showOnlyActiveMembers = true;
[ObservableProperty] [ObservableProperty]
private Member? _selectedMember; private Member? _selectedMember;
@@ -125,10 +125,22 @@ namespace Elwig.ViewModels {
[ObservableProperty] [ObservableProperty]
private string? _exitDate; private string? _exitDate;
[ObservableProperty] [ObservableProperty]
private string? _businessSharesString; private string? _businessShares1String;
public int? BusinessShares { public int? BusinessShares1 {
get => int.TryParse(BusinessSharesString, out var bs) ? bs : null; get => int.TryParse(BusinessShares1String, out var shares) ? shares : null;
set => BusinessSharesString = $"{value}"; set => BusinessShares1String = $"{value}";
}
[ObservableProperty]
private string? _businessShares2String;
public int? BusinessShares2 {
get => int.TryParse(BusinessShares2String, out var shares) ? shares : null;
set => BusinessShares2String = $"{value}";
}
[ObservableProperty]
private string? _businessShares3String;
public int? BusinessShares3 {
get => int.TryParse(BusinessShares3String, out var shares) ? shares : null;
set => BusinessShares3String = $"{value}";
} }
[ObservableProperty] [ObservableProperty]
private string? _accountingNr; private string? _accountingNr;
@@ -189,9 +201,7 @@ namespace Elwig.ViewModels {
[ObservableProperty] [ObservableProperty]
private string? _statusMembersToolTip; private string? _statusMembersToolTip;
[ObservableProperty] [ObservableProperty]
private string _statusBusinessShares = "-"; private TextBlock? _statusBusinessShares;
[ObservableProperty]
private string? _statusBusinessSharesToolTip;
[ObservableProperty] [ObservableProperty]
private string _statusDeliveriesLastSeason = "-"; private string _statusDeliveriesLastSeason = "-";
[ObservableProperty] [ObservableProperty]
@@ -0,0 +1,76 @@
using CommunityToolkit.Mvvm.ComponentModel;
using Elwig.Models.Entities;
using System;
using System.Collections.Generic;
using System.Windows;
namespace Elwig.ViewModels {
public partial class MemberBusinessSharesViewModel : ObservableObject {
[ObservableProperty]
private string _title = "Geschäftsanteilbewegungen - Elwig";
public required Member FilterMember { get; set; }
[ObservableProperty]
private MemberHistory? _selectedHistoryEntry;
[ObservableProperty]
private IEnumerable<MemberHistory> _history = [];
[ObservableProperty]
private string? _dateNoticeString;
public DateOnly? DateNotice {
get => DateOnly.TryParseExact(DateNoticeString, "dd.MM.yyyy", out var d) ? d : null;
set => DateNoticeString = $"{value:dd.MM.yyyy}";
}
[ObservableProperty]
private string? _dateEffectiveString;
public DateOnly? DateEffective {
get => DateOnly.TryParseExact(DateEffectiveString, "dd.MM.yyyy", out var d) ? d : null;
set => DateEffectiveString = $"{value:dd.MM.yyyy}";
}
[ObservableProperty]
private string? _reason;
[ObservableProperty]
private string? _sharesString;
public int? Shares {
get => int.TryParse(SharesString, out var shares) ? shares : null;
set => SharesString = $"{value}";
}
[ObservableProperty]
private string? _otherMgNrString;
public int? OtherMgNr {
get => int.TryParse(OtherMgNrString, out var mgnr) ? mgnr : null;
set => OtherMgNrString = $"{value}";
}
[ObservableProperty]
private string? _deductYearString;
public int? DeductYear {
get => int.TryParse(DeductYearString, out var year) ? year : null;
set => DeductYearString = $"{value}";
}
[ObservableProperty]
private bool _deduct;
[ObservableProperty]
private bool _memberHasSigned;
[ObservableProperty]
private string? _valuePerShareString;
public decimal? ValuePerShare {
get => decimal.TryParse(ValuePerShareString, out var v) ? v : null;
set => ValuePerShareString = $"{value:0.00}";
}
[ObservableProperty]
private string? _totalAmount;
[ObservableProperty]
private string? _comment;
[ObservableProperty]
private Visibility _controlButtonsVisibility = Visibility.Visible;
[ObservableProperty]
private Visibility _editingButtonsVisibility = Visibility.Hidden;
[ObservableProperty]
private Visibility _personalNameVisibility = Visibility.Visible;
[ObservableProperty]
private Visibility _juridicalNameVisibility = Visibility.Hidden;
}
}
+1 -1
View File
@@ -15,7 +15,7 @@
<Bold>Website:</Bold> <Hyperlink NavigateUri="https://elwig.at/" RequestNavigate="Hyperlink_RequestNavigate">https://elwig.at/</Hyperlink><LineBreak/> <Bold>Website:</Bold> <Hyperlink NavigateUri="https://elwig.at/" RequestNavigate="Hyperlink_RequestNavigate">https://elwig.at/</Hyperlink><LineBreak/>
<Bold>Entwickler:</Bold> Lorenz Stechauner, Thomas Hilscher<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>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="https://git.necronda.net/winzer/elwig" RequestNavigate="Hyperlink_RequestNavigate">https://git.necronda.net/winzer/elwig</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>Entwicklungszeitraum:</Bold> 20222026<LineBreak/> <Bold>Entwicklungszeitraum:</Bold> 20222026<LineBreak/>
<LineBreak/> <LineBreak/>
<Bold>Verwendete Technologien:</Bold><LineBreak/> <Bold>Verwendete Technologien:</Bold><LineBreak/>
+8
View File
@@ -11,7 +11,15 @@ namespace Elwig.Windows {
} }
private void Hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e) { private void Hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e) {
try {
Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri) { UseShellExecute = true }); 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 { }
} }
} }
} }
+12 -8
View File
@@ -9,6 +9,7 @@ using System.Threading.Tasks;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Input; using System.Windows.Input;
using Elwig.Services;
namespace Elwig.Windows { namespace Elwig.Windows {
public abstract class AdministrationWindow : ContextWindow { public abstract class AdministrationWindow : ContextWindow {
@@ -104,13 +105,12 @@ namespace Elwig.Windows {
cb.SelectionChanged += ComboBox_SelectionChanged; cb.SelectionChanged += ComboBox_SelectionChanged;
foreach (var lb in ListBoxInputs) foreach (var lb in ListBoxInputs)
lb.SelectionChanged += ComboBox_SelectionChanged; lb.SelectionChanged += ComboBox_SelectionChanged;
LockInputs();
} }
private void OnClosing(object? sender, CancelEventArgs evt) { private void OnClosing(object? sender, CancelEventArgs evt) {
if ((IsCreating || IsEditing) && HasChanged) { if ((IsCreating || IsEditing) && HasChanged) {
var r = MessageBox.Show("Soll das Fenster wirklich geschlossen werden?", "Schließen bestätigen", if (!InteractionService.AskConfirmation("Schließen bestätigen", "Soll das Fenster wirklich geschlossen werden?")) {
MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No);
if (r != MessageBoxResult.Yes) {
evt.Cancel = true; evt.Cancel = true;
return; return;
} }
@@ -164,10 +164,10 @@ namespace Elwig.Windows {
} else if (input is TextBox tb && tb.Text.Length == 0) { } else if (input is TextBox tb && tb.Text.Length == 0) {
ControlUtils.SetInputInvalid(input); ControlUtils.SetInputInvalid(input);
Valid[input] = false; Valid[input] = false;
} else if (input is ComboBox cb && cb.SelectedItem == null && cb.ItemsSource != null && cb.ItemsSource.Cast<object>().Any()) { } else if (input is ComboBox cb && cb.SelectedItem == null && cb.HasItems) {
ControlUtils.SetInputInvalid(input); ControlUtils.SetInputInvalid(input);
Valid[input] = false; Valid[input] = false;
} else if (input is ListBox lb && lb.SelectedItem == null && lb.ItemsSource != null && lb.ItemsSource.Cast<object>().Any()) { } else if (input is ListBox lb && lb.SelectedItem == null && lb.HasItems) {
ControlUtils.SetInputInvalid(input); ControlUtils.SetInputInvalid(input);
Valid[input] = false; Valid[input] = false;
} else if (input is CheckBox ckb && ((ckb.IsThreeState && ckb.IsChecked == null) || (!ckb.IsThreeState && ckb.IsChecked != true))) { } else if (input is CheckBox ckb && ((ckb.IsThreeState && ckb.IsChecked == null) || (!ckb.IsThreeState && ckb.IsChecked != true))) {
@@ -285,8 +285,13 @@ namespace Elwig.Windows {
var binding = cb.GetBindingExpression(ComboBox.SelectedItemProperty); var binding = cb.GetBindingExpression(ComboBox.SelectedItemProperty);
binding?.UpdateSource(); binding?.UpdateSource();
} }
foreach (var lb in ListBoxInputs) foreach (var lb in ListBoxInputs) {
if (lb.SelectionMode == SelectionMode.Single) {
lb.SelectedItem = null;
} else {
lb.SelectedItems.Clear(); lb.SelectedItems.Clear();
}
}
foreach (var cb in CheckBoxInputs) { foreach (var cb in CheckBoxInputs) {
cb.IsChecked = cb.IsThreeState ? null : false; cb.IsChecked = cb.IsThreeState ? null : false;
var binding = cb.GetBindingExpression(CheckBox.IsCheckedProperty); var binding = cb.GetBindingExpression(CheckBox.IsCheckedProperty);
@@ -349,7 +354,6 @@ namespace Elwig.Windows {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
list = await ctx.PlzDestinations list = await ctx.PlzDestinations
.Where(p => p.Plz == plz) .Where(p => p.Plz == plz)
.Include(p => p.Ort)
.ToListAsync(); .ToListAsync();
} }
@@ -390,7 +394,7 @@ namespace Elwig.Windows {
protected bool InputLostFocus(TextBox input, ValidationResult res, string? msg = null) { protected bool InputLostFocus(TextBox input, ValidationResult res, string? msg = null) {
if (DoShowWarningWindows && !res.IsValid && !IsClosing && (IsEditing || IsCreating)) if (DoShowWarningWindows && !res.IsValid && !IsClosing && (IsEditing || IsCreating))
MessageBox.Show(res.ErrorContent?.ToString(), msg ?? res.ErrorContent?.ToString(), MessageBoxButton.OK, MessageBoxImage.Warning); InteractionService.ShowWarning(msg ?? res.ErrorContent?.ToString() ?? "", res.ErrorContent?.ToString() ?? "");
return res.IsValid; return res.IsValid;
} }
+94 -67
View File
@@ -7,8 +7,7 @@
xmlns:local="clr-namespace:Elwig.Windows" xmlns:local="clr-namespace:Elwig.Windows"
xmlns:ctrl="clr-namespace:Elwig.Controls" xmlns:ctrl="clr-namespace:Elwig.Controls"
xmlns:vm="clr-namespace:Elwig.ViewModels" xmlns:vm="clr-namespace:Elwig.ViewModels"
Title="{Binding Title}" Height="600" MinHeight="450" Width="1000" MinWidth="860" Title="{Binding Title}" Height="600" MinHeight="550" Width="1000" MinWidth="860">
Loaded="Window_Loaded">
<Window.DataContext> <Window.DataContext>
<vm:AreaComAdminViewModel/> <vm:AreaComAdminViewModel/>
</Window.DataContext> </Window.DataContext>
@@ -57,7 +56,7 @@
<RowDefinition Height="24"/> <RowDefinition Height="24"/>
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="3*" MinWidth="500"/> <ColumnDefinition Width="2*" MinWidth="500"/>
<ColumnDefinition Width="5"/> <ColumnDefinition Width="5"/>
<ColumnDefinition Width="*" MinWidth="280"/> <ColumnDefinition Width="*" MinWidth="280"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
@@ -78,7 +77,7 @@
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<TextBox x:Name="SearchInput" Text="{Binding SearchQuery, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" <TextBox x:Name="SearchInput" Text="{Binding SearchQuery, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Grid.ColumnSpan="3" Margin="5,5,190,0" IsReadOnly="False" Grid.ColumnSpan="3" Margin="5,5,66,0" IsReadOnly="False"
TextChanged="SearchInput_TextChanged"> TextChanged="SearchInput_TextChanged">
<TextBox.ToolTip> <TextBox.ToolTip>
<TextBlock> <TextBlock>
@@ -94,9 +93,10 @@
</TextBlock> </TextBlock>
</TextBox.ToolTip> </TextBox.ToolTip>
</TextBox> </TextBox>
<CheckBox x:Name="ActiveAreaCommitmentInput" Content="Nur laufende anzeigen (2020)" IsChecked="{Binding ShowOnlyActiveAreaComs}" <ctrl:IntegerUpDown x:Name="SeasonInput" Text="{Binding FilterSeasonString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Checked="ActiveAreaCommitmentInput_Changed" Unchecked="ActiveAreaCommitmentInput_Changed" Grid.ColumnSpan="3" Height="25" Width="56" FontSize="14" Minimum="1900" Maximum="9999"
HorizontalAlignment="Right" Margin="0,10,10,0" VerticalAlignment="Top" Grid.Column="1" Grid.ColumnSpan="2"/> Margin="0,5,5,0" VerticalAlignment="Top" HorizontalAlignment="Right"
TextChanged="SeasonInput_TextChanged"/>
<DataGrid x:Name="AreaCommitmentList" AutoGenerateColumns="False" HeadersVisibility="Column" IsReadOnly="True" GridLinesVisibility="None" SelectionMode="Single" <DataGrid x:Name="AreaCommitmentList" AutoGenerateColumns="False" HeadersVisibility="Column" IsReadOnly="True" GridLinesVisibility="None" SelectionMode="Single"
CanUserDeleteRows="False" CanUserResizeRows="False" CanUserAddRows="False" SelectionChanged="AreaCommitmentList_SelectionChanged" Grid.Column="0" Grid.Row="1" CanUserDeleteRows="False" CanUserResizeRows="False" CanUserAddRows="False" SelectionChanged="AreaCommitmentList_SelectionChanged" Grid.Column="0" Grid.Row="1"
@@ -110,25 +110,24 @@
</DataGridTextColumn.CellStyle> </DataGridTextColumn.CellStyle>
</DataGridTextColumn> </DataGridTextColumn>
<DataGridTextColumn Header="Katastralgemeinde" Binding="{Binding Kg.AtKg.Name}" Width="130"/> <DataGridTextColumn Header="Katastralgemeinde" Binding="{Binding Kg.AtKg.Name}" Width="130"/>
<DataGridTextColumn Header="Sorte" Binding="{Binding AreaComType.WineVar.SortId}" Width="50"> <DataGridTextColumn Header="Sorte" Binding="{Binding Latest.AreaComType.VtrgId}" Width="50">
<DataGridTextColumn.CellStyle> <DataGridTextColumn.CellStyle>
<Style> <Style>
<Setter Property="TextBlock.Foreground" Value="{Binding AreaComType.WineVar.Color}"/> <Setter Property="TextBlock.Foreground" Value="{Binding Latest.AreaComType.WineVar.Color}"/>
<Setter Property="TextBlock.TextAlignment" Value="Center"/> <Setter Property="TextBlock.TextAlignment" Value="Center"/>
</Style> </Style>
</DataGridTextColumn.CellStyle> </DataGridTextColumn.CellStyle>
</DataGridTextColumn> </DataGridTextColumn>
<DataGridTextColumn Header="Fläche" Binding="{Binding Area, StringFormat='{}{0:N0} m² '}" Width="80"> <DataGridTextColumn Header="Fläche" Binding="{Binding Latest.Area, StringFormat='{}{0:N0} m² '}" Width="80">
<DataGridTextColumn.CellStyle> <DataGridTextColumn.CellStyle>
<Style> <Style>
<Setter Property="TextBlock.TextAlignment" Value="Right"/> <Setter Property="TextBlock.TextAlignment" Value="Right"/>
</Style> </Style>
</DataGridTextColumn.CellStyle> </DataGridTextColumn.CellStyle>
</DataGridTextColumn> </DataGridTextColumn>
<DataGridTextColumn Header="Attribut" Binding="{Binding AreaComType.WineAttr.Name}" Width="100"/>
<DataGridTextColumn Header="Ried" Binding="{Binding Rd.Name}" Width="130"/> <DataGridTextColumn Header="Ried" Binding="{Binding Rd.Name}" Width="130"/>
<DataGridTextColumn Header="Parzelle" Binding="{Binding GstNr}" Width="130"/> <DataGridTextColumn Header="Parzelle" Binding="{Binding Latest.GstNr}" Width="130"/>
<DataGridTextColumn Header="Bewirt." Binding="{Binding WineCult.Name}" Width="60"/> <DataGridTextColumn Header="Bewirt." Binding="{Binding Latest.WineCult.Name}" Width="60"/>
<DataGridTextColumn Header="Von" Binding="{Binding YearFrom}" Width="48"/> <DataGridTextColumn Header="Von" Binding="{Binding YearFrom}" Width="48"/>
<DataGridTextColumn Header="Bis" Binding="{Binding YearTo}" Width="48"/> <DataGridTextColumn Header="Bis" Binding="{Binding YearTo}" Width="48"/>
</DataGrid.Columns> </DataGrid.Columns>
@@ -177,91 +176,119 @@
<Grid Grid.Column="2" Grid.Row="1"> <Grid Grid.Column="2" Grid.Row="1">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="1.125*"/> <RowDefinition Height="*"/>
<RowDefinition Height="1*"/> <RowDefinition Height="230"/>
</Grid.RowDefinitions> </Grid.RowDefinitions>
<GroupBox Header="Vertrag" Grid.Column="2" Grid.Row="0" Grid.RowSpan="1" Margin="5,5,5,5"> <GroupBox Header="Vertrag" Grid.Row="0" Margin="5,5,5,5">
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="80"/> <ColumnDefinition Width="80"/>
<ColumnDefinition Width="48"/> <ColumnDefinition Width="60"/>
<ColumnDefinition Width="60"/> <ColumnDefinition Width="60"/>
<ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Label Content="MgNr.:" Margin="10,10,0,0" Grid.Column="0"/> <Label Content="FB-Nr.:" Margin="10,10,0,0" Grid.Column="0"/>
<TextBox x:Name="MgNrInput" Text="{Binding MgNrString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsEnabled="False"
Margin="0,10,0,0" Width="48" HorizontalAlignment="Left" Grid.Column="1" TextAlignment="Right"/>
<Label Content="FbNr.:" Margin="10,10,0,0" Grid.Column="2"/>
<TextBox x:Name="FbNrInput" Text="{Binding FbNrString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" <TextBox x:Name="FbNrInput" Text="{Binding FbNrString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,10,10,0" Width="56" HorizontalAlignment="Left" Grid.Column="3" TextAlignment="Right" Margin="0,10,0,0" Width="56" HorizontalAlignment="Left" Grid.Column="1" TextAlignment="Right"
TextChanged="FbNrInput_TextChanged" LostFocus="FbNrInput_LostFocus"/> TextChanged="FbNrInput_TextChanged" LostFocus="FbNrInput_LostFocus"/>
<Label Content="Zeitraum:" Margin="10,40,0,0" Grid.Column="0"/> <Label Content="Laufzeit:" Margin="10,10,0,0" Grid.Column="2"/>
<TextBox x:Name="YearFromInput" Text="{Binding YearFromString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" <TextBlock x:Name="Period" Text="{Binding Period}"
Margin="0,40,10,0" Width="40" HorizontalAlignment="Left" Grid.Column="1" Grid.ColumnSpan="2" TextAlignment="Right" Margin="0,14,10,0" Grid.Column="3" TextWrapping="NoWrap" VerticalAlignment="Top"/>
TextChanged="IntegerInput_TextChanged"/>
<Label Content="" Grid.Column="1" Grid.ColumnSpan="3" Margin="45,40,0,0"/>
<TextBox x:Name="YearToInput" Text="{Binding YearToString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="60,40,10,0" Width="40" HorizontalAlignment="Left" Grid.Column="1" Grid.ColumnSpan="3" TextAlignment="Right"
TextChanged="IntegerInput_TextChanged"/>
<Label Content="Vertragsart:" Margin="10,70,0,0" Grid.Column="0" Grid.ColumnSpan="2"/> <Label Content="KG:" Margin="10,40,0,0" Grid.Column="0"/>
<ComboBox x:Name="AreaComTypeInput" SelectedItem="{Binding AreaComType, Mode=TwoWay}" ItemsSource="{Binding AreaComTypeSource, Mode=TwoWay}" <ComboBox x:Name="KgInput" SelectedItem="{Binding Kg, Mode=TwoWay}" ItemsSource="{Binding KgSource, Mode=TwoWay}"
ItemTemplate="{StaticResource AreaCommitmentTypeTemplate}" TextSearch.TextPath="DisplayName" ItemTemplate="{StaticResource KgNrTemplate}" TextSearch.TextPath="Name"
HorizontalAlignment="Stretch" Margin="0,70,40,10" Grid.Column="1" Grid.ColumnSpan="3"/> HorizontalAlignment="Stretch" Margin="0,40,40,10" Grid.Column="1" Grid.ColumnSpan="3"
<Button x:Name="AreaComTypeDetailsButton" Content="&#xE712;" FontFamily="Segoe MDL2 Assets" FontSize="14" Padding="0,1,0,0" SelectionChanged="KgInput_SelectionChanged"/>
Click="AreaComTypeDetailsButton_Click" <Button x:Name="KgDetailsButton" Content="&#xE712;" FontFamily="Segoe MDL2 Assets" FontSize="14" Padding="0,1,0,0"
Click="KgDetailsButton_Click"
Grid.Column="3" VerticalAlignment="Top" HorizontalAlignment="Right" Width="25" Height="25" Margin="10,40,10,10"/>
<Label Content="Ried:" Margin="10,70,0,0" Grid.Column="0"/>
<ComboBox x:Name="RdInput" SelectedItem="{Binding RdObj, Mode=TwoWay}" ItemsSource="{Binding RdSource, Mode=TwoWay}"
DisplayMemberPath="Name" TextSearch.TextPath="Name" IsEditable="True"
HorizontalAlignment="Stretch" Margin="0,70,40,10" Grid.Column="1" Grid.ColumnSpan="3"
SelectionChanged="RdInput_SelectionChanged"/>
<Button x:Name="RdAddButton" Content="&#xE73E;" FontFamily="Segoe MDL2 Assets" FontSize="16" Padding="0,0,0,0" IsEnabled="False"
Click="RdAddButton_Click"
Grid.Column="3" VerticalAlignment="Top" HorizontalAlignment="Right" Width="25" Height="25" Margin="10,70,10,10"/> Grid.Column="3" VerticalAlignment="Top" HorizontalAlignment="Right" Width="25" Height="25" Margin="10,70,10,10"/>
<Label Content="Bewirt.-Art:" Margin="10,100,0,0" Grid.Column="0" Grid.ColumnSpan="2"/> <Label Content="Anmerkung:" Margin="10,100,0,0" Grid.Column="0" Grid.ColumnSpan="2"/>
<ComboBox x:Name="WineCultivationInput" SelectedItem="{Binding WineCultObj, Mode=TwoWay}" ItemsSource="{Binding WineCultSource, Mode=TwoWay}"
DisplayMemberPath="Name" TextSearch.TextPath="Name"
HorizontalAlignment="Stretch" Margin="0,100,10,0" Grid.Column="1" Grid.ColumnSpan="3"/>
<Label Content="Anmerkung:" Margin="10,130,0,0" Grid.Column="0" Grid.ColumnSpan="2"/>
<TextBox x:Name="CommentInput" Text="{Binding Comment, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" <TextBox x:Name="CommentInput" Text="{Binding Comment, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
TextChanged="TextBox_TextChanged" TextChanged="TextBox_TextChanged"
HorizontalAlignment="Stretch" Margin="0,130,10,0" Grid.Column="1" Grid.ColumnSpan="3"/> HorizontalAlignment="Stretch" Margin="0,100,10,0" Grid.Column="1" Grid.ColumnSpan="3"/>
<ListBox x:Name="RevisionList" Grid.ColumnSpan="4" Margin="5,135,5,5"
SelectionChanged="RevisionList_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding YearFrom}" Width="28" TextAlignment="Right" Margin="0,0,0,0"/>
<TextBlock Text="&#x2013;" TextAlignment="Center" Margin="0,0,0,0"/>
<TextBlock Text="{Binding YearTo}" Width="28" TextAlignment="Left" Margin="0,0,0,0"/>
<TextBlock Text="{Binding VtrgId}" Width="40" TextAlignment="Center" Foreground="{Binding AreaComType.WineVar.Color}"/>
<TextBlock Text="{Binding Area, StringFormat='{}{0:N0} m²'}" Width="60" TextAlignment="Right" Padding="0,0,10,0"/>
<TextBlock Text="{Binding Member.AdministrativeName}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid> </Grid>
</GroupBox> </GroupBox>
<GroupBox Header="Lage" Grid.Column="2" Grid.Row="1" Grid.RowSpan="1" Margin="5,5,5,10"> <GroupBox Header="Revision" Grid.Row="1" Margin="5,5,5,10">
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="80"/> <ColumnDefinition Width="80"/>
<ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Label Content="KG:" Margin="10,10,0,0" Grid.Column="0"/> <Label Content="Mitglied:" Margin="10,10,0,0" Grid.Column="0"/>
<ComboBox x:Name="KgInput" SelectedItem="{Binding Kg, Mode=TwoWay}" ItemsSource="{Binding KgSource, Mode=TwoWay}" <TextBox x:Name="MgNrInput" Text="{Binding MgNrString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
ItemTemplate="{StaticResource KgNrTemplate}" TextSearch.TextPath="Name" Width="48" Grid.Row="1" Grid.Column="1" Margin="0,10,0,0" HorizontalAlignment="Left" TextAlignment="Right"
HorizontalAlignment="Stretch" Margin="0,10,40,10" Grid.Column="1" TextChanged="MgNrInput_TextChanged" LostFocus="MgNrInput_LostFocus"/>
SelectionChanged="KgInput_SelectionChanged"/> <ComboBox x:Name="MemberInput"
<Button x:Name="KgDetailsButton" Content="&#xE712;" FontFamily="Segoe MDL2 Assets" FontSize="14" Padding="0,1,0,0" Grid.Column="1" Margin="53,10,40,10" IsEditable="True"
Click="KgDetailsButton_Click" ItemTemplate="{StaticResource MemberAdminNameTemplate}" TextSearch.TextPath="AdministrativeName"
Grid.Column="1" VerticalAlignment="Top" HorizontalAlignment="Right" Width="25" Height="25" Margin="10,10,10,10"/> SelectionChanged="MemberInput_SelectionChanged"/>
<Button x:Name="MemberReferenceButton" Grid.Column="1" Height="25" Width="25" FontFamily="Segoe MDL2 Assets" Content="&#xEE35;" Padding="0,0,0,0"
Margin="10,10,10,10" VerticalAlignment="Top" HorizontalAlignment="Right" ToolTip="Zu Mitglied springen"
Click="MemberReferenceButton_Click"/>
<Label Content="Ried:" Margin="10,40,0,0" Grid.Column="0"/> <Label Content="Laufzeit:" Margin="10,40,0,0" Grid.Column="0"/>
<ComboBox x:Name="RdInput" SelectedItem="{Binding RdObj, Mode=TwoWay}" ItemsSource="{Binding RdSource, Mode=TwoWay}" <TextBox x:Name="YearFromInput" Text="{Binding YearFromString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
DisplayMemberPath="Name" TextSearch.TextPath="Name" IsEditable="True" Margin="0,40,10,0" Width="40" HorizontalAlignment="Left" Grid.Column="1" TextAlignment="Right"
HorizontalAlignment="Stretch" Margin="0,40,40,10" Grid.Column="1" TextChanged="IntegerInput_TextChanged"/>
SelectionChanged="RdInput_SelectionChanged"/> <Label Content="&#x2013;" Grid.Column="1" Margin="45,40,0,0"/>
<Button x:Name="RdAddButton" Content="&#xE73E;" FontFamily="Segoe MDL2 Assets" FontSize="16" Padding="0,0,0,0" IsEnabled="False" <TextBox x:Name="YearToInput" Text="{Binding YearToString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Click="RdAddButton_Click" Margin="60,40,10,0" Width="40" HorizontalAlignment="Left" Grid.Column="1" TextAlignment="Right"
Grid.Column="1" VerticalAlignment="Top" HorizontalAlignment="Right" Width="25" Height="25" Margin="10,40,10,10"/> TextChanged="IntegerInput_TextChanged"/>
<Label Content="Parzelle(n):" Margin="10,70,0,0" Grid.Column="0"/> <Label Content="Vertragsart:" Margin="10,70,0,0" Grid.Column="0"/>
<TextBox x:Name="GstNrInput" Text="{Binding GstNr, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" <ComboBox x:Name="AreaComTypeInput" SelectedItem="{Binding AreaComType, Mode=TwoWay}" ItemsSource="{Binding AreaComTypeSource, Mode=TwoWay}"
Margin="0,70,10,0" Grid.Column="1" HorizontalAlignment="Stretch" ItemTemplate="{StaticResource AreaCommitmentTypeTemplate}" TextSearch.TextPath="DisplayName"
TextChanged="TextBox_TextChanged"/> HorizontalAlignment="Stretch" Margin="0,70,40,10" Grid.Column="1"/>
<Button x:Name="AreaComTypeDetailsButton" Content="&#xE712;" FontFamily="Segoe MDL2 Assets" FontSize="14" Padding="0,1,0,0"
Click="AreaComTypeDetailsButton_Click"
Grid.Column="3" VerticalAlignment="Top" HorizontalAlignment="Right" Width="25" Height="25" Margin="10,70,10,10"/>
<Label Content="Fläche:" Margin="10,100,0,0" Grid.Column="0"/> <Label Content="Bewirt.-Art:" Margin="10,100,0,0" Grid.Column="0"/>
<ComboBox x:Name="WineCultivationInput" SelectedItem="{Binding WineCultObj, Mode=TwoWay}" ItemsSource="{Binding WineCultSource, Mode=TwoWay}"
DisplayMemberPath="Name" TextSearch.TextPath="Name"
HorizontalAlignment="Stretch" Margin="0,100,10,0" Grid.Column="1"/>
<Label Content="Fläche:" Margin="10,130,0,0" Grid.Column="0"/>
<ctrl:UnitTextBox x:Name="AreaInput" Unit="m²" Text="{Binding AreaString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" <ctrl:UnitTextBox x:Name="AreaInput" Unit="m²" Text="{Binding AreaString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
TextChanged="IntegerInput_TextChanged" TextChanged="IntegerInput_TextChanged"
Grid.Column="1" Width="70" Margin="0,100,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"/> Grid.Column="1" Width="70" Margin="0,130,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"/>
<Label Content="Parzelle(n):" Margin="10,160,0,0" Grid.Column="0"/>
<TextBox x:Name="GstNrInput" Text="{Binding GstNr, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,160,10,0" Grid.Column="1" HorizontalAlignment="Stretch"
TextChanged="TextBox_TextChanged"/>
</Grid> </Grid>
</GroupBox> </GroupBox>
</Grid> </Grid>
+131 -68
View File
@@ -25,23 +25,18 @@ namespace Elwig.Windows {
ViewModel.FilterMember = ctx.Members.Find(mgnr) ?? throw new ArgumentException("MgNr argument has invalid value"); ViewModel.FilterMember = ctx.Members.Find(mgnr) ?? throw new ArgumentException("MgNr argument has invalid value");
ViewModel.Title = $"Flächenbindungen - {ViewModel.FilterMember.AdministrativeName} - Elwig"; ViewModel.Title = $"Flächenbindungen - {ViewModel.FilterMember.AdministrativeName} - Elwig";
ExemptInputs = [ ExemptInputs = [
MgNrInput, AreaCommitmentList, NewAreaCommitmentButton, AreaCommitmentList, RevisionList,
EditAreaCommitmentButton, DeleteAreaCommitmentButton, SaveButton, NewAreaCommitmentButton, EditAreaCommitmentButton, DeleteAreaCommitmentButton, SaveButton,
ResetButton, CancelButton, SearchInput, ActiveAreaCommitmentInput ResetButton, CancelButton, SearchInput, SeasonInput
]; ];
RequiredInputs = [ RequiredInputs = [
FbNrInput, YearFromInput, KgInput, RdInput, FbNrInput, MgNrInput, MemberInput, YearFromInput, KgInput, RdInput,
GstNrInput, AreaInput, AreaComTypeInput, WineCultivationInput GstNrInput, AreaInput, AreaComTypeInput, WineCultivationInput
]; ];
ControlUtils.InitializeDelayTimer(SearchInput, SearchInput_TextChanged); ControlUtils.InitializeDelayTimer(SearchInput, SearchInput_TextChanged);
SearchInput.TextChanged -= SearchInput_TextChanged; SearchInput.TextChanged -= SearchInput_TextChanged;
ActiveAreaCommitmentInput.Content = ((string)ActiveAreaCommitmentInput.Content).Replace("2020", $"{Utils.CurrentLastSeason}"); ViewModel.FilterSeason = Utils.CurrentYear;
}
private void Window_Loaded(object sender, RoutedEventArgs e) {
ActiveAreaCommitmentInput.IsChecked = true;
LockInputs();
} }
private void FocusSearchInput(object sender, RoutedEventArgs evt) { private void FocusSearchInput(object sender, RoutedEventArgs evt) {
@@ -52,40 +47,49 @@ namespace Elwig.Windows {
} }
private async Task RefreshList(bool updateSort = false) { private async Task RefreshList(bool updateSort = false) {
var vm = ViewModel;
var cursor = Mouse.OverrideCursor != null;
if (!cursor) Mouse.OverrideCursor = Cursors.Wait;
var query = (vm.SearchQuery, vm.FilterSeason);
var (filter, contracts, areaComs, areaComCount, stat) = await Task.Run(async () => {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
var (_, areaComQuery, filter) = await ViewModel.GetFilters(ctx); var (_, contractQuery, areaComQuery, filter) = await vm.GetFilters(ctx);
var areaComs = await areaComQuery var contracts = await contractQuery
.Include(a => a.Kg.AtKg) .Include(c => c.Revisions).ThenInclude(a => a.Member)
.Include(a => a.Rd!.Kg.AtKg)
.Include(a => a.WineCult)
.Include(a => a.AreaComType.WineAttr)
.Include(a => a.AreaComType.WineVar)
.ToListAsync(); .ToListAsync();
var areaComs = await areaComQuery.ToListAsync();
if (filter.Count > 0 && areaComs.Count > 0) { if (filter.Count > 0 && contracts.Count > 0) {
var dict = areaComs.AsParallel() var dict = contracts.AsParallel()
.ToDictionary(d => d, d => d.SearchScore(ViewModel.TextFilter)) .ToDictionary(d => d, d => d.SearchScore(vm.TextFilter))
.OrderByDescending(c => c.Value); .OrderByDescending(c => c.Value);
var threshold = dict.Select(a => a.Value).Max() * 3 / 4; var threshold = dict.Max(a => a.Value) * 3 / 4;
areaComs = dict contracts = [.. dict
.Where(a => a.Value > threshold) .Where(a => a.Value > threshold)
.Select(a => a.Key) .Select(a => a.Key)];
.ToList();
} }
ControlUtils.RenewItemsSource(AreaCommitmentList, areaComs, var areaComCount = await areaComQuery.CountAsync();
AreaCommitmentList_SelectionChanged, filter.Count > 0 ? ControlUtils.RenewSourceDefault.IfOnly : ControlUtils.RenewSourceDefault.None, !updateSort); var season = await ctx.FetchSeasons().FirstOrDefaultAsync();
var stat = await AreaComService.GenerateToolTipData(areaComQuery, season?.MaxKgPerHa ?? 10_000);
return (filter, contracts, areaComs, areaComCount, stat);
});
if (!cursor) Mouse.OverrideCursor = null;
if (query != (ViewModel.SearchQuery, ViewModel.FilterSeason)) return;
ControlUtils.RenewItemsSource(AreaCommitmentList, contracts,
AreaCommitmentList_SelectionChanged, ViewModel.TextFilter.Count > 0 ? ControlUtils.RenewSourceDefault.IfOnly : ControlUtils.RenewSourceDefault.None, !updateSort);
RefreshInputs(); RefreshInputs();
if (filter.Count == 0) { if (filter.Count == 0) {
ViewModel.StatusAreaCommitments = $"{await areaComQuery.CountAsync():N0}"; ViewModel.StatusAreaCommitments = $"{areaComCount:N0}";
var s = await ctx.Seasons.FindAsync(await ctx.Seasons.MaxAsync(s => s.Year)); var (text, gridData) = stat;
var (text, gridData) = await AreaComService.GenerateToolTipData(areaComQuery, s?.MaxKgPerHa ?? 10_000);
ViewModel.StatusArea = text; ViewModel.StatusArea = text;
ViewModel.StatusAreaToolTip = AreaComService.GenerateToolTip(gridData); ViewModel.StatusAreaToolTip = AreaComService.GenerateToolTip(gridData);
} else { } else {
ViewModel.StatusAreaCommitments = $"{areaComs.Count:N0}"; ViewModel.StatusAreaCommitments = $"{contracts.Count:N0}";
ViewModel.StatusArea = $"{areaComs.Select(a => a.Area).Sum():N0} m²"; ViewModel.StatusArea = $"{areaComs.Sum(a => a.Area):N0} m²";
ViewModel.StatusAreaToolTip = null; ViewModel.StatusAreaToolTip = null;
} }
var groups = areaComs.GroupBy(a => $"{a.AreaComType.SortId}{a.AreaComType.AttrId}").Select(a => (a.Key, a.Sum(b => b.Area))).OrderByDescending(a => a.Item2).ToList(); var groups = areaComs.GroupBy(a => $"{a.AreaComType.SortId}{a.AreaComType.AttrId}").Select(a => (a.Key, a.Sum(b => b.Area))).OrderByDescending(a => a.Item2).ToList();
@@ -94,12 +98,25 @@ namespace Elwig.Windows {
ViewModel.StatusContracts += $" ({string.Join(", ", groups.Select(g => g.Key))})"; ViewModel.StatusContracts += $" ({string.Join(", ", groups.Select(g => g.Key))})";
} }
private async Task RefreshRevisions() {
using var ctx = new AppDbContext();
if (AreaCommitmentList.SelectedItem is AreaComContract c) {
ControlUtils.RenewItemsSource(RevisionList, c.Revisions.OrderByDescending(p => p.RevNr).ToList(), RevisionList_SelectionChanged, ControlUtils.RenewSourceDefault.First);
} else {
RevisionList.ItemsSource = null;
}
}
private void RefreshInputs(bool validate = false) { private void RefreshInputs(bool validate = false) {
ClearInputStates(); ClearInputStates();
if (AreaCommitmentList.SelectedItem is AreaCom a) { if (RevisionList.SelectedItem is AreaCom a) {
EditAreaCommitmentButton.IsEnabled = true; EditAreaCommitmentButton.IsEnabled = true;
DeleteAreaCommitmentButton.IsEnabled = true; DeleteAreaCommitmentButton.IsEnabled = true;
FillInputs(a); FillInputs(a);
} else if (AreaCommitmentList.SelectedItem is AreaComContract c) {
EditAreaCommitmentButton.IsEnabled = true;
DeleteAreaCommitmentButton.IsEnabled = true;
FillInputs(c);
} else { } else {
EditAreaCommitmentButton.IsEnabled = false; EditAreaCommitmentButton.IsEnabled = false;
DeleteAreaCommitmentButton.IsEnabled = false; DeleteAreaCommitmentButton.IsEnabled = false;
@@ -111,7 +128,15 @@ namespace Elwig.Windows {
GC.Collect(); GC.Collect();
} }
private void FillInputs(AreaComContract c) {
ClearOriginalValues();
ClearDefaultValues();
ViewModel.FillInputs(c);
FinishInputFilling();
}
private void FillInputs(AreaCom a) { private void FillInputs(AreaCom a) {
FillInputs(a.Contract);
ClearOriginalValues(); ClearOriginalValues();
ClearDefaultValues(); ClearDefaultValues();
ViewModel.FillInputs(a); ViewModel.FillInputs(a);
@@ -126,10 +151,15 @@ namespace Elwig.Windows {
ValidateRequiredInputs(); ValidateRequiredInputs();
} }
new protected void ClearInputs(bool validate = false) {
ViewModel.ClearInputs();
base.ClearInputs(validate);
}
protected override async Task OnRenewContext(AppDbContext ctx) { protected override async Task OnRenewContext(AppDbContext ctx) {
await base.OnRenewContext(ctx); await base.OnRenewContext(ctx);
if (await ctx.Members.FindAsync(ViewModel.FilterMember.MgNr) is not Member m) { if (await ctx.FetchMembers(ViewModel.FilterMember.MgNr).SingleOrDefaultAsync() is not Member m) {
Close(); Close();
return; return;
} }
@@ -146,9 +176,8 @@ namespace Elwig.Windows {
.Include(c => c.WineAttr) .Include(c => c.WineAttr)
.OrderBy(v => v.VtrgId) .OrderBy(v => v.VtrgId)
.ToListAsync()); .ToListAsync());
var cultList = await ctx.WineCultivations ControlUtils.RenewItemsSource(MemberInput, await ctx.FetchMembers(includeNotActive: true).ToListAsync());
.OrderBy(c => c.Name) var cultList = await ctx.FetchWineCultivations().Cast<object>().ToListAsync();
.Cast<object>().ToListAsync();
cultList.Insert(0, new NullItem()); cultList.Insert(0, new NullItem());
ControlUtils.RenewItemsSource(WineCultivationInput, cultList, null, ControlUtils.RenewSourceDefault.First); ControlUtils.RenewItemsSource(WineCultivationInput, cultList, null, ControlUtils.RenewSourceDefault.First);
await RefreshList(); await RefreshList();
@@ -164,6 +193,7 @@ namespace Elwig.Windows {
IsCreating = true; IsCreating = true;
AreaCommitmentList.IsEnabled = false; AreaCommitmentList.IsEnabled = false;
AreaCommitmentList.SelectedItem = null; AreaCommitmentList.SelectedItem = null;
RevisionList.IsEnabled = false;
HideNewEditDeleteButtons(); HideNewEditDeleteButtons();
ShowSaveResetCancelButtons(); ShowSaveResetCancelButtons();
UnlockInputs(); UnlockInputs();
@@ -184,6 +214,7 @@ namespace Elwig.Windows {
IsEditing = true; IsEditing = true;
AreaCommitmentList.IsEnabled = false; AreaCommitmentList.IsEnabled = false;
RevisionList.IsEnabled = false;
HideNewEditDeleteButtons(); HideNewEditDeleteButtons();
ShowSaveResetCancelButtons(); ShowSaveResetCancelButtons();
@@ -198,10 +229,10 @@ namespace Elwig.Windows {
} }
private async void DeleteAreaCommitmentButton_Click(object? sender, RoutedEventArgs? evt) { private async void DeleteAreaCommitmentButton_Click(object? sender, RoutedEventArgs? evt) {
if (AreaCommitmentList.SelectedItem is not AreaCom a) if (RevisionList.SelectedItem is not AreaCom a)
return; return;
var d = new AreaComModifyDialog(a.YearFrom, a.YearTo, a.Area, true); var d = new AreaComModifyDialog(a.YearFrom, a.YearTo, a.Area, true, RevisionList.ItemsSource.Cast<object>().FirstOrDefault() != a);
if (d.ShowDialog() != true) if (d.ShowDialog() != true)
return; return;
@@ -209,15 +240,13 @@ namespace Elwig.Windows {
try { try {
if (d.YearTo is int yearTo) { if (d.YearTo is int yearTo) {
ViewModel.YearTo = yearTo; ViewModel.YearTo = yearTo;
await ViewModel.UpdateAreaCommitment((AreaCommitmentList.SelectedItem as AreaCom)?.FbNr); await ViewModel.UpdateAreaCommitment(a.FbNr, a.RevNr);
} else { } else {
await AreaComService.DeleteAreaCom(a.FbNr); await AreaComService.DeleteAreaCom(a.FbNr);
} }
App.HintContextChange(); App.HintContextChange();
} catch (Exception exc) { } catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message; InteractionService.ShowDbException("Flächenbindung löschen", exc);
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Flächenbindung löschen", MessageBoxButton.OK, MessageBoxImage.Error);
} }
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
} }
@@ -232,48 +261,42 @@ namespace Elwig.Windows {
SaveButton.IsEnabled = false; SaveButton.IsEnabled = false;
int? yearTo = null; int? yearTo = null;
if (InputHasChanged(AreaInput) || InputHasChanged(AreaComTypeInput)) { if (InputHasChanged(AreaInput) || InputHasChanged(AreaComTypeInput) || InputHasChanged(MgNrInput)) {
var a = (AreaCommitmentList.SelectedItem as AreaCom)!; var a = (RevisionList.SelectedItem as AreaCom)!;
var d = new AreaComModifyDialog(a.YearFrom, a.YearTo, a.Area, false); var d = new AreaComModifyDialog(a.YearFrom, a.YearTo, a.Area, false, RevisionList.ItemsSource.Cast<object>().FirstOrDefault() != a);
if (d.ShowDialog() != true) if (d.ShowDialog() != true) {
SaveButton.IsEnabled = true;
return; return;
}
yearTo = d.YearTo; yearTo = d.YearTo;
} }
int fbnr; int fbnr, revnr;
Mouse.OverrideCursor = Cursors.Wait; Mouse.OverrideCursor = Cursors.Wait;
try { try {
AreaCom? temp = null; AreaCom? temp = null;
if (yearTo != null && (!ViewModel.YearTo.HasValue || yearTo < ViewModel.YearTo)) { if (yearTo != null && (!ViewModel.YearTo.HasValue || yearTo < ViewModel.YearTo)) {
temp = new AreaCom { temp = new AreaCom {
FbNr = ViewModel.FbNr!.Value,
MgNr = ViewModel.MgNr!.Value, MgNr = ViewModel.MgNr!.Value,
YearFrom = ViewModel.YearFrom, YearFrom = ViewModel.YearFrom,
YearTo = ViewModel.YearTo, YearTo = ViewModel.YearTo,
VtrgId = ViewModel.AreaComType!.VtrgId, VtrgId = ViewModel.AreaComType!.VtrgId,
CultId = ViewModel.WineCult?.CultId, CultId = ViewModel.WineCult?.CultId,
Comment = ViewModel.Comment,
KgNr = ViewModel.Kg!.KgNr,
RdNr = ViewModel.Rd?.RdNr,
GstNr = ViewModel.GstNr?.Trim() ?? "-", GstNr = ViewModel.GstNr?.Trim() ?? "-",
Area = ViewModel.Area!.Value, Area = ViewModel.Area!.Value,
}; };
RefreshInputs(); RefreshInputs();
ViewModel.YearTo = yearTo; ViewModel.YearTo = yearTo;
} }
fbnr = await ViewModel.UpdateAreaCommitment((AreaCommitmentList.SelectedItem as AreaCom)?.FbNr); (fbnr, revnr) = await ViewModel.UpdateAreaCommitment((AreaCommitmentList.SelectedItem as AreaComContract)?.FbNr, (RevisionList.SelectedItem as AreaCom)?.RevNr);
if (temp is AreaCom t) { if (temp is AreaCom t) {
await ViewModel.InitInputs();
t.FbNr = ViewModel.FbNr!.Value;
t.YearFrom = yearTo + 1; t.YearFrom = yearTo + 1;
ViewModel.FillInputs(t); ViewModel.FillInputs(t);
fbnr = await ViewModel.UpdateAreaCommitment(null); (fbnr, revnr) = await ViewModel.UpdateAreaCommitment((AreaCommitmentList.SelectedItem as AreaComContract)?.FbNr, null);
} }
App.HintContextChange(); App.HintContextChange();
} catch (Exception exc) { } catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message; InteractionService.ShowDbException("Flächenbindung aktualisieren", exc);
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Flächenbindung aktualisieren", MessageBoxButton.OK, MessageBoxImage.Error);
SaveButton.IsEnabled = true; SaveButton.IsEnabled = true;
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
return; return;
@@ -282,6 +305,7 @@ namespace Elwig.Windows {
IsEditing = false; IsEditing = false;
IsCreating = false; IsCreating = false;
AreaCommitmentList.IsEnabled = true; AreaCommitmentList.IsEnabled = true;
RevisionList.IsEnabled = true;
HideSaveResetCancelButtons(); HideSaveResetCancelButtons();
ShowNewEditDeleteButtons(); ShowNewEditDeleteButtons();
LockInputs(); LockInputs();
@@ -290,7 +314,9 @@ namespace Elwig.Windows {
await EnsureContextRenewed(); await EnsureContextRenewed();
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
ViewModel.SearchQuery = ""; ViewModel.SearchQuery = "";
ControlUtils.SelectItem(AreaCommitmentList, AreaCommitmentList.ItemsSource.Cast<AreaCom>().Where(a => a.FbNr == fbnr).FirstOrDefault()); ViewModel.FilterSeason = ViewModel.YearTo ?? ViewModel.YearFrom ?? ViewModel.FilterSeason;
ControlUtils.SelectItemWithPk(AreaCommitmentList, fbnr);
ControlUtils.SelectItemWithPk(RevisionList, fbnr, revnr);
} }
protected override void ShortcutReset() { protected override void ShortcutReset() {
@@ -312,6 +338,7 @@ namespace Elwig.Windows {
IsEditing = false; IsEditing = false;
IsCreating = false; IsCreating = false;
AreaCommitmentList.IsEnabled = true; AreaCommitmentList.IsEnabled = true;
RevisionList.IsEnabled = true;
HideSaveResetCancelButtons(); HideSaveResetCancelButtons();
ShowNewEditDeleteButtons(); ShowNewEditDeleteButtons();
RefreshInputs(); RefreshInputs();
@@ -373,34 +400,65 @@ namespace Elwig.Windows {
private void LockSearchInputs() { private void LockSearchInputs() {
SearchInput.IsEnabled = false; SearchInput.IsEnabled = false;
ActiveAreaCommitmentInput.IsEnabled = false; SeasonInput.IsEnabled = false;
} }
private void UnlockSearchInputs() { private void UnlockSearchInputs() {
SearchInput.IsEnabled = true; SearchInput.IsEnabled = true;
ActiveAreaCommitmentInput.IsEnabled = true; SeasonInput.IsEnabled = true;
} }
private void AreaCommitmentList_SelectionChanged(object sender, SelectionChangedEventArgs evt) { private async void AreaCommitmentList_SelectionChanged(object sender, SelectionChangedEventArgs evt) {
if (AreaCommitmentList.SelectedItem != null) if (AreaCommitmentList.SelectedItem != null)
AreaCommitmentList.ScrollIntoView(AreaCommitmentList.SelectedItem); AreaCommitmentList.ScrollIntoView(AreaCommitmentList.SelectedItem);
RefreshInputs(); await RefreshRevisions();
} }
private void AttributesInput_SelectionChanged(object sender, SelectionChangedEventArgs evt) { private void RevisionList_SelectionChanged(object? sender, SelectionChangedEventArgs? evt) {
RefreshInputs();
if (RevisionList.SelectedItem is AreaCom c) {
EditAreaCommitmentButton.IsEnabled = true;
} else {
EditAreaCommitmentButton.IsEnabled = false;
}
}
private void MgNrInput_TextChanged(object sender, TextChangedEventArgs evt) {
var valid = InputTextChanged((TextBox)sender, Validator.CheckMgNr);
var text = MgNrInput.Text;
var caret = MgNrInput.CaretIndex;
ControlUtils.SelectItemWithPk(MemberInput, valid ? ViewModel.MgNr : null);
MgNrInput.Text = text;
MgNrInput.CaretIndex = caret;
}
private void MgNrInput_LostFocus(object sender, RoutedEventArgs evt) {
var valid = InputLostFocus((TextBox)sender, Validator.CheckMgNr);
ControlUtils.SelectItemWithPk(MemberInput, valid ? ViewModel.MgNr : null);
}
private void MemberInput_SelectionChanged(object? sender, SelectionChangedEventArgs? evt) {
var m = MemberInput.SelectedItem as Member;
ViewModel.MgNr = m?.MgNr;
} }
private async void ActiveAreaCommitmentInput_Changed(object sender, RoutedEventArgs evt) { private async void ActiveAreaCommitmentInput_Changed(object sender, RoutedEventArgs evt) {
if (!HasContextLoaded) return;
await RefreshList(); await RefreshList();
} }
private async void SearchInput_TextChanged(object sender, RoutedEventArgs evt) { private async void SearchInput_TextChanged(object sender, RoutedEventArgs evt) {
if (!HasContextLoaded) return;
var binding = ((TextBox)sender).GetBindingExpression(TextBox.TextProperty); var binding = ((TextBox)sender).GetBindingExpression(TextBox.TextProperty);
binding?.UpdateSource(); binding?.UpdateSource();
await RefreshList(true); await RefreshList(true);
} }
private async void SeasonInput_TextChanged(object sender, TextChangedEventArgs evt) {
if (!HasContextLoaded || ViewModel.FilterSeason == null) return;
await RefreshList();
}
private void KgInput_SelectionChanged(object sender, SelectionChangedEventArgs evt) { private void KgInput_SelectionChanged(object sender, SelectionChangedEventArgs evt) {
if (KgInput.SelectedItem is AT_Kg kg) { if (KgInput.SelectedItem is AT_Kg kg) {
var rdList = kg.WbKg!.Rds.OrderBy(r => r.Name).Cast<object>().ToList(); var rdList = kg.WbKg!.Rds.OrderBy(r => r.Name).Cast<object>().ToList();
@@ -438,12 +496,12 @@ namespace Elwig.Windows {
RdInput.SelectedIndex = s.Count(); RdInput.SelectedIndex = s.Count();
} }
protected void InputTextChanged(TextBox input, Func<TextBox, bool, AreaCom?, ValidationResult> checker) { protected void InputTextChanged(TextBox input, Func<TextBox, bool, AreaComContract?, ValidationResult> checker) {
InputTextChanged(input, checker(input, SenderIsRequired(input), (AreaCom)AreaCommitmentList.SelectedItem)); InputTextChanged(input, checker(input, SenderIsRequired(input), (AreaComContract)AreaCommitmentList.SelectedItem));
} }
protected void InputLostFocus(TextBox input, Func<TextBox, bool, AreaCom?, ValidationResult> checker, string? msg = null) { protected void InputLostFocus(TextBox input, Func<TextBox, bool, AreaComContract?, ValidationResult> checker, string? msg = null) {
InputLostFocus(input, checker(input, SenderIsRequired(input), (AreaCom)AreaCommitmentList.SelectedItem), msg); InputLostFocus(input, checker(input, SenderIsRequired(input), (AreaComContract)AreaCommitmentList.SelectedItem), msg);
} }
private void FbNrInput_TextChanged(object sender, RoutedEventArgs evt) { private void FbNrInput_TextChanged(object sender, RoutedEventArgs evt) {
@@ -453,5 +511,10 @@ namespace Elwig.Windows {
private void FbNrInput_LostFocus(object sender, RoutedEventArgs evt) { private void FbNrInput_LostFocus(object sender, RoutedEventArgs evt) {
InputLostFocus((TextBox)sender, Validator.CheckFbNr); InputLostFocus((TextBox)sender, Validator.CheckFbNr);
} }
private void MemberReferenceButton_Click(object sender, RoutedEventArgs evt) {
if (MemberInput.SelectedItem is not Member m) return;
App.FocusMember(m.MgNr);
}
} }
} }
+21 -7
View File
@@ -8,8 +8,7 @@
xmlns:local="clr-namespace:Elwig.Windows" xmlns:local="clr-namespace:Elwig.Windows"
xmlns:ctrl="clr-namespace:Elwig.Controls" xmlns:ctrl="clr-namespace:Elwig.Controls"
mc:Ignorable="d" mc:Ignorable="d"
Title="Stammdaten - Elwig" Height="520" MinHeight="400" Width="860" MinWidth="810" Title="Stammdaten - Elwig" Height="520" MinHeight="400" Width="860" MinWidth="810">
Loaded="Window_Loaded">
<Window.Resources> <Window.Resources>
<Style TargetType="Label"> <Style TargetType="Label">
<Setter Property="HorizontalAlignment" Value="Left"/> <Setter Property="HorizontalAlignment" Value="Left"/>
@@ -454,13 +453,13 @@
HorizontalAlignment="Left"/> HorizontalAlignment="Left"/>
<Label Content="Lieferpflicht/-recht:" Margin="10,10,0,10" Grid.Column="2"/> <Label Content="Lieferpflicht/-recht:" Margin="10,10,0,10" Grid.Column="2"/>
<ctrl:UnitTextBox x:Name="SeasonMinKgPerBsInput" Unit="kg/GA" TextChanged="SeasonMinMaxKgInput_TextChanged" <ctrl:UnitTextBox x:Name="SeasonMinKgPerShareInput" Unit="kg/GA" TextChanged="SeasonMinMaxKgInput_TextChanged"
Grid.Column="3" Width="80" Margin="0,10,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"/> Grid.Column="3" Width="80" Margin="0,10,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<ctrl:UnitTextBox x:Name="SeasonMaxKgPerBsInput" Unit="kg/GA" TextChanged="SeasonMinMaxKgInput_TextChanged" <ctrl:UnitTextBox x:Name="SeasonMaxKgPerShareInput" Unit="kg/GA" TextChanged="SeasonMinMaxKgInput_TextChanged"
Grid.Column="3" Width="80" Margin="85,10,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"/> Grid.Column="3" Width="80" Margin="85,10,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<Label Content="GA-Wert (Nachz.):" Margin="10,40,0,10" Grid.Column="2"/> <Label Content="GA-Wert (Nachz.):" Margin="10,40,0,10" Grid.Column="2"/>
<ctrl:UnitTextBox x:Name="SeasonBsValueInput" Unit="€/GA" TextChanged="SeasonPenaltyInput_TextChanged" <ctrl:UnitTextBox x:Name="SeasonShareValueInput" Unit="€/GA" TextChanged="SeasonPenaltyInput_TextChanged"
Grid.Column="3" Width="85" Margin="0,40,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"/> Grid.Column="3" Width="85" Margin="0,40,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<GroupBox Header="Strafen bei Unterlieferung lt. GA" Grid.Column="2" Grid.ColumnSpan="2" Margin="0,70,10,0"> <GroupBox Header="Strafen bei Unterlieferung lt. GA" Grid.Column="2" Grid.ColumnSpan="2" Margin="0,70,10,0">
@@ -469,13 +468,13 @@
Width="80" Margin="65,10,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"/> Width="80" Margin="65,10,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<ctrl:UnitTextBox x:Name="SeasonPenaltyInput" Unit="€" TextChanged="SeasonPenaltyInput_TextChanged" <ctrl:UnitTextBox x:Name="SeasonPenaltyInput" Unit="€" TextChanged="SeasonPenaltyInput_TextChanged"
Width="68" Margin="150,10,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"/> Width="68" Margin="150,10,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<ctrl:UnitTextBox x:Name="SeasonPenaltyPerBsInput" Unit="€/GA" TextChanged="SeasonPenaltyPerBsInput_TextChanged" <ctrl:UnitTextBox x:Name="SeasonPenaltyPerShareInput" Unit="€/GA" TextChanged="SeasonPenaltyPerShareInput_TextChanged"
Width="100" Margin="222,10,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"/> Width="100" Margin="222,10,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<Label Content="Zzgl. bei Nicht-Lieferung:" Margin="10,40,0,10"/> <Label Content="Zzgl. bei Nicht-Lieferung:" Margin="10,40,0,10"/>
<ctrl:UnitTextBox x:Name="SeasonPenaltyNoneInput" Unit="€" TextChanged="SeasonPenaltyInput_TextChanged" <ctrl:UnitTextBox x:Name="SeasonPenaltyNoneInput" Unit="€" TextChanged="SeasonPenaltyInput_TextChanged"
Width="68" Margin="150,40,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"/> Width="68" Margin="150,40,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<ctrl:UnitTextBox x:Name="SeasonPenaltyPerBsNoneInput" Unit="€/GA" TextChanged="SeasonPenaltyPerBsInput_TextChanged" <ctrl:UnitTextBox x:Name="SeasonPenaltyPerShareNoneInput" Unit="€/GA" TextChanged="SeasonPenaltyPerShareInput_TextChanged"
Width="100" Margin="222,40,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"/> Width="100" Margin="222,40,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"/>
</Grid> </Grid>
</GroupBox> </GroupBox>
@@ -542,6 +541,21 @@
</TabItem> </TabItem>
<TabItem Header="Parameter"> <TabItem Header="Parameter">
<StackPanel> <StackPanel>
<GroupBox x:Name="ParameterBusinessShare" Header="Geschäftsanteile" Margin="10,10,10,0" VerticalAlignment="Top">
<Grid>
<Label Content="Modus:" Margin="10,10,10,10"/>
<ComboBox x:Name="ParameterBusinessShareModeInput" Margin="160,10,10,10" Width="100"
HorizontalAlignment="Left">
<ComboBoxItem IsSelected="True">Normal</ComboBoxItem>
<ComboBoxItem>Rot/weiß</ComboBoxItem>
</ComboBox>
<Label Content="Mitgliederbewegungen:" Margin="10,40,10,10"/>
<CheckBox x:Name="ParameterBusinessShareHistoryInput" Content="Mit Elwig erfassen" Margin="160,45,10,15"
HorizontalAlignment="Left"
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"/>
</Grid>
</GroupBox>
<GroupBox x:Name="ParameterAreaComGroup" Header="Berechnung Flächenbindungen (aktuelle Saison)" Margin="10,10,10,0" VerticalAlignment="Top"> <GroupBox x:Name="ParameterAreaComGroup" Header="Berechnung Flächenbindungen (aktuelle Saison)" Margin="10,10,10,0" VerticalAlignment="Top">
<Grid> <Grid>
<CheckBox x:Name="ParameterAllowAttrIntoLowerInput" Content="Erlauben Lieferungen auch auf (konfigurierte) &quot;schlechtere&quot; Flächenbindungen aufzuteilen" <CheckBox x:Name="ParameterAllowAttrIntoLowerInput" Content="Erlauben Lieferungen auch auf (konfigurierte) &quot;schlechtere&quot; Flächenbindungen aufzuteilen"
@@ -21,8 +21,6 @@ namespace Elwig.Windows {
private async Task AreaCommitmentTypesInitEditing(AppDbContext ctx) { private async Task AreaCommitmentTypesInitEditing(AppDbContext ctx) {
_actList = new(await ctx.AreaCommitmentTypes _actList = new(await ctx.AreaCommitmentTypes
.OrderBy(v => v.VtrgId) .OrderBy(v => v.VtrgId)
.Include(t => t.WineVar)
.Include(t => t.WineAttr)
.ToListAsync()); .ToListAsync());
_acts = _actList.ToDictionary(v => v.VtrgId, v => (string?)v.VtrgId); _acts = _actList.ToDictionary(v => v.VtrgId, v => (string?)v.VtrgId);
_actIds = _actList.ToDictionary(v => v, v => v.VtrgId); _actIds = _actList.ToDictionary(v => v, v => v.VtrgId);
+5 -12
View File
@@ -19,10 +19,7 @@ namespace Elwig.Windows {
private bool _branchUpdate = false; private bool _branchUpdate = false;
private async Task BranchesInitEditing(AppDbContext ctx) { private async Task BranchesInitEditing(AppDbContext ctx) {
_branchList = new(await ctx.Branches _branchList = new(await ctx.FetchBranches().ToListAsync());
.OrderBy(b => b.Name)
.Include(b => b.PostalDest!.AtPlz)
.ToListAsync());
_branches = _branchList.ToDictionary(b => b.ZwstId, b => (string?)b.ZwstId); _branches = _branchList.ToDictionary(b => b.ZwstId, b => (string?)b.ZwstId);
_branchIds = _branchList.ToDictionary(b => b, b => b.ZwstId); _branchIds = _branchList.ToDictionary(b => b, b => b.ZwstId);
ControlUtils.RenewItemsSource(BranchList, _branchList); ControlUtils.RenewItemsSource(BranchList, _branchList);
@@ -30,10 +27,7 @@ namespace Elwig.Windows {
} }
private async Task BranchesFinishEditing(AppDbContext ctx) { private async Task BranchesFinishEditing(AppDbContext ctx) {
ControlUtils.RenewItemsSource(BranchList, await ctx.Branches ControlUtils.RenewItemsSource(BranchList, await ctx.FetchBranches().ToListAsync());
.OrderBy(b => b.Name)
.Include(b => b.PostalDest!.AtPlz)
.ToListAsync());
_branchList = null; _branchList = null;
_branches = null; _branches = null;
_branchIds = null; _branchIds = null;
@@ -47,9 +41,9 @@ namespace Elwig.Windows {
if (!_branchChanged || _branchList == null || _branches == null || _branchIds == null) if (!_branchChanged || _branchList == null || _branches == null || _branchIds == null)
return; return;
foreach (var (zwstid, _) in _branches.Where(b => b.Value == null)) { var deleteZwstIds = _branches.Where(b => b.Value == null).Select(b => b.Key).ToList();
ctx.Remove(ctx.Branches.Find(zwstid)!); await ctx.Branches.Where(b => deleteZwstIds.Contains(b.ZwstId)).ExecuteDeleteAsync();
}
foreach (var (branch, old) in _branchIds) { foreach (var (branch, old) in _branchIds) {
branch.ZwstId = old; branch.ZwstId = old;
} }
@@ -61,7 +55,6 @@ namespace Elwig.Windows {
foreach (var (old, zwstid) in _branches.Where(b => b.Value != null)) { foreach (var (old, zwstid) in _branches.Where(b => b.Value != null)) {
await ctx.Database.ExecuteSqlAsync($"UPDATE branch SET zwstid = {zwstid} WHERE zwstid = {old}"); await ctx.Database.ExecuteSqlAsync($"UPDATE branch SET zwstid = {zwstid} WHERE zwstid = {old}");
} }
await ctx.SaveChangesAsync();
foreach (var branch in _branchList.Where(b => !_branchIds.ContainsKey(b))) { foreach (var branch in _branchList.Where(b => !_branchIds.ContainsKey(b))) {
if (branch.ZwstId == null) continue; if (branch.ZwstId == null) continue;
+2 -8
View File
@@ -22,10 +22,7 @@ namespace Elwig.Windows {
private async Task ModifiersInitEditing(AppDbContext ctx) { private async Task ModifiersInitEditing(AppDbContext ctx) {
SeasonList.IsEnabled = false; SeasonList.IsEnabled = false;
var year = (SeasonList.SelectedItem as Season)?.Year; var year = (SeasonList.SelectedItem as Season)?.Year;
_modList = new(await ctx.Modifiers _modList = new(await ctx.FetchModifiers(year ?? 0).ToListAsync());
.Where(m => m.Year == year)
.OrderBy(m => m.Ordering)
.ToListAsync());
_mods = _modList.ToDictionary(m => m.ModId, m => (string?)m.ModId); _mods = _modList.ToDictionary(m => m.ModId, m => (string?)m.ModId);
_modIds = _modList.ToDictionary(m => m, m => m.ModId); _modIds = _modList.ToDictionary(m => m, m => m.ModId);
ControlUtils.RenewItemsSource(SeasonModifierList, _modList); ControlUtils.RenewItemsSource(SeasonModifierList, _modList);
@@ -34,10 +31,7 @@ namespace Elwig.Windows {
private async Task ModifiersFinishEditing(AppDbContext ctx) { private async Task ModifiersFinishEditing(AppDbContext ctx) {
var year = (SeasonList.SelectedItem as Season)?.Year; var year = (SeasonList.SelectedItem as Season)?.Year;
ControlUtils.RenewItemsSource(SeasonModifierList, await ctx.Modifiers ControlUtils.RenewItemsSource(SeasonModifierList, await ctx.FetchModifiers(year ?? 0).ToListAsync());
.Where(m => m.Year == year)
.OrderBy(m => m.Ordering)
.ToListAsync());
_modList = null; _modList = null;
_mods = null; _mods = null;
_modIds = null; _modIds = null;
+44 -45
View File
@@ -1,6 +1,7 @@
using Elwig.Dialogs; using Elwig.Dialogs;
using Elwig.Helpers; using Elwig.Helpers;
using Elwig.Models.Entities; using Elwig.Models.Entities;
using Elwig.Services;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -19,22 +20,14 @@ namespace Elwig.Windows {
private async Task SeasonsInitEditing(AppDbContext ctx) { private async Task SeasonsInitEditing(AppDbContext ctx) {
SeasonAddButton.IsEnabled = false; SeasonAddButton.IsEnabled = false;
SeasonRemoveButton.IsEnabled = false; SeasonRemoveButton.IsEnabled = false;
ControlUtils.RenewItemsSource(SeasonList, await ctx.Seasons ControlUtils.RenewItemsSource(SeasonList, await ctx.FetchSeasons(includeModifiers: true).ToListAsync());
.OrderByDescending(s => s.Year)
.Include(s => s.Modifiers)
.Include(s => s.Currency)
.ToListAsync());
SeasonList_SelectionChanged(null, null); SeasonList_SelectionChanged(null, null);
} }
private async Task SeasonsFinishEditing(AppDbContext ctx) { private async Task SeasonsFinishEditing(AppDbContext ctx) {
SeasonAddButton.IsEnabled = true; SeasonAddButton.IsEnabled = true;
SeasonRemoveButton.IsEnabled = true; SeasonRemoveButton.IsEnabled = true;
ControlUtils.RenewItemsSource(SeasonList, await ctx.Seasons ControlUtils.RenewItemsSource(SeasonList, await ctx.FetchSeasons(includeModifiers: true).ToListAsync());
.OrderByDescending(s => s.Year)
.Include(s => s.Modifiers)
.Include(s => s.Currency)
.ToListAsync());
_seasonChanged = false; _seasonChanged = false;
} }
@@ -54,23 +47,23 @@ namespace Elwig.Windows {
SeasonVatFlatrateInput.Text = (s.VatFlatrate * 100).ToString(); SeasonVatFlatrateInput.Text = (s.VatFlatrate * 100).ToString();
SeasonStartInput.Text = $"{s.StartDate:dd.MM.yyyy}"; SeasonStartInput.Text = $"{s.StartDate:dd.MM.yyyy}";
SeasonEndInput.Text = $"{s.EndDate:dd.MM.yyyy}"; SeasonEndInput.Text = $"{s.EndDate:dd.MM.yyyy}";
SeasonMinKgPerBsInput.Text = s.MinKgPerBusinessShare.ToString(); SeasonMinKgPerShareInput.Text = s.MinKgPerShare?.ToString() ?? s.MinKgPerShareRed?.ToString() ?? s.MinKgPerShareWhite?.ToString() ?? "0";
SeasonMaxKgPerBsInput.Text = s.MaxKgPerBusinessShare.ToString(); SeasonMaxKgPerShareInput.Text = s.MaxKgPerShare?.ToString() ?? s.MaxKgPerShareRed?.ToString() ?? s.MaxKgPerShareWhite?.ToString() ?? "0";
SeasonPenaltyPerKgInput.Text = s.PenaltyPerKg?.ToString() ?? ""; SeasonPenaltyPerKgInput.Text = s.PenaltyPerKg?.ToString() ?? "";
SeasonPenaltyInput.Text = s.PenaltyAmount?.ToString() ?? ""; SeasonPenaltyInput.Text = s.PenaltyAmount?.ToString() ?? "";
SeasonPenaltyNoneInput.Text = s.PenaltyNone?.ToString() ?? ""; SeasonPenaltyNoneInput.Text = s.PenaltyNone?.ToString() ?? "";
SeasonPenaltyPerBsInput.Text = s.PenaltyPerBsAmount?.ToString() ?? ""; SeasonPenaltyPerShareInput.Text = s.PenaltyPerShareAmount?.ToString() ?? "";
SeasonPenaltyPerBsNoneInput.Text = s.PenaltyPerBsNone?.ToString() ?? ""; SeasonPenaltyPerShareNoneInput.Text = s.PenaltyPerShareNone?.ToString() ?? "";
SeasonBsValueInput.Text = s.BusinessShareValue?.ToString() ?? ""; SeasonShareValueInput.Text = s.BusinessShareValue?.ToString() ?? "";
var sym = s.Currency.Symbol ?? s.Currency.Code; var sym = s.Currency.Symbol ?? s.Currency.Code;
SeasonModifierAbsInput.Unit = $"{sym}/kg"; SeasonModifierAbsInput.Unit = $"{sym}/kg";
SeasonPenaltyPerKgInput.Unit = $"{sym}/kg"; SeasonPenaltyPerKgInput.Unit = $"{sym}/kg";
SeasonPenaltyInput.Unit = sym; SeasonPenaltyInput.Unit = sym;
SeasonPenaltyNoneInput.Unit = sym; SeasonPenaltyNoneInput.Unit = sym;
SeasonPenaltyPerBsInput.Unit = $"{sym}/GA"; SeasonPenaltyPerShareInput.Unit = $"{sym}/GA";
SeasonPenaltyPerBsNoneInput.Unit = $"{sym}/GA"; SeasonPenaltyPerShareNoneInput.Unit = $"{sym}/GA";
SeasonBsValueInput.Unit = $"{sym}/GA"; SeasonShareValueInput.Unit = $"{sym}/GA";
AreaCommitmentTypePenaltyPerKgInput.Unit = $"{sym}/kg"; AreaCommitmentTypePenaltyPerKgInput.Unit = $"{sym}/kg";
AreaCommitmentTypePenaltyInput.Unit = sym; AreaCommitmentTypePenaltyInput.Unit = sym;
AreaCommitmentTypePenaltyNoneInput.Unit = sym; AreaCommitmentTypePenaltyNoneInput.Unit = sym;
@@ -81,14 +74,14 @@ namespace Elwig.Windows {
SeasonVatFlatrateInput.Text = ""; SeasonVatFlatrateInput.Text = "";
SeasonStartInput.Text = ""; SeasonStartInput.Text = "";
SeasonEndInput.Text = ""; SeasonEndInput.Text = "";
SeasonMinKgPerBsInput.Text = ""; SeasonMinKgPerShareInput.Text = "";
SeasonMaxKgPerBsInput.Text = ""; SeasonMaxKgPerShareInput.Text = "";
SeasonPenaltyPerKgInput.Text = ""; SeasonPenaltyPerKgInput.Text = "";
SeasonPenaltyInput.Text = ""; SeasonPenaltyInput.Text = "";
SeasonPenaltyNoneInput.Text = ""; SeasonPenaltyNoneInput.Text = "";
SeasonPenaltyPerBsInput.Text = ""; SeasonPenaltyPerShareInput.Text = "";
SeasonPenaltyPerBsNoneInput.Text = ""; SeasonPenaltyPerShareNoneInput.Text = "";
SeasonBsValueInput.Text = ""; SeasonShareValueInput.Text = "";
} }
_seasonUpdate = false; _seasonUpdate = false;
} }
@@ -103,16 +96,28 @@ namespace Elwig.Windows {
s.VatNormal = double.Parse(SeasonVatNormalInput.Text) / 100; s.VatNormal = double.Parse(SeasonVatNormalInput.Text) / 100;
if (SeasonVatFlatrateInput.Text.Length > 0) if (SeasonVatFlatrateInput.Text.Length > 0)
s.VatFlatrate = double.Parse(SeasonVatFlatrateInput.Text) / 100; s.VatFlatrate = double.Parse(SeasonVatFlatrateInput.Text) / 100;
if (SeasonMinKgPerBsInput.Text.Length > 0) if (ParameterBusinessShareModeInput.SelectedIndex == 0) {
s.MinKgPerBusinessShare = int.Parse(SeasonMinKgPerBsInput.Text); s.MinKgPerShare = (SeasonMinKgPerShareInput.Text.Length > 0) ? int.Parse(SeasonMinKgPerShareInput.Text) : null;
if (SeasonMaxKgPerBsInput.Text.Length > 0) s.MaxKgPerShare = (SeasonMaxKgPerShareInput.Text.Length > 0) ? int.Parse(SeasonMaxKgPerShareInput.Text) : null;
s.MaxKgPerBusinessShare = int.Parse(SeasonMaxKgPerBsInput.Text); s.MinKgPerShareRed = null;
s.MaxKgPerShareRed = null;
s.MinKgPerShareWhite = null;
s.MaxKgPerShareWhite = null;
} else {
s.MinKgPerShare = null;
s.MaxKgPerShare = null;
s.MinKgPerShareRed = (SeasonMinKgPerShareInput.Text.Length > 0) ? int.Parse(SeasonMinKgPerShareInput.Text) : null;
s.MaxKgPerShareRed = (SeasonMaxKgPerShareInput.Text.Length > 0) ? int.Parse(SeasonMaxKgPerShareInput.Text) : null;
s.MinKgPerShareWhite = s.MinKgPerShareRed;
s.MaxKgPerShareWhite = s.MaxKgPerShareRed;
}
s.PenaltyPerKg = (SeasonPenaltyPerKgInput.Text.Length > 0) ? decimal.Parse(SeasonPenaltyPerKgInput.Text) : null; s.PenaltyPerKg = (SeasonPenaltyPerKgInput.Text.Length > 0) ? decimal.Parse(SeasonPenaltyPerKgInput.Text) : null;
s.PenaltyAmount = (SeasonPenaltyInput.Text.Length > 0) ? decimal.Parse(SeasonPenaltyInput.Text) : null; s.PenaltyAmount = (SeasonPenaltyInput.Text.Length > 0) ? decimal.Parse(SeasonPenaltyInput.Text) : null;
s.PenaltyNone = (SeasonPenaltyNoneInput.Text.Length > 0) ? decimal.Parse(SeasonPenaltyNoneInput.Text) : null; s.PenaltyNone = (SeasonPenaltyNoneInput.Text.Length > 0) ? decimal.Parse(SeasonPenaltyNoneInput.Text) : null;
s.PenaltyPerBsAmount = (SeasonPenaltyPerBsInput.Text.Length > 0) ? decimal.Parse(SeasonPenaltyPerBsInput.Text) : null; s.PenaltyPerShareAmount = (SeasonPenaltyPerShareInput.Text.Length > 0) ? decimal.Parse(SeasonPenaltyPerShareInput.Text) : null;
s.PenaltyPerBsNone = (SeasonPenaltyPerBsNoneInput.Text.Length > 0) ? decimal.Parse(SeasonPenaltyPerBsNoneInput.Text) : null; s.PenaltyPerShareNone = (SeasonPenaltyPerShareNoneInput.Text.Length > 0) ? decimal.Parse(SeasonPenaltyPerShareNoneInput.Text) : null;
s.BusinessShareValue = (SeasonBsValueInput.Text.Length > 0) ? decimal.Parse(SeasonBsValueInput.Text) : null; s.BusinessShareValue = (SeasonShareValueInput.Text.Length > 0) ? decimal.Parse(SeasonShareValueInput.Text) : null;
UpdateButtons(); UpdateButtons();
} }
@@ -138,7 +143,7 @@ namespace Elwig.Windows {
Season_Changed(sender, evt); Season_Changed(sender, evt);
} }
private void SeasonPenaltyPerBsInput_TextChanged(object sender, TextChangedEventArgs evt) { private void SeasonPenaltyPerShareInput_TextChanged(object sender, TextChangedEventArgs evt) {
if (SeasonList.SelectedItem is not Season s) return; if (SeasonList.SelectedItem is not Season s) return;
InputTextChanged((TextBox)sender, Validator.CheckDecimal((TextBox)sender, false, 4, s.Precision)); InputTextChanged((TextBox)sender, Validator.CheckDecimal((TextBox)sender, false, 4, s.Precision));
Season_Changed(sender, evt); Season_Changed(sender, evt);
@@ -167,13 +172,13 @@ namespace Elwig.Windows {
MaxKgPerHa = s?.MaxKgPerHa ?? 10000, MaxKgPerHa = s?.MaxKgPerHa ?? 10000,
VatNormal = s?.VatNormal ?? 0.10, VatNormal = s?.VatNormal ?? 0.10,
VatFlatrate = s?.VatFlatrate ?? 0.13, VatFlatrate = s?.VatFlatrate ?? 0.13,
MinKgPerBusinessShare = s?.MinKgPerBusinessShare ?? 500, MinKgPerShare = s?.MinKgPerShare,
MaxKgPerBusinessShare = s?.MaxKgPerBusinessShare ?? 1000, MaxKgPerShare = s?.MaxKgPerShare,
PenaltyPerKgValue = s?.PenaltyPerKgValue, PenaltyPerKgValue = s?.PenaltyPerKgValue,
PenaltyAmoutValue = s?.PenaltyAmoutValue, PenaltyAmoutValue = s?.PenaltyAmoutValue,
PenaltyNoneValue = s?.PenaltyNoneValue, PenaltyNoneValue = s?.PenaltyNoneValue,
PenaltyPerBsAmountValue = s?.PenaltyPerBsAmountValue, PenaltyPerShareAmountValue = s?.PenaltyPerShareAmountValue,
PenaltyPerBsNoneValue = s?.PenaltyPerBsNoneValue, PenaltyPerShareNoneValue = s?.PenaltyPerShareNoneValue,
BusinessShareValueValue = s?.BusinessShareValueValue, BusinessShareValueValue = s?.BusinessShareValueValue,
CalcMode = s?.CalcMode ?? 0, CalcMode = s?.CalcMode ?? 0,
}); });
@@ -188,13 +193,12 @@ namespace Elwig.Windows {
AbsValue = m.AbsValue * mult / div, AbsValue = m.AbsValue * mult / div,
RelValue = m.RelValue, RelValue = m.RelValue,
IsActive = m.IsActive, IsActive = m.IsActive,
IsRedacted = m.IsRedacted,
})); }));
} }
await ctx.SaveChangesAsync(); await ctx.SaveChangesAsync();
} catch (Exception exc) { } catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message; InteractionService.ShowDbException("Saison anlegen", exc);
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Saison anlegen", MessageBoxButton.OK, MessageBoxImage.Error);
} }
App.HintContextChange(); App.HintContextChange();
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
@@ -205,19 +209,14 @@ namespace Elwig.Windows {
private async void SeasonRemoveButton_Click(object sender, RoutedEventArgs evt) { private async void SeasonRemoveButton_Click(object sender, RoutedEventArgs evt) {
if (SeasonList.SelectedItem is not Season s) if (SeasonList.SelectedItem is not Season s)
return; return;
var r = MessageBox.Show( if (InteractionService.AskContinue("Saison löschen", $"Soll die Saison {s.Year} wirklich unwiderruflich gelöscht werden?")) {
$"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; Mouse.OverrideCursor = Cursors.Wait;
try { try {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
ctx.Remove(s); ctx.Remove(s);
await ctx.SaveChangesAsync(); await ctx.SaveChangesAsync();
} catch (Exception exc) { } catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message; InteractionService.ShowDbException("Saison löschen", exc);
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Saison löschen", MessageBoxButton.OK, MessageBoxImage.Error);
} }
App.HintContextChange(); App.HintContextChange();
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
+4 -10
View File
@@ -19,9 +19,7 @@ namespace Elwig.Windows {
private bool _attrUpdate = false; private bool _attrUpdate = false;
private async Task WineAttributesInitEditing(AppDbContext ctx) { private async Task WineAttributesInitEditing(AppDbContext ctx) {
_attrList = new(await ctx.WineAttributes _attrList = new(await ctx.FetchWineAttributes().ToListAsync());
.OrderBy(a => a.Name)
.ToListAsync());
_attrs = _attrList.ToDictionary(a => a.AttrId, a => (string?)a.AttrId); _attrs = _attrList.ToDictionary(a => a.AttrId, a => (string?)a.AttrId);
_attrIds = _attrList.ToDictionary(a => a, a => a.AttrId); _attrIds = _attrList.ToDictionary(a => a, a => a.AttrId);
ControlUtils.RenewItemsSource(WineAttributeList, _attrList); ControlUtils.RenewItemsSource(WineAttributeList, _attrList);
@@ -29,9 +27,7 @@ namespace Elwig.Windows {
} }
private async Task WineAttributesFinishEditing(AppDbContext ctx) { private async Task WineAttributesFinishEditing(AppDbContext ctx) {
ControlUtils.RenewItemsSource(WineAttributeList, await ctx.WineAttributes ControlUtils.RenewItemsSource(WineAttributeList, await ctx.FetchWineAttributes().ToListAsync());
.OrderBy(a => a.Name)
.ToListAsync());
_attrList = null; _attrList = null;
_attrs = null; _attrs = null;
_attrIds = null; _attrIds = null;
@@ -45,9 +41,8 @@ namespace Elwig.Windows {
if (!_attrChanged || _attrList == null || _attrs == null || _attrIds == null) if (!_attrChanged || _attrList == null || _attrs == null || _attrIds == null)
return; return;
foreach (var (attrid, _) in _attrs.Where(a => a.Value == null)) { var deleteAttrIds = _attrs.Where(a => a.Value == null).Select(a => a.Key).ToList();
ctx.Remove(ctx.WineAttributes.Find(attrid)!); await ctx.WineAttributes.Where(a => deleteAttrIds.Contains(a.AttrId)).ExecuteDeleteAsync();
}
foreach (var (attr, old) in _attrIds) { foreach (var (attr, old) in _attrIds) {
attr.AttrId = old; attr.AttrId = old;
} }
@@ -61,7 +56,6 @@ namespace Elwig.Windows {
await ctx.Database.ExecuteSqlAsync($"UPDATE area_commitment_type SET vtrgid = (sortid || COALESCE(attrid, '') || COALESCE(disc, '')) WHERE attrid = {attrid}"); await ctx.Database.ExecuteSqlAsync($"UPDATE area_commitment_type SET vtrgid = (sortid || COALESCE(attrid, '') || COALESCE(disc, '')) WHERE attrid = {attrid}");
await ctx.Database.ExecuteSqlRawAsync($"UPDATE payment_variant SET data = REPLACE(REPLACE(data, '/{old}\"', '/{attrid}\"'), '/{old}-', '/{attrid}-')"); await ctx.Database.ExecuteSqlRawAsync($"UPDATE payment_variant SET data = REPLACE(REPLACE(data, '/{old}\"', '/{attrid}\"'), '/{old}-', '/{attrid}-')");
} }
await ctx.SaveChangesAsync();
foreach (var attr in _attrList.Where(a => !_attrIds.ContainsKey(a))) { foreach (var attr in _attrList.Where(a => !_attrIds.ContainsKey(a))) {
if (attr.AttrId == null) continue; if (attr.AttrId == null) continue;
+4 -10
View File
@@ -19,9 +19,7 @@ namespace Elwig.Windows {
private bool _cultUpdate = false; private bool _cultUpdate = false;
private async Task WineCultivationsInitEditing(AppDbContext ctx) { private async Task WineCultivationsInitEditing(AppDbContext ctx) {
_cultList = new(await ctx.WineCultivations _cultList = new(await ctx.FetchWineCultivations().ToListAsync());
.OrderBy(c => c.Name)
.ToListAsync());
_cults = _cultList.ToDictionary(c => c.CultId, c => (string?)c.CultId); _cults = _cultList.ToDictionary(c => c.CultId, c => (string?)c.CultId);
_cultIds = _cultList.ToDictionary(c => c, c => c.CultId); _cultIds = _cultList.ToDictionary(c => c, c => c.CultId);
ControlUtils.RenewItemsSource(WineCultivationList, _cultList); ControlUtils.RenewItemsSource(WineCultivationList, _cultList);
@@ -29,9 +27,7 @@ namespace Elwig.Windows {
} }
private async Task WineCultivationsFinishEditing(AppDbContext ctx) { private async Task WineCultivationsFinishEditing(AppDbContext ctx) {
ControlUtils.RenewItemsSource(WineCultivationList, await ctx.WineCultivations ControlUtils.RenewItemsSource(WineCultivationList, await ctx.FetchWineCultivations().ToListAsync());
.OrderBy(c => c.Name)
.ToListAsync());
_cultList = null; _cultList = null;
_cults = null; _cults = null;
_cultIds = null; _cultIds = null;
@@ -45,9 +41,8 @@ namespace Elwig.Windows {
if (!_cultChanged || _cultList == null || _cults == null || _cultIds == null) if (!_cultChanged || _cultList == null || _cults == null || _cultIds == null)
return; return;
foreach (var (cultid, _) in _cults.Where(c => c.Value == null)) { var deleteCultIds = _cults.Where(c => c.Value == null).Select(c => c.Key).ToList();
ctx.Remove(ctx.WineCultivations.Find(cultid)!); await ctx.WineCultivations.Where(c => deleteCultIds.Contains(c.CultId)).ExecuteDeleteAsync();
}
foreach (var (cult, old) in _cultIds) { foreach (var (cult, old) in _cultIds) {
cult.CultId = old; cult.CultId = old;
} }
@@ -60,7 +55,6 @@ namespace Elwig.Windows {
await ctx.Database.ExecuteSqlAsync($"UPDATE wine_cultivation SET cultid = {cultid} WHERE cultid = {old}"); await ctx.Database.ExecuteSqlAsync($"UPDATE wine_cultivation SET cultid = {cultid} WHERE cultid = {old}");
await ctx.Database.ExecuteSqlRawAsync($"UPDATE payment_variant SET data = REPLACE(data, '-{old}\"', '-{cultid}\"')"); await ctx.Database.ExecuteSqlRawAsync($"UPDATE payment_variant SET data = REPLACE(data, '-{old}\"', '-{cultid}\"')");
} }
await ctx.SaveChangesAsync();
foreach (var cult in _cultList.Where(c => !_cultIds.ContainsKey(c))) { foreach (var cult in _cultList.Where(c => !_cultIds.ContainsKey(c))) {
if (cult.CultId == null) continue; if (cult.CultId == null) continue;
+44 -74
View File
@@ -1,5 +1,6 @@
using Elwig.Helpers; using Elwig.Helpers;
using Elwig.Models.Entities; using Elwig.Models.Entities;
using Elwig.Services;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using System; using System;
using System.Linq; using System.Linq;
@@ -31,14 +32,15 @@ namespace Elwig.Windows {
AreaCommitmentTypeMinKgPerHaInput, AreaCommitmentTypePenaltyPerKgInput, AreaCommitmentTypeMinKgPerHaInput, AreaCommitmentTypePenaltyPerKgInput,
AreaCommitmentTypePenaltyInput, AreaCommitmentTypePenaltyNoneInput, AreaCommitmentTypePenaltyInput, AreaCommitmentTypePenaltyNoneInput,
SeasonMaxKgPerHaInput, SeasonVatNormalInput, SeasonVatFlatrateInput, SeasonStartInput, SeasonEndInput, SeasonMaxKgPerHaInput, SeasonVatNormalInput, SeasonVatFlatrateInput, SeasonStartInput, SeasonEndInput,
SeasonMinKgPerBsInput, SeasonMaxKgPerBsInput, SeasonBsValueInput, SeasonMinKgPerShareInput, SeasonMaxKgPerShareInput, SeasonShareValueInput,
SeasonPenaltyPerKgInput, SeasonPenaltyInput, SeasonPenaltyNoneInput, SeasonPenaltyPerKgInput, SeasonPenaltyInput, SeasonPenaltyNoneInput,
SeasonPenaltyPerBsInput, SeasonPenaltyPerBsNoneInput, SeasonPenaltyPerShareInput, SeasonPenaltyPerShareNoneInput,
SeasonModifierIdInput, SeasonModifierNameInput, SeasonModifierRelInput, SeasonModifierAbsInput, SeasonModifierIdInput, SeasonModifierNameInput, SeasonModifierRelInput, SeasonModifierAbsInput,
]; ];
WineAttributeFillLowerInput.Visibility = Visibility.Hidden; WineAttributeFillLowerInput.Visibility = Visibility.Hidden;
WineAttributeFillLowerLabel.Visibility = Visibility.Hidden; WineAttributeFillLowerLabel.Visibility = Visibility.Hidden;
ParameterAreaComGroup.Header = ParameterAreaComGroup.Header.ToString()!.Split('(')[0] + $"({Utils.CurrentLastSeason})"; ParameterAreaComGroup.Header = ParameterAreaComGroup.Header.ToString()!.Split('(')[0] + $"({Utils.CurrentLastSeason})";
LockInputs();
} }
protected override void ShortcutNew() { } protected override void ShortcutNew() { }
@@ -78,25 +80,19 @@ namespace Elwig.Windows {
SeasonMaxKgPerHaInput.IsReadOnly = true; SeasonMaxKgPerHaInput.IsReadOnly = true;
SeasonVatNormalInput.IsReadOnly = true; SeasonVatNormalInput.IsReadOnly = true;
SeasonVatFlatrateInput.IsReadOnly = true; SeasonVatFlatrateInput.IsReadOnly = true;
SeasonMinKgPerBsInput.IsReadOnly = true; SeasonMinKgPerShareInput.IsReadOnly = true;
SeasonMaxKgPerBsInput.IsReadOnly = true; SeasonMaxKgPerShareInput.IsReadOnly = true;
SeasonPenaltyPerKgInput.IsReadOnly = true; SeasonPenaltyPerKgInput.IsReadOnly = true;
SeasonPenaltyInput.IsReadOnly = true; SeasonPenaltyInput.IsReadOnly = true;
SeasonPenaltyNoneInput.IsReadOnly = true; SeasonPenaltyNoneInput.IsReadOnly = true;
SeasonPenaltyPerBsInput.IsReadOnly = true; SeasonPenaltyPerShareInput.IsReadOnly = true;
SeasonPenaltyPerBsNoneInput.IsReadOnly = true; SeasonPenaltyPerShareNoneInput.IsReadOnly = true;
SeasonBsValueInput.IsReadOnly = true; SeasonShareValueInput.IsReadOnly = true;
SeasonModifierIdInput.IsReadOnly = true; SeasonModifierIdInput.IsReadOnly = true;
SeasonModifierNameInput.IsReadOnly = true; SeasonModifierNameInput.IsReadOnly = true;
SeasonModifierRelInput.IsReadOnly = true; SeasonModifierRelInput.IsReadOnly = true;
SeasonModifierAbsInput.IsReadOnly = true; SeasonModifierAbsInput.IsReadOnly = true;
ParameterAllowAttrIntoLowerInput.IsEnabled = false;
ParameterAvoidUnderDeliveriesInput.IsEnabled = false;
ParameterHonorGebundenInput.IsEnabled = false;
ParameterExportEbicsVersion.IsEnabled = false;
ParameterExportEbicsAddress.IsEnabled = false;
} }
new protected void UnlockInputs() { new protected void UnlockInputs() {
@@ -132,65 +128,37 @@ namespace Elwig.Windows {
SeasonMaxKgPerHaInput.IsReadOnly = false; SeasonMaxKgPerHaInput.IsReadOnly = false;
SeasonVatNormalInput.IsReadOnly = false; SeasonVatNormalInput.IsReadOnly = false;
SeasonVatFlatrateInput.IsReadOnly = false; SeasonVatFlatrateInput.IsReadOnly = false;
SeasonMinKgPerBsInput.IsReadOnly = false; SeasonMinKgPerShareInput.IsReadOnly = false;
SeasonMaxKgPerBsInput.IsReadOnly = false; SeasonMaxKgPerShareInput.IsReadOnly = false;
SeasonPenaltyPerKgInput.IsReadOnly = false; SeasonPenaltyPerKgInput.IsReadOnly = false;
SeasonPenaltyInput.IsReadOnly = false; SeasonPenaltyInput.IsReadOnly = false;
SeasonPenaltyNoneInput.IsReadOnly = false; SeasonPenaltyNoneInput.IsReadOnly = false;
SeasonPenaltyPerBsInput.IsReadOnly = false; SeasonPenaltyPerShareInput.IsReadOnly = false;
SeasonPenaltyPerBsNoneInput.IsReadOnly = false; SeasonPenaltyPerShareNoneInput.IsReadOnly = false;
SeasonBsValueInput.IsReadOnly = false; SeasonShareValueInput.IsReadOnly = false;
SeasonModifierIdInput.IsReadOnly = false; SeasonModifierIdInput.IsReadOnly = false;
SeasonModifierNameInput.IsReadOnly = false; SeasonModifierNameInput.IsReadOnly = false;
SeasonModifierRelInput.IsReadOnly = false; SeasonModifierRelInput.IsReadOnly = false;
SeasonModifierAbsInput.IsReadOnly = false; SeasonModifierAbsInput.IsReadOnly = false;
ParameterAllowAttrIntoLowerInput.IsEnabled = true;
ParameterAvoidUnderDeliveriesInput.IsEnabled = true;
ParameterHonorGebundenInput.IsEnabled = true;
ParameterExportEbicsVersion.IsEnabled = true;
ParameterExportEbicsAddress.IsEnabled = true;
}
private void Window_Loaded(object sender, RoutedEventArgs evt) {
LockInputs();
} }
protected override async Task OnRenewContext(AppDbContext ctx) { protected override async Task OnRenewContext(AppDbContext ctx) {
await base.OnRenewContext(ctx); await base.OnRenewContext(ctx);
FillInputs(App.Client, await ctx.Seasons.FindAsync(Utils.CurrentLastSeason)); FillInputs(App.Client, await ctx.FetchSeasons(Utils.CurrentLastSeason).SingleOrDefaultAsync());
ControlUtils.RenewItemsSource(SeasonList, await ctx.Seasons ControlUtils.RenewItemsSource(SeasonList, await ctx.FetchSeasons(includeModifiers: true).ToListAsync(), null, ControlUtils.RenewSourceDefault.First);
.OrderByDescending(s => s.Year)
.Include(s => s.Modifiers)
.Include(s => s.Currency)
.ToListAsync(), null, ControlUtils.RenewSourceDefault.First);
var year = (SeasonList.SelectedItem as Season)?.Year; var year = (SeasonList.SelectedItem as Season)?.Year;
ControlUtils.RenewItemsSource(BranchList, await ctx.Branches ControlUtils.RenewItemsSource(BranchList, await ctx.FetchBranches().ToListAsync(), null, ControlUtils.RenewSourceDefault.First);
.OrderBy(b => b.Name) ControlUtils.RenewItemsSource(WineAttributeList, await ctx.FetchWineAttributes().ToListAsync(), null, ControlUtils.RenewSourceDefault.First);
.Include(b => b.PostalDest!.AtPlz) ControlUtils.RenewItemsSource(AreaCommitmentTypeWineVariantInput, await ctx.FetchWineVarieties().ToListAsync());
.ToListAsync(), null, ControlUtils.RenewSourceDefault.First); var attrList = await ctx.FetchWineAttributes().Cast<object>().ToListAsync();
ControlUtils.RenewItemsSource(WineAttributeList, await ctx.WineAttributes
.OrderBy(a => a.Name)
.ToListAsync(), null, ControlUtils.RenewSourceDefault.First);
ControlUtils.RenewItemsSource(AreaCommitmentTypeWineVariantInput, await ctx.WineVarieties
.OrderBy(s => s.Name)
.ToListAsync());
var attrList = await ctx.WineAttributes.OrderBy(a => a.Name).Cast<object>().ToListAsync();
attrList.Insert(0, new NullItem("")); attrList.Insert(0, new NullItem(""));
ControlUtils.RenewItemsSource(AreaCommitmentTypeWineAttributeInput, attrList); ControlUtils.RenewItemsSource(AreaCommitmentTypeWineAttributeInput, attrList);
ControlUtils.RenewItemsSource(AreaCommitmentTypeList, await ctx.AreaCommitmentTypes ControlUtils.RenewItemsSource(AreaCommitmentTypeList, await ctx.AreaCommitmentTypes
.OrderBy(t => t.VtrgId) .OrderBy(t => t.VtrgId)
.Include(t => t.WineVar)
.Include(t => t.WineAttr)
.ToListAsync(), null, ControlUtils.RenewSourceDefault.First);
ControlUtils.RenewItemsSource(WineCultivationList, await ctx.WineCultivations
.OrderBy(c => c.Name)
.ToListAsync(), null, ControlUtils.RenewSourceDefault.First);
ControlUtils.RenewItemsSource(SeasonModifierList, await ctx.Modifiers
.Where(m => m.Year == year)
.OrderBy(m => m.Ordering)
.ToListAsync(), null, ControlUtils.RenewSourceDefault.First); .ToListAsync(), null, ControlUtils.RenewSourceDefault.First);
ControlUtils.RenewItemsSource(WineCultivationList, await ctx.FetchWineCultivations().ToListAsync(), null, ControlUtils.RenewSourceDefault.First);
ControlUtils.RenewItemsSource(SeasonModifierList, await ctx.FetchModifiers(year ?? 0).ToListAsync(), null, ControlUtils.RenewSourceDefault.First);
} }
protected override void UpdateButtons() { protected override void UpdateButtons() {
@@ -286,7 +254,7 @@ namespace Elwig.Windows {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
ClearInputStates(); ClearInputStates();
FillInputs(App.Client, await ctx.Seasons.FindAsync(Utils.CurrentLastSeason)); FillInputs(App.Client, await ctx.FetchSeasons(Utils.CurrentLastSeason).SingleOrDefaultAsync());
LockInputs(); LockInputs();
} }
@@ -306,7 +274,7 @@ namespace Elwig.Windows {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
ClearInputStates(); ClearInputStates();
FillInputs(App.Client, await ctx.Seasons.FindAsync(Utils.CurrentLastSeason)); FillInputs(App.Client, await ctx.FetchSeasons(Utils.CurrentLastSeason).SingleOrDefaultAsync());
UpdateButtons(); UpdateButtons();
} }
@@ -322,9 +290,7 @@ namespace Elwig.Windows {
try { try {
await Save(); await Save();
} catch (Exception exc) { } catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message; InteractionService.ShowDbException("Stammdaten aktualisieren", exc);
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Stammdaten aktualisieren", MessageBoxButton.OK, MessageBoxImage.Error);
SaveButton.IsEnabled = true; SaveButton.IsEnabled = true;
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
return; return;
@@ -342,7 +308,7 @@ namespace Elwig.Windows {
using (var ctx = new AppDbContext()) { using (var ctx = new AppDbContext()) {
ClearInputStates(); ClearInputStates();
FillInputs(App.Client, await ctx.Seasons.FindAsync(Utils.CurrentLastSeason)); FillInputs(App.Client, await ctx.FetchSeasons(Utils.CurrentLastSeason).SingleOrDefaultAsync());
LockInputs(); LockInputs();
} }
@@ -382,6 +348,8 @@ namespace Elwig.Windows {
TextElementDeliveryConfirmation.Text = p.TextDeliveryConfirmation; TextElementDeliveryConfirmation.Text = p.TextDeliveryConfirmation;
TextElementCreditNote.Text = p.TextCreditNote; TextElementCreditNote.Text = p.TextCreditNote;
ParameterBusinessShareModeInput.SelectedIndex = p.ModeBusinessShares;
ParameterBusinessShareHistoryInput.IsChecked = p.EnableMemberHistory;
ParameterAllowAttrIntoLowerInput.IsChecked = s?.Billing_AllowAttrsIntoLower ?? false; ParameterAllowAttrIntoLowerInput.IsChecked = s?.Billing_AllowAttrsIntoLower ?? false;
ParameterAvoidUnderDeliveriesInput.IsChecked = s?.Billing_AvoidUnderDeliveries ?? false; ParameterAvoidUnderDeliveriesInput.IsChecked = s?.Billing_AvoidUnderDeliveries ?? false;
ParameterHonorGebundenInput.IsChecked = s?.Billing_HonorGebunden ?? false; ParameterHonorGebundenInput.IsChecked = s?.Billing_HonorGebunden ?? false;
@@ -393,27 +361,29 @@ namespace Elwig.Windows {
private async Task UpdateClientParameters(ClientParameters p) { private async Task UpdateClientParameters(ClientParameters p) {
p.Name = ClientNameInput.Text; p.Name = ClientNameInput.Text;
p.NameSuffix = string.IsNullOrEmpty(ClientNameSuffixInput.Text) ? null : ClientNameSuffixInput.Text; p.NameSuffix = string.IsNullOrWhiteSpace(ClientNameSuffixInput.Text) ? null : ClientNameSuffixInput.Text;
p.NameType = ClientNameTypeInput.Text; p.NameType = ClientNameTypeInput.Text;
p.NameToken = ClientNameTokenInput.Text; p.NameToken = ClientNameTokenInput.Text;
p.NameShort = ClientNameShortInput.Text; p.NameShort = ClientNameShortInput.Text;
p.Address = ClientAddressInput.Text; p.Address = ClientAddressInput.Text;
p.Plz = int.Parse(ClientPlzInput.Text); p.Plz = int.Parse(ClientPlzInput.Text);
p.Ort = ClientOrtInput.Text; p.Ort = ClientOrtInput.Text;
p.Iban = string.IsNullOrEmpty(ClientIbanInput.Text) ? null : ClientIbanInput.Text; p.Iban = string.IsNullOrWhiteSpace(ClientIbanInput.Text) ? null : ClientIbanInput.Text;
p.Bic = string.IsNullOrEmpty(ClientBicInput.Text) ? null : ClientBicInput.Text; p.Bic = string.IsNullOrWhiteSpace(ClientBicInput.Text) ? null : ClientBicInput.Text;
p.UstIdNr = string.IsNullOrEmpty(ClientUstIdNrInput.Text) ? null : ClientUstIdNrInput.Text; p.UstIdNr = string.IsNullOrWhiteSpace(ClientUstIdNrInput.Text) ? null : ClientUstIdNrInput.Text;
p.LfbisNr = string.IsNullOrEmpty(ClientLfbisNrInput.Text) ? null : ClientLfbisNrInput.Text; p.LfbisNr = string.IsNullOrWhiteSpace(ClientLfbisNrInput.Text) ? null : ClientLfbisNrInput.Text;
p.OrganicAuthority = string.IsNullOrEmpty(ClientOrganicAuthorityInput.Text) ? null : ClientOrganicAuthorityInput.Text; p.OrganicAuthority = string.IsNullOrWhiteSpace(ClientOrganicAuthorityInput.Text) ? null : ClientOrganicAuthorityInput.Text;
p.PhoneNr = string.IsNullOrEmpty(ClientPhoneNrInput.Text) ? null : ClientPhoneNrInput.Text; p.PhoneNr = string.IsNullOrWhiteSpace(ClientPhoneNrInput.Text) ? null : ClientPhoneNrInput.Text;
p.FaxNr = string.IsNullOrEmpty(ClientFaxNrInput.Text) ? null : ClientFaxNrInput.Text; p.FaxNr = string.IsNullOrWhiteSpace(ClientFaxNrInput.Text) ? null : ClientFaxNrInput.Text;
p.EmailAddress = string.IsNullOrEmpty(ClientEmailAddressInput.Text) ? null : ClientEmailAddressInput.Text; p.EmailAddress = string.IsNullOrWhiteSpace(ClientEmailAddressInput.Text) ? null : ClientEmailAddressInput.Text;
p.Website = string.IsNullOrEmpty(ClientWebsiteInput.Text) ? null : ClientWebsiteInput.Text; p.Website = string.IsNullOrWhiteSpace(ClientWebsiteInput.Text) ? null : ClientWebsiteInput.Text;
p.TextDeliveryNote = string.IsNullOrEmpty(TextElementDeliveryNote.Text) ? null : TextElementDeliveryNote.Text; p.ModeBusinessShares = ParameterBusinessShareModeInput.SelectedIndex;
p.EnableMemberHistory = ParameterBusinessShareHistoryInput.IsChecked ?? false;
p.TextDeliveryNote = string.IsNullOrWhiteSpace(TextElementDeliveryNote.Text) ? null : TextElementDeliveryNote.Text;
p.ModeDeliveryNoteStats = (ModeDeliveryNoteNone.IsChecked == true) ? 0 : (ModeDeliveryNoteGaOnly.IsChecked == true) ? 1 : (ModeDeliveryNoteShort.IsChecked == true) ? 2 : (ModeDeliveryNoteFull.IsChecked == true) ? 3 : 2; p.ModeDeliveryNoteStats = (ModeDeliveryNoteNone.IsChecked == true) ? 0 : (ModeDeliveryNoteGaOnly.IsChecked == true) ? 1 : (ModeDeliveryNoteShort.IsChecked == true) ? 2 : (ModeDeliveryNoteFull.IsChecked == true) ? 3 : 2;
p.TextDeliveryConfirmation = string.IsNullOrEmpty(TextElementDeliveryConfirmation.Text) ? null : TextElementDeliveryConfirmation.Text; p.TextDeliveryConfirmation = string.IsNullOrWhiteSpace(TextElementDeliveryConfirmation.Text) ? null : TextElementDeliveryConfirmation.Text;
p.TextCreditNote = string.IsNullOrEmpty(TextElementCreditNote.Text) ? null : TextElementCreditNote.Text; p.TextCreditNote = string.IsNullOrWhiteSpace(TextElementCreditNote.Text) ? null : TextElementCreditNote.Text;
p.ExportEbicsVersion = ParameterExportEbicsVersion.SelectedIndex + 3; p.ExportEbicsVersion = ParameterExportEbicsVersion.SelectedIndex + 3;
p.ExportEbicsAddress = ParameterExportEbicsAddress.SelectedIndex; p.ExportEbicsAddress = ParameterExportEbicsAddress.SelectedIndex;
@@ -430,7 +400,7 @@ namespace Elwig.Windows {
private async Task UpdateParameters(int year) { private async Task UpdateParameters(int year) {
try { try {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
if (await ctx.Seasons.FindAsync(year) is not Season s) if (await ctx.FetchSeasons(year).SingleOrDefaultAsync() is not Season s)
return; return;
s.Billing_AllowAttrsIntoLower = ParameterAllowAttrIntoLowerInput.IsChecked ?? false; s.Billing_AllowAttrsIntoLower = ParameterAllowAttrIntoLowerInput.IsChecked ?? false;
-1
View File
@@ -9,7 +9,6 @@
xmlns:ScottPlot="clr-namespace:ScottPlot.WPF;assembly=ScottPlot.WPF" xmlns:ScottPlot="clr-namespace:ScottPlot.WPF;assembly=ScottPlot.WPF"
mc:Ignorable="d" mc:Ignorable="d"
Title="Auszahlung - Elwig" Height="700" Width="1500" MinWidth="1000" MinHeight="500" Title="Auszahlung - Elwig" Height="700" Width="1500" MinWidth="1000" MinHeight="500"
Loaded="Window_Loaded"
Closing="Window_Closing"> Closing="Window_Closing">
<Window.Resources> <Window.Resources>
+60 -60
View File
@@ -10,6 +10,7 @@ using Elwig.Helpers.Billing;
using Elwig.Models.Entities; using Elwig.Models.Entities;
using ScottPlot.Plottables; using ScottPlot.Plottables;
using ScottPlot; using ScottPlot;
using Elwig.Services;
namespace Elwig.Windows { namespace Elwig.Windows {
public partial class ChartWindow : ContextWindow { public partial class ChartWindow : ContextWindow {
@@ -25,12 +26,12 @@ namespace Elwig.Windows {
private bool HasChanged = false; private bool HasChanged = false;
private bool Updating = false; private bool Updating = false;
private Scatter DataPlot; private Scatter? DataPlot;
private Scatter? GebundenPlot; private Scatter? GebundenPlot;
private Marker HighlightedPointPlot; private Marker? HighlightedPointPlot;
private Marker PrimaryMarkedPointPlot; private Marker? PrimaryMarkedPointPlot;
private Marker SecondaryMarkedPointPlot; private Marker? SecondaryMarkedPointPlot;
private Text TooltipPlot; private Text? TooltipPlot;
private static readonly LegendItem private static readonly LegendItem
UngebundenLegend = new() { UngebundenLegend = new() {
@@ -76,18 +77,13 @@ namespace Elwig.Windows {
PriceInput.Unit = $"{CurrencySymbol}/kg"; PriceInput.Unit = $"{CurrencySymbol}/kg";
GebundenFlatBonus.Unit = $"{CurrencySymbol}/kg"; GebundenFlatBonus.Unit = $"{CurrencySymbol}/kg";
PaymentVar = ctx.PaymentVariants.Find(year, avnr) ?? throw new ArgumentException("PaymentVar not found"); PaymentVar = ctx.PaymentVariants.Find(year, avnr) ?? throw new ArgumentException("PaymentVar not found");
Title = $"{PaymentVar?.Name} - Lese {year} - Elwig"; Title = $"{PaymentVar.Name} - Lese {year} - Elwig";
LockContext = true; LockContext = true;
} }
private void Window_Loaded(object sender, RoutedEventArgs evt) {
}
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) { private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) {
if (HasChanged) { if (HasChanged) {
var r = MessageBox.Show("Soll das Fenster wirklich geschlossen werden? Nicht gespeicherte Änderungen werden NICHT übernommen!", "Schließen bestätigen", if (!InteractionService.AskConfirmation("Schließen bestätigen", "Soll das Fenster wirklich geschlossen werden? Nicht gespeicherte Änderungen werden NICHT übernommen!")) {
MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No);
if (r != MessageBoxResult.Yes) {
e.Cancel = true; e.Cancel = true;
return; return;
} }
@@ -101,32 +97,31 @@ namespace Elwig.Windows {
private async Task RefreshGraphList(AppDbContext ctx) { private async Task RefreshGraphList(AppDbContext ctx) {
PaymentVar = await ctx.PaymentVariants.FindAsync(Year, AvNr) ?? throw new ArgumentException("PaymentVar not found"); PaymentVar = await ctx.PaymentVariants.FindAsync(Year, AvNr) ?? throw new ArgumentException("PaymentVar not found");
Season = await ctx.Seasons.FindAsync(Year) ?? throw new ArgumentException("Season not found"); Season = await ctx.FetchSeasons(Year).SingleOrDefaultAsync() ?? throw new ArgumentException("Season not found");
CurrencySymbol = Season.Currency.Symbol ?? Season.Currency.Code; CurrencySymbol = Season.Currency.Symbol ?? Season.Currency.Code;
PriceInput.Unit = $"{CurrencySymbol}/kg"; PriceInput.Unit = $"{CurrencySymbol}/kg";
GebundenFlatBonus.Unit = $"{CurrencySymbol}/kg"; GebundenFlatBonus.Unit = $"{CurrencySymbol}/kg";
try { try {
var data = EditBillingData.FromJson(PaymentVar.Data, Utils.GetVaributes(ctx, Year)); var data = EditBillingData.FromJson(PaymentVar.Data, await Utils.GetVaributes(ctx, Year));
var paymentEntries = data.GetPaymentGraphEntries(ctx, Season); var paymentEntries = (await data.GetPaymentGraphEntries(ctx, Season)).ToList();
GraphEntries = [ GraphEntries = [
..paymentEntries, ..paymentEntries,
..data.GetQualityGraphEntries(ctx, Season, paymentEntries.Any() ? paymentEntries.Max(e => e.Id) : 0) ..await data.GetQualityGraphEntries(ctx, Season, paymentEntries.Count != 0 ? paymentEntries.Max(e => e.Id) : 0)
]; ];
} catch (KeyNotFoundException ex) { } catch (KeyNotFoundException exc) {
var key = ex.Message.Split('\'')[1].Split('\'')[0]; var key = exc.Message.Split('\'')[1].Split('\'')[0];
MessageBox.Show($"Fehler beim Laden der Auszahlungsvariante:\n\n" + InteractionService.ShowError("Fehler",
$"Mit unbekanntem Attribut '{key}' kann nicht umgegangen werden.", "Fehler", $"Fehler beim Laden der Auszahlungsvariante:\n\n" +
MessageBoxButton.OK, MessageBoxImage.Error); $"Mit unbekanntem Attribut '{key}' kann nicht umgegangen werden.");
} catch (ArgumentException) { } catch (ArgumentException) {
MessageBox.Show($"Fehler beim Laden der Auszahlungsvariante:\n\n" + InteractionService.ShowError("Fehler",
$"Die Daten der Auszahlungsvariante entsprechen nicht dem benötigtem Format.", "Fehler", $"Fehler beim Laden der Auszahlungsvariante:\n\n" +
MessageBoxButton.OK, MessageBoxImage.Error); $"Die Daten der Auszahlungsvariante entsprechen nicht dem benötigtem Format.");
} catch (Exception ex) { } catch (Exception exc) {
MessageBox.Show("Fehler beim Laden der Auszahlungsvariante:\n\n" + ex.Message, "Fehler", InteractionService.ShowException("Fehler", "Fehler beim Laden der Auszahlungsvariante", exc);
MessageBoxButton.OK, MessageBoxImage.Error);
} }
Vaributes = Utils.GetVaributeList(ctx, Year); Vaributes = await Utils.GetVaributeList(ctx, Year);
GraphEntries.ForEach(e => { GraphEntries.ForEach(e => {
e.Vaributes.ForEach(v => { e.Vaributes.ForEach(v => {
var found = Vaributes.Find(a => a.Variety?.SortId == v.Variety?.SortId && a.Attribute?.AttrId == v.Attribute?.AttrId && a.Cultivation?.CultId == v.Cultivation?.CultId); var found = Vaributes.Find(a => a.Variety?.SortId == v.Variety?.SortId && a.Attribute?.AttrId == v.Attribute?.AttrId && a.Cultivation?.CultId == v.Cultivation?.CultId);
@@ -220,10 +215,12 @@ namespace Elwig.Windows {
GebundenPlot.MarkerStyle = new MarkerStyle(MarkerShape.FilledCircle, 9, ColorGebunden); GebundenPlot.MarkerStyle = new MarkerStyle(MarkerShape.FilledCircle, 9, ColorGebunden);
} }
DataPlot = OechslePricePlot.Plot.Add.Scatter(SelectedGraphEntry!.DataGraph.DataX, SelectedGraphEntry!.DataGraph.DataY); if (SelectedGraphEntry != null) {
DataPlot = OechslePricePlot.Plot.Add.Scatter(SelectedGraphEntry.DataGraph.DataX, SelectedGraphEntry.DataGraph.DataY);
DataPlot.LineStyle.Color = ColorUngebunden; DataPlot.LineStyle.Color = ColorUngebunden;
DataPlot.Color = ColorUngebunden; DataPlot.Color = ColorUngebunden;
DataPlot.MarkerStyle = new MarkerStyle(MarkerShape.FilledCircle, 9, ColorUngebunden); DataPlot.MarkerStyle = new MarkerStyle(MarkerShape.FilledCircle, 9, ColorUngebunden);
}
OechslePricePlot.Plot.Axes.SetLimits(Math.Min(GraphEntry.MinX, GraphEntry.MinXGeb) - 1, GraphEntry.MaxX + 1, -0.1, 1.5); OechslePricePlot.Plot.Axes.SetLimits(Math.Min(GraphEntry.MinX, GraphEntry.MinXGeb) - 1, GraphEntry.MaxX + 1, -0.1, 1.5);
@@ -249,7 +246,10 @@ namespace Elwig.Windows {
SecondaryMarkedPoint = -1; SecondaryMarkedPoint = -1;
ChangeActiveGraph(null); ChangeActiveGraph(null);
HideGradationLines(); HideGradationLines();
if (DataPlot != null) {
OechslePricePlot.Plot.Remove(DataPlot); OechslePricePlot.Plot.Remove(DataPlot);
DataPlot = null;
}
if (GebundenPlot != null) { if (GebundenPlot != null) {
OechslePricePlot.Plot.Remove(GebundenPlot); OechslePricePlot.Plot.Remove(GebundenPlot);
GebundenPlot = null; GebundenPlot = null;
@@ -259,9 +259,9 @@ namespace Elwig.Windows {
OechslePricePlot.Refresh(); OechslePricePlot.Refresh();
} }
private void ChangeMarker(Marker point, bool visible, double x = 0, double y = 0) { private static void ChangeMarker(Marker? point, bool visible, double x = 0, double y = 0) {
point.Location = new Coordinates(x, y); point?.Location = new Coordinates(x, y);
point.IsVisible = visible; point?.IsVisible = visible;
} }
private void EnableActionButtons() { private void EnableActionButtons() {
@@ -421,7 +421,7 @@ namespace Elwig.Windows {
var res = Validator.CheckDecimal(PriceInput, true, 2, Season.Precision); var res = Validator.CheckDecimal(PriceInput, true, 2, Season.Precision);
if (res.IsValid && double.TryParse(PriceInput.Text, out double price)) { if (res.IsValid && double.TryParse(PriceInput.Text, out double price)) {
ActiveGraph.SetPriceAt(PrimaryMarkedPoint, price); ActiveGraph.SetPriceAt(PrimaryMarkedPoint, price);
PrimaryMarkedPointPlot.Location = new Coordinates(PrimaryMarkedPointPlot.Location.X, price); PrimaryMarkedPointPlot?.Location = new Coordinates(PrimaryMarkedPointPlot.Location.X, price);
SetHasChanged(); SetHasChanged();
OechslePricePlot.Refresh(); OechslePricePlot.Refresh();
CheckGebundenTypeFixed(); CheckGebundenTypeFixed();
@@ -497,17 +497,19 @@ namespace Elwig.Windows {
ChangeMarker(PrimaryMarkedPointPlot, true, ActiveGraph.GetOechsleAt(PrimaryMarkedPoint), ActiveGraph.GetPriceAt(PrimaryMarkedPoint)); ChangeMarker(PrimaryMarkedPointPlot, true, ActiveGraph.GetOechsleAt(PrimaryMarkedPoint), ActiveGraph.GetPriceAt(PrimaryMarkedPoint));
if (Highlighted.Graph != null) {
Updating = true; Updating = true;
OechsleInput.Text = Highlighted.Graph!.GetOechsleAt(Highlighted.Index).ToString(); OechsleInput.Text = Highlighted.Graph.GetOechsleAt(Highlighted.Index).ToString();
GebInput.IsChecked = Highlighted.Graph == SelectedGraphEntry?.GebundenGraph; GebInput.IsChecked = Highlighted.Graph == SelectedGraphEntry?.GebundenGraph;
PriceInput.Text = Math.Round(Highlighted.Graph.GetPriceAt(Highlighted.Index), Season.Precision).ToString(); PriceInput.Text = Math.Round(Highlighted.Graph.GetPriceAt(Highlighted.Index), Season.Precision).ToString();
Updating = false; Updating = false;
}
EnableActionButtons(); EnableActionButtons();
} else { } else {
PrimaryMarkedPoint = -1; PrimaryMarkedPoint = -1;
SecondaryMarkedPoint = -1; SecondaryMarkedPoint = -1;
if (SelectedGraphEntry!.GebundenGraph != null) { if (SelectedGraphEntry?.GebundenGraph != null) {
ChangeActiveGraph(null); ChangeActiveGraph(null);
} }
ChangeMarker(PrimaryMarkedPointPlot, false); ChangeMarker(PrimaryMarkedPointPlot, false);
@@ -553,21 +555,26 @@ namespace Elwig.Windows {
if (mouseOnData != null) { if (mouseOnData != null) {
ChangeMarker(HighlightedPointPlot, true, mouseOnData.Value.X, mouseOnData.Value.Y); ChangeMarker(HighlightedPointPlot, true, mouseOnData.Value.X, mouseOnData.Value.Y);
HighlightedPointPlot.IsVisible = true; HighlightedPointPlot?.IsVisible = true;
HoverChanged = true ^ HoverActive; HoverChanged = true ^ HoverActive;
HoverActive = true; HoverActive = true;
HandleTooltip(mouseOnData.Value.X, mouseOnData.Value.Y, mouseOnData.Value.Index, SelectedGraphEntry!.DataGraph, e.GetPosition(OechslePricePlot), e is MouseWheelEventArgs); if (SelectedGraphEntry?.DataGraph is Graph g)
HandleTooltip(mouseOnData.Value.X, mouseOnData.Value.Y, mouseOnData.Value.Index, g, e.GetPosition(OechslePricePlot), e is MouseWheelEventArgs);
} else if (mouseOnGebunden != null) { } else if (mouseOnGebunden != null) {
ChangeMarker(HighlightedPointPlot, true, mouseOnGebunden.Value.X, mouseOnGebunden.Value.Y); ChangeMarker(HighlightedPointPlot, true, mouseOnGebunden.Value.X, mouseOnGebunden.Value.Y);
HighlightedPointPlot.IsVisible = true; HighlightedPointPlot?.IsVisible = true;
HoverChanged = true ^ HoverActive; HoverChanged = true ^ HoverActive;
HoverActive = true; HoverActive = true;
HandleTooltip(mouseOnGebunden.Value.X, mouseOnGebunden.Value.Y, mouseOnGebunden.Value.Index, SelectedGraphEntry!.GebundenGraph!, e.GetPosition(OechslePricePlot), e is MouseWheelEventArgs); if (SelectedGraphEntry?.GebundenGraph is Graph g)
HandleTooltip(mouseOnGebunden.Value.X, mouseOnGebunden.Value.Y, mouseOnGebunden.Value.Index, g, e.GetPosition(OechslePricePlot), e is MouseWheelEventArgs);
} else { } else {
ChangeMarker(HighlightedPointPlot, false); ChangeMarker(HighlightedPointPlot, false);
HoverChanged = false ^ HoverActive; HoverChanged = false ^ HoverActive;
HoverActive = false; HoverActive = false;
if (TooltipPlot != null) {
OechslePricePlot.Plot.PlottableList.Remove(TooltipPlot); OechslePricePlot.Plot.PlottableList.Remove(TooltipPlot);
TooltipPlot = null;
}
OechslePricePlot.Refresh(); OechslePricePlot.Refresh();
} }
} }
@@ -582,7 +589,10 @@ namespace Elwig.Windows {
private void HandleTooltip(double pointX, double pointY, int pointIndex, Graph g, Point p, bool force) { private void HandleTooltip(double pointX, double pointY, int pointIndex, Graph g, Point p, bool force) {
if (force || LastHighlighted != Highlighted || HoverChanged) { if (force || LastHighlighted != Highlighted || HoverChanged) {
if (TooltipPlot != null) {
OechslePricePlot.Plot.PlottableList.Remove(TooltipPlot); OechslePricePlot.Plot.PlottableList.Remove(TooltipPlot);
TooltipPlot = null;
}
if (TooltipInput.IsChecked == true) { if (TooltipInput.IsChecked == true) {
Coordinates mouseLocation = GetMouseCoordinates(new(p.X, p.Y - 30)); Coordinates mouseLocation = GetMouseCoordinates(new(p.X, p.Y - 30));
TooltipPlot = OechslePricePlot.Plot.Add.Text($"Oechsle: {pointX:N2}, Preis: {Math.Round(pointY, Season.Precision)} {CurrencySymbol}/kg", mouseLocation.X, mouseLocation.Y); TooltipPlot = OechslePricePlot.Plot.Add.Text($"Oechsle: {pointX:N2}, Preis: {Math.Round(pointY, Season.Precision)} {CurrencySymbol}/kg", mouseLocation.X, mouseLocation.Y);
@@ -625,11 +635,7 @@ namespace Elwig.Windows {
private void DeleteButton_Click(object sender, RoutedEventArgs e) { private void DeleteButton_Click(object sender, RoutedEventArgs e) {
if (SelectedGraphEntry == null) return; if (SelectedGraphEntry == null) return;
var r = MessageBox.Show( if (InteractionService.AskConfirmation("Kurve löschen", $"Soll die Kurve {SelectedGraphEntry.Id} (verwendet in folgenden Verträgen: {SelectedGraphEntry.VaributeStringSimple}) wirklich gelöscht werden?")) {
$"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); GraphEntries.Remove(SelectedGraphEntry);
SetHasChanged(); SetHasChanged();
GraphList.Items.Refresh(); GraphList.Items.Refresh();
@@ -645,7 +651,7 @@ namespace Elwig.Windows {
await Task.Run(async () => { await Task.Run(async () => {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
var origData = BillingData.FromJson(PaymentVar.Data); var origData = BillingData.FromJson(PaymentVar.Data);
var data = BillingData.FromGraphEntries(GraphEntries, origData, Utils.GetVaributes(ctx, Year), var data = BillingData.FromGraphEntries(GraphEntries, origData, await Utils.GetVaributes(ctx, Year),
AllVaributesAssigned, AllVaributesAssignedAbgew); AllVaributesAssigned, AllVaributesAssignedAbgew);
PaymentVar.Data = data.ToJsonString(); PaymentVar.Data = data.ToJsonString();
@@ -654,22 +660,20 @@ namespace Elwig.Windows {
}); });
} catch (Exception exc) { } catch (Exception exc) {
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
var str = "Der Eintrag konnte nicht in der Datenbank gespeichert werden!\n\n" + exc.Message; InteractionService.ShowDbException("Auszahlungsvariante speichern", exc);
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Auszahlungsvariante speichern", MessageBoxButton.OK, MessageBoxImage.Error);
SaveButton.IsEnabled = true; SaveButton.IsEnabled = true;
return; return;
} }
try { try {
await Task.Run(async () => { await Task.Run(async () => {
var b = new BillingVariant(PaymentVar.Year, PaymentVar.AvNr); var b = await BillingVariant.Create(PaymentVar.Year, PaymentVar.AvNr);
await b.Calculate(false); await b.Calculate(false);
}); });
} catch (KeyNotFoundException exc) { } catch (KeyNotFoundException exc) {
MessageBox.Show(exc.Message, "Noch nicht alle Preise festgelegt", MessageBoxButton.OK, MessageBoxImage.Information); InteractionService.ShowInformation("Noch nicht alle Preise festgelegt", exc.Message);
} catch (Exception exc) { } catch (Exception exc) {
MessageBox.Show(exc.Message, "Berechnungsfehler", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException("Berechnungsfehler", exc);
} }
LockContext = false; LockContext = false;
@@ -687,7 +691,7 @@ namespace Elwig.Windows {
} }
} }
private void DisableTextBox(TextBox u) { private static void DisableTextBox(TextBox u) {
u.IsEnabled = false; u.IsEnabled = false;
u.IsReadOnly = true; u.IsReadOnly = true;
} }
@@ -718,10 +722,8 @@ namespace Elwig.Windows {
ActiveGraph = g; ActiveGraph = g;
} }
private void ChangeLineWidth(Scatter? p, double lineWidth) { private static void ChangeLineWidth(Scatter? p, double lineWidth) {
if (p != null) { p?.LineWidth = (float)lineWidth;
p.LineWidth = (float)lineWidth;
}
} }
private void GraphList_SelectionChanged(object sender, SelectionChangedEventArgs e) { private void GraphList_SelectionChanged(object sender, SelectionChangedEventArgs e) {
@@ -763,7 +765,7 @@ namespace Elwig.Windows {
} }
} }
SelectedGraphEntry!.Vaributes = VaributeInput.SelectedItems.Cast<Varibute>().ToList(); SelectedGraphEntry?.Vaributes = [.. VaributeInput.SelectedItems.Cast<Varibute>()];
SetHasChanged(); SetHasChanged();
GraphList.Items.Refresh(); GraphList.Items.Refresh();
VaributeInput.Items.Refresh(); VaributeInput.Items.Refresh();
@@ -776,9 +778,7 @@ namespace Elwig.Windows {
if (ge != SelectedGraphEntry && ge.Abgewertet == SelectedGraphEntry?.Abgewertet) { if (ge != SelectedGraphEntry && ge.Abgewertet == SelectedGraphEntry?.Abgewertet) {
var toRemove = ge.Vaributes.Where(c => c.Listing.Equals(varibute)).ToList(); var toRemove = ge.Vaributes.Where(c => c.Listing.Equals(varibute)).ToList();
if (toRemove.Count == 0) continue; if (toRemove.Count == 0) continue;
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", if (!InteractionService.AskConfirmation("Entfernen bestätigen", $"Achtung: {string.Join(", ", toRemove)} ist bereits in Kurve {ge.Id} in Verwendung!\nSoll die Zuweisung dort entfernt werden?")) {
MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No);
if (r != MessageBoxResult.Yes) {
return false; return false;
} }
ge.Vaributes.RemoveAll(c => c.Listing.Equals(varibute)); ge.Vaributes.RemoveAll(c => c.Listing.Equals(varibute));
+19 -3
View File
@@ -18,6 +18,8 @@ namespace Elwig.Windows {
} }
} }
protected bool HasContextLoaded { get; private set; }
private bool _renewPending = false; private bool _renewPending = false;
private readonly RoutedCommand CtrlR = new("CtrlR", typeof(ContextWindow), [new KeyGesture(Key.R, ModifierKeys.Control)]); private readonly RoutedCommand CtrlR = new("CtrlR", typeof(ContextWindow), [new KeyGesture(Key.R, ModifierKeys.Control)]);
@@ -30,27 +32,41 @@ namespace Elwig.Windows {
} }
public async void ForceContextReload(object sender, EventArgs evt) { public async void ForceContextReload(object sender, EventArgs evt) {
await HintContextChange(); await ForceContextReload();
} }
public async Task HintContextChange() { public async Task ForceContextReload() {
HintContextChange();
await TryContextReload();
}
public void HintContextChange() {
_renewPending = true; _renewPending = true;
}
public async Task TryContextReload() {
if (LockContext) return; if (LockContext) return;
await EnsureContextRenewed(); await EnsureContextRenewed();
} }
protected async void OnLoaded(object? sender, RoutedEventArgs? evt) { protected async void OnLoaded(object? sender, RoutedEventArgs? evt) {
Mouse.OverrideCursor = Cursors.AppStarting;
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
await OnRenewContext(ctx); await OnRenewContext(ctx);
HasContextLoaded = true;
await OnInit(ctx);
Mouse.OverrideCursor = null;
} }
protected async Task EnsureContextRenewed() { protected async Task EnsureContextRenewed() {
if (!_renewPending) return; if (!_renewPending) return;
_renewPending = false;
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
await OnRenewContext(ctx); await OnRenewContext(ctx);
_renewPending = false;
} }
virtual protected async Task OnInit(AppDbContext ctx) { }
abstract protected Task OnRenewContext(AppDbContext ctx); abstract protected Task OnRenewContext(AppDbContext ctx);
} }
} }
+3 -4
View File
@@ -6,8 +6,7 @@
xmlns:local="clr-namespace:Elwig.Windows" xmlns:local="clr-namespace:Elwig.Windows"
xmlns:vm="clr-namespace:Elwig.ViewModels" xmlns:vm="clr-namespace:Elwig.ViewModels"
xmlns:ctrl="clr-namespace:Elwig.Controls" xmlns:ctrl="clr-namespace:Elwig.Controls"
Title="{Binding Title}" Height="720" Width="1150" MinHeight="720" MinWidth="1000" Title="{Binding Title}" Height="720" Width="1150" MinHeight="720" MinWidth="1000">
Loaded="Window_Loaded">
<Window.DataContext> <Window.DataContext>
<vm:DeliveryAdminViewModel/> <vm:DeliveryAdminViewModel/>
</Window.DataContext> </Window.DataContext>
@@ -530,12 +529,12 @@
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Label Content="Gradation:" Margin="10,10,10,10"/> <Label Content="Gradation:" Margin="10,10,10,10"/>
<ctrl:UnitTextBox x:Name="GradationOeInput" Unit="°Oe" Text="{Binding GradationOeString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" <ctrl:UnitTextBox x:Name="GradationOeInput" Unit="°Oe" Text="{Binding GradationOeString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
TextChanged="GradationOeInput_TextChanged" KeyUp="Input_KeyUp" TextChanged="GradationOeInput_TextChanged" LostFocus="GradationOeInput_LostFocus" KeyUp="Input_KeyUp"
Grid.Column="1" Width="54" Margin="0,10,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"/> Grid.Column="1" Width="54" Margin="0,10,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<Label Content="=" Margin="60,10,10,10" Grid.Column="1"/> <Label Content="=" Margin="60,10,10,10" Grid.Column="1"/>
<ctrl:UnitTextBox x:Name="GradationKmwInput" Unit="°KMW" Text="{Binding GradationKmwString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" <ctrl:UnitTextBox x:Name="GradationKmwInput" Unit="°KMW" Text="{Binding GradationKmwString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
TextChanged="GradationKmwInput_TextChanged" KeyUp="Input_KeyUp" TextChanged="GradationKmwInput_TextChanged" LostFocus="GradationKmwInput_LostFocus" KeyUp="Input_KeyUp"
Grid.Column="1" Width="68" Margin="78,10,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"/> Grid.Column="1" Width="68" Margin="78,10,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<Label Content="Qualitätsstufe:" Margin="10,40,10,10"/> <Label Content="Qualitätsstufe:" Margin="10,40,10,10"/>
+100 -140
View File
@@ -6,7 +6,6 @@ using Elwig.Models.Entities;
using Elwig.Services; using Elwig.Services;
using Elwig.ViewModels; using Elwig.ViewModels;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Win32;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@@ -37,6 +36,7 @@ namespace Elwig.Windows {
private readonly Button[] WeighingButtons; private readonly Button[] WeighingButtons;
private List<WineQualLevel> WineQualityLevels = []; private List<WineQualLevel> WineQualityLevels = [];
private Dictionary<int, List<Modifier>> Modifiers = [];
public DeliveryAdminWindow(bool receipt = false) { public DeliveryAdminWindow(bool receipt = false) {
InitializeComponent(); InitializeComponent();
@@ -122,22 +122,24 @@ namespace Elwig.Windows {
Menu_Export_UploadSeason.IsEnabled = App.Config.SyncUrl != null; Menu_Export_UploadSeason.IsEnabled = App.Config.SyncUrl != null;
} }
public DeliveryAdminWindow(int mgnr) : this() { public DeliveryAdminWindow(int mgnr) :
ViewModel.FilterMember = DeliveryService.GetMember(mgnr) ?? throw new ArgumentException("MgNr argument has invalid value"); this() {
using var ctx = new AppDbContext();
ViewModel.FilterMember = ctx.Members.Find(mgnr) ?? throw new ArgumentException("MgNr argument has invalid value");
ViewModel.Title = $"Lieferungen - {ViewModel.FilterMember.AdministrativeName} - Elwig"; ViewModel.Title = $"Lieferungen - {ViewModel.FilterMember.AdministrativeName} - Elwig";
ViewModel.EnableAllSeasons = true; ViewModel.EnableAllSeasons = true;
} }
private void Window_Loaded(object sender, RoutedEventArgs evt) { protected override async Task OnInit(AppDbContext ctx) {
await base.OnInit(ctx);
OnSecondPassed(null, null); OnSecondPassed(null, null);
SecondsTimer.Start(); SecondsTimer.Start();
LockInputs();
if (ViewModel.IsReceipt) { if (ViewModel.IsReceipt) {
NewDeliveryButton_Click(null, null); NewDeliveryButton_Click(null, null);
using var ctx = new AppDbContext(); if (await ctx.FetchSeasons(Utils.CurrentYear).SingleOrDefaultAsync() == null) {
if (ctx.Seasons.Find(Utils.CurrentYear) == null) { InteractionService.ShowWarning("Saison noch nicht erstellt",
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...)", "Die Saison für das aktuelle Jahr wurde noch nicht erstellt. Neue Lieferungen können nicht abgespeichert werden.\n\n" +
"Saison noch nicht erstellt", MessageBoxButton.OK, MessageBoxImage.Warning); "(Stammdaten -> Saisons -> Neu anlegen...)");
} }
} }
} }
@@ -163,9 +165,7 @@ namespace Elwig.Windows {
private async void Menu_DeliveryNote_Email_Click(object sender, RoutedEventArgs evt) { private async void Menu_DeliveryNote_Email_Click(object sender, RoutedEventArgs evt) {
if (DeliveryList.SelectedItem is not Delivery d) if (DeliveryList.SelectedItem is not Delivery d)
return; return;
var res = MessageBox.Show("Soll eine E-Mail verschickt werden?", "Lieferschein verschicken", if (!InteractionService.AskQuestion("Lieferschein verschicken", "Soll eine E-Mail verschickt werden?", true))
MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.Yes);
if (res != MessageBoxResult.Yes)
return; return;
await DeliveryService.GenerateDeliveryNote(d.Year, d.DId, ExportMode.Email); await DeliveryService.GenerateDeliveryNote(d.Year, d.DId, ExportMode.Email);
} }
@@ -173,16 +173,11 @@ namespace Elwig.Windows {
private async void Menu_Bki_SaveList_Click(object sender, RoutedEventArgs evt) { private async void Menu_Bki_SaveList_Click(object sender, RoutedEventArgs evt) {
if (sender is not MenuItem m) return; if (sender is not MenuItem m) return;
var year = int.Parse(m.Header.ToString()?.Split(" ")[^1] ?? Utils.CurrentLastSeason.ToString()); var year = int.Parse(m.Header.ToString()?.Split(" ")[^1] ?? Utils.CurrentLastSeason.ToString());
var d = new SaveFileDialog() { var filename = InteractionService.SaveFile("Traubentransportscheinliste (BKI)", $"{App.Client.NameToken}-Traubentransportscheinliste-{year}", Bki.FileExtension);
FileName = $"{App.Client.NameToken}-Traubentransportscheinliste-{year}.{Bki.FileExtension}", if (filename != null) {
DefaultExt = Bki.FileExtension,
Filter = "CSV-Datei (*.csv)|*.csv",
Title = $"Traubentransportscheinliste (BKI) speichern unter - Elwig"
};
if (d.ShowDialog() == true) {
Mouse.OverrideCursor = Cursors.Wait; Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => { await Task.Run(async () => {
using var file = new Bki(d.FileName); using var file = new Bki(filename);
await file.ExportAsync(year); await file.ExportAsync(year);
}); });
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
@@ -420,45 +415,57 @@ namespace Elwig.Windows {
} }
private async Task RefreshList(bool updateSort = false) { private async Task RefreshList(bool updateSort = false) {
var vm = ViewModel;
var cursor = Mouse.OverrideCursor != null;
if (!cursor) Mouse.OverrideCursor = Cursors.Wait;
var query = (vm.SearchQuery, vm.FilterSeason, vm.FilterAllSeasons, vm.FilterTodayOnly);
var (filter, deliveries, deliveryPartsNum, varieties, members, stat) = await Task.Run(async () => {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
var (_, deliveryQuery, deliveryPartsQuery, predicate, filter) = await ViewModel.GetFilters(ctx); var (_, deliveryQuery, deliveryPartsQuery, predicate, filter) = await vm.GetFilters(ctx);
var deliveries = await deliveryQuery var deliveries = await deliveryQuery
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers).ThenInclude(m => m.Modifier) .Include(d => d.Parts).ThenInclude(p => p.PartModifiers).ThenInclude(m => m.Modifier)
.Include(d => d.Parts).ThenInclude(p => p.Variety)
.Include(d => d.Parts).ThenInclude(p => p.Attribute) .Include(d => d.Parts).ThenInclude(p => p.Attribute)
.Include(d => d.Parts).ThenInclude(p => p.Cultivation) .Include(d => d.Parts).ThenInclude(p => p.Cultivation)
.Include(d => d.Parts).ThenInclude(p => p.Variety) .IgnoreAutoIncludes()
.Include(d => d.Member.EmailAddresses)
.AsSplitQuery() .AsSplitQuery()
.ToListAsync(); .ToListAsync();
deliveries.Reverse(); deliveries.Reverse();
if (filter.Count > 0 && deliveries.Count > 0) { if (filter.Count > 0 && deliveries.Count > 0) {
var dict = deliveries.AsParallel() var dict = deliveries.AsParallel()
.ToDictionary(d => d, d => d.SearchScore(ViewModel.TextFilter)) .ToDictionary(d => d, d => d.SearchScore(vm.TextFilter))
.OrderByDescending(a => a.Value) .OrderByDescending(a => a.Value)
.ThenBy(a => a.Key.DateTime); .ThenBy(a => a.Key.DateTime);
var threshold = dict.Select(a => a.Value).Max() * 3 / 4; var threshold = dict.Max(a => a.Value) * 3 / 4;
deliveries = dict deliveries = [.. dict
.Where(a => a.Value > threshold) .Where(a => a.Value > threshold)
.Select(a => a.Key) .Select(a => a.Key)];
.ToList();
} }
deliveries.ForEach(d => { d.PartFilter = predicate; }); deliveries.ForEach(d => { d.PartFilter = predicate; });
var deliveryPartsNum = await deliveryPartsQuery.CountAsync();
var varieties = await deliveryPartsQuery.Select(d => d.SortId).Distinct().ToListAsync();
var members = await deliveryQuery.Select(d => d.Member).Distinct().IgnoreAutoIncludes().ToListAsync();
var stat = await DeliveryService.GenerateToolTipData(deliveryPartsQuery);
return (filter, deliveries, deliveryPartsNum, varieties, members, stat);
});
if (!cursor) Mouse.OverrideCursor = null;
if (query != (ViewModel.SearchQuery, ViewModel.FilterSeason, ViewModel.FilterAllSeasons, ViewModel.FilterTodayOnly)) return;
ControlUtils.RenewItemsSource(DeliveryList, deliveries, ControlUtils.RenewItemsSource(DeliveryList, deliveries,
DeliveryList_SelectionChanged, filter.Count > 0 ? ControlUtils.RenewSourceDefault.IfOnly : ControlUtils.RenewSourceDefault.None, !updateSort); DeliveryList_SelectionChanged, ViewModel.TextFilter.Count > 0 ? ControlUtils.RenewSourceDefault.IfOnly : ControlUtils.RenewSourceDefault.None, !updateSort);
await RefreshDeliveryParts(); await RefreshDeliveryParts();
var members = deliveries.Select(d => d.Member).DistinctBy(m => m.MgNr).ToList();
ViewModel.StatusMembers = $"{members.Count:N0}" + (members.Count > 0 && members.Count <= 4 ? $" ({string.Join(", ", members.Select(m => m.AdministrativeName))})" : ""); ViewModel.StatusMembers = $"{members.Count:N0}" + (members.Count > 0 && members.Count <= 4 ? $" ({string.Join(", ", members.Select(m => m.AdministrativeName))})" : "");
ViewModel.StatusDeliveries = $"{deliveries.Count:N0}"; ViewModel.StatusDeliveries = $"{deliveries.Count:N0}";
if (filter.Count == 0) { if (filter.Count == 0) {
var deliveryParts = deliveryPartsQuery; ViewModel.StatusDeliveries = $"{deliveries.Count:N0} ({deliveryPartsNum:N0})";
ViewModel.StatusDeliveries = $"{deliveries.Count:N0} ({await deliveryParts.CountAsync():N0})";
var varieties = await deliveryParts.Select(d => d.SortId).Distinct().ToListAsync();
ViewModel.StatusVarieties = $"{varieties.Count:N0}" + (varieties.Count > 0 && varieties.Count <= 10 ? $" ({string.Join(", ", varieties)})" : ""); ViewModel.StatusVarieties = $"{varieties.Count:N0}" + (varieties.Count > 0 && varieties.Count <= 10 ? $" ({string.Join(", ", varieties)})" : "");
var (wText, wData, gText, gData) = await DeliveryService.GenerateToolTipData(deliveryParts); var (wText, wData, gText, gData) = stat;
ViewModel.StatusWeight = wText; ViewModel.StatusWeight = wText;
ViewModel.StatusGradation = gText; ViewModel.StatusGradation = gText;
(ViewModel.StatusWeightToolTip, ViewModel.StatusGradationToolTip) = DeliveryService.GenerateToolTip(wData, gData); (ViewModel.StatusWeightToolTip, ViewModel.StatusGradationToolTip) = DeliveryService.GenerateToolTip(wData, gData);
@@ -476,7 +483,7 @@ namespace Elwig.Windows {
await base.OnRenewContext(ctx); await base.OnRenewContext(ctx);
if (ViewModel.FilterMember != null) { if (ViewModel.FilterMember != null) {
if (await DeliveryService.GetMemberAsync(ViewModel.FilterMember.MgNr) is not Member m) { if (await ctx.FetchMembers(ViewModel.FilterMember.MgNr).SingleOrDefaultAsync() is not Member m) {
Close(); Close();
return; return;
} }
@@ -486,7 +493,7 @@ namespace Elwig.Windows {
int year = 0; int year = 0;
Menu_Bki_SaveList.Items.Clear(); Menu_Bki_SaveList.Items.Clear();
foreach (var s in await ctx.Seasons.OrderByDescending(s => s.Year).ToListAsync()) { foreach (var s in await ctx.FetchSeasons().ToListAsync()) {
if (s.Year > year) year = s.Year; if (s.Year > year) year = s.Year;
var i = new MenuItem { var i = new MenuItem {
Header = $"Saison {s.Year}", Header = $"Saison {s.Year}",
@@ -495,6 +502,9 @@ namespace Elwig.Windows {
Menu_Bki_SaveList.Items.Add(i); Menu_Bki_SaveList.Items.Add(i);
} }
var attributes = await ctx.FetchWineAttributes(!IsCreating).ToListAsync();
Modifiers = await ctx.FetchModifiers(null).GroupBy(m => m.Year).ToDictionaryAsync(g => g.Key, g => g.ToList());
var font = new FontFamily("Segoe MDL2 Assets"); var font = new FontFamily("Segoe MDL2 Assets");
Menu_BulkAction_SetAttribute.Items.Clear(); Menu_BulkAction_SetAttribute.Items.Clear();
var noAttr = new MenuItem { var noAttr = new MenuItem {
@@ -503,7 +513,7 @@ namespace Elwig.Windows {
}; };
noAttr.Click += Menu_BulkAction_SetAttribute_Click; noAttr.Click += Menu_BulkAction_SetAttribute_Click;
Menu_BulkAction_SetAttribute.Items.Add(noAttr); Menu_BulkAction_SetAttribute.Items.Add(noAttr);
foreach (var attr in await ctx.WineAttributes.OrderBy(a => a.AttrId).ToListAsync()) { foreach (var attr in attributes) {
var i = new MenuItem { var i = new MenuItem {
Header = attr.Name, Header = attr.Name,
}; };
@@ -513,7 +523,7 @@ namespace Elwig.Windows {
Menu_BulkAction_AddModifier.Items.Clear(); Menu_BulkAction_AddModifier.Items.Clear();
Menu_BulkAction_RemoveModifier.Items.Clear(); Menu_BulkAction_RemoveModifier.Items.Clear();
foreach (var mod in await ctx.Modifiers.Where(m => m.Year == year).OrderBy(m => m.ModId).ToListAsync()) { foreach (var mod in Modifiers.GetValueOrDefault(ViewModel.SelectedDelivery?.Year ?? year, [])) {
var i1 = new MenuItem { var i1 = new MenuItem {
Header = mod.Name, Header = mod.Name,
}; };
@@ -527,44 +537,34 @@ namespace Elwig.Windows {
} }
await RefreshList(); await RefreshList();
var d = DeliveryList.SelectedItem as Delivery;
var y = d?.Year ?? ViewModel.FilterSeason; ControlUtils.RenewItemsSource(MemberInput, await ctx.FetchMembers(includeNotActive: !IsCreating, includeContactInfo: true).ToListAsync());
ControlUtils.RenewItemsSource(MemberInput, await ctx.Members ControlUtils.RenewItemsSource(BranchInput, await ctx.FetchBranches().ToListAsync());
.Where(m => m.IsActive || !IsCreating) ControlUtils.RenewItemsSource(WineVarietyInput, await ctx.FetchWineVarieties().ToListAsync());
.Include(m => m.PostalDest.AtPlz!.Ort) var attrList = attributes.Cast<object>().ToList();
.Include(m => m.DefaultWbKg!.AtKg)
.OrderBy(m => m.Name)
.ThenBy(m => m.GivenName)
.ToListAsync());
ControlUtils.RenewItemsSource(BranchInput, await ctx.Branches.OrderBy(b => b.Name).ToListAsync());
ControlUtils.RenewItemsSource(WineVarietyInput, await ctx.WineVarieties.OrderBy(v => v.Name).ToListAsync());
var attrList = await ctx.WineAttributes.Where(a => !IsCreating || a.IsActive).OrderBy(a => a.Name).Cast<object>().ToListAsync();
attrList.Insert(0, new NullItem("")); attrList.Insert(0, new NullItem(""));
ControlUtils.RenewItemsSource(AttributeInput, attrList, null, ControlUtils.RenewSourceDefault.First); ControlUtils.RenewItemsSource(AttributeInput, attrList, null, ControlUtils.RenewSourceDefault.First);
var cultList = await ctx.WineCultivations.OrderBy(a => a.Name).Cast<object>().ToListAsync(); var cultList = await ctx.FetchWineCultivations().Cast<object>().ToListAsync();
cultList.Insert(0, new NullItem("")); cultList.Insert(0, new NullItem(""));
ControlUtils.RenewItemsSource(CultivationInput, cultList, null, ControlUtils.RenewSourceDefault.First); ControlUtils.RenewItemsSource(CultivationInput, cultList, null, ControlUtils.RenewSourceDefault.First);
WineQualityLevels = await ctx.WineQualityLevels.ToListAsync(); WineQualityLevels = await ctx.FetchWineQualityLevels().ToListAsync();
ControlUtils.RenewItemsSource(WineQualityLevelInput, WineQualityLevels); ControlUtils.RenewItemsSource(WineQualityLevelInput, WineQualityLevels);
ControlUtils.RenewItemsSource(ModifiersInput, await ctx.Modifiers ControlUtils.RenewItemsSource(ModifiersInput, Modifiers.GetValueOrDefault(year, []).Where(m => m.IsActive || !IsCreating).ToList());
.Where(m => m.Year == y && (!IsCreating || m.IsActive)) var origins = await ctx.WineOrigins.ToListAsync();
.OrderBy(m => m.Ordering) origins.ForEach(o => { origins.FirstOrDefault(p => p.HkId == o.ParentHkId)?.Children.Add(o); });
.Include(m => m.Season.Currency) origins = [.. origins.OrderByDescending(o => o.SortKey).ThenBy(o => o.HkId)];
.ToListAsync()); ControlUtils.RenewItemsSource(WineOriginInput, origins);
ControlUtils.RenewItemsSource(WineOriginInput, (await ctx.WineOrigins.ToListAsync()).OrderByDescending(o => o.SortKey).ThenBy(o => o.HkId));
var kgList = (await ctx.Katastralgemeinden var kgList = (await ctx.Katastralgemeinden
.Where(k => k.WbKg != null) .Where(k => k.WbKg != null)
.Include(k => k.WbKg) .Include(k => k.WbKg)
.Include(k => k.Gem.WbGem) .Include(k => k.Gem.WbGem)
.OrderBy(k => k.Name) .OrderBy(k => k.Name)
.AsSplitQuery()
.ToListAsync()).Cast<object>().ToList(); .ToListAsync()).Cast<object>().ToList();
kgList.Insert(0, new NullItem()); kgList.Insert(0, new NullItem());
ControlUtils.RenewItemsSource(WineKgInput, kgList); ControlUtils.RenewItemsSource(WineKgInput, kgList);
UpdateRdInput(); UpdateRdInput();
if (IsCreating) await UpdateLsNr(); if (IsCreating) await UpdateLsNr();
await RefreshDeliveryParts();
RefreshInputs(); RefreshInputs();
} }
@@ -576,30 +576,22 @@ namespace Elwig.Windows {
} }
private async Task RefreshDeliveryParts() { private async Task RefreshDeliveryParts() {
using var ctx = new AppDbContext();
if (DeliveryList.SelectedItem is Delivery d) { if (DeliveryList.SelectedItem is Delivery d) {
ControlUtils.RenewItemsSource(ModifiersInput, await ctx.Modifiers ControlUtils.RenewItemsSource(ModifiersInput, Modifiers.GetValueOrDefault(d.Year, []).Where(m => m.IsActive || !IsCreating).ToList());
.Where(m => m.Year == d.Year && (!IsCreating || m.IsActive)) ControlUtils.RenewItemsSource(DeliveryPartList, d.Parts, DeliveryPartList_SelectionChanged, ControlUtils.RenewSourceDefault.First);
.OrderBy(m => m.Ordering)
.Include(m => m.Season.Currency)
.ToListAsync());
ControlUtils.RenewItemsSource(DeliveryPartList, d.FilteredParts.OrderBy(p => p.DPNr).ToList(), DeliveryPartList_SelectionChanged, ControlUtils.RenewSourceDefault.First);
} else { } else {
ControlUtils.RenewItemsSource(ModifiersInput, await ctx.Modifiers ControlUtils.RenewItemsSource(ModifiersInput, Modifiers.GetValueOrDefault(ViewModel.FilterSeason ?? 0, []).Where(m => m.IsActive || !IsCreating).ToList());
.Where(m => m.Year == ViewModel.FilterSeason && (!IsCreating || m.IsActive))
.OrderBy(m => m.Ordering)
.Include(m => m.Season.Currency)
.ToListAsync());
DeliveryPartList.ItemsSource = null; DeliveryPartList.ItemsSource = null;
} }
} }
private void RefreshInputs(bool validate = false) { private void RefreshInputs(bool validate = false) {
ClearInputStates(); ClearInputStates();
if (DeliveryList.SelectedItem is Delivery d) {
FillInputs(d);
if (DeliveryPartList.SelectedItem is DeliveryPart p) { if (DeliveryPartList.SelectedItem is DeliveryPart p) {
FillInputs(p); FillInputs(p);
} else if (DeliveryList.SelectedItem is Delivery d) { }
FillInputs(d);
} else { } else {
ClearOriginalValues(); ClearOriginalValues();
ClearDefaultValues(); ClearDefaultValues();
@@ -617,7 +609,6 @@ namespace Elwig.Windows {
} }
private void FillInputs(DeliveryPart p) { private void FillInputs(DeliveryPart p) {
FillInputs(p.Delivery);
ClearOriginalValues(); ClearOriginalValues();
ClearDefaultValues(); ClearDefaultValues();
ViewModel.FillInputs(p); ViewModel.FillInputs(p);
@@ -644,11 +635,10 @@ namespace Elwig.Windows {
try { try {
var res = await s.Weigh(); var res = await s.Weigh();
OnWeighingResult(s, res); OnWeighingResult(s, res);
} catch (Exception ex) { } catch (Exception exc) {
ViewModel.LastScaleError = ex.Message.Split(": ")[^1]; ViewModel.LastScaleError = exc.Message.Split(": ")[^1];
OnWeighingResult(s, new()); OnWeighingResult(s, new());
MessageBox.Show($"Beim Wiegen ist ein Fehler aufgetreten:\n\n{ex.Message}", "Waagenfehler", InteractionService.ShowException("Waagenfehler", "Beim Wiegen ist ein Fehler aufgetreten", exc);
MessageBoxButton.OK, MessageBoxImage.Error);
} }
ViewModel.ManualWeighingReason = null; ViewModel.ManualWeighingReason = null;
ManualWeighingInput.IsChecked = false; ManualWeighingInput.IsChecked = false;
@@ -681,17 +671,19 @@ namespace Elwig.Windows {
} }
private async void SearchInput_TextChanged(object sender, RoutedEventArgs evt) { private async void SearchInput_TextChanged(object sender, RoutedEventArgs evt) {
if (!HasContextLoaded) return;
await RefreshList(true); await RefreshList(true);
} }
private async void SeasonInput_TextChanged(object sender, TextChangedEventArgs evt) { private async void SeasonInput_TextChanged(object sender, TextChangedEventArgs evt) {
if (ViewModel.FilterSeason == null || TodayOnlyInput == null || AllSeasonsInput == null) return; if (!HasContextLoaded || ViewModel.FilterSeason == null || TodayOnlyInput == null || AllSeasonsInput == null) return;
TodayOnlyInput.IsChecked = false; TodayOnlyInput.IsChecked = false;
AllSeasonsInput.IsChecked = false; AllSeasonsInput.IsChecked = false;
await RefreshList(); await RefreshList();
} }
private async void TodayOnlyInput_Changed(object sender, RoutedEventArgs evt) { private async void TodayOnlyInput_Changed(object sender, RoutedEventArgs evt) {
if (!HasContextLoaded) return;
if (TodayOnlyInput.IsChecked == true && AllSeasonsInput.IsChecked == false) { if (TodayOnlyInput.IsChecked == true && AllSeasonsInput.IsChecked == false) {
ViewModel.FilterSeason = Utils.Today.Year; ViewModel.FilterSeason = Utils.Today.Year;
ViewModel.FilterTodayOnly = true; ViewModel.FilterTodayOnly = true;
@@ -700,6 +692,7 @@ namespace Elwig.Windows {
} }
private async void AllSeasonsInput_Changed(object sender, RoutedEventArgs evt) { private async void AllSeasonsInput_Changed(object sender, RoutedEventArgs evt) {
if (!HasContextLoaded) return;
if (AllSeasonsInput.IsChecked == true) { if (AllSeasonsInput.IsChecked == true) {
SeasonInput.IsEnabled = false; SeasonInput.IsEnabled = false;
ViewModel.FilterSeason = null; ViewModel.FilterSeason = null;
@@ -719,7 +712,7 @@ namespace Elwig.Windows {
Menu_DeliveryNote_Show.IsEnabled = !IsEditing && !IsCreating; Menu_DeliveryNote_Show.IsEnabled = !IsEditing && !IsCreating;
Menu_DeliveryNote_SavePdf.IsEnabled = !IsEditing && !IsCreating; Menu_DeliveryNote_SavePdf.IsEnabled = !IsEditing && !IsCreating;
Menu_DeliveryNote_Print.IsEnabled = !IsEditing && !IsCreating; Menu_DeliveryNote_Print.IsEnabled = !IsEditing && !IsCreating;
Menu_DeliveryNote_Email.IsEnabled = !IsEditing && !IsCreating && App.Config.Smtp != null && d.Member.EmailAddresses.Count > 0; Menu_DeliveryNote_Email.IsEnabled = !IsEditing && !IsCreating && App.Config.Smtp != null && ViewModel.Member?.EmailAddresses.Count > 0;
Menu_Export_ExportSelected.IsEnabled = !IsEditing && !IsCreating; Menu_Export_ExportSelected.IsEnabled = !IsEditing && !IsCreating;
Menu_Export_UploadSelected.IsEnabled = !IsEditing && !IsCreating && App.Config.SyncUrl != null; Menu_Export_UploadSelected.IsEnabled = !IsEditing && !IsCreating && App.Config.SyncUrl != null;
} else { } else {
@@ -801,9 +794,7 @@ namespace Elwig.Windows {
); );
App.HintContextChange(); App.HintContextChange();
} catch (Exception exc) { } catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message; InteractionService.ShowDbException("Lieferung aktualisieren", exc);
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Lieferung aktualisieren", MessageBoxButton.OK, MessageBoxImage.Error);
FinishButton.IsEnabled = true; FinishButton.IsEnabled = true;
SaveButton.IsEnabled = true; SaveButton.IsEnabled = true;
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
@@ -812,11 +803,12 @@ namespace Elwig.Windows {
} }
EmptyScale(); EmptyScale();
await EnsureContextRenewed(); await EnsureContextRenewed();
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
ControlUtils.SelectItem(DeliveryList, p?.Delivery); ControlUtils.SelectItemWithPk(DeliveryList, p?.Year, p?.DId);
DeliveryPartList.SelectedItem = null; DeliveryPartList.SelectedItem = null;
DeliveryPartList.ScrollIntoView(DeliveryPartList.ItemsSource.Cast<object>().Last()); DeliveryPartList.ScrollIntoView(DeliveryPartList.ItemsSource.Cast<object>().LastOrDefault());
InitialInputs(); InitialInputs();
} }
@@ -838,9 +830,7 @@ namespace Elwig.Windows {
); );
App.HintContextChange(); App.HintContextChange();
} catch (Exception exc) { } catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message; InteractionService.ShowDbException("Lieferung aktualisieren", exc);
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Lieferung aktualisieren", MessageBoxButton.OK, MessageBoxImage.Error);
FinishButton.IsEnabled = true; FinishButton.IsEnabled = true;
SaveButton.IsEnabled = true; SaveButton.IsEnabled = true;
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
@@ -849,46 +839,36 @@ namespace Elwig.Windows {
} }
EmptyScale(); EmptyScale();
await EnsureContextRenewed();
if (p?.Delivery != null) { Utils.RunBackground("Lieferschein drucken", async () => {
try { using var doc = await DeliveryNote.Initialize(p.Year, p.DId);
using var ctx = new AppDbContext(); using (var ctx = new AppDbContext()) {
using var doc = new DeliveryNote((await ctx.Deliveries.FindAsync(p.Year, p.DId))!, ctx); await doc.Generate(ctx);
await doc.Generate(); }
if (App.Config.Debug) { if (App.Config.Debug) {
doc.Show(); doc.Show();
} else { } else {
await doc.Print(2); await doc.Print(2);
} }
} catch (Exception exc) { });
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
await EnsureContextRenewed();
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
DeliveryList.SelectedItem = null; DeliveryList.SelectedItem = null;
await EnsureContextRenewed();
InitInputs(); InitInputs();
} }
private async void CancelCreatingButton_Click(object sender, RoutedEventArgs evt) { private async void CancelCreatingButton_Click(object sender, RoutedEventArgs evt) {
if (IsCreating && HasChanged) { if (IsCreating && HasChanged) {
var r = MessageBox.Show("Soll der Vorgang wirklich abgebrochen werden?", "Abbrechen bestätigen", if (!InteractionService.AskConfirmation("Abbrechen bestätigen", "Soll der Vorgang wirklich abgebrochen werden?"))
MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No); return;
if (r != MessageBoxResult.Yes) return;
} }
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
var attrList = await ctx.WineAttributes.OrderBy(a => a.Name).Cast<object>().ToListAsync(); var attrList = await ctx.FetchWineAttributes().Cast<object>().ToListAsync();
attrList.Insert(0, new NullItem("")); attrList.Insert(0, new NullItem(""));
ControlUtils.RenewItemsSource(AttributeInput, attrList, null, ControlUtils.RenewSourceDefault.First); ControlUtils.RenewItemsSource(AttributeInput, attrList, null, ControlUtils.RenewSourceDefault.First);
ControlUtils.RenewItemsSource(MemberInput, await ctx.Members ControlUtils.RenewItemsSource(MemberInput, await ctx.FetchMembers(includeNotActive: !ViewModel.IsReceipt, includeContactInfo: true).ToListAsync());
.Where(m => m.IsActive || !ViewModel.IsReceipt)
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.DefaultWbKg!.AtKg)
.OrderBy(m => m.Name)
.ThenBy(m => m.GivenName)
.ToListAsync());
if (DeliveryList.SelectedItem is not Delivery d) { if (DeliveryList.SelectedItem is not Delivery d) {
// switch away from creating mode // switch away from creating mode
IsCreating = false; IsCreating = false;
@@ -920,21 +900,11 @@ namespace Elwig.Windows {
ViewModel.FilterTodayOnly = true; ViewModel.FilterTodayOnly = true;
ViewModel.SearchQuery = ""; ViewModel.SearchQuery = "";
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
var attrList = await ctx.WineAttributes.Where(a => a.IsActive).OrderBy(a => a.Name).Cast<object>().ToListAsync(); var attrList = await ctx.FetchWineAttributes(false).Cast<object>().ToListAsync();
attrList.Insert(0, new NullItem("")); attrList.Insert(0, new NullItem(""));
ControlUtils.RenewItemsSource(AttributeInput, attrList, null, ControlUtils.RenewSourceDefault.First); ControlUtils.RenewItemsSource(AttributeInput, attrList, null, ControlUtils.RenewSourceDefault.First);
ControlUtils.RenewItemsSource(ModifiersInput, await ctx.Modifiers ControlUtils.RenewItemsSource(ModifiersInput, Modifiers.GetValueOrDefault(ViewModel.FilterSeason ?? 0, []).Where(m => m.IsActive).ToList());
.Where(m => m.Year == ViewModel.FilterSeason && m.IsActive) ControlUtils.RenewItemsSource(MemberInput, await ctx.FetchMembers(includeNotActive: !ViewModel.IsReceipt, includeContactInfo: true).ToListAsync());
.OrderBy(m => m.Ordering)
.Include(m => m.Season.Currency)
.ToListAsync());
ControlUtils.RenewItemsSource(MemberInput, await ctx.Members
.Where(m => m.IsActive || !ViewModel.IsReceipt)
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.DefaultWbKg!.AtKg)
.OrderBy(m => m.Name)
.ThenBy(m => m.GivenName)
.ToListAsync());
IsCreating = true; IsCreating = true;
DeliveryList.IsEnabled = false; DeliveryList.IsEnabled = false;
DeliveryPartList.IsEnabled = false; DeliveryPartList.IsEnabled = false;
@@ -972,9 +942,7 @@ namespace Elwig.Windows {
} }
App.HintContextChange(); App.HintContextChange();
} catch (Exception exc) { } catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message; InteractionService.ShowDbException("Lieferung aktualisieren", exc);
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Lieferung aktualisieren", MessageBoxButton.OK, MessageBoxImage.Error);
} }
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
} }
@@ -1021,18 +989,13 @@ namespace Elwig.Windows {
if (DeliveryList.SelectedItem is not Delivery d) if (DeliveryList.SelectedItem is not Delivery d)
return; return;
var r = MessageBox.Show( if (InteractionService.AskContinue("Lieferung löschen", $"Soll die Lieferung {d.LsNr} ({d.Member.AdministrativeName}, MgNr. {d.Member.MgNr}) wirklich unwiderruflich gelöscht werden?")) {
$"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; Mouse.OverrideCursor = Cursors.Wait;
try { try {
await DeliveryService.DeleteDelivery(d.LsNr); await DeliveryService.DeleteDelivery(d.LsNr);
App.HintContextChange(); App.HintContextChange();
} catch (Exception exc) { } catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message; InteractionService.ShowDbException("Lieferung löschen", exc);
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Lieferung löschen", MessageBoxButton.OK, MessageBoxImage.Error);
} }
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
} }
@@ -1060,9 +1023,7 @@ namespace Elwig.Windows {
); );
App.HintContextChange(); App.HintContextChange();
} catch (Exception exc) { } catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message; InteractionService.ShowDbException("Lieferung aktualisieren", exc);
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Lieferung aktualisieren", MessageBoxButton.OK, MessageBoxImage.Error);
SaveButton.IsEnabled = true; SaveButton.IsEnabled = true;
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
return; return;
@@ -1240,7 +1201,7 @@ namespace Elwig.Windows {
} }
private async Task UpdateLsNr() { private async Task UpdateLsNr() {
if (string.IsNullOrEmpty(ViewModel.Date) || ViewModel.Branch == null) { if (string.IsNullOrWhiteSpace(ViewModel.Date) || ViewModel.Branch == null) {
ViewModel.LsNr = ""; ViewModel.LsNr = "";
} else { } else {
try { try {
@@ -1299,8 +1260,7 @@ namespace Elwig.Windows {
UpdateWineQualityLevels(); UpdateWineQualityLevels();
if (!ViewModel.WineVar?.IsQuw ?? false) { if (!ViewModel.WineVar?.IsQuw ?? false) {
App.MainDispatcher.BeginInvoke(() => { App.MainDispatcher.BeginInvoke(() => {
MessageBox.Show("Die eingegebene Sorte darf nicht als Qualitätswein\nübernommen werden!", "Kein Qualitätswein", InteractionService.ShowWarning("Kein Qualitätswein", "Die eingegebene Sorte darf nicht als Qualitätswein\nübernommen werden!");
MessageBoxButton.OK, MessageBoxImage.Warning);
}); });
} }
} }
+1 -2
View File
@@ -8,8 +8,7 @@
xmlns:local="clr-namespace:Elwig.Windows" xmlns:local="clr-namespace:Elwig.Windows"
xmlns:vm="clr-namespace:Elwig.ViewModels" xmlns:vm="clr-namespace:Elwig.ViewModels"
xmlns:ctrl="clr-namespace:Elwig.Controls" xmlns:ctrl="clr-namespace:Elwig.Controls"
Title="Anmeldungen - Elwig" Height="700" Width="980" MinWidth="600" MinHeight="400" Title="Anmeldungen - Elwig" Height="700" Width="980" MinWidth="600" MinHeight="400">
Loaded="Window_Loaded">
<Window.DataContext> <Window.DataContext>
<vm:DeliveryAncmtAdminViewModel/> <vm:DeliveryAncmtAdminViewModel/>
</Window.DataContext> </Window.DataContext>
+33 -57
View File
@@ -36,11 +36,7 @@ namespace Elwig.Windows {
ControlUtils.InitializeDelayTimer(SearchInput, SearchInput_TextChanged); ControlUtils.InitializeDelayTimer(SearchInput, SearchInput_TextChanged);
SearchInput.TextChanged -= SearchInput_TextChanged; SearchInput.TextChanged -= SearchInput_TextChanged;
ViewModel.FilterSeason = Utils.CurrentLastSeason; ViewModel.FilterSeason = Utils.CurrentLastSeason;
}
private void Window_Loaded(object sender, RoutedEventArgs evt) {
ViewModel.FilterOnlyUpcoming = true; ViewModel.FilterOnlyUpcoming = true;
LockInputs();
} }
private void Input_KeyUp(object sender, KeyEventArgs evt) { private void Input_KeyUp(object sender, KeyEventArgs evt) {
@@ -85,7 +81,6 @@ namespace Elwig.Windows {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
var list = await ctx.DeliverySchedules var list = await ctx.DeliverySchedules
.Where(s => s.Year == ViewModel.FilterSeason) .Where(s => s.Year == ViewModel.FilterSeason)
.Include(s => s.Branch)
.OrderBy(s => s.DateString) .OrderBy(s => s.DateString)
.ThenBy(s => s.Branch.Name) .ThenBy(s => s.Branch.Name)
.ThenBy(s => s.Description) .ThenBy(s => s.Description)
@@ -103,14 +98,14 @@ namespace Elwig.Windows {
} }
private async Task RefreshList(bool updateSort = false) { private async Task RefreshList(bool updateSort = false) {
var vm = ViewModel;
var cursor = Mouse.OverrideCursor != null;
if (!cursor) Mouse.OverrideCursor = Cursors.Wait;
var query = (vm.SearchQuery, vm.FilterSeason, vm.FilterOnlyUpcoming, vm.FilterOnlyUpcoming);
var (filter, deliveryAncmts, stat) = await Task.Run(async () => {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
var (_, deliveryAncmtQuery, filter) = await ViewModel.GetFilters(ctx); var (_, deliveryAncmtQuery, filter) = await vm.GetFilters(ctx);
var deliveryAncmts = await deliveryAncmtQuery var deliveryAncmts = await deliveryAncmtQuery.ToListAsync();
.Include(a => a.Member.BillingAddress)
.Include(a => a.Schedule)
.Include(a => a.Variety)
.AsSplitQuery()
.ToListAsync();
if (filter.Count > 0 && deliveryAncmts.Count > 0) { if (filter.Count > 0 && deliveryAncmts.Count > 0) {
var dict = deliveryAncmts.AsParallel() var dict = deliveryAncmts.AsParallel()
@@ -120,20 +115,25 @@ namespace Elwig.Windows {
.ThenBy(a => a.Key.Member.Name) .ThenBy(a => a.Key.Member.Name)
.ThenBy(a => a.Key.Member.GivenName) .ThenBy(a => a.Key.Member.GivenName)
.ThenBy(a => a.Key.Member.MgNr); .ThenBy(a => a.Key.Member.MgNr);
var threshold = dict.Select(a => a.Value).Max() * 3 / 4; var threshold = dict.Max(a => a.Value) * 3 / 4;
deliveryAncmts = dict deliveryAncmts = [.. dict
.Where(a => a.Value > threshold) .Where(a => a.Value > threshold)
.Select(a => a.Key) .Select(a => a.Key)];
.ToList();
} else { } else {
deliveryAncmts = deliveryAncmts deliveryAncmts = [.. deliveryAncmts
.OrderBy(a => a.Schedule.DateString) .OrderBy(a => a.Schedule.DateString)
.ThenBy(a => a.Member.Name) .ThenBy(a => a.Member.Name)
.ThenBy(a => a.Member.GivenName) .ThenBy(a => a.Member.GivenName)
.ThenBy(a => a.Member.MgNr) .ThenBy(a => a.Member.MgNr)];
.ToList();
} }
var stat = await DeliveryAncmtService.GenerateToolTipData(deliveryAncmtQuery);
return (filter, deliveryAncmts, stat);
});
if (!cursor) Mouse.OverrideCursor = null;
if (query != (ViewModel.SearchQuery, ViewModel.FilterSeason, ViewModel.FilterOnlyUpcoming, ViewModel.FilterOnlyUpcoming)) return;
ControlUtils.RenewItemsSource(DeliveryAncmtList, deliveryAncmts, ControlUtils.RenewItemsSource(DeliveryAncmtList, deliveryAncmts,
DeliveryAncmtList_SelectionChanged, ViewModel.TextFilter.Count > 0 ? ControlUtils.RenewSourceDefault.IfOnly : ControlUtils.RenewSourceDefault.None, !updateSort); DeliveryAncmtList_SelectionChanged, ViewModel.TextFilter.Count > 0 ? ControlUtils.RenewSourceDefault.IfOnly : ControlUtils.RenewSourceDefault.None, !updateSort);
if (updateSort && DeliveryAncmtList.SelectedItem != null) if (updateSort && DeliveryAncmtList.SelectedItem != null)
@@ -141,9 +141,9 @@ namespace Elwig.Windows {
ViewModel.StatusAncmts = $"{deliveryAncmts.Count:N0}"; ViewModel.StatusAncmts = $"{deliveryAncmts.Count:N0}";
if (filter.Count == 0) { if (filter.Count == 0) {
var (text, grid) = await DeliveryAncmtService.GenerateToolTip(deliveryAncmtQuery); var (text, data) = stat;
ViewModel.StatusWeight = text; ViewModel.StatusWeight = text;
ViewModel.StatusWeightToolTip = grid; ViewModel.StatusWeightToolTip = DeliveryAncmtService.GenerateToolTip(data);
} else { } else {
ViewModel.StatusWeight = $"{deliveryAncmts.Sum(a => a.Weight):N0} kg"; ViewModel.StatusWeight = $"{deliveryAncmts.Sum(a => a.Weight):N0} kg";
ViewModel.StatusWeightToolTip = null; ViewModel.StatusWeightToolTip = null;
@@ -177,15 +177,8 @@ namespace Elwig.Windows {
protected override async Task OnRenewContext(AppDbContext ctx) { protected override async Task OnRenewContext(AppDbContext ctx) {
await base.OnRenewContext(ctx); await base.OnRenewContext(ctx);
ControlUtils.RenewItemsSource(MemberInput, await ctx.Members ControlUtils.RenewItemsSource(MemberInput, await ctx.FetchMembers(includeNotActive: !IsCreating).ToListAsync());
.Where(m => m.IsActive || !IsCreating) ControlUtils.RenewItemsSource(WineVarietyInput, await ctx.FetchWineVarieties().ToListAsync());
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.DefaultWbKg!.AtKg)
.OrderBy(m => m.Name)
.ThenBy(m => m.GivenName)
.ThenBy(m => m.MgNr)
.ToListAsync());
ControlUtils.RenewItemsSource(WineVarietyInput, await ctx.WineVarieties.OrderBy(v => v.Name).ToListAsync());
await RefreshDeliveryScheduleList(); await RefreshDeliveryScheduleList();
await RefreshList(); await RefreshList();
@@ -196,6 +189,7 @@ namespace Elwig.Windows {
} }
private async void DeliveryScheduleList_SelectionChanged(object sender, RoutedEventArgs evt) { private async void DeliveryScheduleList_SelectionChanged(object sender, RoutedEventArgs evt) {
if (!HasContextLoaded) return;
await RefreshList(); await RefreshList();
if (DeliveryScheduleList.SelectedItem is DeliverySchedule s) { if (DeliveryScheduleList.SelectedItem is DeliverySchedule s) {
Menu_DeliveryAncmtList_SaveSelected.IsEnabled = !IsEditing && !IsCreating; Menu_DeliveryAncmtList_SaveSelected.IsEnabled = !IsEditing && !IsCreating;
@@ -217,11 +211,13 @@ namespace Elwig.Windows {
} }
private async void OnlyUpcomingInput_Changed(object sender, RoutedEventArgs evt) { private async void OnlyUpcomingInput_Changed(object sender, RoutedEventArgs evt) {
if (!HasContextLoaded) return;
await RefreshDeliveryScheduleList(); await RefreshDeliveryScheduleList();
await RefreshList(true); await RefreshList(true);
} }
private async void FromAllSchedulesInput_Changed(object sender, RoutedEventArgs evt) { private async void FromAllSchedulesInput_Changed(object sender, RoutedEventArgs evt) {
if (!HasContextLoaded) return;
if (ViewModel.FilterFromAllSchedules) { if (ViewModel.FilterFromAllSchedules) {
DeliveryScheduleList.SelectedItem = null; DeliveryScheduleList.SelectedItem = null;
} else if (DeliveryScheduleList.SelectedItem == null) { } else if (DeliveryScheduleList.SelectedItem == null) {
@@ -231,11 +227,12 @@ namespace Elwig.Windows {
} }
private async void SearchInput_TextChanged(object sender, TextChangedEventArgs evt) { private async void SearchInput_TextChanged(object sender, TextChangedEventArgs evt) {
if (!HasContextLoaded) return;
await RefreshList(true); await RefreshList(true);
} }
private async void SeasonInput_TextChanged(object sender, TextChangedEventArgs evt) { private async void SeasonInput_TextChanged(object sender, TextChangedEventArgs evt) {
if (ViewModel.FilterSeason == null) return; if (!HasContextLoaded || ViewModel.FilterSeason == null) return;
ViewModel.FilterOnlyUpcoming = false; ViewModel.FilterOnlyUpcoming = false;
await RefreshDeliveryScheduleList(); await RefreshDeliveryScheduleList();
await RefreshList(); await RefreshList();
@@ -274,14 +271,7 @@ namespace Elwig.Windows {
ViewModel.SelectedDeliveryAncmt = null; ViewModel.SelectedDeliveryAncmt = null;
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
ControlUtils.RenewItemsSource(MemberInput, await ctx.Members ControlUtils.RenewItemsSource(MemberInput, await ctx.FetchMembers(includeNotActive: !IsCreating).ToListAsync());
.Where(m => m.IsActive || !IsCreating)
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.DefaultWbKg!.AtKg)
.OrderBy(m => m.Name)
.ThenBy(m => m.GivenName)
.ThenBy(m => m.MgNr)
.ToListAsync());
HideNewEditDeleteButtons(); HideNewEditDeleteButtons();
ShowSaveResetCancelButtons(); ShowSaveResetCancelButtons();
@@ -319,10 +309,7 @@ namespace Elwig.Windows {
private async void DeleteDeliveryAncmtButton_Click(object? sender, RoutedEventArgs? evt) { private async void DeleteDeliveryAncmtButton_Click(object? sender, RoutedEventArgs? evt) {
if (ViewModel.SelectedDeliveryAncmt is not DeliveryAncmt a) if (ViewModel.SelectedDeliveryAncmt is not DeliveryAncmt a)
return; return;
var r = MessageBox.Show( if (InteractionService.AskContinue("Anmeldung löschen", "Soll die Anmeldung wirklich unwiderruflich gelöscht werden?")) {
$"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; Mouse.OverrideCursor = Cursors.Wait;
try { try {
await Task.Run(async () => { await Task.Run(async () => {
@@ -332,9 +319,7 @@ namespace Elwig.Windows {
}); });
App.HintContextChange(); App.HintContextChange();
} catch (Exception exc) { } catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message; InteractionService.ShowDbException("Anmeldung löschen", exc);
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Anmeldung löschen", MessageBoxButton.OK, MessageBoxImage.Error);
} }
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
} }
@@ -357,9 +342,7 @@ namespace Elwig.Windows {
(year, dsnr, mgnr, sortid) = await ViewModel.UpdateDeliveryAncmt(s?.Year, s?.DsNr, s?.MgNr, s?.SortId, s?.Type); (year, dsnr, mgnr, sortid) = await ViewModel.UpdateDeliveryAncmt(s?.Year, s?.DsNr, s?.MgNr, s?.SortId, s?.Type);
App.HintContextChange(); App.HintContextChange();
} catch (Exception exc) { } catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message; InteractionService.ShowDbException("Anmeldung aktualisieren", exc);
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Anmeldung aktualisieren", MessageBoxButton.OK, MessageBoxImage.Error);
SaveButton.IsEnabled = true; SaveButton.IsEnabled = true;
return; return;
} finally { } finally {
@@ -403,14 +386,7 @@ namespace Elwig.Windows {
DeliveryAncmtList.IsEnabled = true; DeliveryAncmtList.IsEnabled = true;
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
ControlUtils.RenewItemsSource(MemberInput, await ctx.Members ControlUtils.RenewItemsSource(MemberInput, await ctx.FetchMembers(includeNotActive: !IsCreating).ToListAsync());
.Where(m => m.IsActive || !IsCreating)
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.DefaultWbKg!.AtKg)
.OrderBy(m => m.Name)
.ThenBy(m => m.GivenName)
.ThenBy(m => m.MgNr)
.ToListAsync());
HideSaveResetCancelButtons(); HideSaveResetCancelButtons();
ShowNewEditDeleteButtons(); ShowNewEditDeleteButtons();
@@ -7,8 +7,7 @@
xmlns:local="clr-namespace:Elwig.Windows" xmlns:local="clr-namespace:Elwig.Windows"
xmlns:vm="clr-namespace:Elwig.ViewModels" xmlns:vm="clr-namespace:Elwig.ViewModels"
xmlns:ctrl="clr-namespace:Elwig.Controls" xmlns:ctrl="clr-namespace:Elwig.Controls"
Title="Leseplanung - Elwig" Height="600" Width="850" MinHeight="450" MinWidth="800" Title="Leseplanung - Elwig" Height="600" Width="850" MinHeight="450" MinWidth="800">
Loaded="Window_Loaded">
<Window.DataContext> <Window.DataContext>
<vm:DeliveryScheduleAdminViewModel/> <vm:DeliveryScheduleAdminViewModel/>
</Window.DataContext> </Window.DataContext>
@@ -30,20 +30,19 @@ namespace Elwig.Windows {
ControlUtils.InitializeDelayTimer(SearchInput, SearchInput_TextChanged); ControlUtils.InitializeDelayTimer(SearchInput, SearchInput_TextChanged);
SearchInput.TextChanged -= SearchInput_TextChanged; SearchInput.TextChanged -= SearchInput_TextChanged;
ViewModel.FilterSeason = Utils.CurrentLastSeason; ViewModel.FilterSeason = Utils.CurrentLastSeason;
}
private void Window_Loaded(object sender, RoutedEventArgs evt) {
ViewModel.FilterOnlyUpcoming = true; ViewModel.FilterOnlyUpcoming = true;
LockInputs();
} }
private async Task RefreshList(bool updateSort = false) { private async Task RefreshList(bool updateSort = false) {
var vm = ViewModel;
var cursor = Mouse.OverrideCursor != null;
if (!cursor) Mouse.OverrideCursor = Cursors.Wait;
var query = (vm.SearchQuery, vm.FilterSeason, vm.FilterOnlyUpcoming);
var deliverySchedules = await Task.Run(async () => {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
var (_, deliveryScheduleQuery, filter) = await ViewModel.GetFilters(ctx); var (_, deliveryScheduleQuery, filter) = await vm.GetFilters(ctx);
var deliverySchedules = await deliveryScheduleQuery var deliverySchedules = await deliveryScheduleQuery
.Include(s => s.Varieties) .Include(s => s.Varieties)
.Include(s => s.Branch)
.AsSplitQuery()
.ToListAsync(); .ToListAsync();
if (filter.Count > 0 && deliverySchedules.Count > 0) { if (filter.Count > 0 && deliverySchedules.Count > 0) {
@@ -53,19 +52,22 @@ namespace Elwig.Windows {
.ThenBy(a => a.Key.DateString) .ThenBy(a => a.Key.DateString)
.ThenBy(a => a.Key.Branch.Name) .ThenBy(a => a.Key.Branch.Name)
.ThenBy(a => a.Key.Description); .ThenBy(a => a.Key.Description);
var threshold = dict.Select(a => a.Value).Max() * 3 / 4; var threshold = dict.Max(a => a.Value) * 3 / 4;
deliverySchedules = dict deliverySchedules = [.. dict
.Where(a => a.Value > threshold) .Where(a => a.Value > threshold)
.Select(a => a.Key) .Select(a => a.Key)];
.ToList();
} else { } else {
deliverySchedules = deliverySchedules deliverySchedules = [.. deliverySchedules
.OrderBy(s => s.DateString) .OrderBy(s => s.DateString)
.ThenBy(s => s.Branch.Name) .ThenBy(s => s.Branch.Name)
.ThenBy(s => s.Description) .ThenBy(s => s.Description)];
.ToList();
} }
return deliverySchedules;
});
if (!cursor) Mouse.OverrideCursor = null;
if (query != ((ViewModel.SearchQuery, ViewModel.FilterSeason, ViewModel.FilterOnlyUpcoming))) return;
ControlUtils.RenewItemsSource(DeliveryScheduleList, deliverySchedules, ControlUtils.RenewItemsSource(DeliveryScheduleList, deliverySchedules,
DeliveryScheduleList_SelectionChanged, ViewModel.TextFilter.Count > 0 ? ControlUtils.RenewSourceDefault.IfOnly : ControlUtils.RenewSourceDefault.None, !updateSort); DeliveryScheduleList_SelectionChanged, ViewModel.TextFilter.Count > 0 ? ControlUtils.RenewSourceDefault.IfOnly : ControlUtils.RenewSourceDefault.None, !updateSort);
if (updateSort && DeliveryScheduleList.SelectedItem != null) if (updateSort && DeliveryScheduleList.SelectedItem != null)
@@ -99,14 +101,14 @@ namespace Elwig.Windows {
protected override async Task OnRenewContext(AppDbContext ctx) { protected override async Task OnRenewContext(AppDbContext ctx) {
await base.OnRenewContext(ctx); await base.OnRenewContext(ctx);
ControlUtils.RenewItemsSource(BranchInput, await ctx.Branches.OrderBy(b => b.Name).ToListAsync()); ControlUtils.RenewItemsSource(BranchInput, await ctx.FetchBranches().ToListAsync());
var varieties = await ctx.WineVarieties.OrderBy(v => v.Name).ToListAsync(); var varieties = await ctx.FetchWineVarieties().ToListAsync();
ControlUtils.RenewItemsSource(MainWineVarietiesInput, varieties); ControlUtils.RenewItemsSource(MainWineVarietiesInput, varieties);
ControlUtils.RenewItemsSource(OtherWineVarietiesInput, varieties); ControlUtils.RenewItemsSource(OtherWineVarietiesInput, varieties);
var attrList = await ctx.WineAttributes.OrderBy(a => a.Name).Cast<object>().ToListAsync(); var attrList = await ctx.FetchWineAttributes().Cast<object>().ToListAsync();
attrList.Insert(0, new NullItem("- Keine Angabe -")); attrList.Insert(0, new NullItem("- Keine Angabe -"));
ControlUtils.RenewItemsSource(AttributeInput, attrList, null, ControlUtils.RenewSourceDefault.First); ControlUtils.RenewItemsSource(AttributeInput, attrList, null, ControlUtils.RenewSourceDefault.First);
var cultList = await ctx.WineCultivations.OrderBy(a => a.Name).Cast<object>().ToListAsync(); var cultList = await ctx.FetchWineCultivations().Cast<object>().ToListAsync();
cultList.Insert(0, new NullItem("- Kein Angabe -")); cultList.Insert(0, new NullItem("- Kein Angabe -"));
ControlUtils.RenewItemsSource(CultivationInput, cultList, null, ControlUtils.RenewSourceDefault.First); ControlUtils.RenewItemsSource(CultivationInput, cultList, null, ControlUtils.RenewSourceDefault.First);
@@ -118,15 +120,17 @@ namespace Elwig.Windows {
} }
private async void OnlyUpcomingInput_Changed(object sender, RoutedEventArgs evt) { private async void OnlyUpcomingInput_Changed(object sender, RoutedEventArgs evt) {
if (!HasContextLoaded) return;
await RefreshList(); await RefreshList();
} }
private async void SearchInput_TextChanged(object sender, TextChangedEventArgs evt) { private async void SearchInput_TextChanged(object sender, TextChangedEventArgs evt) {
if (!HasContextLoaded) return;
await RefreshList(true); await RefreshList(true);
} }
private async void SeasonInput_TextChanged(object sender, TextChangedEventArgs evt) { private async void SeasonInput_TextChanged(object sender, TextChangedEventArgs evt) {
if (ViewModel.FilterSeason == null) return; if (!HasContextLoaded || ViewModel.FilterSeason == null) return;
ViewModel.FilterOnlyUpcoming = false; ViewModel.FilterOnlyUpcoming = false;
await RefreshList(); await RefreshList();
} }
@@ -173,10 +177,7 @@ namespace Elwig.Windows {
private async void DeleteDeliveryScheduleButton_Click(object? sender, RoutedEventArgs? evt) { private async void DeleteDeliveryScheduleButton_Click(object? sender, RoutedEventArgs? evt) {
if (ViewModel.SelectedDeliverySchedule is not DeliverySchedule s) if (ViewModel.SelectedDeliverySchedule is not DeliverySchedule s)
return; return;
var r = MessageBox.Show( if (InteractionService.AskContinue("Leseplan löschen", $"Soll der Leseplan \"{s.Description}\" vom {s.Date:dd.MM.yyyy} wirklich unwiderruflich gelöscht werden?")) {
$"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; Mouse.OverrideCursor = Cursors.Wait;
try { try {
await Task.Run(async () => { await Task.Run(async () => {
@@ -186,9 +187,7 @@ namespace Elwig.Windows {
}); });
App.HintContextChange(); App.HintContextChange();
} catch (Exception exc) { } catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message; InteractionService.ShowDbException("Leseplan löschen", exc);
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Leseplan löschen", MessageBoxButton.OK, MessageBoxImage.Error);
} }
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
} }
@@ -208,9 +207,7 @@ namespace Elwig.Windows {
await ViewModel.UpdateDeliverySchedule(ViewModel.SelectedDeliverySchedule?.Year, ViewModel.SelectedDeliverySchedule?.DsNr); await ViewModel.UpdateDeliverySchedule(ViewModel.SelectedDeliverySchedule?.Year, ViewModel.SelectedDeliverySchedule?.DsNr);
App.HintContextChange(); App.HintContextChange();
} catch (Exception exc) { } catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message; InteractionService.ShowDbException("Leseplan aktualisieren", exc);
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Leseplan aktualisieren", MessageBoxButton.OK, MessageBoxImage.Error);
SaveButton.IsEnabled = true; SaveButton.IsEnabled = true;
return; return;
} finally { } finally {
+24 -46
View File
@@ -3,6 +3,7 @@ using Elwig.Helpers;
using Elwig.Helpers.Billing; using Elwig.Helpers.Billing;
using Elwig.Models.Dtos; using Elwig.Models.Dtos;
using Elwig.Models.Entities; using Elwig.Models.Entities;
using Elwig.Services;
using MailKit.Net.Smtp; using MailKit.Net.Smtp;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Win32; using Microsoft.Win32;
@@ -107,7 +108,7 @@ namespace Elwig.Windows {
public MailWindow(int? year = null) { public MailWindow(int? year = null) {
InitializeComponent(); InitializeComponent();
using (var ctx = new AppDbContext()) { using (var ctx = new AppDbContext()) {
Year = year ?? ctx.Seasons.OrderBy(s => s.Year).LastOrDefault()?.Year ?? Utils.Today.Year; Year = year ?? ctx.Seasons.OrderByDescending(s => s.Year).FirstOrDefault()?.Year ?? Utils.Today.Year;
Title = $"Rundschreiben - Lese {Year} - Elwig"; Title = $"Rundschreiben - Lese {Year} - Elwig";
} }
@@ -155,7 +156,7 @@ namespace Elwig.Windows {
} }
protected override async Task OnRenewContext(AppDbContext ctx) { protected override async Task OnRenewContext(AppDbContext ctx) {
var season = await ctx.Seasons.FindAsync(Year); var season = await ctx.Seasons.Include(s => s.PaymentVariants).Where(s => s.Year == Year).SingleOrDefaultAsync();
var l = new List<string> { var l = new List<string> {
MemberDataSheet.Name MemberDataSheet.Name
}; };
@@ -165,10 +166,7 @@ namespace Elwig.Windows {
} }
AvaiableDocumentsList.ItemsSource = l; AvaiableDocumentsList.ItemsSource = l;
ControlUtils.RenewItemsSource(MemberBranchInput, await ctx.Branches ControlUtils.RenewItemsSource(MemberBranchInput, await ctx.FetchBranches(includeWithoutMembers: false).ToListAsync(), MemberInput_SelectionChanged);
.Where(b => b.Members.Count != 0)
.OrderBy(b => b.Name)
.ToListAsync(), MemberInput_SelectionChanged);
if (MemberBranchInput.SelectedItems.Count == 0) { if (MemberBranchInput.SelectedItems.Count == 0) {
MemberBranchInput.SelectionChanged -= MemberInput_SelectionChanged; MemberBranchInput.SelectionChanged -= MemberInput_SelectionChanged;
MemberBranchInput.SelectAll(); MemberBranchInput.SelectAll();
@@ -207,13 +205,8 @@ namespace Elwig.Windows {
.OrderBy(m => m.Name) .OrderBy(m => m.Name)
.ThenBy(m => m.GivenName) .ThenBy(m => m.GivenName)
.Include(m => m.Branch) .Include(m => m.Branch)
.Include(m => m.DefaultWbKg!.AtKg)
.Include(m => m.EmailAddresses) .Include(m => m.EmailAddresses)
.Include(m => m.TelephoneNumbers) .Include(m => m.TelephoneNumbers)
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.PostalDest.AtPlz!.Country)
.Include(m => m.BillingAddress!.PostalDest.AtPlz!.Ort)
.Include(m => m.BillingAddress!.PostalDest.AtPlz!.Country)
.ToListAsync(), MemberInput_SelectionChanged); .ToListAsync(), MemberInput_SelectionChanged);
if (MemberCustomInput.SelectedItems.Count == 0) { if (MemberCustomInput.SelectedItems.Count == 0) {
MemberCustomInput.SelectionChanged -= MemberInput_SelectionChanged; MemberCustomInput.SelectionChanged -= MemberInput_SelectionChanged;
@@ -373,7 +366,7 @@ namespace Elwig.Windows {
RecipientsDeliveryMembersInput.IsChecked = true; RecipientsDeliveryMembersInput.IsChecked = true;
} else if (idx >= 2) { } else if (idx >= 2) {
var name = s.Split(" ")[^1]; var name = s.Split(" ")[^1];
var pv = await ctx.PaymentVariants.SingleAsync(v => v.Year == Year && v.Name == name)!; var pv = await ctx.PaymentVariants.Where(v => v.Year == Year && v.Name == name).SingleAsync();
SelectedDocs.Add(new(DocType.CreditNote, s, (pv.Year, pv.AvNr))); SelectedDocs.Add(new(DocType.CreditNote, s, (pv.Year, pv.AvNr)));
RecipientsCreditMembersInput.IsChecked = true; RecipientsCreditMembersInput.IsChecked = true;
} }
@@ -492,13 +485,8 @@ namespace Elwig.Windows {
} }
Recipients = await query Recipients = await query
.Include(m => m.Branch) .Include(m => m.Branch)
.Include(m => m.DefaultWbKg!.AtKg)
.Include(m => m.EmailAddresses) .Include(m => m.EmailAddresses)
.Include(m => m.TelephoneNumbers) .Include(m => m.TelephoneNumbers)
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.PostalDest.AtPlz!.Country)
.Include(m => m.BillingAddress!.PostalDest.AtPlz!.Ort)
.Include(m => m.BillingAddress!.PostalDest.AtPlz!.Country)
.ToListAsync(); .ToListAsync();
} }
UpdatePostalEmailRecipients(); UpdatePostalEmailRecipients();
@@ -703,7 +691,7 @@ namespace Elwig.Windows {
PrintButton.IsEnabled = PrintDocument != null && !hasPreviewDocs; PrintButton.IsEnabled = PrintDocument != null && !hasPreviewDocs;
EmailButton.IsEnabled = EmailDocuments != null && !hasPreviewDocs && App.Config.Smtp != null; EmailButton.IsEnabled = EmailDocuments != null && !hasPreviewDocs && App.Config.Smtp != null;
} catch (Exception exc) { } catch (Exception exc) {
MessageBox.Show(exc.ToString(), "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException(exc);
} finally { } finally {
UnlockInputs(); UnlockInputs();
GenerateButton.IsEnabled = true; GenerateButton.IsEnabled = true;
@@ -725,7 +713,7 @@ namespace Elwig.Windows {
foreach (var doc in docs) { foreach (var doc in docs) {
if (doc.Type == DocType.DeliveryConfirmation) { if (doc.Type == DocType.DeliveryConfirmation) {
var year = (int)doc.Details!; var year = (int)doc.Details!;
var b = new Billing(year); var b = await Billing.Create(year);
await b.FinishSeason(); await b.FinishSeason();
await b.CalculateBuckets(); await b.CalculateBuckets();
App.HintContextChange(); App.HintContextChange();
@@ -755,10 +743,13 @@ namespace Elwig.Windows {
Member = m, Member = m,
Docs = docs.SelectMany<SelectedDoc, GeneratedDoc>(doc => { Docs = docs.SelectMany<SelectedDoc, GeneratedDoc>(doc => {
try { try {
App.MainDispatcher.Invoke(() => {
ProgressBar.Value = offset + 100.0 * i / 2 / totalNum;
});
if (doc.Type == DocType.Custom) { if (doc.Type == DocType.Custom) {
return [new GeneratedDoc((string)doc.Details!)]; return [new GeneratedDoc((string)doc.Details!)];
} else if (doc.Type == DocType.MemberDataSheet) { } else if (doc.Type == DocType.MemberDataSheet) {
return [new GeneratedDoc(new MemberDataSheet(m, ctx) { Date = postalDate })]; return [new GeneratedDoc(new MemberDataSheet(m) { Date = postalDate })];
} else if (doc.Type == DocType.DeliveryConfirmation) { } else if (doc.Type == DocType.DeliveryConfirmation) {
var year = (int)doc.Details!; var year = (int)doc.Details!;
DeliveryConfirmationDeliveryData data; DeliveryConfirmationDeliveryData data;
@@ -769,21 +760,14 @@ namespace Elwig.Windows {
} else { } else {
return []; return [];
} }
return [new GeneratedDoc(new DeliveryConfirmation(ctx, year, m, data) { Date = postalDate })]; return [new GeneratedDoc(new DeliveryConfirmation(year, m, postalDate, data) { Date = postalDate })];
} else if (doc.Type == DocType.CreditNote) { } else if (doc.Type == DocType.CreditNote) {
var details = ((int, int))doc.Details!; var details = ((int, int))doc.Details!;
var year = details.Item1; var year = details.Item1;
var avnr = details.Item2; var avnr = details.Item2;
var data = cnData[(year, avnr)]; var data = cnData[(year, avnr)];
try { try {
return [new GeneratedDoc(new CreditNote( return [new GeneratedDoc(new CreditNote(data.Item2[m.MgNr], postalDate, data.Item3, data.Item1[m.MgNr]) { Date = postalDate })];
ctx, data.Item2[m.MgNr], data.Item1[m.MgNr],
data.Item3.ConsiderContractPenalties,
data.Item3.ConsiderTotalPenalty,
data.Item3.ConsiderAutoBusinessShares,
data.Item3.ConsiderCustomModifiers,
ctx.GetMemberUnderDelivery(year, m.MgNr).GetAwaiter().GetResult()
) { Date = postalDate })];
} catch (Exception) { } catch (Exception) {
return []; return [];
} }
@@ -791,7 +775,7 @@ namespace Elwig.Windows {
throw new NotImplementedException("Invalid DocType"); throw new NotImplementedException("Invalid DocType");
} }
} catch (Exception exc) { } catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException(exc);
return []; return [];
} finally { } finally {
App.MainDispatcher.Invoke(() => { App.MainDispatcher.Invoke(() => {
@@ -804,9 +788,9 @@ namespace Elwig.Windows {
var hasPreviewDocs = memberDocs.Any(m => m.Docs.Any(d => d.Doc.IsPreview)); var hasPreviewDocs = memberDocs.Any(m => m.Docs.Any(d => d.Doc.IsPreview));
if (hasPreviewDocs) { if (hasPreviewDocs) {
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?", if (!InteractionService.AskContinue("Vorläufige Dokumente",
"Vorläufige Dokumente", MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel); "Einige der ausgewählten Dokumente sind nur als vorläufig zu betrachten und können daher nicht verschickt/ausgedruckt werden!\n\n" +
if (res != MessageBoxResult.OK) { "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?")) {
throw new OperationCanceledException("Dokumentenerzeugung abgebrochen!"); throw new OperationCanceledException("Dokumentenerzeugung abgebrochen!");
} }
} }
@@ -827,7 +811,7 @@ namespace Elwig.Windows {
var emailRecipients = email.Select(d => d.Key.MgNr).ToHashSet(); var emailRecipients = email.Select(d => d.Key.MgNr).ToHashSet();
foreach (var item1 in email.Select((e, i) => new { Index = i, e.Key, e.Value })) { foreach (var item1 in email.Select((e, i) => new { Index = i, e.Key, e.Value })) {
foreach (var item2 in item1.Value.Select((d, i) => new { Index = i, Doc = d })) { foreach (var item2 in item1.Value.Select((d, i) => new { Index = i, Doc = d })) {
await item2.Doc.Generate(CancelGeneration?.Token, new Progress<double>(v => App.MainDispatcher.Invoke(() => { await item2.Doc.Generate(ctx, CancelGeneration?.Token, new Progress<double>(v => App.MainDispatcher.Invoke(() => {
ProgressBar.Value = offset + v * (item2.Index + 1) / item1.Value.Count / totalNum + 100.0 * item1.Index / totalNum; ProgressBar.Value = offset + v * (item2.Index + 1) / item1.Value.Count / totalNum + 100.0 * item1.Index / totalNum;
}))); })));
} }
@@ -861,7 +845,7 @@ namespace Elwig.Windows {
if (printDocs.Count > 0) { if (printDocs.Count > 0) {
var print = Document.Merge(printDocs); var print = Document.Merge(printDocs);
await print.Generate(CancelGeneration?.Token, new Progress<double>(v => App.MainDispatcher.Invoke(() => { await print.Generate(ctx, CancelGeneration?.Token, new Progress<double>(v => App.MainDispatcher.Invoke(() => {
ProgressBar.Value = offset + v * printNum / totalNum; ProgressBar.Value = offset + v * printNum / totalNum;
}))); })));
PrintDocument = print; PrintDocument = print;
@@ -909,9 +893,7 @@ namespace Elwig.Windows {
GenerateButton.IsEnabled = false; GenerateButton.IsEnabled = false;
LockInputs(); LockInputs();
var res = MessageBox.Show($"Sollen {PrintDocument.Pages} Blätter ({PrintDocument.TotalPages} Seiten) gedruckt werden?", if (InteractionService.AskQuestion("Rundschreiben drucken", $"Sollen {PrintDocument.Pages} Blätter ({PrintDocument.TotalPages} Seiten) gedruckt werden?", false)) {
"Rundschreiben drucken", MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No);
if (res == MessageBoxResult.Yes) {
Mouse.OverrideCursor = Cursors.Wait; Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => { await Task.Run(async () => {
if (App.Config.Debug) { if (App.Config.Debug) {
@@ -949,11 +931,8 @@ namespace Elwig.Windows {
client = await Task.Run(Utils.GetSmtpClient); client = await Task.Run(Utils.GetSmtpClient);
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
var res = MessageBox.Show($"Sollen {EmailDocuments.Count:N0} E-Mails verschickt werden?", if (!InteractionService.AskQuestion("Rundschreiben verschicken", $"Sollen {EmailDocuments.Count:N0} E-Mails verschickt werden?", false))
"Rundschreiben verschicken", MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No);
if (res != MessageBoxResult.Yes) {
return; return;
}
Mouse.OverrideCursor = Cursors.Wait; Mouse.OverrideCursor = Cursors.Wait;
var subject = EmailSubjectInput.Text; var subject = EmailSubjectInput.Text;
@@ -982,10 +961,9 @@ namespace Elwig.Windows {
} }
}); });
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", 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.");
MessageBoxButton.OK, MessageBoxImage.Information);
} catch (Exception exc) { } catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException(exc);
} finally { } finally {
if (client != null) if (client != null)
await client.DisconnectAsync(true); await client.DisconnectAsync(true);
@@ -1014,7 +992,7 @@ namespace Elwig.Windows {
return; return;
var name = s.Split(" ")[^1]; var name = s.Split(" ")[^1];
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
var pv = ctx.PaymentVariants.Single(v => v.Year == Year && v.Name == name)!; var pv = ctx.PaymentVariants.Where(v => v.Year == Year && v.Name == name).Single();
SelectedDocs.Add(new(DocType.CreditNote, s, (pv.Year, pv.AvNr))); SelectedDocs.Add(new(DocType.CreditNote, s, (pv.Year, pv.AvNr)));
SelectedDocumentsList.SelectedIndex = SelectedDocs.Count - 1; SelectedDocumentsList.SelectedIndex = SelectedDocs.Count - 1;
RecipientsCreditMembersInput.IsChecked = true; RecipientsCreditMembersInput.IsChecked = true;
+1 -1
View File
@@ -5,7 +5,7 @@
xmlns:local="clr-namespace:Elwig.Windows" xmlns:local="clr-namespace:Elwig.Windows"
xmlns:ctrl="clr-namespace:Elwig.Controls" xmlns:ctrl="clr-namespace:Elwig.Controls"
Title="Elwig" Height="390" Width="520" ResizeMode="CanMinimize" Title="Elwig" Height="390" Width="520" ResizeMode="CanMinimize"
Loaded="Window_Loaded" Closing="Window_Closing"> Closing="Window_Closing">
<Window.Resources> <Window.Resources>
<Style TargetType="Button"> <Style TargetType="Button">
<Setter Property="VerticalAlignment" Value="Top"/> <Setter Property="VerticalAlignment" Value="Top"/>
+62 -90
View File
@@ -37,11 +37,11 @@ namespace Elwig.Windows {
SyncButton.Visibility = App.Config.SyncUrl != null ? Visibility.Visible : Visibility.Hidden; SyncButton.Visibility = App.Config.SyncUrl != null ? Visibility.Visible : Visibility.Hidden;
Menu_Database_Upload.IsEnabled = App.Config.SyncUrl != null; Menu_Database_Upload.IsEnabled = App.Config.SyncUrl != null;
Menu_Database_Download.IsEnabled = App.Config.SyncUrl != null; Menu_Database_Download.IsEnabled = App.Config.SyncUrl != null;
SeasonInput.Value = Utils.CurrentLastSeason;
} }
private void Window_Loaded(object sender, RoutedEventArgs evt) { protected override async Task OnInit(AppDbContext ctx) {
SeasonInput.Value = Utils.CurrentLastSeason; await base.OnInit(ctx);
if (Utils.HasInternetConnectivity()) { if (Utils.HasInternetConnectivity()) {
CheckSync(200); CheckSync(200);
} }
@@ -59,9 +59,7 @@ namespace Elwig.Windows {
} }
Thread.Sleep(100); 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 (App.NumWindows > 1 && !App.Current.Windows.Cast<Window>().Any(w => ((w as AdministrationWindow)?.IsEditing ?? false) || ((w as AdministrationWindow)?.IsCreating ?? false))) {
var res = MessageBox.Show("Es sind noch weitere Fenster geöffnet.\nSollen alle Fenster geschlossen werden?", if (!InteractionService.AskConfirmation("Elwig beenden", "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; evt.Cancel = true;
} else { } else {
Application.Current.Shutdown(); Application.Current.Shutdown();
@@ -84,9 +82,9 @@ namespace Elwig.Windows {
try { try {
using var client = await Utils.GetSmtpClient(); using var client = await Utils.GetSmtpClient();
await client!.DisconnectAsync(true); await client!.DisconnectAsync(true);
MessageBox.Show("E-Mail-Einstellungen erfolgreich überprüft!", "Erfolg", MessageBoxButton.OK, MessageBoxImage.Information); InteractionService.ShowInformation("Erfolg", "E -Mail-Einstellungen erfolgreich überprüft!");
} catch (Exception exc) { } catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException(exc);
} }
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
} }
@@ -115,17 +113,17 @@ namespace Elwig.Windows {
private async void Menu_Scale_SetDateTime_Click(object sender, RoutedEventArgs evt) { private async void Menu_Scale_SetDateTime_Click(object sender, RoutedEventArgs evt) {
if (App.CommandScales.Count == 0) { if (App.CommandScales.Count == 0) {
MessageBox.Show("Es sind keine geeigneten Waagen verfügbar!", "Datum und Uhrzeit setzen", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowError("Datum und Uhrzeit setzen", "Es sind keine geeigneten Waagen verfügbar!");
return; return;
} }
foreach (var s in App.CommandScales) { foreach (var s in App.CommandScales) {
try { try {
await s.SetDateAndTime(DateTime.Now); await s.SetDateAndTime(DateTime.Now);
} catch (Exception exc) { } catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException(exc);
} }
} }
MessageBox.Show("Datum und Uhrzeit auf entsprechenden Waagen gesetzt!", "Datum und Uhrzeit setzen", MessageBoxButton.OK, MessageBoxImage.Information); InteractionService.ShowInformation("Datum und Uhrzeit setzen", "Datum und Uhrzeit auf entsprechenden Waagen gesetzt!");
} }
private void Menu_Database_Query_Click(object sender, RoutedEventArgs evt) { private void Menu_Database_Query_Click(object sender, RoutedEventArgs evt) {
@@ -157,29 +155,23 @@ namespace Elwig.Windows {
}); });
} }
} catch (Exception exc) { } catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException(exc);
} }
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
} }
private async void Menu_Database_Backup_Click(object sender, RoutedEventArgs evt) { private async void Menu_Database_Backup_Click(object sender, RoutedEventArgs evt) {
try { try {
var d = new SaveFileDialog() { var filename = InteractionService.SaveFile("Datenbank-Sicherung", $"database_{Utils.Today:yyyy-MM-dd}", "sql.zip");
Title = "Datenbank sichern - Elwig", if (filename != null) {
FileName = $"database_{Utils.Today:yyyy-MM-dd}.sql.zip", if (!filename.EndsWith(".sql.zip")) filename += ".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; Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => { await Task.Run(async () => {
await Database.ExportSql(d.FileName, true); await Database.ExportSql(filename, true);
}); });
} }
} catch (Exception exc) { } catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException(exc);
} }
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
} }
@@ -192,16 +184,13 @@ namespace Elwig.Windows {
Filter = "SQLite-Datenbank (*.sqlite3, *.sqlite3.zip, *.sql, *.sql.zip)|*.sqlite3;*.sqlite3.zip;*.sql;*.sql.zip", Filter = "SQLite-Datenbank (*.sqlite3, *.sqlite3.zip, *.sql, *.sql.zip)|*.sqlite3;*.sqlite3.zip;*.sql;*.sql.zip",
}; };
if (d.ShowDialog() == true) { if (d.ShowDialog() == true) {
var res = MessageBox.Show("Soll die Datenbank wirklich unwiederruflich durch die wiederhergestellte Version ersetzt werden?", "Datenbank wiederherstellen", if (!InteractionService.AskContinue("Datenbank wiederherstellen", "Soll die Datenbank wirklich unwiederruflich durch die wiederhergestellte Version ersetzt werden?"))
MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
if (res != MessageBoxResult.OK)
return; return;
Mouse.OverrideCursor = Cursors.Wait; Mouse.OverrideCursor = Cursors.Wait;
await App.ReplaceDatabase(d.FileName); await App.ReplaceDatabase(d.FileName);
} }
} catch (Exception exc) { } catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException(exc);
} }
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
} }
@@ -266,15 +255,15 @@ namespace Elwig.Windows {
.ToList(); .ToList();
if (files.Count == 0) { if (files.Count == 0) {
MessageBox.Show("Die Datenbank wurde noch nicht vom Hauptgerät hochgeladen!", "Datenbank herunterladen", InteractionService.ShowError("Datenbank herunterladen", "Die Datenbank wurde noch nicht vom Hauptgerät hochgeladen!");
MessageBoxButton.OK, MessageBoxImage.Error);
return; return;
} }
var file = files[0]; var file = files[0];
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", if (!InteractionService.AskContinue("Datenbank herunterladen",
MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel); $"Es wurde eine komprimierte Datenbank (ca. {file.Size / 1024 / 1024} MB) vom {file.Timestamp:dd.MM.yyyy, HH:mm} gefunden.\n\n" +
if (res != MessageBoxResult.OK) $"Wollen Sie wirklich die aktuelle Datenbank unwiederruflich\nlöschen und durch die gefundene ersetzen?\n\n" +
$"Das kann zu Datenverlust führen!"))
return; return;
var filename = Path.Combine(App.TempPath, file.Name); var filename = Path.Combine(App.TempPath, file.Name);
@@ -283,20 +272,21 @@ namespace Elwig.Windows {
await client.DownloadAsync(file.Url, stream); await client.DownloadAsync(file.Url, stream);
} }
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", if (!InteractionService.AskContinue("Datenbank herunterladen",
MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel); "Die Datenbank wurde erfolgreich heruntergeladen!\n\n" +
if (res != MessageBoxResult.OK) "Soll die Datenbank wirklich unwiederruflich ersetzt werden?\n\n" +
"Wenn Sie unsicher sind sprechen Sie sich mit dem Benutzer des Hauptgerätes ab!"))
return; return;
await App.MainDispatcher.BeginInvoke(async () => { await App.MainDispatcher.BeginInvoke(async () => {
await App.ReplaceDatabase(filename); await App.ReplaceDatabase(filename);
}); });
} catch (HttpRequestException exc) { } catch (HttpRequestException exc) {
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Datenbank herunterladen", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException("Datenbank herunterladen", "Eventuell Internetverbindung prüfen!", exc);
} catch (TaskCanceledException exc) { } catch (TaskCanceledException exc) {
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Datenbank herunterladen", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException("Datenbank herunterladen", "Eventuell Internetverbindung prüfen!", exc);
} catch (Exception exc) { } catch (Exception exc) {
MessageBox.Show(exc.Message, "Datenbank herunterladen", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException("Datenbank herunterladen", exc);
} }
}); });
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
@@ -306,9 +296,7 @@ namespace Elwig.Windows {
if (App.Config.SyncUrl == null) if (App.Config.SyncUrl == null)
return; return;
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", 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!"))
MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
if (res != MessageBoxResult.OK)
return; return;
Mouse.OverrideCursor = Cursors.Wait; Mouse.OverrideCursor = Cursors.Wait;
@@ -317,14 +305,13 @@ namespace Elwig.Windows {
var path = Path.Combine(App.TempPath, "database.sql.zip"); var path = Path.Combine(App.TempPath, "database.sql.zip");
await Database.ExportSql(path, true); await Database.ExportSql(path, true);
await Utils.UploadExportData(path, App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword); await Utils.UploadExportData(path, App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
MessageBox.Show($"Hochladen der gesamten Datenbank erfolgreich!", "Datenbank hochladen", InteractionService.ShowInformation("Datenbank hochladen", $"Hochladen der gesamten Datenbank erfolgreich!");
MessageBoxButton.OK, MessageBoxImage.Information);
} catch (HttpRequestException exc) { } catch (HttpRequestException exc) {
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Datenbank hochladen", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException("Datenbank hochladen", "Eventuell Internetverbindung prüfen!", exc);
} catch (TaskCanceledException exc) { } catch (TaskCanceledException exc) {
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Datenbank hochladen", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException("Datenbank hochladen", "Eventuell Internetverbindung prüfen!", exc);
} catch (Exception exc) { } catch (Exception exc) {
MessageBox.Show(exc.Message, "Datenbank hochladen", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException("Datenbank hochladen", exc);
} }
}); });
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
@@ -405,7 +392,7 @@ namespace Elwig.Windows {
private async void SeasonInput_TextChanged(object? sender, TextChangedEventArgs? evt) { private async void SeasonInput_TextChanged(object? sender, TextChangedEventArgs? evt) {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
var year = SeasonInput.Value; var year = SeasonInput.Value;
var s0 = await ctx.Seasons.FindAsync(year); var s0 = await ctx.FetchSeasons(year).SingleOrDefaultAsync();
var valid = (s0 != null); var valid = (s0 != null);
DeliveryConfirmationButton.IsEnabled = valid; DeliveryConfirmationButton.IsEnabled = valid;
PaymentButton.IsEnabled = valid; PaymentButton.IsEnabled = valid;
@@ -457,19 +444,14 @@ namespace Elwig.Windows {
private async void OverUnderDeliveryButton_Click(object sender, RoutedEventArgs evt) { private async void OverUnderDeliveryButton_Click(object sender, RoutedEventArgs evt) {
if (SeasonInput.Value is not int year) if (SeasonInput.Value is not int year)
return; return;
var d = new SaveFileDialog() { var filename = InteractionService.SaveFile($"Über-/Unterlieferungen {year}", $"Über-Unterlieferungen-{year}", "ods");
FileName = $"Über-Unterlieferungen-{year}.ods", if (filename == null)
DefaultExt = "ods",
Filter = "OpenDocument Format Spreadsheet (*.ods)|*.ods",
Title = $"Über-/Unterlieferungen {year} speichern unter - Elwig"
};
if (d.ShowDialog() == false)
return; return;
Mouse.OverrideCursor = Cursors.Wait; Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => { await Task.Run(async () => {
try { try {
var b = new Billing(year); var b = await Billing.Create(year);
await b.FinishSeason(); await b.FinishSeason();
await b.CalculateBuckets(); await b.CalculateBuckets();
App.HintContextChange(); App.HintContextChange();
@@ -477,11 +459,16 @@ namespace Elwig.Windows {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
var tbl1 = await OverUnderDeliveryData.ForSeason(ctx.OverUnderDeliveryRows, year); var tbl1 = await OverUnderDeliveryData.ForSeason(ctx.OverUnderDeliveryRows, year);
var tbl2 = await AreaComUnderDeliveryData.ForSeason(ctx.AreaComUnderDeliveryRows, year); var tbl2 = await AreaComUnderDeliveryData.ForSeason(ctx.AreaComUnderDeliveryRows, year);
using var ods = new OdsFile(d.FileName); using var ods = new OdsFile(filename);
await ods.AddTable(tbl1); if (App.Client.HasRedWhite) {
await ods.AddTable(tbl1.Red);
await ods.AddTable(tbl1.White);
} else {
await ods.AddTable(tbl1.Total);
}
await ods.AddTable(tbl2); await ods.AddTable(tbl2);
} catch (Exception exc) { } catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException(exc);
} }
}); });
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
@@ -490,33 +477,28 @@ namespace Elwig.Windows {
private async void BreakdownButton_Click(object sender, RoutedEventArgs evt) { private async void BreakdownButton_Click(object sender, RoutedEventArgs evt) {
if (SeasonInput.Value is not int year) if (SeasonInput.Value is not int year)
return; return;
var d = new SaveFileDialog() { var filename = InteractionService.SaveFile($"Sorten-/Qualitätsaufschlüsselung {year}", $"Aufschlüsselung-{year}", "ods");
FileName = $"Aufschlüsselung-{year}.ods", if (filename == null)
DefaultExt = "ods",
Filter = "OpenDocument Format Spreadsheet (*.ods)|*.ods",
Title = $"Sorten-/Qualitätsaufschlüsselung {year} speichern unter - Elwig"
};
if (d.ShowDialog() == false)
return; return;
Mouse.OverrideCursor = Cursors.Wait; Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => { await Task.Run(async () => {
try { try {
var b = new Billing(year); var b = await Billing.Create(year);
await b.FinishSeason(); await b.FinishSeason();
await b.CalculateBuckets(); await b.CalculateBuckets();
App.HintContextChange(); App.HintContextChange();
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
using var ods = new OdsFile(d.FileName); using var ods = new OdsFile(filename);
var tblTotal = await WeightBreakdownData.ForSeason(ctx.WeightBreakDownRows, year); var tblTotal = await WeightBreakdownData.ForSeason(ctx.WeightBreakDownRows, year);
await ods.AddTable(tblTotal); await ods.AddTable(tblTotal);
foreach (var branch in await ctx.Branches.OrderBy(b => b.Name).ToListAsync()) { foreach (var branch in await ctx.FetchBranches().ToListAsync()) {
var tbl = await WeightBreakdownData.ForSeason(ctx.WeightBreakDownRows, year, branch); var tbl = await WeightBreakdownData.ForSeason(ctx.WeightBreakDownRows, year, branch);
await ods.AddTable(tbl); await ods.AddTable(tbl);
} }
} catch (Exception exc) { } catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException(exc);
} }
}); });
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
@@ -525,29 +507,24 @@ namespace Elwig.Windows {
private async void AreaCommitmentsButton_Click(object sender, RoutedEventArgs evt) { private async void AreaCommitmentsButton_Click(object sender, RoutedEventArgs evt) {
if (SeasonInput.Value is not int year) if (SeasonInput.Value is not int year)
return; return;
var d = new SaveFileDialog() { var filename = InteractionService.SaveFile($"Flächenbindungen {year}", $"Flächenbindungen-{year}", "ods");
FileName = $"Flächenbindungen-{year}.ods", if (filename == null)
DefaultExt = "ods",
Filter = "OpenDocument Format Spreadsheet (*.ods)|*.ods",
Title = $"Flächenbindungen {year} speichern unter - Elwig"
};
if (d.ShowDialog() == false)
return; return;
Mouse.OverrideCursor = Cursors.Wait; Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => { await Task.Run(async () => {
try { try {
var b = new Billing(year); var b = await Billing.Create(year);
await b.FinishSeason(); await b.FinishSeason();
await b.CalculateBuckets(); await b.CalculateBuckets();
App.HintContextChange(); App.HintContextChange();
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
var tbl = await MemberAreaComsData.ForSeason(ctx.MemberAreaComsRows, year); var tbl = await MemberAreaComsData.ForSeason(ctx.MemberAreaComsRows, year);
using var ods = new OdsFile(d.FileName); using var ods = new OdsFile(filename);
await ods.AddTable(tbl); await ods.AddTable(tbl);
} catch (Exception exc) { } catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException(exc);
} }
}); });
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
@@ -556,29 +533,24 @@ namespace Elwig.Windows {
private async void BreakdownMemberVarietyButton_Click(object sender, RoutedEventArgs evt) { private async void BreakdownMemberVarietyButton_Click(object sender, RoutedEventArgs evt) {
if (SeasonInput.Value is not int year) if (SeasonInput.Value is not int year)
return; return;
var d = new SaveFileDialog() { var filename = InteractionService.SaveFile($"Liefermengen/Ertrag {year}", $"Liefermengen-Ertrag-{year}", "ods");
FileName = $"Liefermengen-Ertrag-{year}.ods", if (filename == null)
DefaultExt = "ods",
Filter = "OpenDocument Format Spreadsheet (*.ods)|*.ods",
Title = $"Liefermengen/Ertrag {year} speichern unter - Elwig"
};
if (d.ShowDialog() == false)
return; return;
Mouse.OverrideCursor = Cursors.Wait; Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => { await Task.Run(async () => {
try { try {
var b = new Billing(year); var b = await Billing.Create(year);
await b.FinishSeason(); await b.FinishSeason();
await b.CalculateBuckets(); await b.CalculateBuckets();
App.HintContextChange(); App.HintContextChange();
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
var tbl = await MemberDeliveryYieldsPerVarietyData.ForSeason(ctx.MemberDeliveryPerVariantRows, year); var tbl = await MemberDeliveryYieldsPerVarietyData.ForSeason(ctx.MemberDeliveryPerVariantRows, year);
using var ods = new OdsFile(d.FileName); using var ods = new OdsFile(filename);
await ods.AddTable(tbl); await ods.AddTable(tbl);
} catch (Exception exc) { } catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException(exc);
} }
}); });
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
+23 -17
View File
@@ -5,8 +5,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Elwig.Windows" xmlns:local="clr-namespace:Elwig.Windows"
xmlns:vm="clr-namespace:Elwig.ViewModels" xmlns:vm="clr-namespace:Elwig.ViewModels"
Title="Mitglieder - Elwig" Height="700" Width="1250" MinHeight="650" MinWidth="1150" Title="Mitglieder - Elwig" Height="700" Width="1250" MinHeight="650" MinWidth="1150">
Loaded="Window_Loaded">
<Window.DataContext> <Window.DataContext>
<vm:MemberAdminViewModel/> <vm:MemberAdminViewModel/>
</Window.DataContext> </Window.DataContext>
@@ -234,7 +233,7 @@
</DataGridTextColumn> </DataGridTextColumn>
<DataGridTextColumn Header="Nachname" Binding="{Binding Name}" Width="140"/> <DataGridTextColumn Header="Nachname" Binding="{Binding Name}" Width="140"/>
<DataGridTextColumn Header="Vorname" Binding="{Binding GivenName}" Width="140"/> <DataGridTextColumn Header="Vorname" Binding="{Binding GivenName}" Width="140"/>
<DataGridTextColumn Header="GA" Binding="{Binding BusinessShares, StringFormat='{}{0} '}" Width="40"> <DataGridTextColumn Header="GA" Binding="{Binding SharesActive, StringFormat='{}{0} '}" Width="40">
<DataGridTextColumn.CellStyle> <DataGridTextColumn.CellStyle>
<Style> <Style>
<Setter Property="TextBlock.TextAlignment" Value="Right"/> <Setter Property="TextBlock.TextAlignment" Value="Right"/>
@@ -620,16 +619,27 @@
Margin="0,40,10,0" Width="78" Grid.Column="1" HorizontalAlignment="Left" TextAlignment="Right" Margin="0,40,10,0" Width="78" Grid.Column="1" HorizontalAlignment="Left" TextAlignment="Right"
TextChanged="DateInput_TextChanged" LostFocus="DateInput_LostFocus"/> TextChanged="DateInput_TextChanged" LostFocus="DateInput_LostFocus"/>
<Label Content="Geschäftsanteile:" Margin="10,70,0,0" Grid.Column="0"/> <Label Content="BH-Konto:" Margin="10,70,0,0" Grid.Column="0"/>
<TextBox x:Name="BusinessSharesInput" Text="{Binding BusinessSharesString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,70,10,0" Width="48" Grid.Column="1" HorizontalAlignment="Left" TextAlignment="Right"
TextChanged="IntegerInput_TextChanged"/>
<Label Content="BH-Konto:" Margin="10,100,0,0" Grid.Column="0"/>
<TextBox x:Name="AccountingNrInput" Text="{Binding AccountingNr, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" <TextBox x:Name="AccountingNrInput" Text="{Binding AccountingNr, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,100,10,0" Grid.Column="1" Margin="0,70,10,0" Width="63" Grid.Column="1" HorizontalAlignment="Left"
TextChanged="TextBox_TextChanged"/> TextChanged="TextBox_TextChanged"/>
<Label Content="Geschäftsanteile:" Margin="10,95,0,0" Grid.Column="0"/>
<Label x:Name="BusinessSharesLabel" Content="(rot/weiß/ruhend)" Margin="10,108,0,0" Grid.Column="0" FontSize="10"/>
<TextBox x:Name="BusinessShares1Input" Text="{Binding BusinessShares1String, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,100,10,0" Width="32" Grid.Column="1" Grid.ColumnSpan="2" HorizontalAlignment="Left" TextAlignment="Right"
TextChanged="IntegerInput_TextChanged"/>
<TextBox x:Name="BusinessShares2Input" Text="{Binding BusinessShares2String, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="37,100,10,0" Width="32" Grid.Column="1" Grid.ColumnSpan="2" HorizontalAlignment="Left" TextAlignment="Right"
TextChanged="IntegerInput_TextChanged"/>
<TextBox x:Name="BusinessShares3Input" Text="{Binding BusinessShares3String, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="74,100,10,0" Width="32" Grid.Column="1" Grid.ColumnSpan="2" HorizontalAlignment="Left" TextAlignment="Right"
TextChanged="IntegerInput_TextChanged"/>
<Button x:Name="BusinessSharesButton" FontFamily="Segoe MDL2 Assets" Content="&#xEB05;" FontSize="16" Padding="0.5,0,0,0" IsEnabled="{Binding IsMemberSelected}"
Margin="111,100,10,0" Width="25" Height="25" Grid.Column="1" Grid.ColumnSpan="2" HorizontalAlignment="Left" VerticalAlignment="Top"
ToolTip="Geschäftsanteile bearbeiten"
Click="BusinessSharesButton_Click"/>
<CheckBox x:Name="ActiveInput" Content="Aktiv" IsChecked="{Binding IsActive, Mode=TwoWay}" IsEnabled="False" <CheckBox x:Name="ActiveInput" Content="Aktiv" IsChecked="{Binding IsActive, Mode=TwoWay}" IsEnabled="False"
Checked="ActiveInput_Changed" Unchecked="ActiveInput_Changed" Checked="ActiveInput_Changed" Unchecked="ActiveInput_Changed"
Grid.Column="2" HorizontalAlignment="Left" Margin="10,15,0,0" VerticalAlignment="Top"/> Grid.Column="2" HorizontalAlignment="Left" Margin="10,15,0,0" VerticalAlignment="Top"/>
@@ -657,7 +667,7 @@
<Label Content="Anmerkung:" Margin="10,190,0,0" Grid.Column="0"/> <Label Content="Anmerkung:" Margin="10,190,0,0" Grid.Column="0"/>
<TextBox x:Name="CommentInput" Text="{Binding Comment, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" <TextBox x:Name="CommentInput" Text="{Binding Comment, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,190,10,70" Grid.Column="1" Grid.ColumnSpan="2" Margin="0,190,10,70" Grid.Column="1" Grid.ColumnSpan="2" FontSize="12"
TextChanged="TextBox_TextChanged" TextChanged="TextBox_TextChanged"
VerticalAlignment="Stretch" Height="auto" AcceptsReturn="True" TextWrapping="Wrap" VerticalScrollBarVisibility="Visible"/> VerticalAlignment="Stretch" Height="auto" AcceptsReturn="True" TextWrapping="Wrap" VerticalScrollBarVisibility="Visible"/>
@@ -713,7 +723,7 @@
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="150"/> <ColumnDefinition Width="150"/>
<ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="200"/> <ColumnDefinition Width="1*"/>
<ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="1*"/> <ColumnDefinition Width="1*"/>
<ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/>
@@ -730,11 +740,7 @@
</TextBlock> </TextBlock>
</StatusBarItem> </StatusBarItem>
<Separator Grid.Column="1"/> <Separator Grid.Column="1"/>
<StatusBarItem Grid.Column="2"> <StatusBarItem Grid.Column="2" Content="{Binding StatusBusinessShares}"/>
<TextBlock ToolTip="{Binding StatusBusinessSharesToolTip}">
Geschäftsanteile: <Run Text="{Binding StatusBusinessShares}"/>
</TextBlock>
</StatusBarItem>
<Separator Grid.Column="3"/> <Separator Grid.Column="3"/>
<StatusBarItem Grid.Column="4"> <StatusBarItem Grid.Column="4">
<TextBlock ToolTip="{Binding StatusAreaCommitmentToolTip}"> <TextBlock ToolTip="{Binding StatusAreaCommitmentToolTip}">
+209 -74
View File
@@ -1,18 +1,21 @@
using Microsoft.EntityFrameworkCore; using Elwig.Dialogs;
using System; using Elwig.Documents;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Elwig.Helpers; using Elwig.Helpers;
using Elwig.Models.Entities; using Elwig.Models.Entities;
using System.Threading.Tasks;
using Elwig.Documents;
using System.Diagnostics;
using Elwig.Dialogs;
using Elwig.Services; using Elwig.Services;
using Elwig.ViewModels; using Elwig.ViewModels;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data; using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
namespace Elwig.Windows { namespace Elwig.Windows {
public partial class MemberAdminWindow : AdministrationWindow { public partial class MemberAdminWindow : AdministrationWindow {
@@ -37,13 +40,20 @@ namespace Elwig.Windows {
CommandBindings.Add(new CommandBinding(CtrlO, Menu_List_ShowActive_Click)); CommandBindings.Add(new CommandBinding(CtrlO, Menu_List_ShowActive_Click));
CommandBindings.Add(new CommandBinding(CtrlShiftP, Menu_MemberDataSheet_Print_Click)); CommandBindings.Add(new CommandBinding(CtrlShiftP, Menu_MemberDataSheet_Print_Click));
CommandBindings.Add(new CommandBinding(CtrlShiftO, Menu_List_PrintActive_Click)); CommandBindings.Add(new CommandBinding(CtrlShiftO, Menu_List_PrintActive_Click));
ExemptInputs = [ List<Control> exempt = [
SearchInput, ActiveMemberInput, MemberList, SearchInput, ActiveMemberInput, MemberList,
]; ];
if (App.Client.EnableMemberHistory) {
exempt.AddRange([BusinessShares1Input, BusinessShares2Input, BusinessShares3Input]);
BusinessShares1Input.IsReadOnly = true;
BusinessShares2Input.IsReadOnly = true;
BusinessShares3Input.IsReadOnly = true;
}
ExemptInputs = [.. exempt];
RequiredInputs = [ RequiredInputs = [
MgNrInput, GivenNameInput, NameInput, MgNrInput, GivenNameInput, NameInput,
AddressInput, PlzInput, OrtInput, BillingOrtInput, AddressInput, PlzInput, OrtInput, BillingOrtInput,
BusinessSharesInput, BranchInput, DefaultKgInput BusinessShares1Input, BusinessShares2Input, BusinessShares3Input, BranchInput, DefaultKgInput
]; ];
EmailAddressInputs = [ EmailAddressInputs = [
(EmailAddress1Label, EmailAddress1Input), (EmailAddress1Label, EmailAddress1Input),
@@ -82,12 +92,32 @@ namespace Elwig.Windows {
Menu_Export_UploadFilters.IsEnabled = App.Config.SyncUrl != null; Menu_Export_UploadFilters.IsEnabled = App.Config.SyncUrl != null;
Menu_Export_UploadAll.IsEnabled = App.Config.SyncUrl != null; Menu_Export_UploadAll.IsEnabled = App.Config.SyncUrl != null;
ViewModel.ShowOnlyActiveMembers = true;
if (App.Client.HasRedWhite) {
BusinessSharesLabel.Content = "(rot/weiß/ruhend)";
//BusinessShares1Input.Background = Brushes.MistyRose;
BusinessShares1Input.Foreground = Brushes.DarkRed;
BusinessShares1Input.ToolTip = "Geschäftsanteile (rot)";
//BusinessShares2Input.Background = Brushes.MintCream;
BusinessShares2Input.Foreground = Brushes.DarkGreen;
BusinessShares2Input.ToolTip = "Geschäftsanteile (weiß)";
BusinessShares3Input.Background = Brushes.WhiteSmoke;
BusinessShares3Input.ToolTip = "Geschäftsanteile (ruhend)";
} else {
BusinessSharesLabel.Content = "(normal/ruhend)";
BusinessShares1Input.ToolTip = "Geschäftsanteile (normal)";
BusinessShares2Input.Background = Brushes.WhiteSmoke;
BusinessShares2Input.ToolTip = "Geschäftsanteile (ruhend)";
BusinessShares3Input.Visibility = Visibility.Hidden;
BusinessSharesButton.Margin = new(74, 100, 10, 0);
}
if (!App.Client.EnableMemberHistory) {
BusinessSharesButton.Visibility = Visibility.Hidden;
} }
private void Window_Loaded(object sender, RoutedEventArgs evt) {
ViewModel.ShowOnlyActiveMembers = true;
UpdateContactInfoVisibility(); UpdateContactInfoVisibility();
LockInputs();
} }
public void FocusMember(int mgnr) { public void FocusMember(int mgnr) {
@@ -113,17 +143,17 @@ namespace Elwig.Windows {
} }
private async Task RefreshList(bool updateSort = false) { private async Task RefreshList(bool updateSort = false) {
var vm = ViewModel;
var cursor = Mouse.OverrideCursor != null;
if (!cursor) Mouse.OverrideCursor = Cursors.Wait;
var query = (vm.SearchQuery, vm.ShowOnlyActiveMembers);
var (members, stat) = await Task.Run(async () => {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
var (_, memberQuery, filter) = await ViewModel.GetFilters(ctx); var (_, memberQuery, filter) = await vm.GetFilters(ctx);
var members = await memberQuery var members = await memberQuery
.Include(m => m.Branch)
.Include(m => m.DefaultWbKg!.AtKg)
.Include(m => m.EmailAddresses) .Include(m => m.EmailAddresses)
.Include(m => m.TelephoneNumbers) .Include(m => m.TelephoneNumbers)
.Include(m => m.PostalDest.AtPlz!.Ort) .AsSplitQuery()
.Include(m => m.PostalDest.AtPlz!.Country)
.Include(m => m.BillingAddress!.PostalDest.AtPlz!.Ort)
.Include(m => m.BillingAddress!.PostalDest.AtPlz!.Country)
.ToListAsync(); .ToListAsync();
if (filter.Count > 0 && members.Count > 0) { if (filter.Count > 0 && members.Count > 0) {
@@ -134,25 +164,67 @@ namespace Elwig.Windows {
.ThenBy(a => a.Key.GivenName) .ThenBy(a => a.Key.GivenName)
.ThenBy(a => a.Key.MgNr); .ThenBy(a => a.Key.MgNr);
var threshold = dict.Select(a => a.Value).Max() * 3 / 4; var threshold = dict.Select(a => a.Value).Max() * 3 / 4;
members = dict members = [.. dict
.Where(a => a.Value > threshold) .Where(a => a.Value > threshold)
.Select(a => a.Key) .Select(a => a.Key)];
.ToList();
} else { } else {
members = members members = [.. members
.OrderBy(m => m.Name) .OrderBy(m => m.Name)
.ThenBy(m => m.GivenName) .ThenBy(m => m.GivenName)
.ThenBy(m => m.MgNr) .ThenBy(m => m.MgNr)];
.ToList();
} }
var stat = (await ctx.Members.GroupBy(m => 1).Select(g => new {
Count = g.Count(),
Shares = g.Sum(m => m.Shares),
SharesRed = g.Sum(m => m.SharesRed),
SharesWhite = g.Sum(m => m.SharesWhite),
SharesDormant = g.Sum(m => m.SharesDormant),
SharesTotal = g.Sum(m => m.Shares + m.SharesRed + m.SharesWhite + m.SharesDormant),
SharesActive = g.Sum(m => m.Shares + m.SharesRed + m.SharesWhite),
}).ToListAsync()).Select(g => (g.Count, g.Shares, g.SharesRed, g.SharesWhite, g.SharesDormant, g.SharesTotal, g.SharesActive)).ToList();
return (members, stat[0]);
});
if (!cursor) Mouse.OverrideCursor = null;
if (query != (ViewModel.SearchQuery, ViewModel.ShowOnlyActiveMembers)) return;
ControlUtils.RenewItemsSource(MemberList, members, ControlUtils.RenewItemsSource(MemberList, members,
MemberList_SelectionChanged, ViewModel.TextFilter.Count > 0 ? ControlUtils.RenewSourceDefault.IfOnly : ControlUtils.RenewSourceDefault.None, !updateSort); MemberList_SelectionChanged, ViewModel.TextFilter.Count > 0 ? ControlUtils.RenewSourceDefault.IfOnly : ControlUtils.RenewSourceDefault.None, !updateSort);
if (updateSort && MemberList.SelectedItem != null) if (updateSort && MemberList.SelectedItem != null)
MemberList.ScrollIntoView(MemberList.SelectedItem); MemberList.ScrollIntoView(MemberList.SelectedItem);
ViewModel.StatusMembers = $"{members.Count:N0} ({await ctx.Members.CountAsync():N0})"; ViewModel.StatusMembers = $"{members.Count:N0} ({stat.Count:N0})";
ViewModel.StatusBusinessShares = $"{members.Sum(m => m.BusinessShares):N0} ({await ctx.Members.SumAsync(m => m.BusinessShares):N0})";
var sA = members.Sum(m => m.Shares);
var rA = members.Sum(m => m.SharesRed);
var wA = members.Sum(m => m.SharesWhite);
var dA = members.Sum(m => m.SharesDormant);
List<(int Count, Brush? Color)> a = [];
if (sA > 0) a.Add((sA, null));
if (rA > 0) a.Add((rA, Brushes.DarkRed));
if (wA > 0) a.Add((wA, Brushes.DarkGreen));
if (a.Count == 0) a.Add((0, null));
List<(int Count, Brush? Color)> b = [];
if (stat.Shares > 0) b.Add((stat.Shares, null));
if (stat.SharesRed > 0) b.Add((stat.SharesRed, Brushes.DarkRed));
if (stat.SharesWhite > 0) b.Add((stat.SharesWhite, Brushes.DarkGreen));
if (a.Count == 0) b.Add((0, null));
Run[] inlines = [
new("Geschäftsanteile: "),
.. a.Select(i => new Run($"{i.Count:N0}") { Foreground = i.Color ?? Brushes.Black }).Join(() => new("+")),
new(" ("),
.. b.Select(i => new Run($"{i.Count:N0}") { Foreground = i.Color ?? Brushes.Black }).Join(() => new("+")),
new(")")
];
if (ViewModel.StatusBusinessShares == null) {
ViewModel.StatusBusinessShares = new();
} else {
ViewModel.StatusBusinessShares.Inlines.Clear();
}
ViewModel.StatusBusinessShares.Inlines.AddRange(inlines);
} }
private void RefreshInputs(bool validate = false) { private void RefreshInputs(bool validate = false) {
@@ -176,6 +248,17 @@ namespace Elwig.Windows {
ClearOriginalValues(); ClearOriginalValues();
ClearDefaultValues(); ClearDefaultValues();
await ViewModel.InitInputs(); await ViewModel.InitInputs();
if (App.Client.EnableMemberHistory) {
BusinessShares1Input.Text = "0";
BusinessShares2Input.Text = "0";
BusinessShares3Input.Text = "0";
} else if (App.Client.HasRedWhite) {
BusinessShares3Input.Text = "0";
SetDefaultValue(BusinessShares3Input);
} else {
BusinessShares2Input.Text = "0";
SetDefaultValue(BusinessShares2Input);
}
SetDefaultValue(MgNrInput); SetDefaultValue(MgNrInput);
SetDefaultValue(EntryDateInput); SetDefaultValue(EntryDateInput);
SetDefaultValue(ActiveInput); SetDefaultValue(ActiveInput);
@@ -184,12 +267,12 @@ namespace Elwig.Windows {
protected override async Task OnRenewContext(AppDbContext ctx) { protected override async Task OnRenewContext(AppDbContext ctx) {
await base.OnRenewContext(ctx); await base.OnRenewContext(ctx);
ControlUtils.RenewItemsSource(BranchInput, await ctx.Branches.OrderBy(b => b.Name).ToListAsync()); ControlUtils.RenewItemsSource(BranchInput, await ctx.FetchBranches().ToListAsync());
ControlUtils.RenewItemsSource(DefaultKgInput, await ctx.WbKgs.Select(k => k.AtKg).OrderBy(k => k.Name).ToListAsync()); ControlUtils.RenewItemsSource(DefaultKgInput, await ctx.WbKgs.Select(k => k.AtKg).OrderBy(k => k.Name).ToListAsync());
var font = new System.Windows.Media.FontFamily("Segoe MDL2 Assets"); var font = new FontFamily("Segoe MDL2 Assets");
MenuItem? temp = null; MenuItem? temp = null;
var seasons = await ctx.Seasons.OrderByDescending(s => s.Year).ToListAsync(); var seasons = await ctx.Seasons.Include(s => s.PaymentVariants).OrderByDescending(s => s.Year).ToListAsync();
Menu_DeliveryConfirmation.Items.Clear(); Menu_DeliveryConfirmation.Items.Clear();
foreach (var s in seasons) { foreach (var s in seasons) {
var i = new MenuItem { var i = new MenuItem {
@@ -264,10 +347,21 @@ namespace Elwig.Windows {
await RefreshList(); await RefreshList();
var stat = await ctx.Members.GroupBy(m => m.IsActive).Select(g => new {
IsActive = g.Key,
Count = g.Count(),
Shares = g.Sum(m => m.Shares),
SharesRed = g.Sum(m => m.SharesRed),
SharesWhite = g.Sum(m => m.SharesWhite),
SharesDormant = g.Sum(m => m.SharesDormant),
SharesTotal = g.Sum(m => m.Shares + m.SharesRed + m.SharesWhite + m.SharesDormant),
SharesActive = g.Sum(m => m.Shares + m.SharesRed + m.SharesWhite),
}).ToDictionaryAsync(g => g.IsActive);
var (s1, s2) = ('\u2007', '\u202f'); var (s1, s2) = ('\u2007', '\u202f');
var mA = $"{await ctx.Members.CountAsync(m => m.IsActive):N0}"; var mA = $"{stat.GetValueOrDefault(true)?.Count ?? 0:N0}";
var mI = $"{await ctx.Members.CountAsync(m => !m.IsActive):N0}"; var mI = $"{stat.GetValueOrDefault(false)?.Count ?? 0:N0}";
var mT = $"{await ctx.Members.CountAsync():N0}"; var mT = $"{stat.Sum(g => g.Value.Count):N0}";
var mM = Math.Max(mA.Length, Math.Max(mI.Length, mT.Length)); var mM = Math.Max(mA.Length, Math.Max(mI.Length, mT.Length));
var mS = mM > 3; var mS = mM > 3;
if (mS) mM--; if (mS) mM--;
@@ -276,16 +370,53 @@ namespace Elwig.Windows {
$"{new string(s1, Math.Max(0, mM - mI.Length))}{(mS && mI.Length < 4 ? s2 : "")}{mI} nicht aktive Mitglieder\n" + $"{new string(s1, Math.Max(0, mM - mI.Length))}{(mS && mI.Length < 4 ? s2 : "")}{mI} nicht aktive Mitglieder\n" +
$"{new string(s1, Math.Max(0, mM - mT.Length))}{(mS && mT.Length < 4 ? s2 : "")}{mT} Mitglieder gesamt"; $"{new string(s1, Math.Max(0, mM - mT.Length))}{(mS && mT.Length < 4 ? s2 : "")}{mT} Mitglieder gesamt";
var bA = $"{await ctx.Members.Where(m => m.IsActive).SumAsync(m => m.BusinessShares):N0}"; var grid = new Grid();
var bI = $"{await ctx.Members.Where(m => !m.IsActive).SumAsync(m => m.BusinessShares):N0}"; grid.ColumnDefinitions.Add(new() { Width = new(100) });
var bT = $"{await ctx.Members.SumAsync(m => m.BusinessShares):N0}"; grid.AddToolTipCell("Geschäftsanteile:", 0, 0, bold: true);
var bM = Math.Max(bA.Length, Math.Max(bI.Length, bT.Length)); grid.AddToolTipCell("Aktive Mitglieder", 1, 0);
var bS = bM > 3; grid.AddToolTipCell("Nicht aktive Mg.", 2, 0);
if (bS) bM--; grid.AddToolTipCell("Alle Mitglieder", 3, 0, bold: true);
ViewModel.StatusBusinessSharesToolTip = if (App.Client.HasRedWhite) {
$"{new string(s1, Math.Max(0, bM - bA.Length))}{(bS && bA.Length < 4 ? s2 : "")}{bA} Geschäftsanteile von aktiven Mitgliedern\n" + grid.ColumnDefinitions.Add(new() { Width = new(50) });
$"{new string(s1, Math.Max(0, bM - bI.Length))}{(bS && bI.Length < 4 ? s2 : "")}{bI} Geschäftsanteile von nicht aktiven Mitgliedern\n" + grid.ColumnDefinitions.Add(new() { Width = new(50) });
$"{new string(s1, Math.Max(0, bM - bT.Length))}{(bS && bT.Length < 4 ? s2 : "")}{bT} Geschäftsanteile gesamt"; grid.ColumnDefinitions.Add(new() { Width = new(50) });
grid.ColumnDefinitions.Add(new() { Width = new(50) });
grid.AddToolTipCell("rot", 0, 1, alignRight: true);
grid.AddToolTipCell("weiß", 0, 2, alignRight: true);
grid.AddToolTipCell("ruhend", 0, 3, alignRight: true);
grid.AddToolTipCell("gesamt", 0, 4, alignRight: true);
grid.AddToolTipCell($"{stat.GetValueOrDefault(true)?.SharesRed ?? 0:N0}", 1, 1, alignRight: true);
grid.AddToolTipCell($"{stat.GetValueOrDefault(true)?.SharesWhite ?? 0:N0}", 1, 2, alignRight: true);
grid.AddToolTipCell($"{stat.GetValueOrDefault(true)?.SharesDormant ?? 0:N0}", 1, 3, alignRight: true);
grid.AddToolTipCell($"{stat.GetValueOrDefault(true)?.SharesTotal ?? 0:N0}", 1, 4, alignRight: true);
grid.AddToolTipCell($"{stat.GetValueOrDefault(false)?.SharesRed ?? 0:N0}", 2, 1, alignRight: true);
grid.AddToolTipCell($"{stat.GetValueOrDefault(false)?.SharesWhite ?? 0:N0}", 2, 2, alignRight: true);
grid.AddToolTipCell($"{stat.GetValueOrDefault(false)?.SharesDormant ?? 0:N0}", 2, 3, alignRight: true);
grid.AddToolTipCell($"{stat.GetValueOrDefault(false)?.SharesTotal ?? 0:N0}", 2, 4, alignRight: true);
grid.AddToolTipCell($"{stat.Sum(g => g.Value.SharesRed):N0}", 3, 1, alignRight: true, bold: true);
grid.AddToolTipCell($"{stat.Sum(g => g.Value.SharesWhite):N0}", 3, 2, alignRight: true, bold: true);
grid.AddToolTipCell($"{stat.Sum(g => g.Value.SharesDormant):N0}", 3, 3, alignRight: true, bold: true);
grid.AddToolTipCell($"{stat.Sum(g => g.Value.SharesTotal):N0}", 3, 4, alignRight: true, bold: true);
} else {
grid.ColumnDefinitions.Add(new() { Width = new(50) });
grid.ColumnDefinitions.Add(new() { Width = new(50) });
grid.ColumnDefinitions.Add(new() { Width = new(50) });
grid.AddToolTipCell("normal", 0, 1, alignRight: true);
grid.AddToolTipCell("ruhend", 0, 2, alignRight: true);
grid.AddToolTipCell("gesamt", 0, 3, alignRight: true);
grid.AddToolTipCell($"{stat.GetValueOrDefault(true)?.Shares ?? 0:N0}", 1, 1, alignRight: true);
grid.AddToolTipCell($"{stat.GetValueOrDefault(true)?.SharesDormant ?? 0:N0}", 1, 2, alignRight: true);
grid.AddToolTipCell($"{stat.GetValueOrDefault(true)?.SharesTotal ?? 0:N0}", 1, 3, alignRight: true);
grid.AddToolTipCell($"{stat.GetValueOrDefault(false)?.Shares ?? 0:N0}", 2, 1, alignRight: true);
grid.AddToolTipCell($"{stat.GetValueOrDefault(false)?.SharesDormant ?? 0:N0}", 2, 2, alignRight: true);
grid.AddToolTipCell($"{stat.GetValueOrDefault(false)?.SharesTotal ?? 0:N0}", 2, 3, alignRight: true);
grid.AddToolTipCell($"{stat.Sum(g => g.Value.Shares):N0}", 3, 1, alignRight: true, bold: true);
grid.AddToolTipCell($"{stat.Sum(g => g.Value.SharesDormant):N0}", 3, 2, alignRight: true, bold: true);
grid.AddToolTipCell($"{stat.Sum(g => g.Value.SharesTotal):N0}", 3, 3, alignRight: true, bold: true);
}
ViewModel.StatusBusinessShares?.ToolTip = grid;
} }
private void SetPhoneNrInputVisible(int nr, bool visible, int? position = null) { private void SetPhoneNrInputVisible(int nr, bool visible, int? position = null) {
@@ -328,6 +459,7 @@ namespace Elwig.Windows {
} }
private async void ActiveMemberInput_Changed(object sender, RoutedEventArgs evt) { private async void ActiveMemberInput_Changed(object sender, RoutedEventArgs evt) {
if (!HasContextLoaded) return;
await RefreshList(); await RefreshList();
} }
@@ -384,10 +516,9 @@ namespace Elwig.Windows {
int areaComs = 0, deliveries = 0, credits = 0; int areaComs = 0, deliveries = 0, credits = 0;
using (var ctx = new AppDbContext()) { using (var ctx = new AppDbContext()) {
var l = (await ctx.Members.FindAsync(m.MgNr))!; areaComs = await ctx.AreaCommitments.Where(c => c.MgNr == m.MgNr).CountAsync();
areaComs = l.AreaCommitments.Count; deliveries = await ctx.Deliveries.Where(d => d.MgNr == m.MgNr).CountAsync();
deliveries = l.Deliveries.Count; credits = await ctx.Credits.Where(c => c.MgNr == m.MgNr).CountAsync();
credits = l.Credits.Count;
} }
var d = new DeleteMemberDialog(m.MgNr, m.AdministrativeName, areaComs, deliveries, credits); var d = new DeleteMemberDialog(m.MgNr, m.AdministrativeName, areaComs, deliveries, credits);
if (d.ShowDialog() == true) { if (d.ShowDialog() == true) {
@@ -396,9 +527,7 @@ namespace Elwig.Windows {
await MemberService.DeleteMember(m.MgNr, d.DeletePaymentData, d.DeleteDeliveries, d.DeleteAreaComs); await MemberService.DeleteMember(m.MgNr, d.DeletePaymentData, d.DeleteDeliveries, d.DeleteAreaComs);
App.HintContextChange(); App.HintContextChange();
} catch (Exception exc) { } catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message; InteractionService.ShowDbException("Mitglied löschen", exc);
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Mitglied löschen", MessageBoxButton.OK, MessageBoxImage.Error);
} }
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
} }
@@ -419,9 +548,7 @@ namespace Elwig.Windows {
mgnr = await ViewModel.UpdateMember(ViewModel.SelectedMember?.MgNr); mgnr = await ViewModel.UpdateMember(ViewModel.SelectedMember?.MgNr);
App.HintContextChange(); App.HintContextChange();
} catch (Exception exc) { } catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message; InteractionService.ShowDbException("Mitglied aktualisieren", exc);
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Mitglied aktualisieren", MessageBoxButton.OK, MessageBoxImage.Error);
SaveButton.IsEnabled = true; SaveButton.IsEnabled = true;
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
return; return;
@@ -475,6 +602,10 @@ namespace Elwig.Windows {
ViewModel.EnableSearchInputs = true; ViewModel.EnableSearchInputs = true;
} }
private void BusinessSharesButton_Click(object sender, RoutedEventArgs evt) {
App.FocusMemberBusinessSharesWindow(ViewModel.SelectedMember!.MgNr);
}
private void AreaCommitmentButton_Click(object sender, RoutedEventArgs evt) { private void AreaCommitmentButton_Click(object sender, RoutedEventArgs evt) {
App.FocusMemberAreaComs(ViewModel.SelectedMember!.MgNr); App.FocusMemberAreaComs(ViewModel.SelectedMember!.MgNr);
} }
@@ -484,6 +615,7 @@ namespace Elwig.Windows {
} }
private async void SearchInput_TextChanged(object sender, RoutedEventArgs evt) { private async void SearchInput_TextChanged(object sender, RoutedEventArgs evt) {
if (!HasContextLoaded) return;
await RefreshList(true); await RefreshList(true);
} }
@@ -498,7 +630,9 @@ namespace Elwig.Windows {
try { try {
await Task.Run(async () => { await Task.Run(async () => {
using var doc = new Letterhead(m); using var doc = new Letterhead(m);
await doc.Generate(); using (var ctx = new AppDbContext()) {
await doc.Generate(ctx);
}
if (!App.Config.Debug) { if (!App.Config.Debug) {
await doc.Print(); await doc.Print();
} else { } else {
@@ -506,7 +640,7 @@ namespace Elwig.Windows {
} }
}); });
} catch (Exception exc) { } catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException(exc);
} }
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
} }
@@ -528,9 +662,7 @@ namespace Elwig.Windows {
private async void Menu_MemberDataSheet_Email_Click(object sender, RoutedEventArgs evt) { private async void Menu_MemberDataSheet_Email_Click(object sender, RoutedEventArgs evt) {
if (ViewModel.SelectedMember is not Member m) return; if (ViewModel.SelectedMember is not Member m) return;
var res = MessageBox.Show("Soll eine E-Mail verschickt werden?", "Stammdatenblatt verschicken", if (!InteractionService.AskQuestion("Stammdatenblatt verschicken", "Soll eine E-Mail verschickt werden?", true))
MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.Yes);
if (res != MessageBoxResult.Yes)
return; return;
await MemberService.GenerateMemberDataSheet(m, ExportMode.Email); await MemberService.GenerateMemberDataSheet(m, ExportMode.Email);
} }
@@ -560,9 +692,7 @@ namespace Elwig.Windows {
var year = (int?)((sender as MenuItem)?.Parent as MenuItem)?.Tag; var year = (int?)((sender as MenuItem)?.Parent as MenuItem)?.Tag;
if (ViewModel.SelectedMember is not Member m || year == null) if (ViewModel.SelectedMember is not Member m || year == null)
return; return;
var res = MessageBox.Show("Soll eine E-Mail verschickt werden?", "Anlieferungsbestätigung verschicken", if (!InteractionService.AskQuestion("Anlieferungsbestätigung verschicken", "Soll eine E-Mail verschickt werden?", true))
MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.Yes);
if (res != MessageBoxResult.Yes)
return; return;
await MemberService.GenerateDeliveryConfirmation(m, (int)year, ExportMode.Email); await MemberService.GenerateDeliveryConfirmation(m, (int)year, ExportMode.Email);
} }
@@ -596,9 +726,7 @@ namespace Elwig.Windows {
var avnr = (int?)((sender as MenuItem)?.Parent as MenuItem)?.Tag; var avnr = (int?)((sender as MenuItem)?.Parent as MenuItem)?.Tag;
if (ViewModel.SelectedMember is not Member m || year == null || avnr == null) if (ViewModel.SelectedMember is not Member m || year == null || avnr == null)
return; return;
var res = MessageBox.Show("Soll eine E-Mail verschickt werden?", "Traubengutschrift verschicken", if (!InteractionService.AskQuestion("Traubengutschrift verschicken", "Soll eine E-Mail verschickt werden?", true))
MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.Yes);
if (res != MessageBoxResult.Yes)
return; return;
await MemberService.GenerateCreditNote(m, (int)year, (int)avnr, ExportMode.Email); await MemberService.GenerateCreditNote(m, (int)year, (int)avnr, ExportMode.Email);
} }
@@ -720,7 +848,7 @@ namespace Elwig.Windows {
lastVisible = true; lastVisible = true;
for (int i = 0; i < EmailAddressInputs.Length; i++) { for (int i = 0; i < EmailAddressInputs.Length; i++) {
var input = EmailAddressInputs[i]; var input = EmailAddressInputs[i];
var vis = !string.IsNullOrEmpty(input.Address.Text) || (m?.EmailAddresses.Any(a => a.Nr - 1 == i) ?? false); var vis = !string.IsNullOrWhiteSpace(input.Address.Text) || (m?.EmailAddresses.Any(a => a.Nr - 1 == i) ?? false);
var cVis = vis || (extra && lastVisible); var cVis = vis || (extra && lastVisible);
SetEmailAddressInputVisible(i, cVis, cVis ? num++ : null); SetEmailAddressInputVisible(i, cVis, cVis ? num++ : null);
lastVisible = vis; lastVisible = vis;
@@ -728,7 +856,7 @@ namespace Elwig.Windows {
lastVisible = true; lastVisible = true;
for (int i = 0; i < PhoneNrInputs.Length; i++) { for (int i = 0; i < PhoneNrInputs.Length; i++) {
var input = PhoneNrInputs[i]; var input = PhoneNrInputs[i];
var vis = !string.IsNullOrEmpty(input.Number.Text) || (m?.TelephoneNumbers.Any(n => n.Nr - 1 == i) ?? false); var vis = !string.IsNullOrWhiteSpace(input.Number.Text) || (m?.TelephoneNumbers.Any(n => n.Nr - 1 == i) ?? false);
var cVis = vis || (extra && lastVisible); var cVis = vis || (extra && lastVisible);
SetPhoneNrInputVisible(i, cVis, cVis ? num++ : null); SetPhoneNrInputVisible(i, cVis, cVis ? num++ : null);
lastVisible = vis; lastVisible = vis;
@@ -745,6 +873,14 @@ namespace Elwig.Windows {
new protected void ClearInputs(bool validate = false) { new protected void ClearInputs(bool validate = false) {
ViewModel.ClearInputs(); ViewModel.ClearInputs();
if (App.Client.EnableMemberHistory) {
BusinessShares1Input.Text = "";
BusinessShares2Input.Text = "";
BusinessShares3Input.Text = "";
ControlUtils.ClearInputState(BusinessShares1Input);
ControlUtils.ClearInputState(BusinessShares2Input);
ControlUtils.ClearInputState(BusinessShares3Input);
}
base.ClearInputs(validate); base.ClearInputs(validate);
} }
@@ -787,16 +923,15 @@ namespace Elwig.Windows {
if (areaComs.Count == 0) if (areaComs.Count == 0)
return; return;
var oldMember = (await ctx.Members.FindAsync(mgnr))!; var oldMember = await ctx.FetchMembers(mgnr).SingleAsync();
var newName = $"{ViewModel.Name?.Replace('ß', 'ẞ').ToUpper()} " + var newName = $"{ViewModel.Name?.Replace('ß', 'ẞ').ToUpper()} " +
$"{ViewModel.Prefix}{(!string.IsNullOrEmpty(ViewModel.Prefix) ? " " : "")}" + $"{ViewModel.Prefix}{(!string.IsNullOrWhiteSpace(ViewModel.Prefix) ? " " : "")}" +
$"{ViewModel.GivenName}{(!string.IsNullOrEmpty(ViewModel.GivenName) ? " " : "")}" + $"{ViewModel.GivenName}{(!string.IsNullOrWhiteSpace(ViewModel.GivenName) ? " " : "")}" +
$"{ViewModel.Suffix}{(!string.IsNullOrEmpty(ViewModel.Suffix) ? " " : "")}"; $"{ViewModel.Suffix}{(!string.IsNullOrWhiteSpace(ViewModel.Suffix) ? " " : "")}";
var d = new AreaComTransferDialog(oldMember.AdministrativeName, newName, areaComs.Count, areaComs.Sum(c => c.Area)); var d = new AreaComTransferDialog(oldMember.AdministrativeName, newName, areaComs.Count, areaComs.Sum(c => c.Area));
if (d.ShowDialog() != true) if (d.ShowDialog() != true)
return; return;
ViewModel.TransferPredecessorAreaComs = d.SuccessorSeason; ViewModel.TransferPredecessorAreaComs = d.SuccessorSeason;
ViewModel.MaintainAreaComYearFrom = d.MaintainYearFrom;
if (IsEditing) if (IsEditing)
SetOriginalValue(PredecessorMgNrInput, -1); // hack to allow user to save SetOriginalValue(PredecessorMgNrInput, -1); // hack to allow user to save
UpdateButtons(); UpdateButtons();
@@ -0,0 +1,214 @@
<local:AdministrationWindow
x:Class="Elwig.Windows.MemberBusinessSharesAdminWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Elwig.Windows"
xmlns:ctrl="clr-namespace:Elwig.Controls"
xmlns:vm="clr-namespace:Elwig.ViewModels"
Title="{Binding Title}" Height="450" Width="800" MinHeight="400" MinWidth="700">
<Window.DataContext>
<vm:MemberBusinessSharesViewModel/>
</Window.DataContext>
<Window.Resources>
<Style TargetType="Label">
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="VerticalAlignment" Value="Top"/>
<Setter Property="Padding" Value="2,4,2,4"/>
<Setter Property="Height" Value="25"/>
</Style>
<Style TargetType="TextBox">
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalAlignment" Value="Top"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="Padding" Value="2"/>
<Setter Property="Height" Value="25"/>
<Setter Property="TextWrapping" Value="NoWrap"/>
</Style>
<Style TargetType="ctrl:UnitTextBox">
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalAlignment" Value="Top"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="Padding" Value="2"/>
<Setter Property="Height" Value="25"/>
<Setter Property="TextWrapping" Value="NoWrap"/>
</Style>
<Style TargetType="ComboBox">
<Setter Property="Height" Value="25"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalAlignment" Value="Top"/>
</Style>
<Style TargetType="Button">
<Setter Property="FontSize" Value="14"/>
<Setter Property="Padding" Value="9,3"/>
<Setter Property="Height" Value="27"/>
</Style>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" MinWidth="300"/>
<ColumnDefinition Width="5"/>
<ColumnDefinition Width="1*" MinWidth="350"/>
</Grid.ColumnDefinitions>
<Grid Margin="5,0,0,0">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="42"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ListBox x:Name="MemberHistoryList" Margin="5,10,5,0" Grid.ColumnSpan="3"
ItemsSource="{Binding History, Mode=TwoWay}" SelectedItem="{Binding SelectedHistoryEntry, Mode=TwoWay}"
SelectionChanged="MemberHistoryList_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding DateNotice, StringFormat='{}{0:dd.MM.yy}'}" Width="55" TextAlignment="Left" Margin="0,0,0,0"/>
<TextBlock Text="{Binding DateEffective, StringFormat='{}{0:dd.MM.yy}'}" Width="55" TextAlignment="Left" Margin="0,0,0,0"/>
<TextBlock Text="{Binding Shares, StringFormat='{}{0:N0}'}" Width="15" TextAlignment="Right" Margin="0,0,10,0"/>
<TextBlock Text="{Binding PoVReasonPhrase}" TextAlignment="Left" Margin="0,0,0,0"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button x:Name="NewHistoryButton" Content="Neu" Visibility="{Binding ControlButtonsVisibility}"
HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="5,5,2.5,10" Grid.Column="0" Grid.Row="2"
Click="NewHistoryButton_Click">
<Button.ToolTip>
<TextBlock FontWeight="Bold">Alt+Einfg</TextBlock>
</Button.ToolTip>
</Button>
<Button x:Name="EditHistoryButton" Content="Bearbeiten" IsEnabled="False" Visibility="{Binding ControlButtonsVisibility}"
HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="2.5,5,2.5,10" Grid.Column="1" Grid.Row="2"
Click="EditHistoryButton_Click">
<Button.ToolTip>
<TextBlock FontWeight="Bold">Strg+B</TextBlock>
</Button.ToolTip>
</Button>
<Button x:Name="DeleteHistoryButton" Content="Löschen" IsEnabled="False" Visibility="{Binding ControlButtonsVisibility}"
HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="2.5,5,5,10" Grid.Column="2" Grid.Row="2"
Click="DeleteHistoryButton_Click">
<Button.ToolTip>
<TextBlock FontWeight="Bold">Alt+Entf</TextBlock>
</Button.ToolTip>
</Button>
<Button x:Name="SaveButton" Content="Speichern" IsEnabled="False" Visibility="{Binding EditingButtonsVisibility}"
HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="5,5,2.5,10" Grid.Column="0" Grid.Row="2"
Click="SaveButton_Click">
<Button.ToolTip>
<TextBlock FontWeight="Bold">Strg+S</TextBlock>
</Button.ToolTip>
</Button>
<Button x:Name="ResetButton" Content="Zurücksetzen" IsEnabled="False" Visibility="{Binding EditingButtonsVisibility}"
HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="2.5,5,2.5,10" Grid.Column="1" Grid.Row="2"
Click="ResetButton_Click">
<Button.ToolTip>
<TextBlock FontWeight="Bold">Strg+Z</TextBlock>
</Button.ToolTip>
</Button>
<Button x:Name="CancelButton" Content="Abbrechen" IsEnabled="False" Visibility="{Binding EditingButtonsVisibility}" IsCancel="True"
HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="2.5,5,5,10" Grid.Column="2" Grid.Row="2"
Click="CancelButton_Click">
<Button.ToolTip>
<TextBlock FontWeight="Bold">Esc</TextBlock>
</Button.ToolTip>
</Button>
</Grid>
<GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
<Grid Grid.Column="2">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="95"/>
</Grid.RowDefinitions>
<GroupBox Header="Geschäftsanteilbewegung" Margin="5,10,5,5">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="110"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="Grund:" Margin="10,10,0,0" Grid.Column="0"/>
<ComboBox x:Name="ReasonInput" SelectedValue="{Binding Reason, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,10,10,0" Grid.Column="1"
SelectedValuePath="Tag"
SelectionChanged="ReasonInput_SelectionChanged">
<ComboBoxItem Tag="purchase">Kauf</ComboBoxItem>
<ComboBoxItem Tag="transfer_to">Übertragung an...</ComboBoxItem>
<ComboBoxItem Tag="transfer_from">Übertragung von...</ComboBoxItem>
<ComboBoxItem Tag="prescription">Vorschreibung</ComboBoxItem>
<ComboBoxItem Tag="exclusion">Ausschluss</ComboBoxItem>
<ComboBoxItem Tag="deceased">Tod</ComboBoxItem>
<ComboBoxItem Tag="retirement">Kündigung</ComboBoxItem>
<ComboBoxItem Tag="payout">Auszahlung</ComboBoxItem>
</ComboBox>
<Label Content="Anderes Mitgl.:" Margin="10,40,0,0" Grid.Column="0"/>
<TextBox x:Name="OtherMgNrInput" Text="{Binding OtherMgNrString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Width="48" Grid.Column="1" Margin="0,40,0,0" HorizontalAlignment="Left" TextAlignment="Right"
TextChanged="OtherMgNrInput_TextChanged" LostFocus="OtherMgNrInput_LostFocus"/>
<ComboBox x:Name="OtherMemberInput"
Grid.Column="1" Margin="53,40,40,10" IsEditable="True"
ItemTemplate="{StaticResource MemberAdminNameTemplate}" TextSearch.TextPath="AdministrativeName"
SelectionChanged="OtherMemberInput_SelectionChanged"/>
<Button x:Name="OtherMemberReferenceButton" Grid.Column="1" Height="25" Width="25" FontFamily="Segoe MDL2 Assets" Content="&#xEE35;" Padding="0,0,0,0"
Margin="10,40,10,10" VerticalAlignment="Top" HorizontalAlignment="Right" ToolTip="Zu Mitglied springen"
Click="OtherMemberReferenceButton_Click"/>
<Label Content="Anmerkung:" Margin="10,70,0,0" Grid.Column="0"/>
<TextBox x:Name="CommentInput" Text="{Binding Comment, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,70,10,0" Grid.Column="1"/>
<Label Content="Meldung:" Margin="10,100,0,0" Grid.Column="0"/>
<TextBox x:Name="DateNoticeInput" Text="{Binding DateNoticeString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,100,10,0" Width="78" Grid.Column="1" HorizontalAlignment="Left" TextAlignment="Right"
TextChanged="DateNoticeInput_TextChanged" LostFocus="DateInput_LostFocus"/>
<CheckBox x:Name="HasMemberSignedInput" IsChecked="{Binding MemberHasSigned, Mode=TwoWay}" Content="Von Mg. unterfertigt"
Margin="88,105,10,0" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="TOp"
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"/>
<Label Content="Wirksam:" Margin="10,130,0,0" Grid.Column="0"/>
<TextBox x:Name="DateEffeciveInput" Text="{Binding DateEffectiveString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,130,10,0" Width="78" Grid.Column="1" HorizontalAlignment="Left" TextAlignment="Right"
TextChanged="DateInput_TextChanged" LostFocus="DateInput_LostFocus"/>
<Label Content="Geschäftsanteile:" Margin="10,160,0,0" Grid.Column="0"/>
<TextBox x:Name="SharesInput" Text="{Binding SharesString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,160,10,0" Width="32" Grid.Column="1" HorizontalAlignment="Left" TextAlignment="Right"
TextChanged="SharesInput_TextChanged"/>
<CheckBox x:Name="DeductInput" IsChecked="{Binding Deduct, Mode=TwoWay}"
Margin="42,165,10,0" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="TOp"
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed">
<TextBlock>
bei Auszahlung <Run Text="{Binding DeductYearString}"/> abziehen
</TextBlock>
</CheckBox>
<Label Content="Betrag:" Margin="10,190,0,10"/>
<ctrl:UnitTextBox x:Name="ValuePerShareInput" Text="{Binding ValuePerShareString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Unit="€/GA" TextChanged="AmountPerShareInput_TextChanged"
Grid.Column="1" Width="76" Margin="0,190,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<ctrl:UnitTextBox x:Name="TotalAmountInput" Text="{Binding TotalAmount}" Unit="€" IsEnabled="False"
Grid.Column="1" Width="77" Margin="81,190,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"/>
</Grid>
</GroupBox>
<GroupBox Header="Mitglied" Grid.Row="1" Margin="5,5,5,10">
<Grid>
<TextBlock x:Name="MemberInfo" Text="Name (1234)"
FontSize="14" Margin="10,10,10,10"/>
</Grid>
</GroupBox>
</Grid>
</Grid>
</local:AdministrationWindow>
@@ -0,0 +1,347 @@
using Elwig.Helpers;
using Elwig.Models.Entities;
using Elwig.Services;
using Elwig.ViewModels;
using Microsoft.EntityFrameworkCore;
using System;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace Elwig.Windows {
public partial class MemberBusinessSharesAdminWindow : AdministrationWindow {
public MemberBusinessSharesViewModel ViewModel => (MemberBusinessSharesViewModel)DataContext;
public MemberBusinessSharesAdminWindow(int mgnr) {
InitializeComponent();
using var ctx = new AppDbContext();
ViewModel.FilterMember = ctx.Members.Find(mgnr) ?? throw new ArgumentException("MgNr argument has invalid value");
ViewModel.Title = $"Geschäftsanteilbewegungen - {ViewModel.FilterMember.AdministrativeName} - Elwig";
ExemptInputs = [
MemberHistoryList, TotalAmountInput
];
RequiredInputs = [
ReasonInput, DateNoticeInput, DateEffeciveInput, SharesInput
];
}
public void FocusMemberHistory(int histnr) {
if (IsEditing || IsCreating) return;
var item = ViewModel.History.FirstOrDefault(h => h.HistNr == histnr);
if (item != null) {
ControlUtils.SelectItem(MemberHistoryList, item);
}
}
private async Task RefreshList() {
var vm = ViewModel;
var cursor = Mouse.OverrideCursor != null;
if (!cursor) Mouse.OverrideCursor = Cursors.Wait;
var history = await Task.Run(async () => {
using var ctx = new AppDbContext();
return await ctx.MemberHistory
.Where(h => h.FromMgNr == vm.FilterMember.MgNr || h.ToMgNr == vm.FilterMember.MgNr)
.OrderBy(h => h.DateNoticeString).ThenBy(h => h.HistNr)
.ToListAsync();
});
if (!cursor) Mouse.OverrideCursor = null;
history.ForEach(h => h.PoVMgNr = vm.FilterMember.MgNr);
ControlUtils.RenewItemsSource(MemberHistoryList, history,
MemberHistoryList_SelectionChanged, ControlUtils.RenewSourceDefault.None);
RefreshInputs();
}
private void RefreshInputs(bool validate = false) {
ClearInputStates();
if (ViewModel.SelectedHistoryEntry is MemberHistory h) {
EditHistoryButton.IsEnabled = true;
DeleteHistoryButton.IsEnabled = true;
FillInputs(h);
} else {
EditHistoryButton.IsEnabled = false;
DeleteHistoryButton.IsEnabled = false;
ClearOriginalValues();
ClearDefaultValues();
ClearInputs(validate);
ClearInputStates();
}
GC.Collect();
}
private void FillInputs(MemberHistory h) {
ClearOriginalValues();
ClearDefaultValues();
ViewModel.FillInputs(h);
ReasonInput.SelectedValue = h.Reason + (h.Reason == MemberHistory.REASON_TRANSFER ? $"_{(h.FromMgNr == ViewModel.FilterMember.MgNr ? "to" : "from")}" : "");
FinishInputFilling();
}
private async Task InitInputs() {
ClearOriginalValues();
ClearDefaultValues();
await ViewModel.InitInputs();
SetDefaultValue(DateNoticeInput);
if (ViewModel.ValuePerShare != null)
SetDefaultValue(ValuePerShareInput);
ValidateRequiredInputs();
}
new protected void ClearInputs(bool validate = false) {
ViewModel.ClearInputs();
base.ClearInputs(validate);
}
override protected void UpdateButtons() {
if (!IsEditing && !IsCreating) return;
bool ch = HasChanged, v = IsValid;
ResetButton.IsEnabled = ch;
SaveButton.IsEnabled = v && ch;
}
protected override async Task OnRenewContext(AppDbContext ctx) {
await base.OnRenewContext(ctx);
if (await ctx.FetchMembers(ViewModel.FilterMember.MgNr).SingleOrDefaultAsync() is not Member m) {
Close();
return;
}
ViewModel.FilterMember = m;
ViewModel.Title = $"Geschäftsanteilbewegungen - {ViewModel.FilterMember.AdministrativeName} - Elwig";
ControlUtils.RenewItemsSource(OtherMemberInput, await ctx.FetchMembers(includeNotActive: true).ToListAsync());
MemberInfo.Text = $"{m.FullAdministrativeName}\nGA: {m.Shares:N0} (normal) / {m.SharesRed:N0} (rot) / {m.SharesWhite:N0} (weiß) / {m.SharesDormant:N0} (ruhend)";
await RefreshList();
}
private void MemberHistoryList_SelectionChanged(object? sender, SelectionChangedEventArgs? evt) {
RefreshInputs();
}
protected override void ShortcutNew() {
if (!NewHistoryButton.IsEnabled || NewHistoryButton.Visibility != Visibility.Visible)
return;
NewHistoryButton_Click(null, null);
}
private async void NewHistoryButton_Click(object? sender, RoutedEventArgs? evt) {
IsCreating = true;
MemberHistoryList.IsEnabled = false;
ViewModel.SelectedHistoryEntry = null;
HideNewEditDeleteButtons();
ShowSaveResetCancelButtons();
UnlockInputs();
await InitInputs();
DeductInput.IsEnabled = false;
OtherMgNrInput.IsEnabled = false;
OtherMemberInput.IsEnabled = false;
}
protected override void ShortcutEdit() {
if (!EditHistoryButton.IsEnabled || EditHistoryButton.Visibility != Visibility.Visible)
return;
EditHistoryButton_Click(null, null);
}
private void EditHistoryButton_Click(object? sender, RoutedEventArgs? evt) {
if (ViewModel.SelectedHistoryEntry == null) return;
IsEditing = true;
MemberHistoryList.IsEnabled = false;
HideNewEditDeleteButtons();
ShowSaveResetCancelButtons();
UnlockInputs();
DeductInput.IsEnabled = ViewModel.Reason == MemberHistory.REASON_PURCHASE || ViewModel.Reason == MemberHistory.REASON_PRESCRIPTION;
OtherMgNrInput.IsEnabled = ViewModel.Reason?.StartsWith(MemberHistory.REASON_TRANSFER) ?? false;
OtherMemberInput.IsEnabled = OtherMgNrInput.IsEnabled;
}
protected override void ShortcutDelete() {
if (!DeleteHistoryButton.IsEnabled || DeleteHistoryButton.Visibility != Visibility.Visible)
return;
DeleteHistoryButton_Click(null, null);
}
private async void DeleteHistoryButton_Click(object? sender, RoutedEventArgs? evt) {
if (ViewModel.SelectedHistoryEntry is not MemberHistory h)
return;
if (InteractionService.AskContinueYesNo("Geschäftsanteilbewegung löschen", $"Soll die Geschäftsanteilbewegung wirklich unwiderruflich\ngelöscht werden?\n\nFalls ja:\nSoll die Änderung der aktuellen GA wieder rückgängig gemacht werden?") is bool enableTriggers) {
Mouse.OverrideCursor = Cursors.Wait;
try {
await MemberBusinessSharesService.DeleteMemberHistory(h.HistNr, enableTriggers);
App.HintContextChange();
} catch (Exception exc) {
InteractionService.ShowDbException("Geschäftsanteilbewegung löschen", exc);
}
Mouse.OverrideCursor = null;
}
}
protected override void ShortcutSave() {
if (!SaveButton.IsEnabled || SaveButton.Visibility != Visibility.Visible)
return;
SaveButton_Click(null, null);
}
private async void SaveButton_Click(object? sender, RoutedEventArgs? evt) {
Mouse.OverrideCursor = Cursors.Wait;
SaveButton.IsEnabled = false;
int mgnr;
try {
mgnr = await ViewModel.UpdateMemberHistory(ViewModel.SelectedHistoryEntry?.HistNr, IsEditing || ViewModel.DateNotice >= DateOnly.FromDateTime(Utils.Today).AddDays(-14));
App.HintContextChange();
} catch (Exception exc) {
InteractionService.ShowDbException("Geschäftsanteilbewegung aktualisieren", exc);
SaveButton.IsEnabled = true;
Mouse.OverrideCursor = null;
return;
}
IsEditing = false;
IsCreating = false;
MemberHistoryList.IsEnabled = true;
OtherMgNrInput.IsEnabled = true;
HideSaveResetCancelButtons();
ShowNewEditDeleteButtons();
LockInputs();
FinishInputFilling();
await EnsureContextRenewed();
Mouse.OverrideCursor = null;
if (mgnr is int m)
FocusMemberHistory(m);
}
protected override void ShortcutReset() {
if (!ResetButton.IsEnabled || ResetButton.Visibility != Visibility.Visible)
return;
ResetButton_Click(null, null);
}
private async void ResetButton_Click(object? sender, RoutedEventArgs? evt) {
if (IsEditing) {
RefreshInputs();
} else if (IsCreating) {
ClearInputs();
await InitInputs();
}
UpdateButtons();
}
private void CancelButton_Click(object sender, RoutedEventArgs evt) {
IsEditing = false;
IsCreating = false;
MemberHistoryList.IsEnabled = true;
OtherMgNrInput.IsEnabled = true;
HideSaveResetCancelButtons();
ShowNewEditDeleteButtons();
RefreshInputs();
LockInputs();
}
private void ShowSaveResetCancelButtons() {
SaveButton.IsEnabled = false;
ResetButton.IsEnabled = false;
CancelButton.IsEnabled = true;
ViewModel.EditingButtonsVisibility = Visibility.Visible;
}
private void HideSaveResetCancelButtons() {
SaveButton.IsEnabled = false;
ResetButton.IsEnabled = false;
CancelButton.IsEnabled = false;
ViewModel.EditingButtonsVisibility = Visibility.Hidden;
}
private void ShowNewEditDeleteButtons() {
NewHistoryButton.IsEnabled = true;
EditHistoryButton.IsEnabled = ViewModel.SelectedHistoryEntry != null;
DeleteHistoryButton.IsEnabled = ViewModel.SelectedHistoryEntry != null;
ViewModel.ControlButtonsVisibility = Visibility.Visible;
}
private void HideNewEditDeleteButtons() {
NewHistoryButton.IsEnabled = false;
EditHistoryButton.IsEnabled = false;
DeleteHistoryButton.IsEnabled = false;
ViewModel.ControlButtonsVisibility = Visibility.Hidden;
}
private void OtherMgNrInput_TextChanged(object sender, TextChangedEventArgs evt) {
var valid = InputTextChanged((TextBox)sender, Validator.CheckMgNr);
var text = OtherMgNrInput.Text;
var caret = OtherMgNrInput.CaretIndex;
ControlUtils.SelectItemWithPk(OtherMemberInput, valid ? ViewModel.OtherMgNr : null);
OtherMgNrInput.Text = text;
OtherMgNrInput.CaretIndex = caret;
}
private void OtherMgNrInput_LostFocus(object sender, RoutedEventArgs evt) {
var valid = InputLostFocus((TextBox)sender, Validator.CheckMgNr);
ControlUtils.SelectItemWithPk(OtherMemberInput, valid ? ViewModel.OtherMgNr : null);
}
private void OtherMemberInput_SelectionChanged(object? sender, SelectionChangedEventArgs? evt) {
var m = OtherMemberInput.SelectedItem as Member;
ViewModel.OtherMgNr = m?.MgNr;
}
private void OtherMemberReferenceButton_Click(object sender, RoutedEventArgs evt) {
if (OtherMemberInput.SelectedItem is not Member m) return;
App.FocusMember(m.MgNr);
}
private void ReasonInput_SelectionChanged(object sender, RoutedEventArgs evt) {
ComboBox_SelectionChanged(sender, evt);
if (!IsEditing && !IsCreating) return;
if (ViewModel.DateNotice is not DateOnly d) return;
if (ViewModel.Reason == MemberHistory.REASON_EXCLUSION || ViewModel.Reason == MemberHistory.REASON_DECEASED || ViewModel.Reason == MemberHistory.REASON_RETIREMENT) {
ViewModel.DateEffectiveString = $"31.12.{d.Year + 1}";
} else {
ViewModel.DateEffectiveString = ViewModel.DateNoticeString;
}
DeductInput.IsEnabled = ViewModel.Reason == MemberHistory.REASON_PURCHASE || ViewModel.Reason == MemberHistory.REASON_PRESCRIPTION;
if (!DeductInput.IsEnabled) DeductInput.IsChecked = false;
OtherMgNrInput.IsEnabled = ViewModel.Reason?.StartsWith(MemberHistory.REASON_TRANSFER) ?? false;
OtherMemberInput.IsEnabled = OtherMgNrInput.IsEnabled;
if (!OtherMgNrInput.IsEnabled) OtherMgNrInput.Text = "";
}
private void DateNoticeInput_TextChanged(object sender, TextChangedEventArgs evt) {
DateInput_TextChanged(sender, evt);
if (!IsEditing && !IsCreating) return;
if (ViewModel.DateNotice is not DateOnly d) return;
ViewModel.DeductYear = d.Year;
if (ViewModel.DateEffective == null && ViewModel.Reason != null) {
if (ViewModel.Reason == MemberHistory.REASON_EXCLUSION || ViewModel.Reason == MemberHistory.REASON_DECEASED || ViewModel.Reason == MemberHistory.REASON_RETIREMENT) {
ViewModel.DateEffectiveString = $"31.12.{d.Year + 1}";
} else {
ViewModel.DateEffectiveString = ViewModel.DateNoticeString;
}
}
}
private void UpdateAmount() {
ViewModel.TotalAmount = $"{ViewModel.Shares * ViewModel.ValuePerShare:N2}";
}
private void SharesInput_TextChanged(object sender, TextChangedEventArgs evt) {
IntegerInput_TextChanged(sender, evt);
UpdateAmount();
}
private void AmountPerShareInput_TextChanged(object sender, TextChangedEventArgs evt) {
InputTextChanged((TextBox)sender, Validator.CheckDecimal((TextBox)sender, false, 3, 2));
UpdateAmount();
}
}
}
+14 -21
View File
@@ -1,5 +1,6 @@
using Elwig.Helpers; using Elwig.Helpers;
using Elwig.Models.Entities; using Elwig.Models.Entities;
using Elwig.Services;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -21,12 +22,11 @@ namespace Elwig.Windows {
} }
protected override async Task OnRenewContext(AppDbContext ctx) { protected override async Task OnRenewContext(AppDbContext ctx) {
var origins = (await ctx.WineOrigins var origins = await ctx.WineOrigins
.Include("Gems.AtGem.Kgs.WbKg.Gl") .Include(o => o.Gems).ThenInclude(g => g.AtGem.Kgs).ThenInclude(k => k.WbKg!.Gl)
.AsSplitQuery() .ToListAsync();
.ToListAsync()) origins.ForEach(o => { origins.FirstOrDefault(p => p.HkId == o.ParentHkId)?.Children.Add(o); });
.OrderByDescending(o => o.SortKey) origins = [.. origins.OrderByDescending(o => o.SortKey).ThenBy(o => o.HkId)];
.ThenBy(o => o.HkId);
ControlUtils.RenewItemsSource(WineOrigins, origins, WineOrigins_SelectionChanged); ControlUtils.RenewItemsSource(WineOrigins, origins, WineOrigins_SelectionChanged);
if (WineOrigins.SelectedItem == null) { if (WineOrigins.SelectedItem == null) {
var hkid = await ctx.WbKgs var hkid = await ctx.WbKgs
@@ -39,8 +39,7 @@ namespace Elwig.Windows {
} }
var gls = await ctx.WbGls var gls = await ctx.WbGls
.OrderBy(g => g.GlNr) .OrderBy(g => g.GlNr)
.Include("Kgs.Rds") .Include(g => g.Kgs).ThenInclude(k => k.Rds)
.AsSplitQuery()
.ToListAsync(); .ToListAsync();
ControlUtils.RenewItemsSource(WbGls, gls, WbGls_SelectionChanged, ControlUtils.RenewSourceDefault.First); ControlUtils.RenewItemsSource(WbGls, gls, WbGls_SelectionChanged, ControlUtils.RenewSourceDefault.First);
UpdateWbGems(); UpdateWbGems();
@@ -100,8 +99,8 @@ namespace Elwig.Windows {
var allMembers = await ctx.Members.Where(m => m.DefaultKgNr == k.KgNr).CountAsync(); var allMembers = await ctx.Members.Where(m => m.DefaultKgNr == k.KgNr).CountAsync();
StatusDefaultKgs.Text += $"{activeMembers:N0} ({allMembers:N0})"; StatusDefaultKgs.Text += $"{activeMembers:N0} ({allMembers:N0})";
var year = Utils.CurrentNextSeason; var year = Utils.CurrentNextSeason;
var activeAreaComs = await Utils.ActiveAreaCommitments(ctx.AreaCommitments.Where(c => c.KgNr == k.KgNr), year).CountAsync(); var activeAreaComs = await Utils.ActiveAreaCommitments(ctx.AreaCommitments.Where(c => c.Contract.KgNr == k.KgNr), year).CountAsync();
var allAreaComs = await ctx.AreaCommitments.Where(c => c.KgNr == k.KgNr).CountAsync(); var allAreaComs = await ctx.AreaCommitments.Where(c => c.Contract.KgNr == k.KgNr).CountAsync();
StatusAreaCommitments.Text += $"{activeAreaComs:N0} ({allAreaComs:N0})"; StatusAreaCommitments.Text += $"{activeAreaComs:N0} ({allAreaComs:N0})";
var deliveryParts = await ctx.DeliveryParts.Where(p => p.KgNr == k.KgNr).CountAsync(); var deliveryParts = await ctx.DeliveryParts.Where(p => p.KgNr == k.KgNr).CountAsync();
var deliveries = await ctx.Deliveries.Where(d => d.Parts.Any(p => p.KgNr == k.KgNr)).CountAsync(); var deliveries = await ctx.Deliveries.Where(d => d.Parts.Any(p => p.KgNr == k.KgNr)).CountAsync();
@@ -194,18 +193,14 @@ namespace Elwig.Windows {
App.HintContextChange(); App.HintContextChange();
ControlUtils.SelectItemWithPk(WbGlKgs, k.KgNr); ControlUtils.SelectItemWithPk(WbGlKgs, k.KgNr);
} catch (Exception exc) { } catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message; InteractionService.ShowDbException("Katastralgemeinde aktivieren", exc);
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) { private async void DeactivateKgButton_Click(object sender, RoutedEventArgs e) {
if (WbGlKgs.SelectedItem is not AT_Kg k || k.WbKg == null) return; if (WbGlKgs.SelectedItem is not AT_Kg k || k.WbKg == null) return;
var r = MessageBox.Show( if (!InteractionService.AskConfirmation("Katastralgemeinde deaktivieren", $"Sollen alle Riede und Stammgemeinden-Einträge von der KG {k.Name} wirklich unwiderruflich gelöscht werden?"))
$"Sollen alle Riede und Stammgemeinden-Einträge von der KG {k.Name} wirklich unwiderruflich gelöscht werden?", return;
"Katastralgemeinde deaktivieren", MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No);
if (r != MessageBoxResult.Yes) return;
try { try {
using (var ctx = new AppDbContext()) { using (var ctx = new AppDbContext()) {
ctx.Remove(k.WbKg); ctx.Remove(k.WbKg);
@@ -214,10 +209,8 @@ namespace Elwig.Windows {
App.HintContextChange(); App.HintContextChange();
ControlUtils.SelectItemWithPk(WbKgs, k.KgNr); ControlUtils.SelectItemWithPk(WbKgs, k.KgNr);
} catch (Exception exc) { } catch (Exception exc) {
await HintContextChange(); await ForceContextReload();
var str = "Der Eintrag konnte nicht aus der Datenbank gelöscht werden!\n\n" + exc.Message; InteractionService.ShowDbException("Katastralgemeinde deaktivieren", exc);
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Katastralgemeinde deaktivieren", MessageBoxButton.OK, MessageBoxImage.Error);
} }
} }
+11 -11
View File
@@ -76,7 +76,7 @@
</DataGridTextColumn> </DataGridTextColumn>
<DataGridTextColumn Header="Nachname" Binding="{Binding Name}" Width="100"/> <DataGridTextColumn Header="Nachname" Binding="{Binding Name}" Width="100"/>
<DataGridTextColumn Header="Vorname" Binding="{Binding GivenName}" Width="90"/> <DataGridTextColumn Header="Vorname" Binding="{Binding GivenName}" Width="90"/>
<DataGridTextColumn Header="GA" Binding="{Binding BusinessShares, StringFormat='{}{0:N0} '}" Width="35"> <DataGridTextColumn Header="GA" Binding="{Binding SharesActive, StringFormat='{}{0:N0} '}" Width="35">
<DataGridTextColumn.CellStyle> <DataGridTextColumn.CellStyle>
<Style> <Style>
<Setter Property="TextBlock.TextAlignment" Value="Right"/> <Setter Property="TextBlock.TextAlignment" Value="Right"/>
@@ -104,7 +104,7 @@
</Style> </Style>
</DataGridTextColumn.CellStyle> </DataGridTextColumn.CellStyle>
</DataGridTextColumn> </DataGridTextColumn>
<DataGridTextColumn Header="Strafe GA" Binding="{Binding PenaltyBs, Converter={StaticResource CurrencyConverter}, StringFormat='{}{0} '}" Width="65"> <DataGridTextColumn Header="Strafe GA" Binding="{Binding PenaltyShares, Converter={StaticResource CurrencyConverter}, StringFormat='{}{0} '}" Width="65">
<DataGridTextColumn.CellStyle> <DataGridTextColumn.CellStyle>
<Style> <Style>
<Setter Property="TextBlock.TextAlignment" Value="Right"/> <Setter Property="TextBlock.TextAlignment" Value="Right"/>
@@ -194,7 +194,7 @@
</Grid> </Grid>
</GroupBox> </GroupBox>
<GroupBox Header="Automatische Nachzeichnung der Geschäftsanteile" Margin="5,10,10,10" Height="180" Width="365" <GroupBox Header="Automatische Nachzeichnung von Geschäftsanteilen" Margin="5,10,10,10" Height="180" Width="365"
VerticalAlignment="Bottom" HorizontalAlignment="Left"> VerticalAlignment="Bottom" HorizontalAlignment="Left">
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
@@ -204,28 +204,28 @@
<Label Content="Absoluter Freibetrag:" Margin="10,10,0,0" Grid.ColumnSpan="2"/> <Label Content="Absoluter Freibetrag:" Margin="10,10,0,0" Grid.ColumnSpan="2"/>
<ctrl:UnitTextBox x:Name="AllowanceKgInput" Unit="kg" Margin="128,10,0,0" Width="70" <ctrl:UnitTextBox x:Name="AllowanceKgInput" Unit="kg" Margin="128,10,0,0" Width="70"
TextChanged="KgInput_TextChanged" Grid.Column="1"/> TextChanged="KgInput_TextChanged" Grid.Column="1"/>
<ctrl:UnitTextBox x:Name="AllowanceBsInput" Unit="GA" Margin="203,10,0,0" Width="60" <ctrl:UnitTextBox x:Name="AllowanceShareInput" Unit="GA" Margin="203,10,0,0" Width="60"
TextChanged="PercentInput_TextChanged" Grid.Column="1"/> TextChanged="PercentInput_TextChanged" Grid.Column="1"/>
<Label Content="Relativer Freibetrag:" Margin="10,40,0,0" Grid.ColumnSpan="2"/> <Label Content="Relativer Freibetrag:" Margin="10,40,0,0" Grid.ColumnSpan="2"/>
<ctrl:UnitTextBox x:Name="AllowanceKgPerBsInput" Unit="kg/GA" Margin="128,40,0,0" Width="87" <ctrl:UnitTextBox x:Name="AllowanceKgPerShareInput" Unit="kg/GA" Margin="128,40,0,0" Width="87"
TextChanged="KgInput_TextChanged" Grid.Column="1"/> TextChanged="KgInput_TextChanged" Grid.Column="1"/>
<ctrl:UnitTextBox x:Name="AllowancePercentInput" Unit="%" Margin="220,40,0,0" Width="60" <ctrl:UnitTextBox x:Name="AllowancePercentInput" Unit="%" Margin="220,40,0,0" Width="60"
TextChanged="PercentInput_TextChanged" Grid.Column="1"/> TextChanged="PercentInput_TextChanged" Grid.Column="1"/>
<Label Content="Nur mind. nachz.:" Margin="10,70,0,0" Grid.ColumnSpan="2"/> <Label Content="Nur mind. nachz.:" Margin="10,70,0,0" Grid.ColumnSpan="2"/>
<ctrl:UnitTextBox x:Name="MinBsInput" Unit="GA" Margin="128,70,0,0" Width="50" <ctrl:UnitTextBox x:Name="MinSharesInput" Unit="GA" Margin="128,70,0,0" Width="50"
TextChanged="BsInput_TextChanged" Grid.Column="1"/> TextChanged="SharesInput_TextChanged" Grid.Column="1"/>
<Button x:Name="SeasonButton" Content="GA-Wert" Margin="0,0,10,42" Width="120" <Button x:Name="SeasonButton" Content="GA-Wert" Margin="0,0,10,42" Width="120"
HorizontalAlignment="Right" VerticalAlignment="Bottom" HorizontalAlignment="Right" VerticalAlignment="Bottom"
Click="SeasonButton_Click" Grid.Column="1"/> Click="SeasonButton_Click" Grid.Column="1"/>
<Button x:Name="AutoAdjustBsButton" Content="Nachzeichnen" Margin="0,0,135,10" Width="120" <Button x:Name="AutoAdjustSharesButton" Content="Nachzeichnen" Margin="0,0,135,10" Width="120"
HorizontalAlignment="Right" VerticalAlignment="Bottom" HorizontalAlignment="Right" VerticalAlignment="Bottom"
Click="AutoAdjustBsButton_Click" Grid.Column="1"/> Click="AutoAdjustSharesButton_Click" Grid.Column="1"/>
<Button x:Name="UnAdjustBsButton" Content="Rückgängig" Margin="0,0,10,10" Width="120" <Button x:Name="UnAdjustSharesButton" Content="Rückgängig" Margin="0,0,10,10" Width="120"
HorizontalAlignment="Right" VerticalAlignment="Bottom" HorizontalAlignment="Right" VerticalAlignment="Bottom"
Click="UnAdjustBsButton_Click" Grid.Column="1"/> Click="UnAdjustSharesButton_Click" Grid.Column="1"/>
</Grid> </Grid>
</GroupBox> </GroupBox>
</Grid> </Grid>
+53 -65
View File
@@ -2,6 +2,7 @@ using Elwig.Helpers;
using Elwig.Helpers.Billing; using Elwig.Helpers.Billing;
using Elwig.Models.Dtos; using Elwig.Models.Dtos;
using Elwig.Models.Entities; using Elwig.Models.Entities;
using Elwig.Services;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -25,59 +26,56 @@ namespace Elwig.Windows {
Year = year; Year = year;
// using (var ctx = new AppDbContext()) { SeasonLocked = ctx.Seasons.Find(Year + 1) != null; } // using (var ctx = new AppDbContext()) { SeasonLocked = ctx.Seasons.Find(Year + 1) != null; }
Title = $"Auszahlung anpassen - Lese {Year} - Elwig"; Title = $"Auszahlung anpassen - Lese {Year} - Elwig";
AutoAdjustBsButton.IsEnabled = !SeasonLocked; AutoAdjustSharesButton.IsEnabled = !SeasonLocked;
UnAdjustBsButton.IsEnabled = !SeasonLocked; UnAdjustSharesButton.IsEnabled = !SeasonLocked;
SaveCustomButton.IsEnabled = !SeasonLocked; SaveCustomButton.IsEnabled = !SeasonLocked;
RemoveCustomButton.IsEnabled = !SeasonLocked; RemoveCustomButton.IsEnabled = !SeasonLocked;
CustomAmountInput.IsEnabled = !SeasonLocked; CustomAmountInput.IsEnabled = !SeasonLocked;
CustomCommentInput.IsEnabled = !SeasonLocked; CustomCommentInput.IsEnabled = !SeasonLocked;
AllowanceKgInput.Text = $"{App.Client.AutoAdjustBs.AllowanceKg}"; AllowanceKgInput.Text = $"{App.Client.AutoAdjustShares.AllowanceKg}";
AllowanceBsInput.Text = $"{App.Client.AutoAdjustBs.AllowanceBs}"; AllowanceShareInput.Text = $"{App.Client.AutoAdjustShares.AllowanceShares}";
AllowanceKgPerBsInput.Text = $"{App.Client.AutoAdjustBs.AllowanceKgPerBs}"; AllowanceKgPerShareInput.Text = $"{App.Client.AutoAdjustShares.AllowanceKgPerShare}";
AllowancePercentInput.Text = $"{App.Client.AutoAdjustBs.AllowancePercent}"; AllowancePercentInput.Text = $"{App.Client.AutoAdjustShares.AllowancePercent}";
MinBsInput.Text = $"{App.Client.AutoAdjustBs.MinBs}"; MinSharesInput.Text = $"{App.Client.AutoAdjustShares.MinShares}";
} }
protected override async Task OnRenewContext(AppDbContext ctx) { protected override async Task OnRenewContext(AppDbContext ctx) {
var members = await ctx.Members var members = await ctx.FetchMembers(includeNotActive: true)
.Select(m => new { .Select(m => new {
m.MgNr, m.MgNr,
m.Name, m.Name,
m.GivenName, m.GivenName,
m.BusinessShares, m.SharesActive,
m.IsActive, m.IsActive,
}) })
.OrderBy(m => m.Name)
.ThenBy(m => m.GivenName)
.ThenBy(m => m.MgNr)
.ToListAsync(); .ToListAsync();
var season = (await ctx.Seasons.FindAsync(Year))!; var season = await ctx.FetchSeasons(Year).SingleAsync();
var contracts = await ctx.AreaCommitmentTypes.ToDictionaryAsync(t => t.VtrgId, t => t); var contracts = await ctx.AreaCommitmentTypes.ToDictionaryAsync(t => t.VtrgId, t => t);
var tbl1 = await OverUnderDeliveryData.ForSeason(ctx.OverUnderDeliveryRows, Year); var (tbl1, _, _) = await OverUnderDeliveryData.ForSeason(ctx.OverUnderDeliveryRows, Year);
var tbl2 = await AreaComUnderDeliveryData.ForSeason(ctx.AreaComUnderDeliveryRows, Year); var tbl2 = await AreaComUnderDeliveryData.ForSeason(ctx.AreaComUnderDeliveryRows, Year);
var weight = tbl1.Rows.ToDictionary(r => r.MgNr, r => r.Weight); var weight = tbl1.Rows.ToDictionary(r => r.MgNr, r => r.WeightTotal);
var areaComs = tbl2.Rows.ToDictionary(r => r.MgNr, r => r.VtrgIds.Zip(r.UnderDeliveries).ToDictionary(r => r.First, r => r.Second)); var areaComs = tbl2.Rows.ToDictionary(r => r.MgNr, r => r.VtrgIds.Zip(r.UnderDeliveries).ToDictionary(r => r.First, r => r.Second));
CustomPayments = await ctx.CustomPayments.Where(p => p.Year == Year).ToDictionaryAsync(p => p.MgNr, p => p); CustomPayments = await ctx.CustomPayments.Where(p => p.Year == Year).ToDictionaryAsync(p => p.MgNr, p => p);
var history = await ctx.MemberHistory var history = await ctx.MemberHistory
.Where(h => h.DateString.CompareTo($"{Year}-01-01") >= 0 && h.DateString.CompareTo($"{Year}-12-31") <= 0 && h.Type == "auto" && h.BusinessShares > 0) .Where(h => h.DeductYear == Year)
.GroupBy(h => h.Member) .GroupBy(h => h.ToMember)
.ToDictionaryAsync(h => h.Key.MgNr, h => h.Sum(g => g.BusinessShares)); .ToDictionaryAsync(h => h.Key.MgNr, h => h.Sum(g => g.Shares));
var list = members var list = members
.Select(m => new { .Select(m => new {
m.MgNr, m.Name, m.GivenName, m.MgNr, m.Name, m.GivenName,
m.IsActive, m.IsActive,
BusinessShares = m.BusinessShares - history.GetValueOrDefault(m.MgNr, 0), SharesActive = m.SharesActive - history.GetValueOrDefault(m.MgNr, 0),
DeliveryObligation = (m.BusinessShares - history.GetValueOrDefault(m.MgNr, 0)) * season.MinKgPerBusinessShare, DeliveryObligation = (m.SharesActive - history.GetValueOrDefault(m.MgNr, 0)) * season.MinKgPerShare,
DeliveryRight = (m.BusinessShares - history.GetValueOrDefault(m.MgNr, 0)) * season.MaxKgPerBusinessShare, DeliveryRight = (m.SharesActive - history.GetValueOrDefault(m.MgNr, 0)) * season.MaxKgPerShare,
Adjust = history.TryGetValue(m.MgNr, out int v2) ? (int?)v2 : null, Adjust = history.TryGetValue(m.MgNr, out int v2) ? (int?)v2 : null,
}) })
.Select(m => new { .Select(m => new {
m.MgNr, m.Name, m.GivenName, m.MgNr, m.Name, m.GivenName,
m.BusinessShares, m.SharesActive,
Weight = weight.GetValueOrDefault(m.MgNr, 0), Weight = weight.GetValueOrDefault(m.MgNr, 0),
OverUnder = weight.TryGetValue(m.MgNr, out int v1) ? OverUnder = weight.TryGetValue(m.MgNr, out int v1) ?
(v1 < m.DeliveryObligation ? (int?)v1 - m.DeliveryObligation : (v1 < m.DeliveryObligation ? (int?)v1 - m.DeliveryObligation :
@@ -88,12 +86,12 @@ namespace Elwig.Windows {
}) })
.Select(m => new { .Select(m => new {
m.MgNr, m.Name, m.GivenName, m.MgNr, m.Name, m.GivenName,
m.BusinessShares, m.Weight, m.OverUnder, m.SharesActive, m.Weight, m.OverUnder,
PenaltyBs = m.OverUnder != null && m.OverUnder < 0 ? PenaltyShares = m.OverUnder != null && m.OverUnder < 0 ?
(season.PenaltyPerKg * m.OverUnder ?? 0) + (season.PenaltyPerKg * m.OverUnder ?? 0) +
(-season.PenaltyAmount ?? 0) + (-season.PenaltyAmount ?? 0) +
(season.PenaltyPerBsAmount * Math.Floor(m.OverUnder / season.MinKgPerBusinessShare ?? 0m) ?? 0) + (season.PenaltyPerShareAmount * Math.Floor(m.OverUnder / season.MinKgPerShare ?? 0m) ?? 0) +
(m.Weight == 0 ? (-season.PenaltyNone ?? 0) + (-season.PenaltyPerBsNone * m.BusinessShares ?? 0) : 0) (m.Weight == 0 ? (-season.PenaltyNone ?? 0) + (-season.PenaltyPerShareNone * m.SharesActive ?? 0) : 0)
: (decimal?)null, : (decimal?)null,
PenaltyAc = areaComs.TryGetValue(m.MgNr, out var c) ? c.Select(r => { PenaltyAc = areaComs.TryGetValue(m.MgNr, out var c) ? c.Select(r => {
var con = contracts[r.Key]; var con = contracts[r.Key];
@@ -105,30 +103,30 @@ namespace Elwig.Windows {
}) })
.Select(m => new { .Select(m => new {
m.MgNr, m.Name, m.GivenName, m.MgNr, m.Name, m.GivenName,
m.BusinessShares, m.Weight, m.OverUnder, m.SharesActive, m.Weight, m.OverUnder,
PenaltyBs = m.PenaltyBs == null || m.PenaltyBs == 0 ? (decimal?)null : Math.Round((decimal)m.PenaltyBs, 2), PenaltyShares = m.PenaltyShares == null || m.PenaltyShares == 0 ? (decimal?)null : Math.Round((decimal)m.PenaltyShares, 2),
PenaltyAc = m.PenaltyAc == null ? (decimal?)null : Math.Round((decimal)m.PenaltyAc, 2), PenaltyAc = m.PenaltyAc == null ? (decimal?)null : Math.Round((decimal)m.PenaltyAc, 2),
m.Adjust, m.Adjust,
AdjustAmount = m.AdjustAmount == null ? (decimal?)null : Math.Round((decimal)m.AdjustAmount, 2), AdjustAmount = m.AdjustAmount == null ? (decimal?)null : Math.Round((decimal)m.AdjustAmount, 2),
CustomAmount = m.Custom?.Amount, CustomAmount = m.Custom?.Amount,
ModAbs = m.Custom?.ModAbs, m.Custom?.ModAbs,
ModRel = m.Custom?.ModRel, m.Custom?.ModRel,
}) })
.Select(m => new { .Select(m => new {
m.MgNr, m.Name, m.GivenName, m.MgNr, m.Name, m.GivenName,
m.BusinessShares, m.Weight, m.OverUnder, m.SharesActive, m.Weight, m.OverUnder,
m.PenaltyBs, m.PenaltyAc, m.Adjust, m.AdjustAmount, m.CustomAmount, m.ModAbs, m.ModRel, m.PenaltyShares, m.PenaltyAc, m.Adjust, m.AdjustAmount, m.CustomAmount, m.ModAbs, m.ModRel,
Total = (m.PenaltyBs ?? 0) + (m.PenaltyAc ?? 0) + (m.AdjustAmount ?? 0) + (m.CustomAmount ?? 0), Total = (m.PenaltyShares ?? 0) + (m.PenaltyAc ?? 0) + (m.AdjustAmount ?? 0) + (m.CustomAmount ?? 0),
}) })
.Select(m => new { .Select(m => new {
m.MgNr, m.Name, m.GivenName, m.MgNr, m.Name, m.GivenName,
m.BusinessShares, m.Weight, m.OverUnder, m.SharesActive, m.Weight, m.OverUnder,
m.PenaltyBs, m.PenaltyAc, m.Adjust, m.AdjustAmount, m.CustomAmount, m.ModAbs, m.ModRel, m.PenaltyShares, m.PenaltyAc, m.Adjust, m.AdjustAmount, m.CustomAmount, m.ModAbs, m.ModRel,
m.Total, m.Total,
Background = m.Weight == 0 ? Brushes.Orange : m.Weight / 2 < -m.Total ? Brushes.Red : Brushes.White, Background = m.Weight == 0 ? Brushes.Orange : m.Weight / 2 < -m.Total ? Brushes.Red : Brushes.White,
Foreground = m.Total == 0 ? Brushes.Gray : Brushes.Black, Foreground = m.Total == 0 ? Brushes.Gray : Brushes.Black,
}) })
.Where(m => m.OverUnder != null || m.Adjust != null || m.PenaltyBs != null || m.PenaltyAc != null || m.CustomAmount != null || m.ModAbs != null || m.ModRel != null) .Where(m => m.OverUnder != null || m.Adjust != null || m.PenaltyShares != null || m.PenaltyAc != null || m.CustomAmount != null || m.ModAbs != null || m.ModRel != null)
.OrderByDescending(m => m.OverUnder ?? 0) .OrderByDescending(m => m.OverUnder ?? 0)
.ThenBy(m => m.Name) .ThenBy(m => m.Name)
.ThenBy(m => m.GivenName) .ThenBy(m => m.GivenName)
@@ -138,62 +136,54 @@ namespace Elwig.Windows {
MemberList.ItemsSource = list; MemberList.ItemsSource = list;
var sym = season.Currency.Symbol ?? season.Currency.Code; var sym = season.Currency.Symbol ?? season.Currency.Code;
PenaltyBusinessShares.Text = $"{list.Count(r => r.PenaltyBs != null && r.PenaltyBs != 0)} Mg. / {list.Sum(r => r.PenaltyBs):N2} {sym}"; PenaltyBusinessShares.Text = $"{list.Count(r => r.PenaltyShares != null && r.PenaltyShares != 0)} Mg. / {list.Sum(r => r.PenaltyShares):N2} {sym}";
PenaltyAreaCommitments.Text = $"{list.Count(r => r.PenaltyAc != null && r.PenaltyAc != 0)} Mg. / {list.Sum(r => r.PenaltyAc):N2} {sym}"; PenaltyAreaCommitments.Text = $"{list.Count(r => r.PenaltyAc != null && r.PenaltyAc != 0)} Mg. / {list.Sum(r => r.PenaltyAc):N2} {sym}";
AutoBusinessShareAdjustment.Text = $"{list.Count(r => r.Adjust > 0)} Mg. / {list.Sum(r => r.Adjust)} GA / {list.Sum(r => r.AdjustAmount):N2} {sym}"; AutoBusinessShareAdjustment.Text = $"{list.Count(r => r.Adjust > 0)} Mg. / {list.Sum(r => r.Adjust)} GA / {list.Sum(r => r.AdjustAmount):N2} {sym}";
CustomModifiers.Text = $"{list.Count(r => r.CustomAmount != null)} Mg. / {list.Sum(r => r.CustomAmount):N2} {sym}"; CustomModifiers.Text = $"{list.Count(r => r.CustomAmount != null)} Mg. / {list.Sum(r => r.CustomAmount):N2} {sym}";
TotalModifiers.Text = $"{list.Count(r => r.Total != 0)} Mg. / {list.Sum(r => r.Total):N2} {sym}"; TotalModifiers.Text = $"{list.Count(r => r.Total != 0)} Mg. / {list.Sum(r => r.Total):N2} {sym}";
NonDeliveries.Text = $"{list.Count(r => r.Weight == 0):N0}"; NonDeliveries.Text = $"{list.Count(r => r.Weight == 0):N0}";
ControlUtils.RenewItemsSource(MemberInput, await ctx.Members ControlUtils.RenewItemsSource(MemberInput, await ctx.FetchMembers(includeNotActive: true).ToListAsync());
.OrderBy(m => m.Name)
.ThenBy(m => m.GivenName)
.ThenBy(m => m.MgNr)
.ToListAsync());
CustomAmountInput.Unit = sym; CustomAmountInput.Unit = sym;
} }
private async void AutoAdjustBsButton_Click(object sender, RoutedEventArgs evt) { private async void AutoAdjustSharesButton_Click(object sender, RoutedEventArgs evt) {
Mouse.OverrideCursor = Cursors.Wait; Mouse.OverrideCursor = Cursors.Wait;
try { try {
int? kg = AllowanceKgInput.Text == "" ? null : int.Parse(AllowanceKgInput.Text); int? kg = AllowanceKgInput.Text == "" ? null : int.Parse(AllowanceKgInput.Text);
double? bs = AllowanceBsInput.Text == "" ? null : double.Parse(AllowanceBsInput.Text); double? shares = AllowanceShareInput.Text == "" ? null : double.Parse(AllowanceShareInput.Text);
int? kgPerBs = AllowanceKgPerBsInput.Text == "" ? null : int.Parse(AllowanceKgPerBsInput.Text); int? kgPerShare = AllowanceKgPerShareInput.Text == "" ? null : int.Parse(AllowanceKgPerShareInput.Text);
double? percent = AllowancePercentInput.Text == "" ? null : double.Parse(AllowancePercentInput.Text); double? percent = AllowancePercentInput.Text == "" ? null : double.Parse(AllowancePercentInput.Text);
int? minBs = MinBsInput.Text == "" ? null : int.Parse(MinBsInput.Text); int? minShares = MinSharesInput.Text == "" ? null : int.Parse(MinSharesInput.Text);
App.Client.AutoAdjustBs.AllowanceKg = kg; App.Client.AutoAdjustShares.AllowanceKg = kg;
App.Client.AutoAdjustBs.AllowanceBs = bs; App.Client.AutoAdjustShares.AllowanceShares = shares;
App.Client.AutoAdjustBs.AllowanceKgPerBs = kgPerBs; App.Client.AutoAdjustShares.AllowanceKgPerShare = kgPerShare;
App.Client.AutoAdjustBs.AllowancePercent = percent; App.Client.AutoAdjustShares.AllowancePercent = percent;
App.Client.AutoAdjustBs.MinBs = minBs; App.Client.AutoAdjustShares.MinShares = minShares;
await Task.Run(async () => { await Task.Run(async () => {
await App.Client.UpdateValues(); await App.Client.UpdateValues();
var b = new Billing(Year); var b = await Billing.Create(Year);
await b.AutoAdjustBusinessShares(new DateOnly(Year, 11, 30), kg ?? default, bs ?? default, kgPerBs ?? default, percent / 100.0 ?? default, minBs ?? default); await b.AutoAdjustBusinessShares(new DateOnly(Year, 11, 30), kg ?? default, shares ?? default, kgPerShare ?? default, percent / 100.0 ?? default, minShares ?? default);
}); });
App.HintContextChange(); App.HintContextChange();
} catch (Exception exc) { } catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message; InteractionService.ShowDbException("GA Nachzeichnen", exc);
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "GA Nachzeichnen", MessageBoxButton.OK, MessageBoxImage.Error);
} }
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
} }
private async void UnAdjustBsButton_Click(object sender, RoutedEventArgs evt) { private async void UnAdjustSharesButton_Click(object sender, RoutedEventArgs evt) {
Mouse.OverrideCursor = Cursors.Wait; Mouse.OverrideCursor = Cursors.Wait;
try { try {
await Task.Run(async () => { await Task.Run(async () => {
var b = new Billing(Year); var b = await Billing.Create(Year);
await b.UnAdjustBusinessShares(); await b.UnAdjustBusinessShares();
}); });
App.HintContextChange(); App.HintContextChange();
} catch (Exception exc) { } catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message; InteractionService.ShowDbException("GA Nachzeichnen", exc);
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "GA Nachzeichnen", MessageBoxButton.OK, MessageBoxImage.Error);
} }
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
} }
@@ -206,7 +196,7 @@ namespace Elwig.Windows {
Validator.CheckInteger((TextBox)sender, false, 6); Validator.CheckInteger((TextBox)sender, false, 6);
} }
private void BsInput_TextChanged(object sender, TextChangedEventArgs evt) { private void SharesInput_TextChanged(object sender, TextChangedEventArgs evt) {
Validator.CheckInteger((TextBox)sender, false, 3); Validator.CheckInteger((TextBox)sender, false, 3);
} }
@@ -310,9 +300,7 @@ namespace Elwig.Windows {
}); });
App.HintContextChange(); App.HintContextChange();
} catch (Exception exc) { } catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message; InteractionService.ShowDbException("Benutzerdefinierten Zu-/Abschlag speichern", exc);
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Benutzerdefinierten Zu-/Abschlag speichern", MessageBoxButton.OK, MessageBoxImage.Error);
} }
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
} }
+1 -1
View File
@@ -188,7 +188,7 @@
Margin="110,135,10,10" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="110,135,10,10" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Top"
Checked="ConsiderPenaltyInput_Changed" Unchecked="ConsiderPenaltyInput_Changed"/> Checked="ConsiderPenaltyInput_Changed" Unchecked="ConsiderPenaltyInput_Changed"/>
<CheckBox x:Name="ConsiderAutoInput" IsChecked="{Binding ConsiderAuto, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsEnabled="{Binding IsEnabled}" <CheckBox x:Name="ConsiderAutoInput" IsChecked="{Binding ConsiderAuto, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsEnabled="{Binding IsEnabled}"
Content="Automatische Nachzeichnungen der GA" Content="(Automatische) Nachzeichnungen von GA"
Margin="110,155,10,10" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="110,155,10,10" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Top"
Checked="ConsiderAutoInput_Changed" Unchecked="ConsiderAutoInput_Changed"/> Checked="ConsiderAutoInput_Changed" Unchecked="ConsiderAutoInput_Changed"/>
<CheckBox x:Name="ConsiderCustomInput" IsChecked="{Binding ConsiderCustom, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsEnabled="{Binding IsEnabled}" <CheckBox x:Name="ConsiderCustomInput" IsChecked="{Binding ConsiderCustom, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsEnabled="{Binding IsEnabled}"
+13 -27
View File
@@ -48,7 +48,6 @@ namespace Elwig.Windows {
ControlUtils.RenewItemsSource(PaymentVariantList, await ctx.PaymentVariants ControlUtils.RenewItemsSource(PaymentVariantList, await ctx.PaymentVariants
.Where(v => v.Year == Year) .Where(v => v.Year == Year)
.OrderBy(v => v.AvNr) .OrderBy(v => v.AvNr)
.Include(v => v.Season.Currency)
.ToListAsync()); .ToListAsync());
if (PaymentVariantList.SelectedItem == null && PaymentVariantList.Items.Count > 0) { if (PaymentVariantList.SelectedItem == null && PaymentVariantList.Items.Count > 0) {
PaymentVariantList.SelectedIndex = PaymentVariantList.Items.Count - 1; PaymentVariantList.SelectedIndex = PaymentVariantList.Items.Count - 1;
@@ -91,9 +90,7 @@ namespace Elwig.Windows {
App.HintContextChange(); App.HintContextChange();
ControlUtils.SelectItem(PaymentVariantList, v); ControlUtils.SelectItem(PaymentVariantList, v);
} catch (Exception exc) { } catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message; InteractionService.ShowDbException("Auszahlungsvariante erstellen", exc);
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Auszahlungsvariante erstellen", MessageBoxButton.OK, MessageBoxImage.Error);
} }
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
} }
@@ -107,9 +104,7 @@ namespace Elwig.Windows {
App.HintContextChange(); App.HintContextChange();
ControlUtils.SelectItem(PaymentVariantList, n); ControlUtils.SelectItem(PaymentVariantList, n);
} catch (Exception exc) { } catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message; InteractionService.ShowDbException("Auszahlungsvariante kopieren", exc);
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Auszahlungsvariante kopieren", MessageBoxButton.OK, MessageBoxImage.Error);
} }
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
} }
@@ -117,19 +112,14 @@ namespace Elwig.Windows {
private async void DeleteButton_Click(object sender, RoutedEventArgs evt) { private async void DeleteButton_Click(object sender, RoutedEventArgs evt) {
if (PaymentVariantList.SelectedItem is not PaymentVar v || !v.TestVariant) if (PaymentVariantList.SelectedItem is not PaymentVar v || !v.TestVariant)
return; return;
var res = MessageBox.Show( if (!InteractionService.AskContinue("Auszahlungsvariante löschen", $"Soll die Auszahlungsvariante \"{v.Name}\" wirklich unwiderruflich gelöscht werden?"))
$"Soll die Auszahlungsvariante \"{v.Name}\" wirklich unwiderruflich gelöscht werden?",
"Auszahlungsvariante löschen", MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
if (res != MessageBoxResult.OK)
return; return;
Mouse.OverrideCursor = Cursors.Wait; Mouse.OverrideCursor = Cursors.Wait;
try { try {
await PaymentVariantService.DeletePaymentVariant(v.Year, v.AvNr); await PaymentVariantService.DeletePaymentVariant(v.Year, v.AvNr);
App.HintContextChange(); App.HintContextChange();
} catch (Exception exc) { } catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message; InteractionService.ShowDbException("Auszahlungsvariante löschen", exc);
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Auszahlungsvariante löschen", MessageBoxButton.OK, MessageBoxImage.Error);
} }
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
} }
@@ -143,7 +133,7 @@ namespace Elwig.Windows {
await PaymentVariantService.Calculate(v.Year, v.AvNr); await PaymentVariantService.Calculate(v.Year, v.AvNr);
App.HintContextChange(); App.HintContextChange();
} catch (Exception exc) { } catch (Exception exc) {
MessageBox.Show(exc.Message, "Berechnungsfehler", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException("Berechnungsfehler", exc);
} }
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
ViewModel.CalculateIsEnabled = true; ViewModel.CalculateIsEnabled = true;
@@ -205,7 +195,7 @@ namespace Elwig.Windows {
await PaymentVariantService.Commit(v.Year, v.AvNr); await PaymentVariantService.Commit(v.Year, v.AvNr);
App.HintContextChange(); App.HintContextChange();
} catch (Exception exc) { } catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException(exc);
} }
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
ViewModel.RevertIsEnabled = true; ViewModel.RevertIsEnabled = true;
@@ -214,11 +204,9 @@ namespace Elwig.Windows {
private async void RevertButton_Click(object sender, RoutedEventArgs evt) { private async void RevertButton_Click(object sender, RoutedEventArgs evt) {
if (PaymentVariantList.SelectedItem is not PaymentVar v) if (PaymentVariantList.SelectedItem is not PaymentVar v)
return; return;
var res = MessageBox.Show( if (!InteractionService.AskConfirmation("Traubengutschriften löschen",
"Sollen wirklich alle festgesetzten Traubengutschriften der ausgewählten Auszahlungsvariante unwiderruflich gelöscht werden?\n\n" + "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; return;
ViewModel.RevertIsEnabled = false; ViewModel.RevertIsEnabled = false;
Mouse.OverrideCursor = Cursors.Wait; Mouse.OverrideCursor = Cursors.Wait;
@@ -226,7 +214,7 @@ namespace Elwig.Windows {
await PaymentVariantService.Revert(v.Year, v.AvNr); await PaymentVariantService.Revert(v.Year, v.AvNr);
App.HintContextChange(); App.HintContextChange();
} catch (Exception exc) { } catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException(exc);
} }
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
ViewModel.CommitIsEnabled = true; ViewModel.CommitIsEnabled = true;
@@ -236,7 +224,7 @@ namespace Elwig.Windows {
if (PaymentVariantList.SelectedItem is not PaymentVar v) { if (PaymentVariantList.SelectedItem is not PaymentVar v) {
return; return;
} else if (v.TransferDate == null) { } else if (v.TransferDate == null) {
MessageBox.Show("Überweisungsdatum muss gesetzt sein!", "Exportieren nicht möglich", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowError("Exportieren nicht möglich", "Überweisungsdatum muss gesetzt sein!");
return; return;
} }
await PaymentVariantService.GenerateEbics(v.Year, v.AvNr); await PaymentVariantService.GenerateEbics(v.Year, v.AvNr);
@@ -256,13 +244,11 @@ namespace Elwig.Windows {
await ViewModel.UpdatePaymentVariant(v.Year, v.AvNr); await ViewModel.UpdatePaymentVariant(v.Year, v.AvNr);
App.HintContextChange(); App.HintContextChange();
} catch (Exception exc) { } catch (Exception exc) {
await HintContextChange(); await ForceContextReload();
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message; InteractionService.ShowDbException("Auszahlungsvariante aktualisieren", exc);
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Auszahlungsvariante aktualisieren", MessageBoxButton.OK, MessageBoxImage.Error);
} }
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
await HintContextChange(); await EnsureContextRenewed();
CommentInput_TextChanged(null, null); CommentInput_TextChanged(null, null);
DateInput_TextChanged(null, null); DateInput_TextChanged(null, null);
TransferDateInput_TextChanged(null, null); TransferDateInput_TextChanged(null, null);
+7 -12
View File
@@ -1,6 +1,6 @@
using Elwig.Helpers; using Elwig.Helpers;
using Elwig.Helpers.Export; using Elwig.Helpers.Export;
using Microsoft.Win32; using Elwig.Services;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data.Common; using System.Data.Common;
@@ -42,9 +42,9 @@ namespace Elwig.Windows {
Mouse.OverrideCursor = Cursors.Wait; Mouse.OverrideCursor = Cursors.Wait;
await DisplayQuery(QueryInput.Text); await DisplayQuery(QueryInput.Text);
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
} catch (Exception e) { } catch (Exception exc) {
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
MessageBox.Show(e.Message, "Fehler beim Ausführen", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException("Fehler beim Ausführen", exc);
} }
} }
@@ -85,21 +85,16 @@ namespace Elwig.Windows {
} }
private static async Task SaveQuery(string sqlQuery) { private static async Task SaveQuery(string sqlQuery) {
var d = new SaveFileDialog() { var filename = InteractionService.SaveFile("Datenbank Abfrage", "Abfrage", "csv");
FileName = $"Abfrage.csv", if (filename != null) {
DefaultExt = "csv",
Filter = "CSV-Datei (*.csv)|*.csv",
Title = $"Datenbank Abfrage speichern unter - Elwig"
};
if (d.ShowDialog() == true) {
Mouse.OverrideCursor = Cursors.Wait; Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => { await Task.Run(async () => {
try { try {
var (header, rows) = await ExecuteQuery(sqlQuery); var (header, rows) = await ExecuteQuery(sqlQuery);
using var csv = new CsvSimple(d.FileName, ';', Utils.UTF8BOM); using var csv = new CsvSimple(filename, ';', Utils.UTF8BOM);
await csv.ExportAsync(rows.Prepend([.. header.Select(h => h.ColumnName)])); await csv.ExportAsync(rows.Prepend([.. header.Select(h => h.ColumnName)]));
} catch (Exception exc) { } catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler beim Ausführen", MessageBoxButton.OK, MessageBoxImage.Error); InteractionService.ShowException("Fehler beim Ausführen", exc);
} }
}); });
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;

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