Compare commits
68
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9ef630feaa | ||
|
|
34b40535a6 | ||
|
|
3dca099248 | ||
|
|
155a599878 | ||
|
|
fda337c3cb | ||
|
|
d8126e254d | ||
|
|
96441a6701 | ||
|
|
03867bcd74 | ||
|
|
83dfde9203 | ||
|
|
805c5efda8 | ||
|
|
e86edc080a | ||
|
|
0d5d1d4d3d | ||
|
|
ffd3dc9631 | ||
|
|
d592fef352 | ||
|
|
f2b84053e6 | ||
|
|
7fef895491 | ||
|
|
0e9121c462 | ||
|
|
15e191d74e | ||
|
|
abf06c558f | ||
|
|
6436762e8d | ||
|
|
6441fa4f50 | ||
|
|
6bed370eba | ||
|
|
4cc33b56c8 | ||
|
|
f4cc443521 | ||
|
|
8ba051198f | ||
|
|
fea779bd95 | ||
|
|
e66780ccd0 | ||
|
|
cc01f92005 | ||
|
|
0a93167ea7 | ||
|
|
848a6d1ce0 | ||
|
|
f0745eae4e | ||
|
|
8471ac9319 | ||
|
|
7add96dfd5 | ||
|
|
2360402124 | ||
|
|
cadac4302d | ||
|
|
c1690bf104 | ||
|
|
ca5b719630 | ||
|
|
163fe0fac8 | ||
|
|
edf3678154 | ||
|
|
f450dc35b1 | ||
|
|
0c4611024f | ||
|
|
46e596ae23 | ||
|
|
3366cc25eb | ||
|
|
ff71e9fb7f | ||
|
|
7d5d7d9307 | ||
|
|
b468bbce31 | ||
|
|
a79631c586 | ||
|
|
20b6e11b7f | ||
|
|
77e812f5e8 | ||
|
|
58bfb4f56d | ||
|
|
e6e140dc08 | ||
|
|
eaddf0c3cb | ||
|
|
fc5ad82686 | ||
|
|
b76367f73a | ||
|
|
76ea3513ac | ||
|
|
07b197958d | ||
|
|
470c6e09e5 | ||
|
|
20b19775b1 | ||
|
|
f13a836ebd | ||
|
|
2bf926c84c | ||
|
|
a8cc3c9cb9 | ||
|
|
88616b2c0b | ||
|
|
e6712732cd | ||
|
|
cfabf99c99 | ||
|
|
668030fbff | ||
|
|
b445928c4d | ||
|
|
2a3999f300 | ||
|
|
309f118739 |
No files matched your search
@@ -2,7 +2,7 @@ name: Test
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: ["**"]
|
branches: ["**"]
|
||||||
paths: ["Elwig/**", "Tests/**", "Installer/Files/*.exe", ".gitea/workflows/test.yaml"]
|
paths: ["Elwig/**", "Tests/**", ".gitea/workflows/test.yaml"]
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
name: Run tests
|
name: Run tests
|
||||||
|
|||||||
+161
-1
@@ -2,6 +2,166 @@
|
|||||||
Changelog
|
Changelog
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
[v1.1.2.2][v1.1.2.2] (2026-09-14) {#v1.1.2.2}
|
||||||
|
---------------------------------------------
|
||||||
|
|
||||||
|
### Neue Funktionen {#v1.1.2.2-features}
|
||||||
|
|
||||||
|
* Bei einigen Fenstern werden in den Titeln nun die aktiven Filter der Suche angezeigt. (fea779bd95)
|
||||||
|
* Im Lieferungen-Fenster (`DeliveryAdminWindow`) ist es nun möglich die Tara nachträglich zu korrigieren. (8ba051198f, 6436762e8d)
|
||||||
|
|
||||||
|
### Behobene Fehler {#v1.1.2.2-bugfixes}
|
||||||
|
|
||||||
|
* Bei Lieferscheinen (`DeliveryNote`) hat bei Anmerkungen zu Teil-Lfrg. ein `:` gefehlt.
|
||||||
|
Außerdem wurden Seitenumbrüche so platziert, dass sie nicht mehr innerhalb einer Teil-Lfrg. liegen. (e66780ccd0, f4cc443521)
|
||||||
|
|
||||||
|
### Sonstiges {#v1.1.2.2-misc}
|
||||||
|
|
||||||
|
* Bei Datenbank-Fehler sind die Fehlermeldungen nun genauer bzw. auf deutsch übersetzt. (cc01f92005)
|
||||||
|
* Im Mitglieder-Fenster (`MemberAdminWindow`) wurden Überschriften und Tooltips leicht angepasst. (6441fa4f50)
|
||||||
|
* Abhängigkeiten aktualisiert. (4cc33b56c8, 6bed370eba)
|
||||||
|
|
||||||
|
[v1.1.2.2]: https://git.necronda.net/winzer/elwig/releases/tag/v1.1.2.2
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[v1.1.2.1][v1.1.2.1] (2026-08-27) {#v1.1.2.1}
|
||||||
|
---------------------------------------------
|
||||||
|
|
||||||
|
### Behobene Fehler {#v1.1.2.1-bugfixes}
|
||||||
|
|
||||||
|
* Im Anmeldungen-Fenster (`DeliveryAncmtAdminWindow`) und im Leseplanung-Fenster (`DeliveryScheduleAdminWindow`) kam es seit [v1.1.1.2](#v1.1.1.2) (2026-08-25) zu einem Absturz. (f0745eae4e)
|
||||||
|
|
||||||
|
### Sonstiges {#v1.1.2.1-misc}
|
||||||
|
|
||||||
|
* Bei E-Mails wird ab jetzt auch Datum und Uhrzeit gesetzt. (848a6d1ce0)
|
||||||
|
|
||||||
|
[v1.1.2.1]: https://git.necronda.net/winzer/elwig/releases/tag/v1.1.2.1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[v1.1.2.0][v1.1.2.0] (2026-08-26) {#v1.1.2.0}
|
||||||
|
---------------------------------------------
|
||||||
|
|
||||||
|
### Neue Funktionen {#v1.1.2.0-features}
|
||||||
|
|
||||||
|
* Eine Automatische Backup-/Sicherungs-Funktion für die Datenbank wurde hinzugefügt. (ca5b719630, cadac4302d)
|
||||||
|
|
||||||
|
### Behobene Fehler {#v1.1.2.0-bugfixes}
|
||||||
|
|
||||||
|
* Wenn am heutigen Tag noch keine Lieferung übernommen wurde, wurden im Lieferungen-/Übernahme-Fenster (`DeliveryAdminWindow`) mit dem Filter "Nur heute" auch Lieferungen des vorhergehenden Tages angezeigt. (c1690bf104)
|
||||||
|
|
||||||
|
### Sonstiges {#v1.1.2.0-misc}
|
||||||
|
|
||||||
|
* Abhängigkeiten aktualisiert. (2360402124, 7add96dfd5)
|
||||||
|
|
||||||
|
[v1.1.2.0]: https://git.necronda.net/winzer/elwig/releases/tag/v1.1.2.0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[v1.1.1.2][v1.1.1.2] (2026-08-25) {#v1.1.1.2}
|
||||||
|
---------------------------------------------
|
||||||
|
|
||||||
|
### Behobene Fehler {#v1.1.1.2-bugfixes}
|
||||||
|
|
||||||
|
* Auf Lieferscheinen (`DeliveryNote`) waren die Mengenangaben nicht rechtsbündig. (ff71e9fb7f)
|
||||||
|
* Beim Importieren von Mitgliedern mit Stamm-KG ohne Großlage kam es zu einem Fehler, obwohl die Großlage automatisch hätte zugewiesen werden müssen. (edf3678154)
|
||||||
|
|
||||||
|
### Sonstiges {#v1.1.1.2-misc}
|
||||||
|
|
||||||
|
* In Matzen werden für Planenw./Kipper und Lesewagen die Klassen automatisch gesetzt. (3366cc25eb)
|
||||||
|
* Im Lieferungen-Fenster (`DeliveryAdminWindow`) wird für "Nur heute" nicht mehr nur das Datum, sondern die letzten zusammenhängenden Lieferungen verwendet. (46e596ae23)
|
||||||
|
* Für Pamhagen wird als standard Wiege-Methode "brutto" verwendet. (0c4611024f)
|
||||||
|
* Für Waagen kann das automatische setzen von Datum und Uhrzeit nun per Opt-out ausgeschalten werden (Konfigurationsdatei -> `[scale.X]` -> `synctime = false`). (f450dc35b1)
|
||||||
|
|
||||||
|
[v1.1.1.2]: https://git.necronda.net/winzer/elwig/releases/tag/v1.1.1.2
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[v1.1.1.1][v1.1.1.1] (2026-08-24) {#v1.1.1.1}
|
||||||
|
---------------------------------------------
|
||||||
|
|
||||||
|
### Sonstiges {#v1.1.1.1-misc}
|
||||||
|
|
||||||
|
* Beim Export der Flächenbindungen im Haupt-Fenster (`MainWindow`) werden neben der zusammengefassten gebundenen Fläche nun auch die jeweiligen Flächenindungen exportiert. (b468bbce31)
|
||||||
|
|
||||||
|
[v1.1.1.1]: https://git.necronda.net/winzer/elwig/releases/tag/v1.1.1.1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[v1.1.1.0][v1.1.1.0] (2026-08-19) {#v1.1.1.0}
|
||||||
|
---------------------------------------------
|
||||||
|
|
||||||
|
### Sonstiges {#v1.1.1.0-misc}
|
||||||
|
|
||||||
|
* Bei der BKI-Traubentransportscheinliste werden Volllieferanten/Vollablieferer nun auch als solche markiert. (20b6e11b7f)
|
||||||
|
|
||||||
|
[v1.1.1.0]: https://git.necronda.net/winzer/elwig/releases/tag/v1.1.1.0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[v1.1.0.3][v1.1.0.3] (2026-08-17) {#v1.1.0.3}
|
||||||
|
---------------------------------------------
|
||||||
|
|
||||||
|
### Sonstiges {#v1.1.0.3-misc}
|
||||||
|
|
||||||
|
* Beim Drucken mehrerer Kopien einer PDF-Datei wird nun nur mehr ein einzelner Druck-Auftrag verwendet. (fc5ad82686)
|
||||||
|
* Beim Synchronisieren können Geräte als Hauptgerät festgelegt werden. (eaddf0c3cb)
|
||||||
|
* Abhängigkeiten aktualisiert. (e6e140dc08, 58bfb4f56d)
|
||||||
|
|
||||||
|
[v1.1.0.3]: https://git.necronda.net/winzer/elwig/releases/tag/v1.1.0.3
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[v1.1.0.2][v1.1.0.2] (2026-08-11) {#v1.1.0.2}
|
||||||
|
---------------------------------------------
|
||||||
|
|
||||||
|
### Neue Funktionen {#v1.1.0.2-features}
|
||||||
|
|
||||||
|
* Es ist nun möglich zwischen dem Senden von E-Mail einige Sekunden zu warten (Konfigurationsdatei -> `[smtp]` -> `wait = 0.5`). (76ea3513ac)
|
||||||
|
|
||||||
|
### Behobene Fehler {#v1.1.0.2-bugfixes}
|
||||||
|
|
||||||
|
* Beim Drucken von Dokumenten waren die Seitenränder nicht korrekt. (f13a836ebd, 20b19775b1, 470c6e09e5, 07b197958d)
|
||||||
|
|
||||||
|
[v1.1.0.2]: https://git.necronda.net/winzer/elwig/releases/tag/v1.1.0.2
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[v1.1.0.1][v1.1.0.1] (2026-08-05) {#v1.1.0.1}
|
||||||
|
---------------------------------------------
|
||||||
|
|
||||||
|
### Neue Funktionen {#v1.1.0.1-features}
|
||||||
|
|
||||||
|
* Auf Lieferscheinen sind nun Waage und Terminal angegeben. (309f118739)
|
||||||
|
* Beim Starten von Elwig wird Datum/Uhrzeit auf allen angeschlossenen Waagen gesetzt. (2a3999f300)
|
||||||
|
|
||||||
|
### Behobene Fehler {#v1.1.0.1-bugfixes}
|
||||||
|
|
||||||
|
* Im Stammdaten-Fenster (`BaseDataWindow`) war es nach einem Fehler beim Bearbeiten bis zum Schließen des Fensters nicht mehr möglich zu speichern. ([#82][i82])
|
||||||
|
|
||||||
|
### Sonstiges {#v1.1.0.1-misc}
|
||||||
|
|
||||||
|
* Im Auszahlungsvarianten-Fenster (`PaymentVariantsWindow`)...
|
||||||
|
* wurde auf 3 Knöpfen das Symbol "in neuem Fenster öffnen" hinzugefügt. (88616b2c0b)
|
||||||
|
* wird beim "Speichern" die Variante automatisch auch berechnet um Fehler/Missverständnisse zu vermeiden. ([#83][i83])
|
||||||
|
* Abhängigkeiten aktualisiert. (b445928c4d, 668030fbff, a8cc3c9cb9)
|
||||||
|
|
||||||
|
[v1.1.0.1]: https://git.necronda.net/winzer/elwig/releases/tag/v1.1.0.1
|
||||||
|
[i82]: https://git.necronda.net/winzer/elwig/issues/82
|
||||||
|
[i83]: https://git.necronda.net/winzer/elwig/issues/83
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[v1.1.0.0][v1.1.0.0] (2026-07-09) {#v1.1.0.0}
|
[v1.1.0.0][v1.1.0.0] (2026-07-09) {#v1.1.0.0}
|
||||||
---------------------------------------------
|
---------------------------------------------
|
||||||
|
|
||||||
@@ -290,7 +450,7 @@ Changelog
|
|||||||
|
|
||||||
[v1.0.3.0]: https://git.necronda.net/winzer/elwig/releases/tag/v1.0.3.0
|
[v1.0.3.0]: https://git.necronda.net/winzer/elwig/releases/tag/v1.0.3.0
|
||||||
[i50]: https://git.necronda.net/winzer/elwig/issues/50
|
[i50]: https://git.necronda.net/winzer/elwig/issues/50
|
||||||
[i66]: https://git.necronda.net/winzer/elwig/issues/60
|
[i66]: https://git.necronda.net/winzer/elwig/issues/66
|
||||||
[i71]: https://git.necronda.net/winzer/elwig/issues/71
|
[i71]: https://git.necronda.net/winzer/elwig/issues/71
|
||||||
[i73]: https://git.necronda.net/winzer/elwig/issues/73
|
[i73]: https://git.necronda.net/winzer/elwig/issues/73
|
||||||
|
|
||||||
|
|||||||
@@ -16,14 +16,7 @@
|
|||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<dependentAssembly>
|
<dependentAssembly>
|
||||||
<assemblyIdentity
|
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*" />
|
||||||
type="win32"
|
|
||||||
name="Microsoft.Windows.Common-Controls"
|
|
||||||
version="6.0.0.0"
|
|
||||||
processorArchitecture="*"
|
|
||||||
publicKeyToken="6595b64144ccf1df"
|
|
||||||
language="*"
|
|
||||||
/>
|
|
||||||
</dependentAssembly>
|
</dependentAssembly>
|
||||||
</dependency>
|
</dependency>
|
||||||
</assembly>
|
</assembly>
|
||||||
+1
-2
@@ -2,8 +2,7 @@
|
|||||||
x:Class="Elwig.App"
|
x:Class="Elwig.App"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:ctrl="clr-namespace:Elwig.Controls"
|
xmlns:ctrl="clr-namespace:Elwig.Controls">
|
||||||
Exit="Application_Exit">
|
|
||||||
<Application.Resources>
|
<Application.Resources>
|
||||||
<ctrl:BoolToStringConverter x:Key="BoolToStarConverter" FalseValue="" TrueValue="*"/>
|
<ctrl:BoolToStringConverter x:Key="BoolToStarConverter" FalseValue="" TrueValue="*"/>
|
||||||
<ctrl:WidthToMarginConverter x:Key="WidthToMarginConverter"/>
|
<ctrl:WidthToMarginConverter x:Key="WidthToMarginConverter"/>
|
||||||
|
|||||||
+61
-21
@@ -18,16 +18,18 @@ using System.Reflection;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
using System.Windows.Input;
|
||||||
using System.Windows.Threading;
|
using System.Windows.Threading;
|
||||||
|
|
||||||
namespace Elwig {
|
namespace Elwig {
|
||||||
public partial class App : Application {
|
public partial class App : Application {
|
||||||
|
|
||||||
protected static App CurrentApp;
|
public static App CurrentApp;
|
||||||
public static int NumWindows => CurrentApp.Windows.Count;
|
public static int NumWindows => CurrentApp.Windows.Count;
|
||||||
public static bool ForceShutdown { get; private set; } = false;
|
public static bool ForceShutdown { get; set; } = false;
|
||||||
|
|
||||||
private readonly DispatcherTimer _autoUpdateTimer = new() { Interval = TimeSpan.FromHours(1) };
|
private readonly DispatcherTimer _autoUpdateTimer = new() { Interval = TimeSpan.FromHours(1) };
|
||||||
|
private readonly DispatcherTimer _autoBackupTimer = new() { Interval = TimeSpan.FromMinutes(10) };
|
||||||
public readonly SerialPortWatcher SerialPortWatcher = new();
|
public readonly SerialPortWatcher SerialPortWatcher = new();
|
||||||
|
|
||||||
public static readonly string DataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Elwig");
|
public static readonly string DataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Elwig");
|
||||||
@@ -74,7 +76,7 @@ namespace Elwig {
|
|||||||
Config = new(Path.GetFullPath(args[1]));
|
Config = new(Path.GetFullPath(args[1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
ContextTimer.Tick += (object? sender, EventArgs evt) => {
|
ContextTimer.Tick += (sender, evt) => {
|
||||||
var ch = CurrentLastWrite;
|
var ch = CurrentLastWrite;
|
||||||
if (ch > LastChanged) {
|
if (ch > LastChanged) {
|
||||||
LastChanged = ch;
|
LastChanged = ch;
|
||||||
@@ -92,12 +94,16 @@ namespace Elwig {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await AppDbUpdater.CheckDb();
|
await AppDbUpdater.CheckDb();
|
||||||
|
} catch (FileNotFoundException exc) {
|
||||||
|
InteractionService.ShowException("Datenbank nicht gefunden", "Die Datenbank konnte nicht gefunden werden", exc);
|
||||||
} catch (Exception exc) {
|
} catch (Exception exc) {
|
||||||
if (Config.UpdateUrl != null && Utils.HasInternetConnectivity()) {
|
if (Config.UpdateUrl != null && Utils.HasInternetConnectivity()) {
|
||||||
await CheckForUpdates();
|
await CheckForUpdates();
|
||||||
}
|
}
|
||||||
InteractionService.ShowException("Fehlerhafte Datenbank", "Fehlerhafte Datenbank", exc);
|
InteractionService.ShowException("Fehlerhafte Datenbank", "Schwerwiegender Fehler in der Datenbank, unbedingt den Programmierern melden!", exc);
|
||||||
Shutdown();
|
if (InteractionService.AskQuestion("Backup wiederherstellen", "Soll die Datenbank aus einem Backup wiederhergestellt werden?\n\nAchtung: Das kann zu Datenverlust führen!", false))
|
||||||
|
await BackupService.RestoreDatabase();
|
||||||
|
ShutdownNow();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,14 +112,15 @@ 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.FetchBranches()
|
branches = await 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))
|
.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 exc) {
|
} catch (Exception exc) {
|
||||||
InteractionService.ShowException("Fehler", "Fehler beim Laden der Mandantendaten", exc);
|
InteractionService.ShowException("Fehler", "Fehler beim Laden der Mandantendaten, unbedingt den Programmierern melden!", exc);
|
||||||
Shutdown();
|
if (InteractionService.AskQuestion("Backup wiederherstellen", "Soll die Datenbank aus einem Backup wiederhergestellt werden?\n\nAchtung: Das kann zu Datenverlust führen!", false))
|
||||||
|
await BackupService.RestoreDatabase();
|
||||||
|
ShutdownNow();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
BranchNum = branches.Count;
|
BranchNum = branches.Count;
|
||||||
@@ -124,9 +131,23 @@ namespace Elwig {
|
|||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
});
|
});
|
||||||
|
|
||||||
Utils.RunBackground("PDF Initialization", () => Pdf.Init());
|
Utils.RunBackground("PDF Initialization", async () => Pdf.Init());
|
||||||
Utils.RunBackground("JSON Schema Initialization", BillingData.Init);
|
Utils.RunBackground("JSON Schema Initialization", BillingData.Init);
|
||||||
|
|
||||||
|
if (Config.BackupAuto) {
|
||||||
|
Utils.RunBackground("Automatisches Backup", async () => {
|
||||||
|
Directory.CreateDirectory(Config.BackupPath);
|
||||||
|
await Task.Delay(500);
|
||||||
|
await BackupService.TryDatabaseBackup();
|
||||||
|
});
|
||||||
|
_autoBackupTimer.Tick += new EventHandler((sender, evt) => {
|
||||||
|
Utils.RunBackground("Automatisches Backup", async () => {
|
||||||
|
await BackupService.TryDatabaseBackup();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
_autoBackupTimer.Start();
|
||||||
|
}
|
||||||
|
|
||||||
if (Config.UpdateAuto && Config.UpdateUrl != null) {
|
if (Config.UpdateAuto && Config.UpdateUrl != null) {
|
||||||
if (Utils.HasInternetConnectivity()) {
|
if (Utils.HasInternetConnectivity()) {
|
||||||
Utils.RunBackground("Auto Updater", async () => {
|
Utils.RunBackground("Auto Updater", async () => {
|
||||||
@@ -145,7 +166,13 @@ namespace Elwig {
|
|||||||
var list = new List<IScale>();
|
var list = new List<IScale>();
|
||||||
foreach (var s in Config.Scales) {
|
foreach (var s in Config.Scales) {
|
||||||
try {
|
try {
|
||||||
list.Add(Scale.FromConfig(s));
|
var scale = Scale.FromConfig(s);
|
||||||
|
if (s.SyncTime && scale is ICommandScale cmd) {
|
||||||
|
try {
|
||||||
|
await cmd.SetDateAndTime(DateTime.Now);
|
||||||
|
} catch { }
|
||||||
|
}
|
||||||
|
list.Add(scale);
|
||||||
} catch (Exception exc) {
|
} catch (Exception exc) {
|
||||||
list.Add(new InvalidScale(s.Id));
|
list.Add(new InvalidScale(s.Id));
|
||||||
if (s.Required)
|
if (s.Required)
|
||||||
@@ -157,7 +184,7 @@ namespace Elwig {
|
|||||||
if (Config.Branch != null) {
|
if (Config.Branch != null) {
|
||||||
if (!branches.ContainsKey(Config.Branch.ToLower())) {
|
if (!branches.ContainsKey(Config.Branch.ToLower())) {
|
||||||
InteractionService.ShowError("Ungültige Zweigstelle", "Ungültige Zweigstelle in Konfigurationsdatei!");
|
InteractionService.ShowError("Ungültige Zweigstelle", "Ungültige Zweigstelle in Konfigurationsdatei!");
|
||||||
Shutdown();
|
ShutdownNow();
|
||||||
} else {
|
} else {
|
||||||
SetBranch(branches[Config.Branch.ToLower()]);
|
SetBranch(branches[Config.Branch.ToLower()]);
|
||||||
}
|
}
|
||||||
@@ -165,7 +192,7 @@ namespace Elwig {
|
|||||||
SetBranch(branches.First().Value);
|
SetBranch(branches.First().Value);
|
||||||
} else {
|
} else {
|
||||||
InteractionService.ShowError("Ungültige Zweigstelle", "Erkennen der lokalen Zweigstelle nicht möglich!");
|
InteractionService.ShowError("Ungültige Zweigstelle", "Erkennen der lokalen Zweigstelle nicht möglich!");
|
||||||
Shutdown();
|
ShutdownNow();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Config.WeighingMode == null) {
|
if (Config.WeighingMode == null) {
|
||||||
@@ -173,7 +200,7 @@ namespace Elwig {
|
|||||||
Config.WeighingMode = WeighingMode.Net;
|
Config.WeighingMode = WeighingMode.Net;
|
||||||
} else if (Client.IsHaugsdorf || Client.IsSitzendorf) {
|
} else if (Client.IsHaugsdorf || Client.IsSitzendorf) {
|
||||||
Config.WeighingMode = WeighingMode.Box;
|
Config.WeighingMode = WeighingMode.Box;
|
||||||
} else if (Client.IsBaden || Client.IsGrInzersdorf) {
|
} else if (Client.IsBaden || Client.IsGrInzersdorf || Client.IsPamhagen) {
|
||||||
Config.WeighingMode = WeighingMode.Gross;
|
Config.WeighingMode = WeighingMode.Gross;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -184,12 +211,27 @@ namespace Elwig {
|
|||||||
window.Show();
|
window.Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void Application_Exit(object sender, ExitEventArgs evt) {
|
public static void ShutdownNow() {
|
||||||
|
ForceShutdown = true;
|
||||||
|
Current.Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void ShutdownGracefully() {
|
||||||
|
Mouse.OverrideCursor = Cursors.AppStarting;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await BackupService.TryDatabaseBackup();
|
||||||
|
} catch (Exception exc) {
|
||||||
|
InteractionService.ShowException("Automatisches Backup", exc);
|
||||||
|
}
|
||||||
|
|
||||||
SerialPortWatcher.Dispose();
|
SerialPortWatcher.Dispose();
|
||||||
foreach (var s in EventScales) {
|
foreach (var s in EventScales) {
|
||||||
s.Dispose();
|
s.Dispose();
|
||||||
}
|
}
|
||||||
await Pdf.Cleanup();
|
Pdf.Cleanup();
|
||||||
|
|
||||||
|
Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SetBranch(Branch b) {
|
public static void SetBranch(Branch b) {
|
||||||
@@ -300,8 +342,7 @@ namespace Elwig {
|
|||||||
await MainDispatcher.BeginInvoke(() => {
|
await MainDispatcher.BeginInvoke(() => {
|
||||||
var d = new UpdateDialog(latest.Value.Version, latest.Value.Url, latest.Value.Size);
|
var d = new UpdateDialog(latest.Value.Version, latest.Value.Url, latest.Value.Size);
|
||||||
if (d.ShowDialog() == true) {
|
if (d.ShowDialog() == true) {
|
||||||
ForceShutdown = true;
|
ShutdownNow();
|
||||||
Current.Shutdown();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else if (showAlert) {
|
} else if (showAlert) {
|
||||||
@@ -319,8 +360,7 @@ namespace Elwig {
|
|||||||
await Database.Import(filename);
|
await Database.Import(filename);
|
||||||
});
|
});
|
||||||
InteractionService.ShowInformation("Datenbank ersetzen", "Das Ersetzen war erfolgreich!\n\nBitte starten Sie Elwig neu!");
|
InteractionService.ShowInformation("Datenbank ersetzen", "Das Ersetzen war erfolgreich!\n\nBitte starten Sie Elwig neu!");
|
||||||
ForceShutdown = true;
|
ShutdownNow();
|
||||||
Current.Shutdown();
|
|
||||||
} catch (Exception exc) {
|
} catch (Exception exc) {
|
||||||
InteractionService.ShowException("Datenbank ersetzen", "Fehler beim Ersetzen", exc);
|
InteractionService.ShowException("Datenbank ersetzen", "Fehler beim Ersetzen", exc);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:local="clr-namespace:Elwig.Dialogs"
|
xmlns:local="clr-namespace:Elwig.Dialogs"
|
||||||
|
xmlns:ctrl="clr-namespace:Elwig.Controls"
|
||||||
ResizeMode="NoResize" ShowInTaskbar="False" Topmost="True"
|
ResizeMode="NoResize" ShowInTaskbar="False" Topmost="True"
|
||||||
WindowStartupLocation="CenterOwner"
|
WindowStartupLocation="CenterOwner"
|
||||||
FocusManager.FocusedElement="{Binding ElementName=WeightInput}"
|
FocusManager.FocusedElement="{Binding ElementName=WeightInput}"
|
||||||
@@ -37,11 +38,9 @@
|
|||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
<Label Content="Gewicht:" Margin="10,20,10,10"/>
|
<Label Content="Gewicht:" Margin="10,20,10,10"/>
|
||||||
<Grid Grid.Column="1" Width="70" Height="25" Margin="0,20,10,10" HorizontalAlignment="Left" VerticalAlignment="Top">
|
<ctrl:UnitTextBox x:Name="WeightInput" Grid.Column="1" Width="62" Height="25" Unit="kg"
|
||||||
<TextBox x:Name="WeightInput" TextAlignment="Right" Padding="2,2,17,2"
|
Margin="0,20,10,10" HorizontalAlignment="Left" VerticalAlignment="Top" FontSize="14" Padding="2"
|
||||||
TextChanged="WeightInput_TextChanged"/>
|
TextChanged="WeightInput_TextChanged"/>
|
||||||
<Label Content="kg" Margin="0,4,3,0" HorizontalAlignment="Right" FontSize="10" Padding="2,4,2,4"/>
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<Label Content="Grund:" Margin="10,50,10,10"/>
|
<Label Content="Grund:" Margin="10,50,10,10"/>
|
||||||
<TextBox x:Name="ReasonInput" Grid.Column="1" Margin="0,50,10,10"
|
<TextBox x:Name="ReasonInput" Grid.Column="1" Margin="0,50,10,10"
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ using System.Windows.Controls;
|
|||||||
namespace Elwig.Dialogs {
|
namespace Elwig.Dialogs {
|
||||||
public partial class ManualWeighingDialog : Window {
|
public partial class ManualWeighingDialog : Window {
|
||||||
|
|
||||||
public int Weight = 0;
|
public int Weight { get; private set; }
|
||||||
public string? Reason = null;
|
public string? Reason { get; private set; }
|
||||||
|
|
||||||
public ManualWeighingDialog(string? reason = null) {
|
public ManualWeighingDialog(string? reason = null) {
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
<Window x:Class="Elwig.Dialogs.TareCorrectionDialog"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:local="clr-namespace:Elwig.Dialogs"
|
||||||
|
xmlns:ctrl="clr-namespace:Elwig.Controls"
|
||||||
|
ResizeMode="NoResize" ShowInTaskbar="False" Topmost="True"
|
||||||
|
WindowStartupLocation="CenterOwner"
|
||||||
|
FocusManager.FocusedElement="{Binding ElementName=TargetTareInput}"
|
||||||
|
Title="Tara korrigieren" Height="170" Width="300">
|
||||||
|
<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="Button">
|
||||||
|
<Setter Property="HorizontalAlignment" Value="Right"/>
|
||||||
|
<Setter Property="VerticalAlignment" Value="Bottom"/>
|
||||||
|
<Setter Property="Width" Value="100"/>
|
||||||
|
<Setter Property="Height" Value="25"/>
|
||||||
|
</Style>
|
||||||
|
</Window.Resources>
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
<ColumnDefinition Width="70"/>
|
||||||
|
<ColumnDefinition Width="3*"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<Label Content="Ist-Tara:" Margin="10,20,0,10" Grid.Column="1"/>
|
||||||
|
<ctrl:UnitTextBox x:Name="ActualTareInput" Grid.Column="2" Width="56" Height="25" Unit="kg" IsReadOnly="True"
|
||||||
|
Margin="0,20,10,10" HorizontalAlignment="Left" VerticalAlignment="Top" FontSize="14" Padding="2"
|
||||||
|
TextChanged="TareInput_TextChanged"/>
|
||||||
|
|
||||||
|
<Label Content="Soll-Tara:" Margin="10,50,0,10" Grid.Column="1"/>
|
||||||
|
<ctrl:UnitTextBox x:Name="TargetTareInput" Grid.Column="2" Width="56" Height="25" Unit="kg"
|
||||||
|
Margin="0,50,10,10" HorizontalAlignment="Left" VerticalAlignment="Top" FontSize="14" Padding="2"
|
||||||
|
TextChanged="TareInput_TextChanged"/>
|
||||||
|
|
||||||
|
<Button x:Name="ConfirmButton" Content="Bestätigen" Margin="10,10,115,10" Grid.ColumnSpan="3" IsEnabled="False" IsDefault="True"
|
||||||
|
Click="ConfirmButton_Click"/>
|
||||||
|
<Button x:Name="CancelButton" Content="Abbrechen" Margin="10,10,10,10" Grid.ColumnSpan="3" IsCancel="True"/>
|
||||||
|
</Grid>
|
||||||
|
</Window>
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
using Elwig.Helpers;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
|
||||||
|
namespace Elwig.Dialogs {
|
||||||
|
public partial class TareCorrectionDialog : Window {
|
||||||
|
|
||||||
|
public int ActualTare { get; private set; }
|
||||||
|
public int TargetTare { get; private set; }
|
||||||
|
|
||||||
|
public TareCorrectionDialog(int? actualTare, int? targetTare = null) {
|
||||||
|
InitializeComponent();
|
||||||
|
ActualTare = actualTare ?? 0;
|
||||||
|
TargetTare = targetTare ?? actualTare ?? 0;
|
||||||
|
ActualTareInput.IsReadOnly = actualTare != null;
|
||||||
|
ActualTareInput.Text = ActualTare.ToString();
|
||||||
|
TargetTareInput.Text = TargetTare.ToString();
|
||||||
|
TargetTareInput.SelectAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ConfirmButton_Click(object sender, RoutedEventArgs evt) {
|
||||||
|
DialogResult = true;
|
||||||
|
ActualTare = int.Parse(ActualTareInput.Text);
|
||||||
|
TargetTare = int.Parse(TargetTareInput.Text);
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateButtons() {
|
||||||
|
ConfirmButton.IsEnabled = ActualTareInput.Text.Length > 0 && TargetTareInput.Text.Length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TareInput_TextChanged(object sender, TextChangedEventArgs evt) {
|
||||||
|
if (sender is not TextBox b) return;
|
||||||
|
Validator.CheckInteger(b, true, 4);
|
||||||
|
UpdateButtons();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,23 +30,27 @@ namespace Elwig.Documents {
|
|||||||
get {
|
get {
|
||||||
IAddress addr = (Member.BillingAddress != null && UseBillingAddress) ? Member.BillingAddress : Member;
|
IAddress addr = (Member.BillingAddress != null && UseBillingAddress) ? Member.BillingAddress : Member;
|
||||||
var plz = addr.PostalDest.AtPlz;
|
var plz = addr.PostalDest.AtPlz;
|
||||||
return string.Join("\n", ((string?[])[Member.BillingAddress?.FullName, Member.AdministrativeName, Member.ForTheAttentionOf, addr.Address, $"{plz?.Plz} {plz?.Ort.Name.Split(",")[0]}", addr.PostalDest.Country.Name]).Where(s => !string.IsNullOrWhiteSpace(s)));
|
return string.Join("\n", ((string?[])[addr is BillingAddr ? addr.FullName : null, Member.AdministrativeName, Member.ForTheAttentionOf, addr.Address, $"{plz?.Plz} {plz?.Ort.Name.Split(",")[0]}", addr.PostalDest.Country.Name]).Where(s => !string.IsNullOrWhiteSpace(s)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Cell NewAsideCell(Paragraph text, int colspan = 1, bool isName = false) {
|
protected Cell NewAsideCell(Paragraph text, int colspan = 1, bool isName = false, bool right = false, bool center = false) {
|
||||||
var cell = NewCell(text, colspan: colspan).SetPaddingsMM(0.25f, 0.5f, 0.25f, isName ? 1 : 0);
|
var cell = NewCell(text, colspan: colspan).SetPaddingsMM(0.25f, center ? 0 : right ? 1 : 0.5f, 0.25f, isName ? 1 : 0);
|
||||||
if (colspan > 1) {
|
if (colspan == 26) {
|
||||||
cell.SetTextAlignment(TextAlignment.CENTER).SetFont(BF)
|
cell.SetTextAlignment(TextAlignment.CENTER).SetFont(BF)
|
||||||
.SetBackgroundColor(new DeviceRgb(0xe0, 0xe0, 0xe0))
|
.SetBackgroundColor(new DeviceRgb(0xe0, 0xe0, 0xe0))
|
||||||
.SetBorderTop(new SolidBorder(new DeviceRgb(0x80, 0x80, 0x80), BorderThickness))
|
.SetBorderTop(new SolidBorder(new DeviceRgb(0x80, 0x80, 0x80), BorderThickness))
|
||||||
.SetPaddingsMM(0.5f, 1, 0.5f, 1);
|
.SetPaddingsMM(0.5f, 1, 0.5f, 1);
|
||||||
|
} else if (isName) {
|
||||||
|
cell.SetBorderLeft(new SolidBorder(new DeviceRgb(0x80, 0x80, 0x80), BorderThickness));
|
||||||
}
|
}
|
||||||
|
if (right) cell.SetTextAlignment(TextAlignment.RIGHT);
|
||||||
|
if (center) cell.SetTextAlignment(TextAlignment.CENTER);
|
||||||
return cell;
|
return cell;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Cell NewAsideCell(string text, int colspan = 1, bool isName = false) {
|
protected Cell NewAsideCell(string text, int colspan = 1, bool isName = false, bool right = false, bool center = false) {
|
||||||
return NewAsideCell(new KernedParagraph(text, 10), colspan, isName);
|
return NewAsideCell(new KernedParagraph(text, 10), colspan, isName, right, center);
|
||||||
}
|
}
|
||||||
|
|
||||||
public BusinessDocument(string title, Member m, DateOnly? dateFrom, bool includeSender = false) :
|
public BusinessDocument(string title, Member m, DateOnly? dateFrom, bool includeSender = false) :
|
||||||
@@ -60,16 +64,27 @@ namespace Elwig.Documents {
|
|||||||
|
|
||||||
protected override void BeforeRenderBody(iText.Layout.Document doc, PdfDocument pdf) {
|
protected override void BeforeRenderBody(iText.Layout.Document doc, PdfDocument pdf) {
|
||||||
base.BeforeRenderBody(doc, pdf);
|
base.BeforeRenderBody(doc, pdf);
|
||||||
var uid = new KernedParagraph(Member.UstIdNr ?? "-", 10);
|
Aside = new Table(ColsMM(2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5))
|
||||||
if (!Member.IsBuchführend) uid.Add(Normal(" ")).Add(Italic("(pauschaliert)"));
|
.SetWidth(UnitValue.CreatePointValue(65 * PtInMM)).SetFixedLayout()
|
||||||
Aside = new Table(ColsMM(22.5, 42.5))
|
|
||||||
.SetFont(NF).SetFontSize(10)
|
|
||||||
.SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE)
|
.SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE)
|
||||||
|
.SetFont(NF).SetFontSize(10)
|
||||||
.SetBorder(new SolidBorder(new DeviceRgb(0x80, 0x80, 0x80), BorderThickness))
|
.SetBorder(new SolidBorder(new DeviceRgb(0x80, 0x80, 0x80), BorderThickness))
|
||||||
.AddCell(NewAsideCell("Mitglied", 2))
|
.AddCell(NewAsideCell("Mitglied", 26));
|
||||||
.AddCell(NewAsideCell("Mitglieds-Nr.:", isName: true)).AddCell(NewAsideCell($"{Member.MgNr}"))
|
if (Member.IsOrganic) {
|
||||||
.AddCell(NewAsideCell("Betriebs-Nr.:", isName: true)).AddCell(NewAsideCell(Member.LfbisNr ?? ""))
|
Aside
|
||||||
.AddCell(NewAsideCell("UID:", isName: true)).AddCell(NewAsideCell(uid));
|
.AddCell(NewAsideCell("Mitgl.-Nr.:", 8, isName: true)).AddCell(NewAsideCell($"{Member.MgNr}", 4, right: true))
|
||||||
|
.AddCell(NewAsideCell("Bio-KSt.:", 6, isName: true)).AddCell(NewAsideCell(Member.OrganicAuthorityCode ?? "-", 8, right: true, center: Member.OrganicAuthorityCode == null))
|
||||||
|
.AddCell(NewAsideCell("Betr.-Nr.:", 6, isName: true)).AddCell(NewAsideCell(Member.LfbisNr ?? "-", 6, right: true, center: Member.LfbisNr == null))
|
||||||
|
.AddCell(NewAsideCell("OOC-ID:", 6, isName: true)).AddCell(NewAsideCell(Member.OrganicOperatorId ?? "-", 8, right: true, center: Member.OrganicOperatorId == null))
|
||||||
|
.AddCell(NewAsideCell("UID:", 6, isName: true)).AddCell(NewAsideCell(Member.UstIdNr ?? "-", 10, right: true, center: Member.UstIdNr == null))
|
||||||
|
.AddCell(NewAsideCell(new KernedParagraph("", 10).Add(Italic(Member.IsBuchführend ? "(buchführend)" : "(pauschaliert)")), 10, center: true));
|
||||||
|
} else {
|
||||||
|
Aside
|
||||||
|
.AddCell(NewAsideCell("Mitglieds-Nr.:", 12, isName: true)).AddCell(NewAsideCell($"{Member.MgNr}", 4, right: true)).AddCell(NewAsideCell("", 10))
|
||||||
|
.AddCell(NewAsideCell("Betriebs-Nr.:", 10, isName: true)).AddCell(NewAsideCell(Member.LfbisNr ?? "-", 6, right: true, center: Member.LfbisNr == null)).AddCell(NewAsideCell("", 10))
|
||||||
|
.AddCell(NewAsideCell("UID:", 6, isName: true)).AddCell(NewAsideCell(Member.UstIdNr ?? "-", 10, right: true, center: Member.UstIdNr == null))
|
||||||
|
.AddCell(NewAsideCell(new KernedParagraph("", 10).Add(Italic(Member.IsBuchführend ? "(buchführend)" : "(pauschaliert)")), 10, center: true));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void RenderAddress(Canvas canvas, Rectangle pageSize) {
|
protected void RenderAddress(Canvas canvas, Rectangle pageSize) {
|
||||||
@@ -122,11 +137,15 @@ namespace Elwig.Documents {
|
|||||||
return new KernedParagraph(10)
|
return new KernedParagraph(10)
|
||||||
.AddAll(Utils.GenerateFooter("\n", " \u00b7 ")
|
.AddAll(Utils.GenerateFooter("\n", " \u00b7 ")
|
||||||
.Item(c.NameFull).NextLine()
|
.Item(c.NameFull).NextLine()
|
||||||
.Item(c.Address).Item($"{c.Plz} {c.Ort}").Item("Österreich").Item("Tel.", c.PhoneNr).Item("Fax", c.FaxNr).NextLine()
|
.Item(c.Address).Item($"{c.Plz} {c.Ort}").Item("Österreich").NextGroup()
|
||||||
.Item(c.EmailAddress != null ? link1 : null)
|
.Item("Tel.", c.PhoneNr).Item("Fax", c.FaxNr).NextGroup()
|
||||||
.Item(c.Website != null ? link2 : null)
|
.Item(c.EmailAddress != null ? link1 : null).NextLine()
|
||||||
.Item("Betriebs-Nr.", c.LfbisNr).Item("Bio-KSt.", c.OrganicAuthority).NextLine()
|
.Item(c.Website != null ? link2 : null).NextGroup()
|
||||||
|
.Item("Betriebs-Nr.", c.LfbisNr).NextGroup()
|
||||||
|
.Item("Bio-KSt.", c.OrganicAuthorityCode).NextGroup()
|
||||||
|
.Item("OOC-ID", c.OrganicOperatorId).NextLine()
|
||||||
.Item("UID", c.UstIdNr).Item("BIC", c.Bic).Item("IBAN", c.Iban)
|
.Item("UID", c.UstIdNr).Item("BIC", c.Bic).Item("IBAN", c.Iban)
|
||||||
|
.RebalanceLines()
|
||||||
.ToLeafElements());
|
.ToLeafElements());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -125,10 +125,10 @@ namespace Elwig.Documents {
|
|||||||
|
|
||||||
protected override void BeforeRenderBody(iText.Layout.Document doc, PdfDocument pdf) {
|
protected override void BeforeRenderBody(iText.Layout.Document doc, PdfDocument pdf) {
|
||||||
base.BeforeRenderBody(doc, pdf);
|
base.BeforeRenderBody(doc, pdf);
|
||||||
Aside?.AddCell(NewAsideCell("Gutschrift", 2))
|
Aside?.AddCell(NewAsideCell("Gutschrift", 26))
|
||||||
.AddCell(NewAsideCell("TG-Nr.:", isName: true)).AddCell(NewAsideCell(Payment?.Credit != null ? $"{Payment.Credit.Year}/{Payment.Credit.TgNr:000}" : "-"))
|
.AddCell(NewAsideCell("Tr.-Gutschr.-Nr.:", 12, isName: true)).AddCell(NewAsideCell(Payment?.Credit != null ? $"{Payment.Credit.Year}/{Payment.Credit.TgNr:000}" : "-", 14))
|
||||||
.AddCell(NewAsideCell("Datum:", isName: true)).AddCell(NewAsideCell($"{Payment?.Variant.Date:dd.MM.yyyy}"))
|
.AddCell(NewAsideCell("Datum:", 12, isName: true)).AddCell(NewAsideCell($"{Payment?.Variant.Date:dd.MM.yyyy}", 14))
|
||||||
.AddCell(NewAsideCell("Überw. am:", isName: true)).AddCell(NewAsideCell($"{Payment?.Variant.TransferDate:dd.MM.yyyy}"));
|
.AddCell(NewAsideCell("Überwiesen am:", 12, isName: true)).AddCell(NewAsideCell($"{Payment?.Variant.TransferDate:dd.MM.yyyy}", 14));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void RenderBody(iText.Layout.Document doc, PdfDocument pdf) {
|
protected override void RenderBody(iText.Layout.Document doc, PdfDocument pdf) {
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ namespace Elwig.Documents {
|
|||||||
_year = year;
|
_year = year;
|
||||||
ShowDateAndLocation = true;
|
ShowDateAndLocation = true;
|
||||||
UseBillingAddress = true;
|
UseBillingAddress = true;
|
||||||
DocumentId = $"Anl.-Best. {_year}/{m.MgNr}";
|
DocumentId = $"Anlfrg.-Bstng. {_year}/{m.MgNr}";
|
||||||
Data = data;
|
Data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,10 +55,10 @@ namespace Elwig.Documents {
|
|||||||
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;
|
||||||
Aside?.AddCell(NewAsideCell("Saison", 2))
|
Aside?.AddCell(NewAsideCell("Saison", 26))
|
||||||
.AddCell(NewAsideCell("Lieferungen:", isName: true)).AddCell(NewAsideCell($"{Data.Rows.DistinctBy(r => r.LsNr).Count():N0} (Teil-Lfrg.: {Data.RowNum:N0})"))
|
.AddCell(NewAsideCell("Lieferungen:", 12, isName: true)).AddCell(NewAsideCell($"{Data.Rows.DistinctBy(r => r.LsNr).Count():N0} (Teil-Lfrg.: {Data.RowNum:N0})", 14))
|
||||||
.AddCell(NewAsideCell("Zeitraum:", isName: true)).AddCell(NewAsideCell(firstDay == null || lastDay == null ? "-" : firstDay == lastDay ? $"{firstDay:dd.MM.} (1 Tag)" : $"{firstDay:dd.MM.}\u2013{lastDay:dd.MM.} ({lastDay?.DayNumber - firstDay?.DayNumber + 1:N0} Tage)"))
|
.AddCell(NewAsideCell("Zeitraum:", 8, isName: true)).AddCell(NewAsideCell(firstDay == null || lastDay == null ? "-" : firstDay == lastDay ? $"{firstDay:dd.MM.} (1 Tag)" : $"{firstDay:dd.MM.}\u2013{lastDay:dd.MM.} ({lastDay?.DayNumber - firstDay?.DayNumber + 1:N0} Tage)", 18, center: true))
|
||||||
.AddCell(NewAsideCell("Menge:", isName: true)).AddCell(NewAsideCell($"{MemberStats.Sum(s => s.Weight):N0} kg"));
|
.AddCell(NewAsideCell("Menge:", 12, isName: true)).AddCell(NewAsideCell($"{MemberStats.Sum(s => s.Weight):N0} kg", 14));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void RenderBody(iText.Layout.Document doc, PdfDocument pdf) {
|
protected override void RenderBody(iText.Layout.Document doc, PdfDocument pdf) {
|
||||||
|
|||||||
@@ -72,10 +72,10 @@ namespace Elwig.Documents {
|
|||||||
|
|
||||||
protected override void BeforeRenderBody(iText.Layout.Document doc, PdfDocument pdf) {
|
protected override void BeforeRenderBody(iText.Layout.Document doc, PdfDocument pdf) {
|
||||||
base.BeforeRenderBody(doc, pdf);
|
base.BeforeRenderBody(doc, pdf);
|
||||||
Aside?.AddCell(NewAsideCell("Lieferung", 2))
|
Aside?.AddCell(NewAsideCell("Lieferung", 26))
|
||||||
.AddCell(NewAsideCell("LS-Nr.:", isName: true)).AddCell(NewAsideCell(Delivery.LsNr))
|
.AddCell(NewAsideCell("Lieferschein-Nr.:", 12, isName: true)).AddCell(NewAsideCell(Delivery.LsNr, 14))
|
||||||
.AddCell(NewAsideCell("Datum/Zeit:", isName: true)).AddCell(NewAsideCell($"{Delivery.Date:dd.MM.yyyy} / {Delivery.Time:HH:mm}"))
|
.AddCell(NewAsideCell("Datum/Zeit:", 12, isName: true)).AddCell(NewAsideCell($"{Delivery.Date:dd.MM.yyyy} / {Delivery.Time:HH:mm}", 14))
|
||||||
.AddCell(NewAsideCell("Zweigstelle:", isName: true)).AddCell(NewAsideCell(Delivery.Branch.Name));
|
.AddCell(NewAsideCell("Zweigstelle:", 12, isName: true)).AddCell(NewAsideCell(Delivery.Branch.Name, 14));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void RenderBody(iText.Layout.Document doc, PdfDocument pdf) {
|
protected override void RenderBody(iText.Layout.Document doc, PdfDocument pdf) {
|
||||||
@@ -121,7 +121,7 @@ namespace Elwig.Documents {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected Table NewDeliveryTable() {
|
protected Table NewDeliveryTable() {
|
||||||
var tbl = new Table(ColsMM(10, 21, 25, 19.5, 19.5, 30, 12.5, 12.5, 15), true)
|
var tbl = new Table(ColsMM(10, 21, 25, 20, 20, 30, 12.5, 12.5, 14), true)
|
||||||
.SetWidth(UnitValue.CreatePercentValue(100)).SetFixedLayout()
|
.SetWidth(UnitValue.CreatePercentValue(100)).SetFixedLayout()
|
||||||
.SetBorder(Border.NO_BORDER).SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE);
|
.SetBorder(Border.NO_BORDER).SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE);
|
||||||
|
|
||||||
@@ -130,15 +130,16 @@ namespace Elwig.Documents {
|
|||||||
.AddHeaderCell(NewTh("Attribut", colspan: 2, rowspan: 2, left: true))
|
.AddHeaderCell(NewTh("Attribut", colspan: 2, rowspan: 2, left: true))
|
||||||
.AddHeaderCell(NewTh("Qualitätsstufe", rowspan: 2, left: true))
|
.AddHeaderCell(NewTh("Qualitätsstufe", rowspan: 2, left: true))
|
||||||
.AddHeaderCell(NewTh("Gradation", colspan: 2))
|
.AddHeaderCell(NewTh("Gradation", colspan: 2))
|
||||||
.AddHeaderCell(NewTh("Menge"))
|
.AddHeaderCell(NewTh("Menge").SetPaddingRight(0))
|
||||||
.AddHeaderCell(NewTh("[°Oe]", 8))
|
.AddHeaderCell(NewTh("[°Oe]", 8))
|
||||||
.AddHeaderCell(NewTh("[°KMW]", 8))
|
.AddHeaderCell(NewTh("[°KMW]", 8))
|
||||||
.AddHeaderCell(NewTh("[kg]", 8));
|
.AddHeaderCell(NewTh("[kg]", 8).SetPaddingRight(0));
|
||||||
|
|
||||||
foreach (var part in Delivery.Parts.OrderBy(p => p.DPNr)) {
|
foreach (var part in Delivery.Parts.OrderBy(p => p.DPNr)) {
|
||||||
var sub = new Table(ColsMM(10, 21, 25, 19.5, 19.5, 30, 12.5, 12.5, 15), true)
|
var sub = new Table(ColsMM(10, 21, 25, 20, 20, 30, 12.5, 12.5, 14), true)
|
||||||
.SetWidth(UnitValue.CreatePercentValue(100)).SetFixedLayout()
|
.SetWidth(UnitValue.CreatePercentValue(100)).SetFixedLayout()
|
||||||
.SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE);
|
.SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE)
|
||||||
|
.SetKeepTogether(true);
|
||||||
|
|
||||||
int rowspan = 1 + (part.Cultivation != null ? 1 : 0) + 1 + part.Modifiers.Count() + 1 + (part.Comment != null ? 1 : 0) + (part.Temperature != null || part.Acid != null ? 1 : 0);
|
int rowspan = 1 + (part.Cultivation != null ? 1 : 0) + 1 + part.Modifiers.Count() + 1 + (part.Comment != null ? 1 : 0) + (part.Temperature != null || part.Acid != null ? 1 : 0);
|
||||||
sub.AddCell(NewDeliveryMainTd($"{part.DPNr:N0}", center: true))
|
sub.AddCell(NewDeliveryMainTd($"{part.DPNr:N0}", center: true))
|
||||||
@@ -147,11 +148,14 @@ namespace Elwig.Documents {
|
|||||||
.AddCell(NewDeliveryMainTd(part.Quality.Name))
|
.AddCell(NewDeliveryMainTd(part.Quality.Name))
|
||||||
.AddCell(NewDeliveryMainTd($"{part.Oe:N0}", center: true))
|
.AddCell(NewDeliveryMainTd($"{part.Oe:N0}", center: true))
|
||||||
.AddCell(NewDeliveryMainTd($"{part.Kmw:N1}", center: true))
|
.AddCell(NewDeliveryMainTd($"{part.Kmw:N1}", center: true))
|
||||||
.AddCell(NewDeliveryMainTd($"{part.Weight:N0}", center: true));
|
.AddCell(NewDeliveryMainTd($"{part.Weight:N0}", right: true).SetPaddingRight(0));
|
||||||
|
|
||||||
if (part.Cultivation != null) {
|
if (part.Cultivation != null) {
|
||||||
var cult = new KernedParagraph(8);
|
var cult = new KernedParagraph(8);
|
||||||
cult.Add(Italic("Bewirtschaftung:")).Add(Normal(" " + part.Cultivation.Name + (part.Cultivation.Description != null ? $" ({part.Cultivation.Description})" : "")));
|
cult.Add(Italic("Bewirtschaftung:")).Add(Normal(" " + part.Cultivation.Name + (part.Cultivation.Description != null ? $" ({part.Cultivation.Description})" : "")));
|
||||||
|
if (part.Cultivation.IsOrganic) {
|
||||||
|
cult.Add(" \u2013 ").Add(Italic("Kontrollstelle:")).Add(Normal($" {Member.OrganicAuthorityCode ?? "?"}"));
|
||||||
|
}
|
||||||
sub.AddCell(NewTd())
|
sub.AddCell(NewTd())
|
||||||
.AddCell(NewTd(cult, colspan: 5))
|
.AddCell(NewTd(cult, colspan: 5))
|
||||||
.AddCell(NewTd(colspan: 3));
|
.AddCell(NewTd(colspan: 3));
|
||||||
@@ -181,8 +185,8 @@ namespace Elwig.Documents {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var info = part.WeighingInfo;
|
var info = part.WeighingInfo;
|
||||||
weighing.Add(Italic("Waage:"))
|
weighing.Add(Italic("Waage/Terminal:"))
|
||||||
.Add(Normal(" " + (part.ScaleId ?? "?") + ", "))
|
.Add(Normal(" " + (info.ScaleId ?? "?") + "/" + (part.ScaleTerminalId ?? "?") + ", "))
|
||||||
.Add(Italic("ID:"))
|
.Add(Italic("ID:"))
|
||||||
.Add(Normal(" " + (info.Id ?? "?")));
|
.Add(Normal(" " + (info.Id ?? "?")));
|
||||||
if (info.Date != null || info.Time != null)
|
if (info.Date != null || info.Time != null)
|
||||||
@@ -196,9 +200,17 @@ namespace Elwig.Documents {
|
|||||||
.Add(Italic("Brutto:"))
|
.Add(Italic("Brutto:"))
|
||||||
.Add(Normal($" {info.Gross:N0} kg \u2013 "))
|
.Add(Normal($" {info.Gross:N0} kg \u2013 "))
|
||||||
.Add(Italic("Tara:"))
|
.Add(Italic("Tara:"))
|
||||||
.Add(Normal($" {info.Tare:N0} kg \u2013 "))
|
.Add(Normal($" {info.Tare:N0} kg "));
|
||||||
|
if (info.TareCorrection != null && info.TareCorrection != 0)
|
||||||
|
weighing.Add(Bold($"(Korr.: {Utils.GetSign(info.TareCorrection.Value)}{Math.Abs(info.TareCorrection.Value)} kg)")).Add(" ");
|
||||||
|
weighing
|
||||||
|
.Add(Normal("\u2013 "))
|
||||||
.Add(Italic("Netto:"))
|
.Add(Italic("Netto:"))
|
||||||
.Add(Normal($" {info.Net:N0} kg \u2013 "))
|
.Add(Normal($" {info.Net:N0} kg "));
|
||||||
|
if (info.TareCorrection != null && info.TareCorrection != 0)
|
||||||
|
weighing.Add(Normal($"({Utils.GetSign(-info.TareCorrection.Value)}{Math.Abs(info.TareCorrection.Value)} kg) "));
|
||||||
|
weighing
|
||||||
|
.Add(Normal("\u2013 "))
|
||||||
.Add(Italic(part.IsNetWeight ? "gerebelt gewogen" : "nicht gerebelt gewogen"));
|
.Add(Italic(part.IsNetWeight ? "gerebelt gewogen" : "nicht gerebelt gewogen"));
|
||||||
} else {
|
} else {
|
||||||
weighing.Add(" ")
|
weighing.Add(" ")
|
||||||
@@ -210,7 +222,7 @@ namespace Elwig.Documents {
|
|||||||
.AddCell(NewCell(colspan: 3));
|
.AddCell(NewCell(colspan: 3));
|
||||||
if (part.Comment != null) {
|
if (part.Comment != null) {
|
||||||
sub.AddCell(NewCell())
|
sub.AddCell(NewCell())
|
||||||
.AddCell(NewCell(new KernedParagraph(8).Add(Italic("Anmerkung")).Add(Normal(" " + part.Comment)), colspan: 5))
|
.AddCell(NewCell(new KernedParagraph(8).Add(Italic("Anmerkung:")).Add(Normal(" " + part.Comment)), colspan: 5))
|
||||||
.AddCell(NewCell(colspan: 3));
|
.AddCell(NewCell(colspan: 3));
|
||||||
}
|
}
|
||||||
if (part.Temperature != null || part.Acid != null) {
|
if (part.Temperature != null || part.Acid != null) {
|
||||||
@@ -220,7 +232,7 @@ namespace Elwig.Documents {
|
|||||||
if (part.Temperature != null && part.Acid != null)
|
if (part.Temperature != null && part.Acid != null)
|
||||||
p.Add(Normal(", "));
|
p.Add(Normal(", "));
|
||||||
if (part.Acid != null)
|
if (part.Acid != null)
|
||||||
p.Add(Italic("Säure")).Add(Normal($" {part.Acid:N1} g/l"));
|
p.Add(Italic("Säure:")).Add(Normal($" {part.Acid:N1} g/l"));
|
||||||
sub.AddCell(NewCell())
|
sub.AddCell(NewCell())
|
||||||
.AddCell(NewCell(p, colspan: 5))
|
.AddCell(NewCell(p, colspan: 5))
|
||||||
.AddCell(NewCell(colspan: 3));
|
.AddCell(NewCell(colspan: 3));
|
||||||
@@ -229,10 +241,10 @@ namespace Elwig.Documents {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Delivery.Parts.Count > 1) {
|
if (Delivery.Parts.Count > 1) {
|
||||||
tbl.AddCell(NewTd("Gesamt:", 12, bold: true, borderTop: true, colspan: 6).SetPaddingsMM(1, 1, 1, 1))
|
tbl.AddCell(NewTd("Gesamt:", 12, bold: true, borderTop: true, colspan: 6).SetPaddingsMM(1, 1, 1, 0))
|
||||||
.AddCell(NewTd($"{Delivery.Oe:N0}", 12, bold: true, center: true, borderTop: true).SetPaddingsMM(1, 1, 1, 1))
|
.AddCell(NewTd($"{Delivery.Oe:N0}", 12, bold: true, center: true, borderTop: true).SetPaddingsMM(1, 1, 1, 1))
|
||||||
.AddCell(NewTd($"{Delivery.Kmw:N1}", 12, bold: true, center: true, borderTop: true).SetPaddingsMM(1, 1, 1, 1))
|
.AddCell(NewTd($"{Delivery.Kmw:N1}", 12, bold: true, center: true, borderTop: true).SetPaddingsMM(1, 1, 1, 1))
|
||||||
.AddCell(NewTd($"{Delivery.Weight:N0}", 12, bold: true, right: true, borderTop: true).SetPaddingsMM(1, 1, 1, 1));
|
.AddCell(NewTd($"{Delivery.Weight:N0}", 12, bold: true, right: true, borderTop: true).SetPaddingsMM(1, 0, 1, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
return tbl;
|
return tbl;
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ namespace Elwig.Documents {
|
|||||||
public Document(string title) {
|
public Document(string title) {
|
||||||
Title = title;
|
Title = title;
|
||||||
Author = App.Client.NameFull;
|
Author = App.Client.NameFull;
|
||||||
Date = DateOnly.FromDateTime(Utils.Today);
|
Date = DateOnly.FromDateTime(DateTime.Today);
|
||||||
}
|
}
|
||||||
|
|
||||||
~Document() {
|
~Document() {
|
||||||
@@ -252,7 +252,7 @@ namespace Elwig.Documents {
|
|||||||
|
|
||||||
public async Task Print(int copies = 1) {
|
public async Task Print(int copies = 1) {
|
||||||
if (PdfPath == null) throw new InvalidOperationException("Pdf file has not been generated yet");
|
if (PdfPath == null) throw new InvalidOperationException("Pdf file has not been generated yet");
|
||||||
await Pdf.Print(PdfPath, copies, IsDoublePaged);
|
Pdf.Print(PdfPath, copies, IsDoublePaged);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Show() {
|
public void Show() {
|
||||||
|
|||||||
@@ -161,7 +161,8 @@ namespace Elwig.Documents {
|
|||||||
.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(new KernedParagraph(Member.IsOrganic ? "Ja" : "Nein", 10)
|
||||||
|
.Add(Normal(Member.OrganicAuthorityCode != null || Member.OrganicOperatorId != null ? $" ({Member.OrganicAuthorityCode}{(Member.OrganicAuthorityCode != null && Member.OrganicOperatorId != null ? ", " : "")}{Member.OrganicOperatorId})" : "", 8)), 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))))
|
||||||
|
|||||||
+11
-11
@@ -9,10 +9,10 @@
|
|||||||
<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.1.0.0</Version>
|
<Version>1.1.2.2</Version>
|
||||||
<SatelliteResourceLanguages>de-AT</SatelliteResourceLanguages>
|
<SatelliteResourceLanguages>de-AT</SatelliteResourceLanguages>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
<ApplicationManifest>App.manifest</ApplicationManifest>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -23,21 +23,21 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="bblanchon.PDFium.Win32" Version="152.0.7934" />
|
<PackageReference Include="bblanchon.PDFium.Win32" Version="155.0.8044" />
|
||||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.2" />
|
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.2" />
|
||||||
<PackageReference Include="itext" Version="9.7.0" />
|
<PackageReference Include="itext" Version="9.7.0" />
|
||||||
<PackageReference Include="itext.bouncy-castle-adapter" Version="9.7.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.17.0" />
|
<PackageReference Include="MailKit" Version="4.18.0" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.9" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.12" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Ini" Version="10.0.9" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Ini" Version="10.0.12" />
|
||||||
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.4078.44" />
|
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.4191.47" />
|
||||||
<PackageReference Include="NJsonSchema" Version="11.6.1" />
|
<PackageReference Include="NJsonSchema" Version="11.6.1" />
|
||||||
<PackageReference Include="ScottPlot.WPF" Version="5.1.59" />
|
<PackageReference Include="ScottPlot.WPF" Version="5.1.59" />
|
||||||
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="3.0.3" />
|
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="3.0.5" />
|
||||||
<PackageReference Include="System.IO.Hashing" Version="10.0.9" />
|
<PackageReference Include="System.IO.Hashing" Version="10.0.12" />
|
||||||
<PackageReference Include="System.IO.Ports" Version="10.0.9" />
|
<PackageReference Include="System.IO.Ports" Version="10.0.12" />
|
||||||
<PackageReference Include="System.Management" Version="10.0.9" />
|
<PackageReference Include="System.Management" Version="10.0.12" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
@@ -69,7 +69,8 @@ namespace Elwig.Helpers {
|
|||||||
public DbSet<OverUnderDeliveryRow> OverUnderDeliveryRows { get; private set; }
|
public DbSet<OverUnderDeliveryRow> OverUnderDeliveryRows { get; private set; }
|
||||||
public DbSet<AreaComUnderDeliveryRowSingle> AreaComUnderDeliveryRows { get; private set; }
|
public DbSet<AreaComUnderDeliveryRowSingle> AreaComUnderDeliveryRows { get; private set; }
|
||||||
public DbSet<MemberDeliveryPerVarietyRowSingle> MemberDeliveryPerVariantRows { get; private set; }
|
public DbSet<MemberDeliveryPerVarietyRowSingle> MemberDeliveryPerVariantRows { get; private set; }
|
||||||
public DbSet<MemberAreaComsRowSingle> MemberAreaComsRows { get; private set; }
|
public DbSet<MemberAreaComTotalsRowSingle> MemberAreaComTotalsRows { get; private set; }
|
||||||
|
public DbSet<MemberAreaComsRow> MemberAreaComsRows { get; private set; }
|
||||||
public DbSet<CreditNoteDeliveryRowSingle> CreditNoteDeliveryRows { get; private set; }
|
public DbSet<CreditNoteDeliveryRowSingle> CreditNoteDeliveryRows { get; private set; }
|
||||||
public DbSet<CreditNoteRowSingle> CreditNoteRows { get; private set; }
|
public DbSet<CreditNoteRowSingle> CreditNoteRows { get; private set; }
|
||||||
public DbSet<WeightBreakdownRow> WeightBreakDownRows { get; private set; }
|
public DbSet<WeightBreakdownRow> WeightBreakDownRows { get; private set; }
|
||||||
@@ -169,16 +170,25 @@ namespace Elwig.Helpers {
|
|||||||
SavedChanges += OnSavedChanges;
|
SavedChanges += OnSavedChanges;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void CreateFunctions(SqliteConnection cnx) {
|
||||||
|
cnx.CreateFunction<string, string?, bool?>("REGEXP", (pattern, value) => {
|
||||||
|
return value == null ? null : Regex.IsMatch(value, pattern);
|
||||||
|
}, true);
|
||||||
|
cnx.CreateFunction<string?, string?, string?>("NORMALIZE_ADDRESS", (address, locality) => {
|
||||||
|
return string.IsNullOrWhiteSpace(address) ? null : Normalizer.NormalizeAddress(address, locality);
|
||||||
|
}, true);
|
||||||
|
}
|
||||||
|
|
||||||
public static SqliteConnection Connect(string? connectionString = null) {
|
public static SqliteConnection Connect(string? connectionString = null) {
|
||||||
var cnx = new SqliteConnection(connectionString ?? ConnectionString);
|
var cnx = new SqliteConnection(connectionString ?? ConnectionString);
|
||||||
cnx.CreateFunction<string, string?, bool?>("REGEXP", (pattern, value) => value == null ? null : Regex.Match(value, pattern).Success, true);
|
CreateFunctions(cnx);
|
||||||
cnx.Open();
|
cnx.Open();
|
||||||
return cnx;
|
return cnx;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<SqliteConnection> ConnectAsync(string? connectionString = null) {
|
public static async Task<SqliteConnection> ConnectAsync(string? connectionString = null) {
|
||||||
var cnx = new SqliteConnection(connectionString ?? ConnectionString);
|
var cnx = new SqliteConnection(connectionString ?? ConnectionString);
|
||||||
cnx.CreateFunction<string, string?, bool?>("REGEXP", (pattern, value) => value == null ? null : Regex.Match(value, pattern).Success, true);
|
CreateFunctions(cnx);
|
||||||
await cnx.OpenAsync();
|
await cnx.OpenAsync();
|
||||||
return cnx;
|
return cnx;
|
||||||
}
|
}
|
||||||
@@ -233,6 +243,8 @@ namespace Elwig.Helpers {
|
|||||||
modelBuilder.Entity<DeliveryAncmt>().Navigation(a => a.Schedule).AutoInclude();
|
modelBuilder.Entity<DeliveryAncmt>().Navigation(a => a.Schedule).AutoInclude();
|
||||||
modelBuilder.Entity<DeliveryAncmt>().Navigation(a => a.Variety).AutoInclude();
|
modelBuilder.Entity<DeliveryAncmt>().Navigation(a => a.Variety).AutoInclude();
|
||||||
modelBuilder.Entity<DeliverySchedule>().Navigation(s => s.Branch).AutoInclude();
|
modelBuilder.Entity<DeliverySchedule>().Navigation(s => s.Branch).AutoInclude();
|
||||||
|
modelBuilder.Entity<DeliverySchedule>().Navigation(s => s.Attribute).AutoInclude();
|
||||||
|
modelBuilder.Entity<DeliverySchedule>().Navigation(s => s.Cultivation).AutoInclude();
|
||||||
modelBuilder.Entity<MemberHistory>().Navigation(s => s.FromMember).AutoInclude();
|
modelBuilder.Entity<MemberHistory>().Navigation(s => s.FromMember).AutoInclude();
|
||||||
modelBuilder.Entity<MemberHistory>().Navigation(s => s.ToMember).AutoInclude();
|
modelBuilder.Entity<MemberHistory>().Navigation(s => s.ToMember).AutoInclude();
|
||||||
modelBuilder.Entity<MemberHistory>().Navigation(s => s.Currency).AutoInclude();
|
modelBuilder.Entity<MemberHistory>().Navigation(s => s.Currency).AutoInclude();
|
||||||
|
|||||||
@@ -1,23 +1,33 @@
|
|||||||
|
using Elwig.Services;
|
||||||
|
using Microsoft.Data.Sqlite;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
namespace Elwig.Helpers {
|
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 = 40;
|
public static readonly int RequiredSchemaVersion = 42;
|
||||||
|
|
||||||
private static int VersionOffset = 0;
|
private static int VersionOffset = 0;
|
||||||
|
|
||||||
public static async Task<Version> CheckDb() {
|
public static async Task<Version> CheckDb() {
|
||||||
|
if (!File.Exists(App.Config.DatabaseFile))
|
||||||
|
throw new FileNotFoundException($"Die Datei \"{App.Config.DatabaseFile}\" exisitiert nicht");
|
||||||
|
|
||||||
long? applId, schemaVers;
|
long? applId, schemaVers;
|
||||||
using (var cnx = await AppDbContext.ConnectAsync()) {
|
using (var cnx = await AppDbContext.ConnectAsync()) {
|
||||||
|
|
||||||
|
await cnx.QuickCheck();
|
||||||
|
|
||||||
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 FileFormatException($"Invalid application_id in database (0x{applId:X08})");
|
||||||
|
|
||||||
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);
|
||||||
@@ -61,11 +71,11 @@ namespace Elwig.Helpers {
|
|||||||
})
|
})
|
||||||
.OrderBy(s => s.Item1).ThenBy(s => s.Item2)];
|
.OrderBy(s => s.Item1).ThenBy(s => s.Item2)];
|
||||||
|
|
||||||
List<string> toExecute = [];
|
List<(int ToVersion, string File)> toExecute = [];
|
||||||
var vers = fromVersion;
|
var vers = fromVersion;
|
||||||
while (vers < toVersion) {
|
while (vers < toVersion) {
|
||||||
var (_, to, name) = scripts.Last(s => s.From == vers);
|
var (_, to, name) = scripts.Last(s => s.From == vers);
|
||||||
toExecute.Add(name);
|
toExecute.Add((to, name));
|
||||||
vers = to;
|
vers = to;
|
||||||
}
|
}
|
||||||
if (toExecute.Count == 0)
|
if (toExecute.Count == 0)
|
||||||
@@ -76,16 +86,19 @@ namespace Elwig.Helpers {
|
|||||||
try {
|
try {
|
||||||
using var cnx = await AppDbContext.ConnectAsync();
|
using var cnx = await AppDbContext.ConnectAsync();
|
||||||
await cnx.ExecuteBatch("PRAGMA locking_mode = EXCLUSIVE");
|
await cnx.ExecuteBatch("PRAGMA locking_mode = EXCLUSIVE");
|
||||||
foreach (var script in toExecute) {
|
|
||||||
|
await cnx.IntegrityCheck();
|
||||||
|
await cnx.ForeignKeyCheck();
|
||||||
|
|
||||||
|
foreach (var (to, script) in toExecute) {
|
||||||
await cnx.ExecuteEmbeddedScript(asm, script);
|
await cnx.ExecuteEmbeddedScript(asm, script);
|
||||||
|
if (to == 42) {
|
||||||
|
await UpdateDbSchema_41_To_42(cnx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var violations = await cnx.ForeignKeyCheck();
|
await cnx.IntegrityCheck();
|
||||||
if (violations.Length > 0) {
|
await cnx.ForeignKeyCheck();
|
||||||
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}")));
|
|
||||||
}
|
|
||||||
|
|
||||||
await cnx.ExecuteBatch("VACUUM");
|
await cnx.ExecuteBatch("VACUUM");
|
||||||
await cnx.ExecuteBatch($"PRAGMA schema_version = {toVersion * 100 + VersionOffset}");
|
await cnx.ExecuteBatch($"PRAGMA schema_version = {toVersion * 100 + VersionOffset}");
|
||||||
@@ -96,5 +109,57 @@ namespace Elwig.Helpers {
|
|||||||
File.Delete(backup);
|
File.Delete(backup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static async Task UpdateDbSchema_41_To_42(SqliteConnection cnx) {
|
||||||
|
List<(int MgNr, string LfbisNr, string Name, string Address, int Plz)> members = [];
|
||||||
|
using (var cmd = cnx.CreateCommand()) {
|
||||||
|
cmd.CommandText = """
|
||||||
|
SELECT m.mgnr, m.lfbis_nr,
|
||||||
|
COALESCE(a.name, (COALESCE(m.prefix || ' ', '') || COALESCE(m.given_name || ' ', '') || m.name || COALESCE(' ' || m.middle_names, '') || COALESCE(' ' || m.suffix, ''))),
|
||||||
|
COALESCE(a.address, m.address),
|
||||||
|
COALESCE(aplz.plz, mplz.plz)
|
||||||
|
FROM member m
|
||||||
|
JOIN postal_dest mp ON (mp.country, mp.id) = (m.country, m.postal_dest)
|
||||||
|
JOIN AT_plz_dest ma ON (ma.country, ma.id) = (mp.country, mp.id)
|
||||||
|
JOIN AT_plz mplz ON mplz.plz = ma.plz
|
||||||
|
LEFT JOIN member_billing_address a ON a.mgnr = m.mgnr
|
||||||
|
LEFT JOIN postal_dest ap ON (ap.country, ap.id) = (a.country, a.postal_dest)
|
||||||
|
LEFT JOIN AT_plz_dest aa ON (aa.country, aa.id) = (ap.country, mp.id)
|
||||||
|
LEFT JOIN AT_plz aplz ON aplz.plz = aa.plz
|
||||||
|
WHERE organic
|
||||||
|
""";
|
||||||
|
using var reader = await cmd.ExecuteReaderAsync();
|
||||||
|
var header = await reader.GetColumnSchemaAsync();
|
||||||
|
while (await reader.ReadAsync()) {
|
||||||
|
members.Add((reader.GetInt32(0), reader.GetString(1), reader.GetString(2), reader.GetString(3), reader.GetInt32(4)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (members.Count > 0)
|
||||||
|
InteractionService.ShowInformation("Datenbank-Update", "Es wird versucht, die Bio-Kontrollstellen-Informationen der Mitglieder automatisch abzurufen. Dies könnte einen kurzen Moment dauern.");
|
||||||
|
|
||||||
|
try {
|
||||||
|
Mouse.OverrideCursor = Cursors.Wait;
|
||||||
|
foreach (var m in members) {
|
||||||
|
string? oocId = null;
|
||||||
|
string? authCode = null;
|
||||||
|
|
||||||
|
var certs = await OrganicService.FetchTracesCertificates(lfbisNr: m.LfbisNr, address: (m.Name, m.Address, m.Plz.ToString()));
|
||||||
|
|
||||||
|
if (certs.Length > 0) {
|
||||||
|
oocId = certs[0].OperatorId;
|
||||||
|
authCode = certs[0].AuthorityCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oocId != null || authCode != null) {
|
||||||
|
oocId = oocId == null ? "NULL" : $"'{oocId}'";
|
||||||
|
authCode = authCode == null ? "NULL" : $"'{authCode}'";
|
||||||
|
await cnx.ExecuteBatch($"UPDATE member SET ooc_id = {oocId}, org_auth_code = {authCode} WHERE mgnr = {m.MgNr}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
Mouse.OverrideCursor = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -49,7 +49,8 @@ namespace Elwig.Helpers {
|
|||||||
public string? Bic;
|
public string? Bic;
|
||||||
public string? UstIdNr;
|
public string? UstIdNr;
|
||||||
public string? LfbisNr;
|
public string? LfbisNr;
|
||||||
public string? OrganicAuthority;
|
public string? OrganicOperatorId;
|
||||||
|
public string? OrganicAuthorityCode;
|
||||||
|
|
||||||
public string? PhoneNr;
|
public string? PhoneNr;
|
||||||
public string? FaxNr;
|
public string? FaxNr;
|
||||||
@@ -114,7 +115,8 @@ namespace Elwig.Helpers {
|
|||||||
UstIdNr = parameters.GetValueOrDefault("CLIENT_USTIDNR");
|
UstIdNr = parameters.GetValueOrDefault("CLIENT_USTIDNR");
|
||||||
Bic = parameters.GetValueOrDefault("CLIENT_BIC");
|
Bic = parameters.GetValueOrDefault("CLIENT_BIC");
|
||||||
Iban = parameters.GetValueOrDefault("CLIENT_IBAN");
|
Iban = parameters.GetValueOrDefault("CLIENT_IBAN");
|
||||||
OrganicAuthority = parameters.GetValueOrDefault("CLIENT_ORGANIC_AUTHORITY");
|
OrganicOperatorId = parameters.GetValueOrDefault("CLIENT_ORGANIC_OPERATORID");
|
||||||
|
OrganicAuthorityCode = parameters.GetValueOrDefault("CLIENT_ORGANIC_AUTHORITYCODE");
|
||||||
|
|
||||||
EnableMemberHistory = (parameters.GetValueOrDefault("ENABLE_MEMBERHISTORY")?.ToUpper()) switch {
|
EnableMemberHistory = (parameters.GetValueOrDefault("ENABLE_MEMBERHISTORY")?.ToUpper()) switch {
|
||||||
"1" or "TRUE" or "YES" or "JA" => true,
|
"1" or "TRUE" or "YES" or "JA" => true,
|
||||||
@@ -273,7 +275,8 @@ namespace Elwig.Helpers {
|
|||||||
("CLIENT_USTIDNR", UstIdNr),
|
("CLIENT_USTIDNR", UstIdNr),
|
||||||
("CLIENT_BIC", Bic),
|
("CLIENT_BIC", Bic),
|
||||||
("CLIENT_IBAN", Iban),
|
("CLIENT_IBAN", Iban),
|
||||||
("CLIENT_ORGANIC_AUTHORITY", OrganicAuthority),
|
("CLIENT_ORGANIC_OPERATORID", OrganicOperatorId),
|
||||||
|
("CLIENT_ORGANIC_AUTHORITYCODE", OrganicAuthorityCode),
|
||||||
("ENABLE_MEMBERHISTORY", EnableMemberHistory ? "YES" : "NO"),
|
("ENABLE_MEMBERHISTORY", EnableMemberHistory ? "YES" : "NO"),
|
||||||
("MODE_BUSINESSSHARES", businessShares),
|
("MODE_BUSINESSSHARES", businessShares),
|
||||||
("MODE_DELIVERYNOTE_STATS", deliveryNoteStats),
|
("MODE_DELIVERYNOTE_STATS", deliveryNoteStats),
|
||||||
|
|||||||
+30
-4
@@ -17,10 +17,11 @@ namespace Elwig.Helpers {
|
|||||||
public string? Filling;
|
public string? Filling;
|
||||||
public string? Limit;
|
public string? Limit;
|
||||||
public bool Required;
|
public bool Required;
|
||||||
|
public bool SyncTime;
|
||||||
public string? Log;
|
public string? Log;
|
||||||
public string? _Log;
|
public string? _Log;
|
||||||
|
|
||||||
public ScaleConfig(string id, string? type, string? model, string? cnx, string? empty, string? filling, string? limit, bool? required, string? log) {
|
public ScaleConfig(string id, string? type, string? model, string? cnx, string? empty, string? filling, string? limit, bool? required, bool? syncTime, string? log) {
|
||||||
Id = id;
|
Id = id;
|
||||||
Type = type;
|
Type = type;
|
||||||
Model = model;
|
Model = model;
|
||||||
@@ -29,6 +30,7 @@ namespace Elwig.Helpers {
|
|||||||
Filling = filling;
|
Filling = filling;
|
||||||
Limit = limit;
|
Limit = limit;
|
||||||
Required = required ?? true;
|
Required = required ?? true;
|
||||||
|
SyncTime = syncTime ?? true;
|
||||||
_Log = log;
|
_Log = log;
|
||||||
Log = log != null ? Path.Combine(App.DataPath, log) : null;
|
Log = log != null ? Path.Combine(App.DataPath, log) : null;
|
||||||
}
|
}
|
||||||
@@ -37,19 +39,30 @@ namespace Elwig.Helpers {
|
|||||||
public class Config {
|
public class Config {
|
||||||
|
|
||||||
private static readonly string[] TrueValues = ["1", "true", "yes", "on"];
|
private static readonly string[] TrueValues = ["1", "true", "yes", "on"];
|
||||||
|
private static readonly string[] FalseValues = ["0", "false", "no", "off"];
|
||||||
|
|
||||||
private readonly string FileName;
|
private readonly string FileName;
|
||||||
|
|
||||||
public bool Debug;
|
public bool Debug;
|
||||||
public string DatabaseFile = App.DataPath + "database.sqlite3";
|
public string DatabaseFile = Path.Combine(App.DataPath, "database.sqlite3");
|
||||||
public string? DatabaseLog = null;
|
public string? DatabaseLog = null;
|
||||||
public string? Branch = null;
|
public string? Branch = null;
|
||||||
public WeighingMode? WeighingMode;
|
public WeighingMode? WeighingMode;
|
||||||
|
|
||||||
|
public bool BackupAuto = true;
|
||||||
|
public string BackupPath = Path.Combine(App.DataPath, "backups");
|
||||||
|
public int BackupRetainHours = 36;
|
||||||
|
public int BackupRetainDays = 8;
|
||||||
|
public int BackupRetainWeeks = 6;
|
||||||
|
public int BackupRetainMonths = 18;
|
||||||
|
|
||||||
public string? UpdateUrl = null;
|
public string? UpdateUrl = null;
|
||||||
public bool UpdateAuto = false;
|
public bool UpdateAuto = false;
|
||||||
|
|
||||||
public string? SyncUrl = null;
|
public string? SyncUrl = null;
|
||||||
public string SyncUsername = "";
|
public string SyncUsername = "";
|
||||||
public string SyncPassword = "";
|
public string SyncPassword = "";
|
||||||
|
public bool SyncMain = false;
|
||||||
|
|
||||||
public string? SmtpHost = null;
|
public string? SmtpHost = null;
|
||||||
public int? SmtpPort = null;
|
public int? SmtpPort = null;
|
||||||
@@ -57,9 +70,10 @@ namespace Elwig.Helpers {
|
|||||||
public string? SmtpUsername = null;
|
public string? SmtpUsername = null;
|
||||||
public string? SmtpPassword = null;
|
public string? SmtpPassword = null;
|
||||||
public string? SmtpFrom = null;
|
public string? SmtpFrom = null;
|
||||||
public (string Host, int Port, string Mode, string Username, string Password, string From)? Smtp =>
|
public double SmtpWait = 0;
|
||||||
|
public (string Host, int Port, string Mode, string Username, string Password, string From, double Wait)? Smtp =>
|
||||||
SmtpHost == null || SmtpPort == null || SmtpMode == null || SmtpUsername == null || SmtpPassword == null || SmtpFrom == null ?
|
SmtpHost == null || SmtpPort == null || SmtpMode == null || SmtpUsername == null || SmtpPassword == null || SmtpFrom == null ?
|
||||||
null : (SmtpHost, (int)SmtpPort, SmtpMode, SmtpUsername, SmtpPassword, SmtpFrom);
|
null : (SmtpHost, (int)SmtpPort, SmtpMode, SmtpUsername, SmtpPassword, SmtpFrom, SmtpWait);
|
||||||
|
|
||||||
public IList<ScaleConfig> Scales;
|
public IList<ScaleConfig> Scales;
|
||||||
private readonly List<ScaleConfig> ScaleList = [];
|
private readonly List<ScaleConfig> ScaleList = [];
|
||||||
@@ -80,11 +94,21 @@ namespace Elwig.Helpers {
|
|||||||
Debug = TrueValues.Contains(config["general:debug"]?.ToLower());
|
Debug = TrueValues.Contains(config["general:debug"]?.ToLower());
|
||||||
var weighing = config["general:weighing"];
|
var weighing = config["general:weighing"];
|
||||||
WeighingMode = weighing != null && Enum.TryParse<WeighingMode>(weighing, true, out var w) ? w : null;
|
WeighingMode = weighing != null && Enum.TryParse<WeighingMode>(weighing, true, out var w) ? w : null;
|
||||||
|
|
||||||
|
BackupAuto = !FalseValues.Contains(config["backup:auto"]?.ToLower());
|
||||||
|
BackupPath = Path.Combine(Path.GetDirectoryName(DatabaseFile) ?? App.DataPath, config["backup:path"] ?? "backups");
|
||||||
|
BackupRetainHours = int.TryParse(config["backup:retain_hours"], out var hours) ? hours : 36;
|
||||||
|
BackupRetainDays = int.TryParse(config["backup:retain_days"], out var days) ? days : 8;
|
||||||
|
BackupRetainWeeks = int.TryParse(config["backup:retain_weeks"], out var weeks) ? weeks : 6;
|
||||||
|
BackupRetainMonths = int.TryParse(config["backup:retain_months"], out var months) ? months : 18;
|
||||||
|
|
||||||
UpdateUrl = config["update:url"];
|
UpdateUrl = config["update:url"];
|
||||||
UpdateAuto = TrueValues.Contains(config["update:auto"]?.ToLower());
|
UpdateAuto = TrueValues.Contains(config["update:auto"]?.ToLower());
|
||||||
|
|
||||||
SyncUrl = config["sync:url"];
|
SyncUrl = config["sync:url"];
|
||||||
SyncUsername = config["sync:username"] ?? "";
|
SyncUsername = config["sync:username"] ?? "";
|
||||||
SyncPassword = config["sync:password"] ?? "";
|
SyncPassword = config["sync:password"] ?? "";
|
||||||
|
SyncMain = TrueValues.Contains(config["sync:main"]?.ToLower());
|
||||||
|
|
||||||
SmtpHost = config["smtp:host"];
|
SmtpHost = config["smtp:host"];
|
||||||
SmtpPort = config["smtp:port"]?.All(char.IsAsciiDigit) == true && config["smtp:port"]?.Length > 0 ? int.Parse(config["smtp:port"]!) : null;
|
SmtpPort = config["smtp:port"]?.All(char.IsAsciiDigit) == true && config["smtp:port"]?.Length > 0 ? int.Parse(config["smtp:port"]!) : null;
|
||||||
@@ -92,6 +116,7 @@ namespace Elwig.Helpers {
|
|||||||
SmtpUsername = config["smtp:username"];
|
SmtpUsername = config["smtp:username"];
|
||||||
SmtpPassword = config["smtp:password"];
|
SmtpPassword = config["smtp:password"];
|
||||||
SmtpFrom = config["smtp:from"];
|
SmtpFrom = config["smtp:from"];
|
||||||
|
SmtpWait = double.TryParse(config["smtp:wait"], out var res) ? res : 0;
|
||||||
|
|
||||||
var scales = config.AsEnumerable().Where(i => i.Key.StartsWith("scale.")).GroupBy(i => i.Key.Split(':')[0][6..]).Select(i => i.Key).Order();
|
var scales = config.AsEnumerable().Where(i => i.Key.StartsWith("scale.")).GroupBy(i => i.Key.Split(':')[0][6..]).Select(i => i.Key).Order();
|
||||||
ScaleList.Clear();
|
ScaleList.Clear();
|
||||||
@@ -101,6 +126,7 @@ namespace Elwig.Helpers {
|
|||||||
s, config[$"scale.{s}:type"], config[$"scale.{s}:model"], config[$"scale.{s}:connection"],
|
s, config[$"scale.{s}:type"], config[$"scale.{s}:model"], config[$"scale.{s}:connection"],
|
||||||
config[$"scale.{s}:empty"], config[$"scale.{s}:filling"], config[$"scale.{s}:limit"],
|
config[$"scale.{s}:empty"], config[$"scale.{s}:filling"], config[$"scale.{s}:limit"],
|
||||||
config[$"scale.{s}:required"] != null ? TrueValues.Contains(config[$"scale.{s}:required"]?.ToLower()) : null,
|
config[$"scale.{s}:required"] != null ? TrueValues.Contains(config[$"scale.{s}:required"]?.ToLower()) : null,
|
||||||
|
config[$"scale.{s}:synctime"] != null ? !FalseValues.Contains(config[$"scale.{s}:synctime"]?.ToLower()) : null,
|
||||||
config[$"scale.{s}:log"]
|
config[$"scale.{s}:log"]
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ using System;
|
|||||||
|
|
||||||
namespace Elwig.Helpers.Export {
|
namespace Elwig.Helpers.Export {
|
||||||
|
|
||||||
using Row = Tuple<(string?, string?, string?, string?, string, int, string, int), (string, int, string, string, string, int, string, double, double)>;
|
using Row = Tuple<(string?, string?, string?, string?, string, int, string, bool, int), (string, int, string, string, string, int, string, double, double)>;
|
||||||
|
|
||||||
public class Bki : Csv<Row> {
|
public class Bki : Csv<Row> {
|
||||||
|
|
||||||
@@ -29,7 +29,7 @@ namespace Elwig.Helpers.Export {
|
|||||||
using var cnx = await AppDbContext.ConnectAsync();
|
using var cnx = await AppDbContext.ConnectAsync();
|
||||||
using var cmd = cnx.CreateCommand();
|
using var cmd = cnx.CreateCommand();
|
||||||
cmd.CommandText = $"""
|
cmd.CommandText = $"""
|
||||||
SELECT lfbis_nr, name, other_names, billing_name, address, plz, ort, area,
|
SELECT lfbis_nr, name, other_names, billing_name, address, plz, ort, vollablieferer, area,
|
||||||
date, weight, type, sortid, qualid, year, hkid, kmw, oe
|
date, weight, type, sortid, qualid, year, hkid, kmw, oe
|
||||||
FROM v_bki_delivery
|
FROM v_bki_delivery
|
||||||
WHERE year = {year}
|
WHERE year = {year}
|
||||||
@@ -38,8 +38,8 @@ namespace Elwig.Helpers.Export {
|
|||||||
List<Row> rows = [];
|
List<Row> rows = [];
|
||||||
while (await r.ReadAsync()) {
|
while (await r.ReadAsync()) {
|
||||||
rows.Add(new(
|
rows.Add(new(
|
||||||
(r.IsDBNull(0) ? null : r.GetString(0), r.IsDBNull(1) ? null : r.GetString(1), r.IsDBNull(2) ? null : r.GetString(2), r.IsDBNull(3) ? null : r.GetString(3), r.GetString(4), r.GetInt32(5), r.GetString(6), r.GetInt32(7)),
|
(r.IsDBNull(0) ? null : r.GetString(0), r.IsDBNull(1) ? null : r.GetString(1), r.IsDBNull(2) ? null : r.GetString(2), r.IsDBNull(3) ? null : r.GetString(3), r.GetString(4), r.GetInt32(5), r.GetString(6), r.GetBoolean(7), r.GetInt32(8)),
|
||||||
(r.GetString(8), r.GetInt32(9), r.GetString(10), r.GetString(11), r.GetString(12), r.GetInt32(13), r.GetString(14), r.GetDouble(15), r.GetDouble(16))
|
(r.GetString(9), r.GetInt32(10), r.GetString(11), r.GetString(12), r.GetString(13), r.GetInt32(14), r.GetString(15), r.GetDouble(16), r.GetDouble(17))
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,14 +52,14 @@ namespace Elwig.Helpers.Export {
|
|||||||
|
|
||||||
public override string FormatRow(Row row) {
|
public override string FormatRow(Row row) {
|
||||||
var (member, delivery) = row;
|
var (member, delivery) = row;
|
||||||
var (lfBisNr, familyName, name, billingName, address, plz, ort, area) = member;
|
var (lfBisNr, familyName, name, billingName, address, plz, ort, vollablieferer, area) = member;
|
||||||
var (date, weight, type, sortid, qualid, year, hkid, kmw, oe) = delivery;
|
var (date, weight, type, sortid, qualid, year, hkid, kmw, oe) = delivery;
|
||||||
|
|
||||||
var (n1, n2) = billingName == null ? (familyName, name) : Utils.SplitName(billingName, familyName);
|
var (n1, n2) = billingName == null ? (familyName, name) : Utils.SplitName(billingName, familyName);
|
||||||
var (a1, a2) = Utils.SplitAddress(address);
|
var (a1, a2) = Utils.SplitAddress(address);
|
||||||
var memberData = $"{lfBisNr};{n1};{n2};{a1};\t{a2};{plz};{ort}";
|
var memberData = $"{lfBisNr};{n1};{n2};{a1};\t{a2};{plz};{ort}";
|
||||||
var deliveryData = $"{string.Join(".", date.Split("-").Reverse())};{weight};TB;{(type == "W" ? "J" : "")};{(type == "R" ? "J" : "")};{sortid};;;{qualid};{year};{hkid};{kmw:0.0};{oe:0}";
|
var deliveryData = $"{string.Join(".", date.Split("-").Reverse())};{weight};TB;{(type == "W" ? "J" : "")};{(type == "R" ? "J" : "")};{sortid};;;{qualid};{year};{hkid};{kmw:0.0};{oe:0}";
|
||||||
var vollData = $"N;;;{area / 10_000.0}";
|
var vollData = $"{(vollablieferer ? "J" : "N")};{(vollablieferer ? area / 10_000.0 : null):N4};{(vollablieferer ? area / 10_000.0 : null):N4};{area / 10_000.0:N4}";
|
||||||
|
|
||||||
return $"{_clientData};{memberData};{deliveryData};{vollData}";
|
return $"{_clientData};{memberData};{deliveryData};{vollData}";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,73 +18,85 @@ namespace Elwig.Helpers.Export {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static async Task ExportSqlite(string filename, bool zipFile) {
|
public static async Task ExportSqlite(string filename, bool zipFile) {
|
||||||
if (zipFile) {
|
var tmp = filename + ".tmp";
|
||||||
File.Delete(filename);
|
try {
|
||||||
using var zip = ZipFile.Open(filename, ZipArchiveMode.Create);
|
File.Delete(tmp);
|
||||||
|
if (zipFile) {
|
||||||
|
using var zip = ZipFile.Open(tmp, ZipArchiveMode.Create);
|
||||||
|
|
||||||
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:1");
|
||||||
|
}
|
||||||
|
|
||||||
|
var (applId, userVers, schemaVers, size) = await GetMeta();
|
||||||
|
var meta = zip.CreateEntry("meta.json", CompressionLevel.NoCompression);
|
||||||
|
using (var writer = new StreamWriter(meta.Open(), Utils.UTF8)) {
|
||||||
|
var obj = new JsonObject {
|
||||||
|
["timestamp"] = $"{DateTime.UtcNow:yyyy-MM-ddTHH:mm:ssZ}",
|
||||||
|
["zwstid"] = App.ZwstId,
|
||||||
|
["device"] = Environment.MachineName,
|
||||||
|
["database"] = new JsonObject {
|
||||||
|
["application_id"] = applId,
|
||||||
|
["user_version"] = userVers,
|
||||||
|
["schema_version"] = schemaVers,
|
||||||
|
["file_size"] = size,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
await writer.WriteAsync(obj.ToJsonString(Utils.JsonOpts));
|
||||||
|
}
|
||||||
|
|
||||||
|
var db = zip.CreateEntryFromFile(App.Config.DatabaseFile, "database.sqlite3", CompressionLevel.SmallestSize);
|
||||||
|
} else {
|
||||||
|
File.Copy(App.Config.DatabaseFile, tmp);
|
||||||
}
|
}
|
||||||
|
File.Move(tmp, filename, true);
|
||||||
var (applId, userVers, schemaVers, size) = await GetMeta();
|
} finally {
|
||||||
var meta = zip.CreateEntry("meta.json", CompressionLevel.NoCompression);
|
File.Delete(tmp);
|
||||||
using (var writer = new StreamWriter(meta.Open(), Utils.UTF8)) {
|
|
||||||
var obj = new JsonObject {
|
|
||||||
["timestamp"] = $"{DateTime.UtcNow:yyyy-MM-ddTHH:mm:ssZ}",
|
|
||||||
["zwstid"] = App.ZwstId,
|
|
||||||
["device"] = Environment.MachineName,
|
|
||||||
["database"] = new JsonObject {
|
|
||||||
["application_id"] = applId,
|
|
||||||
["user_version"] = userVers,
|
|
||||||
["schema_version"] = schemaVers,
|
|
||||||
["file_size"] = size,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
await writer.WriteAsync(obj.ToJsonString(Utils.JsonOpts));
|
|
||||||
}
|
|
||||||
|
|
||||||
var db = zip.CreateEntryFromFile(App.Config.DatabaseFile, "database.sqlite3", CompressionLevel.SmallestSize);
|
|
||||||
} else {
|
|
||||||
File.Copy(App.Config.DatabaseFile, filename, true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task ExportSql(string filename, bool zipFile) {
|
public static async Task ExportSql(string filename, bool zipFile) {
|
||||||
if (zipFile) {
|
var tmp = filename + ".tmp";
|
||||||
File.Delete(filename);
|
try {
|
||||||
using var zip = ZipFile.Open(filename, ZipArchiveMode.Create);
|
File.Delete(tmp);
|
||||||
|
if (zipFile) {
|
||||||
|
using var zip = ZipFile.Open(tmp, ZipArchiveMode.Create);
|
||||||
|
|
||||||
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:1");
|
||||||
}
|
}
|
||||||
|
|
||||||
var (applId, userVers, schemaVers, size) = await GetMeta();
|
var (applId, userVers, schemaVers, size) = await GetMeta();
|
||||||
var meta = zip.CreateEntry("meta.json", CompressionLevel.NoCompression);
|
var meta = zip.CreateEntry("meta.json", CompressionLevel.NoCompression);
|
||||||
using (var writer = new StreamWriter(meta.Open(), Utils.UTF8)) {
|
using (var writer = new StreamWriter(meta.Open(), Utils.UTF8)) {
|
||||||
var obj = new JsonObject {
|
var obj = new JsonObject {
|
||||||
["timestamp"] = $"{DateTime.UtcNow:yyyy-MM-ddTHH:mm:ssZ}",
|
["timestamp"] = $"{DateTime.UtcNow:yyyy-MM-ddTHH:mm:ssZ}",
|
||||||
["zwstid"] = App.ZwstId,
|
["zwstid"] = App.ZwstId,
|
||||||
["device"] = Environment.MachineName,
|
["device"] = Environment.MachineName,
|
||||||
["database"] = new JsonObject {
|
["database"] = new JsonObject {
|
||||||
["application_id"] = applId,
|
["application_id"] = applId,
|
||||||
["user_version"] = userVers,
|
["user_version"] = userVers,
|
||||||
["schema_version"] = schemaVers,
|
["schema_version"] = schemaVers,
|
||||||
["file_size"] = size,
|
["file_size"] = size,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
await writer.WriteAsync(obj.ToJsonString(Utils.JsonOpts));
|
await writer.WriteAsync(obj.ToJsonString(Utils.JsonOpts));
|
||||||
}
|
}
|
||||||
|
|
||||||
var sql = zip.CreateEntry("database.sql", CompressionLevel.SmallestSize);
|
var sql = zip.CreateEntry("database.sql", CompressionLevel.SmallestSize);
|
||||||
using (var writer = new StreamWriter(sql.Open(), Utils.UTF8)) {
|
using (var writer = new StreamWriter(sql.Open(), Utils.UTF8)) {
|
||||||
|
await ExportSql(writer);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
using var stream = File.OpenWrite(tmp);
|
||||||
|
using var writer = new StreamWriter(stream, Utils.UTF8);
|
||||||
await ExportSql(writer);
|
await ExportSql(writer);
|
||||||
}
|
}
|
||||||
} else {
|
File.Move(tmp, filename, true);
|
||||||
using var stream = File.OpenWrite(filename);
|
} finally {
|
||||||
using var writer = new StreamWriter(stream, Utils.UTF8);
|
File.Delete(tmp);
|
||||||
await ExportSql(writer);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,7 +212,7 @@ namespace Elwig.Helpers.Export {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task ImportSqlite(string filename, bool zipFile = false) {
|
public static async Task ImportSqlite(string filename, bool zipFile = false, bool keepSource = true) {
|
||||||
if (zipFile) {
|
if (zipFile) {
|
||||||
var newName = Path.ChangeExtension(App.Config.DatabaseFile, ".new.sqlite3");
|
var newName = Path.ChangeExtension(App.Config.DatabaseFile, ".new.sqlite3");
|
||||||
try {
|
try {
|
||||||
@@ -209,7 +221,7 @@ namespace Elwig.Helpers.Export {
|
|||||||
foreach (var entry in zip.Entries) {
|
foreach (var entry in zip.Entries) {
|
||||||
if (entry.Name.EndsWith(".sqlite3")) {
|
if (entry.Name.EndsWith(".sqlite3")) {
|
||||||
entry.ExtractToFile(newName);
|
entry.ExtractToFile(newName);
|
||||||
await ImportSqlite(newName);
|
await ImportSqlite(newName, keepSource: false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -221,7 +233,11 @@ namespace Elwig.Helpers.Export {
|
|||||||
|
|
||||||
var oldName = Path.ChangeExtension(App.Config.DatabaseFile, ".old.sqlite3");
|
var oldName = Path.ChangeExtension(App.Config.DatabaseFile, ".old.sqlite3");
|
||||||
File.Move(App.Config.DatabaseFile, oldName, true);
|
File.Move(App.Config.DatabaseFile, oldName, true);
|
||||||
File.Move(filename, App.Config.DatabaseFile, false);
|
if (keepSource) {
|
||||||
|
File.Copy(filename, App.Config.DatabaseFile, false);
|
||||||
|
} else {
|
||||||
|
File.Move(filename, App.Config.DatabaseFile, false);
|
||||||
|
}
|
||||||
|
|
||||||
using var cnx = await AppDbContext.ConnectAsync();
|
using var cnx = await AppDbContext.ConnectAsync();
|
||||||
await cnx.ExecuteBatch("VACUUM");
|
await cnx.ExecuteBatch("VACUUM");
|
||||||
@@ -234,7 +250,7 @@ namespace Elwig.Helpers.Export {
|
|||||||
using (var cnx = await AppDbContext.ConnectAsync($"Data Source=\"{newName}\"; Mode=ReadWriteCreate; Foreign Keys=False; Cache=Default; Pooling=False")) {
|
using (var cnx = await AppDbContext.ConnectAsync($"Data Source=\"{newName}\"; Mode=ReadWriteCreate; Foreign Keys=False; Cache=Default; Pooling=False")) {
|
||||||
await cnx.ExecuteBatch(await reader.ReadToEndAsync());
|
await cnx.ExecuteBatch(await reader.ReadToEndAsync());
|
||||||
}
|
}
|
||||||
await ImportSqlite(newName);
|
await ImportSqlite(newName, keepSource: false);
|
||||||
} finally {
|
} finally {
|
||||||
if (File.Exists(newName)) File.Delete(newName);
|
if (File.Exists(newName)) File.Delete(newName);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ using System.IO.Compression;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.Json.Nodes;
|
using System.Text.Json.Nodes;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
|
||||||
|
|
||||||
namespace Elwig.Helpers.Export {
|
namespace Elwig.Helpers.Export {
|
||||||
public static class ElwigData {
|
public static class ElwigData {
|
||||||
@@ -36,14 +35,16 @@ namespace Elwig.Helpers.Export {
|
|||||||
public static async Task Import(IEnumerable<string> filenames, ImportMode mode) {
|
public static async Task Import(IEnumerable<string> filenames, ImportMode mode) {
|
||||||
try {
|
try {
|
||||||
Dictionary<string, Branch> branches;
|
Dictionary<string, Branch> branches;
|
||||||
|
Dictionary<int, AT_Kg> kgs;
|
||||||
Dictionary<int, int> currentDids;
|
Dictionary<int, int> currentDids;
|
||||||
Dictionary<string, int> currentLsNrs;
|
Dictionary<string, int> currentLsNrs;
|
||||||
Dictionary<int, List<WbRd>> currentWbRde;
|
Dictionary<int, List<WbRd>> currentWbRde;
|
||||||
Dictionary<int, AT_Kg> kgs;
|
Dictionary<int, WbKg> currentWbKgs;
|
||||||
List<WbGl> currentWbGls;
|
List<WbGl> currentWbGls;
|
||||||
|
|
||||||
using (var ctx = new AppDbContext()) {
|
using (var ctx = new AppDbContext()) {
|
||||||
branches = await ctx.FetchBranches().ToDictionaryAsync(b => b.ZwstId);
|
branches = await ctx.FetchBranches().ToDictionaryAsync(b => b.ZwstId);
|
||||||
|
kgs = await ctx.Katastralgemeinden.ToDictionaryAsync(k => k.KgNr);
|
||||||
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));
|
||||||
@@ -52,8 +53,8 @@ namespace Elwig.Helpers.Export {
|
|||||||
currentWbRde = await ctx.WbRde
|
currentWbRde = await ctx.WbRde
|
||||||
.GroupBy(r => r.KgNr)
|
.GroupBy(r => r.KgNr)
|
||||||
.ToDictionaryAsync(g => g.Key, g => g.ToList());
|
.ToDictionaryAsync(g => g.Key, g => g.ToList());
|
||||||
|
currentWbKgs = await ctx.WbKgs.ToDictionaryAsync(k => k.KgNr);
|
||||||
currentWbGls = await ctx.WbGls.ToListAsync();
|
currentWbGls = await ctx.WbGls.ToListAsync();
|
||||||
kgs = await ctx.Katastralgemeinden.Include(k => k.WbKg).ToDictionaryAsync(k => k.KgNr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var data = new List<(
|
var data = new List<(
|
||||||
@@ -122,6 +123,7 @@ namespace Elwig.Helpers.Export {
|
|||||||
var obj = JsonNode.Parse(line)!.AsObject();
|
var obj = JsonNode.Parse(line)!.AsObject();
|
||||||
var (k, g) = obj.ToWbKg(currentWbGls);
|
var (k, g) = obj.ToWbKg(currentWbGls);
|
||||||
r.WbKgs.Add(k);
|
r.WbKgs.Add(k);
|
||||||
|
currentWbKgs[k.KgNr] = k;
|
||||||
if (g != null) {
|
if (g != null) {
|
||||||
currentWbGls[g.GlNr] = g;
|
currentWbGls[g.GlNr] = g;
|
||||||
r.WbGls.Add(g);
|
r.WbGls.Add(g);
|
||||||
@@ -135,7 +137,7 @@ namespace Elwig.Helpers.Export {
|
|||||||
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 (m, b, telNrs, emailAddrs, timestamps) = obj.ToMember(kgs);
|
var (m, b, telNrs, emailAddrs, timestamps) = obj.ToMember(kgs, currentWbKgs);
|
||||||
r.Members.Add(m);
|
r.Members.Add(m);
|
||||||
if (b != null) r.BillingAddresses.Add(b);
|
if (b != null) r.BillingAddresses.Add(b);
|
||||||
r.TelephoneNumbers.AddRange(telNrs);
|
r.TelephoneNumbers.AddRange(telNrs);
|
||||||
@@ -163,7 +165,7 @@ namespace Elwig.Helpers.Export {
|
|||||||
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 (contract, areaCom, wbrd, timestamps) = obj.ToAreaCom(currentWbRde);
|
var (contract, areaCom, wbrd, timestamps) = obj.ToAreaCom(kgs, currentWbKgs, currentWbRde);
|
||||||
r.Contracts.Add(contract);
|
r.Contracts.Add(contract);
|
||||||
r.AreaCommitments.Add(areaCom);
|
r.AreaCommitments.Add(areaCom);
|
||||||
if (wbrd != null) {
|
if (wbrd != null) {
|
||||||
@@ -182,7 +184,7 @@ namespace Elwig.Helpers.Export {
|
|||||||
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 (contract, areaComs, wbrd, timestamps) = obj.ToAreaComContract(currentWbRde);
|
var (contract, areaComs, wbrd, timestamps) = obj.ToAreaComContract(kgs, currentWbKgs, currentWbRde);
|
||||||
r.Contracts.Add(contract);
|
r.Contracts.Add(contract);
|
||||||
r.AreaCommitments.AddRange(areaComs.Select(v => v.Item1));
|
r.AreaCommitments.AddRange(areaComs.Select(v => v.Item1));
|
||||||
if (wbrd != null) {
|
if (wbrd != null) {
|
||||||
@@ -203,7 +205,7 @@ namespace Elwig.Helpers.Export {
|
|||||||
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 (d, parts, mods, rde, timestamps) = obj.ToDelivery(currentLsNrs, currentDids, kgs, currentWbRde);
|
var (d, parts, mods, rde, timestamps) = obj.ToDelivery(currentLsNrs, currentDids, kgs, currentWbKgs, currentWbRde);
|
||||||
r.Deliveries.Add(d);
|
r.Deliveries.Add(d);
|
||||||
r.DeliveryParts.AddRange(parts.Select(p => p.Item1));
|
r.DeliveryParts.AddRange(parts.Select(p => p.Item1));
|
||||||
r.Modifiers.AddRange(mods);
|
r.Modifiers.AddRange(mods);
|
||||||
@@ -636,6 +638,8 @@ namespace Elwig.Helpers.Export {
|
|||||||
["zwstid"] = m.ZwstId,
|
["zwstid"] = m.ZwstId,
|
||||||
["lfbis_nr"] = m.LfbisNr,
|
["lfbis_nr"] = m.LfbisNr,
|
||||||
["ustid_nr"] = m.UstIdNr,
|
["ustid_nr"] = m.UstIdNr,
|
||||||
|
["ooc_id"] = m.OrganicOperatorId,
|
||||||
|
["org_auth_code"] = m.OrganicAuthorityCode,
|
||||||
["juridical_pers"] = m.IsJuridicalPerson,
|
["juridical_pers"] = m.IsJuridicalPerson,
|
||||||
["volllieferant"] = m.IsVollLieferant,
|
["volllieferant"] = m.IsVollLieferant,
|
||||||
["buchführend"] = m.IsBuchführend,
|
["buchführend"] = m.IsBuchführend,
|
||||||
@@ -680,11 +684,11 @@ namespace Elwig.Helpers.Export {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static (Member, BillingAddr?, List<MemberTelNr>, List<MemberEmailAddr>, (DateTime CreatedAt, DateTime ModifiedAt)?) ToMember(this JsonNode json, Dictionary<int, AT_Kg> kgs) {
|
public static (Member, BillingAddr?, List<MemberTelNr>, List<MemberEmailAddr>, (DateTime CreatedAt, DateTime ModifiedAt)?) ToMember(this JsonNode json, Dictionary<int, AT_Kg> kgs, Dictionary<int, WbKg> currentWbKgs) {
|
||||||
var mgnr = json["mgnr"]!.AsValue().GetValue<int>();
|
var mgnr = json["mgnr"]!.AsValue().GetValue<int>();
|
||||||
var kgnr = json["default_kgnr"]?.AsValue().GetValue<int>();
|
var kgnr = json["default_kgnr"]?.AsValue().GetValue<int>();
|
||||||
if (kgnr != null && !kgs.Values.Any(k => k.WbKg?.KgNr == kgnr)) {
|
if (kgnr != null && !currentWbKgs.Values.Any(k => k.KgNr == kgnr)) {
|
||||||
throw new ArgumentException($"Für KG {(kgs.TryGetValue(kgnr.Value, out var k) ? k.Name : "?")} ({kgnr:00000}) ist noch keine Großlage festgelegt!\n(Stammdaten → Herkunftshierarchie)");
|
throw new KeyNotFoundException($"Für KG {(kgs.TryGetValue(kgnr.Value, out var k) ? k.Name : "?")} ({kgnr:00000}) ist noch keine Großlage festgelegt!\n(Stammdaten \u2192 Herkunftshierarchie)");
|
||||||
}
|
}
|
||||||
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>();
|
||||||
@@ -708,6 +712,8 @@ namespace Elwig.Helpers.Export {
|
|||||||
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>(),
|
||||||
UstIdNr = json["ustid_nr"]?.AsValue().GetValue<string>(),
|
UstIdNr = json["ustid_nr"]?.AsValue().GetValue<string>(),
|
||||||
|
OrganicOperatorId = json["ooc_id"]?.AsValue().GetValue<string>(),
|
||||||
|
OrganicAuthorityCode = json["org_auth_code"]?.AsValue().GetValue<string>(),
|
||||||
IsJuridicalPerson = json["juridical_pers"]?.AsValue().GetValue<bool>() ?? false,
|
IsJuridicalPerson = json["juridical_pers"]?.AsValue().GetValue<bool>() ?? false,
|
||||||
IsVollLieferant = json["volllieferant"]?.AsValue().GetValue<bool>() ?? false,
|
IsVollLieferant = json["volllieferant"]?.AsValue().GetValue<bool>() ?? false,
|
||||||
IsBuchführend = json["buchführend"]?.AsValue().GetValue<bool>() ?? false,
|
IsBuchführend = json["buchführend"]?.AsValue().GetValue<bool>() ?? false,
|
||||||
@@ -760,7 +766,8 @@ namespace Elwig.Helpers.Export {
|
|||||||
["reason"] = h.Reason,
|
["reason"] = h.Reason,
|
||||||
["source"] = h.Source,
|
["source"] = h.Source,
|
||||||
["shares"] = h.Shares,
|
["shares"] = h.Shares,
|
||||||
["signed"] = h.MemberHasSigned,
|
["signed_company"] = h.CompanyHasSigned,
|
||||||
|
["signed_member"] = h.MemberHasSigned,
|
||||||
["value_per_share"] = h.ValuePerShare,
|
["value_per_share"] = h.ValuePerShare,
|
||||||
["currency"] = h.CurrencyCode,
|
["currency"] = h.CurrencyCode,
|
||||||
["deduct_year"] = h.DeductYear,
|
["deduct_year"] = h.DeductYear,
|
||||||
@@ -780,7 +787,8 @@ namespace Elwig.Helpers.Export {
|
|||||||
Reason = json["reason"]!.AsValue().GetValue<string>(),
|
Reason = json["reason"]!.AsValue().GetValue<string>(),
|
||||||
Source = json["source"]!.AsValue().GetValue<string>(),
|
Source = json["source"]!.AsValue().GetValue<string>(),
|
||||||
Shares = json["shares"]!.AsValue().GetValue<int>(),
|
Shares = json["shares"]!.AsValue().GetValue<int>(),
|
||||||
MemberHasSigned = json["signed"]?.AsValue().GetValue<bool>() ?? false,
|
CompanyHasSigned = json["signed_company"]?.AsValue().GetValue<bool>() ?? false,
|
||||||
|
MemberHasSigned = json["signed_member"]?.AsValue().GetValue<bool>() ?? false,
|
||||||
ValuePerShare = json["value_per_share"]?.AsValue().GetValue<decimal>(),
|
ValuePerShare = json["value_per_share"]?.AsValue().GetValue<decimal>(),
|
||||||
CurrencyCode = json["currency"]?.AsValue().GetValue<string>(),
|
CurrencyCode = json["currency"]?.AsValue().GetValue<string>(),
|
||||||
DeductYear = json["deduct_year"]?.AsValue().GetValue<int>(),
|
DeductYear = json["deduct_year"]?.AsValue().GetValue<int>(),
|
||||||
@@ -815,10 +823,13 @@ namespace Elwig.Helpers.Export {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static (AreaComContract, List<(AreaCom, (DateTime CreatedAt, DateTime ModifiedAt)?)>, WbRd?, (DateTime CreatedAt, DateTime ModifiedAt)?) ToAreaComContract(this JsonNode json, Dictionary<int, List<WbRd>> riede) {
|
public static (AreaComContract, List<(AreaCom, (DateTime CreatedAt, DateTime ModifiedAt)?)>, WbRd?, (DateTime CreatedAt, DateTime ModifiedAt)?) ToAreaComContract(this JsonNode json, Dictionary<int, AT_Kg> kgs, Dictionary<int, WbKg> currentWbKgs, 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>();
|
||||||
var fbnr = json["fbnr"]!.AsValue()!.GetValue<int>();
|
var fbnr = json["fbnr"]!.AsValue()!.GetValue<int>();
|
||||||
|
if (!currentWbKgs.Values.Any(k => k.KgNr == kgnr)) {
|
||||||
|
throw new KeyNotFoundException($"Für KG {(kgs.TryGetValue(kgnr, out var k) ? k.Name : "?")} ({kgnr:00000}) ist noch keine Großlage festgelegt!\n(Stammdaten \u2192 Herkunftshierarchie)");
|
||||||
|
}
|
||||||
WbRd? rd = null;
|
WbRd? rd = null;
|
||||||
bool newRd = false;
|
bool newRd = false;
|
||||||
if (ried != null) {
|
if (ried != null) {
|
||||||
@@ -866,9 +877,12 @@ namespace Elwig.Helpers.Export {
|
|||||||
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 (AreaComContract, AreaCom, WbRd?, (DateTime CreatedAt, DateTime ModifiedAt)?) ToAreaCom(this JsonNode json, Dictionary<int, List<WbRd>> riede) {
|
public static (AreaComContract, AreaCom, WbRd?, (DateTime CreatedAt, DateTime ModifiedAt)?) ToAreaCom(this JsonNode json, Dictionary<int, AT_Kg> kgs, Dictionary<int, WbKg> currentWbKgs, 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>();
|
||||||
|
if (!currentWbKgs.Values.Any(k => k.KgNr == kgnr)) {
|
||||||
|
throw new KeyNotFoundException($"Für KG {(kgs.TryGetValue(kgnr, out var k) ? k.Name : "?")} ({kgnr:00000}) ist noch keine Großlage festgelegt!\n(Stammdaten \u2192 Herkunftshierarchie)");
|
||||||
|
}
|
||||||
WbRd? rd = null;
|
WbRd? rd = null;
|
||||||
bool newRd = false;
|
bool newRd = false;
|
||||||
if (ried != null) {
|
if (ried != null) {
|
||||||
@@ -951,13 +965,13 @@ namespace Elwig.Helpers.Export {
|
|||||||
if (p.Unloading != null) obj["unloading"] = p.Unloading;
|
if (p.Unloading != null) obj["unloading"] = p.Unloading;
|
||||||
if (p.Temperature != null) obj["temperature"] = p.Temperature;
|
if (p.Temperature != null) obj["temperature"] = p.Temperature;
|
||||||
if (p.Acid != null) obj["acid"] = p.Acid;
|
if (p.Acid != null) obj["acid"] = p.Acid;
|
||||||
if (p.ScaleId != null) obj["scale_id"] = p.ScaleId;
|
if (p.ScaleTerminalId != null) obj["scale_terminal"] = p.ScaleTerminalId;
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
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, WbKg> currentWbKgs, 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);
|
||||||
@@ -983,6 +997,9 @@ namespace Elwig.Helpers.Export {
|
|||||||
}, [.. json["parts"]!.AsArray().Select(p => p!.AsObject()).Select<JsonObject, (DeliveryPart, (DateTime, DateTime)?)>(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>();
|
||||||
|
if (kgnr != null && !currentWbKgs.Values.Any(k => k.KgNr == kgnr)) {
|
||||||
|
throw new KeyNotFoundException($"Für KG {(kgs.TryGetValue(kgnr.Value, out var k) ? k.Name : "?")} ({kgnr:00000}) ist noch keine Großlage festgelegt!\n(Stammdaten \u2192 Herkunftshierarchie)");
|
||||||
|
}
|
||||||
WbRd? rd = null;
|
WbRd? rd = null;
|
||||||
if (ried != null && kgnr != null) {
|
if (ried != null && kgnr != null) {
|
||||||
var rde = riede.GetValueOrDefault(kgnr.Value, []);
|
var rde = riede.GetValueOrDefault(kgnr.Value, []);
|
||||||
@@ -1022,7 +1039,7 @@ namespace Elwig.Helpers.Export {
|
|||||||
Unloading = p["unloading"]?.AsValue().GetValue<string>() ?? ((p["lesewagen"]?.AsValue().GetValue<bool>() ?? false) ? DeliveryPart.Pumped : null),
|
Unloading = p["unloading"]?.AsValue().GetValue<string>() ?? ((p["lesewagen"]?.AsValue().GetValue<bool>() ?? false) ? DeliveryPart.Pumped : null),
|
||||||
Temperature = p["temperature"]?.AsValue().GetValue<double>(),
|
Temperature = p["temperature"]?.AsValue().GetValue<double>(),
|
||||||
Acid = p["acid"]?.AsValue().GetValue<double>(),
|
Acid = p["acid"]?.AsValue().GetValue<double>(),
|
||||||
ScaleId = p["scale_id"]?.AsValue().GetValue<string>(),
|
ScaleTerminalId = p["scale_terminal"]?.AsValue().GetValue<string>() ?? 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 :
|
}, createdAt == null || modifiedAt == null ? null :
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using Microsoft.Data.Sqlite;
|
using Microsoft.Data.Sqlite;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.IO.Hashing;
|
using System.IO.Hashing;
|
||||||
@@ -12,6 +13,7 @@ using System.Threading;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Media;
|
||||||
|
|
||||||
namespace Elwig.Helpers {
|
namespace Elwig.Helpers {
|
||||||
public static partial class Extensions {
|
public static partial class Extensions {
|
||||||
@@ -134,11 +136,39 @@ namespace Elwig.Helpers {
|
|||||||
return await cmd.ExecuteScalarAsync();
|
return await cmd.ExecuteScalarAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<(string Table, long RowId, string Parent, long FkId)[]> ForeignKeyCheck(this SqliteConnection cnx) {
|
public static async Task QuickCheck(this SqliteConnection cnx) {
|
||||||
|
using var cmd = cnx.CreateCommand();
|
||||||
|
cmd.CommandText = "PRAGMA quick_check";
|
||||||
|
using var reader = await cmd.ExecuteReaderAsync();
|
||||||
|
var list = new List<string>();
|
||||||
|
while (await reader.ReadAsync()) {
|
||||||
|
list.Add(reader.GetString(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (list.Count != 1 || list[0] != "ok") {
|
||||||
|
throw new FileFormatException($"Integrity problems ({list.Count}):\n" + string.Join("\n", list.Take(50)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task IntegrityCheck(this SqliteConnection cnx) {
|
||||||
|
using var cmd = cnx.CreateCommand();
|
||||||
|
cmd.CommandText = "PRAGMA integrity_check";
|
||||||
|
using var reader = await cmd.ExecuteReaderAsync();
|
||||||
|
var list = new List<string>();
|
||||||
|
while (await reader.ReadAsync()) {
|
||||||
|
list.Add(reader.GetString(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (list.Count != 1 || list[0] != "ok") {
|
||||||
|
throw new FileFormatException($"Integrity problems ({list.Count}):\n" + string.Join("\n", list.Take(50)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task ForeignKeyCheck(this SqliteConnection cnx) {
|
||||||
using var cmd = cnx.CreateCommand();
|
using var cmd = cnx.CreateCommand();
|
||||||
cmd.CommandText = "PRAGMA foreign_key_check";
|
cmd.CommandText = "PRAGMA foreign_key_check";
|
||||||
using var reader = await cmd.ExecuteReaderAsync();
|
using var reader = await cmd.ExecuteReaderAsync();
|
||||||
var list = new List<(string, long, string, long)>();
|
var list = new List<(string Table, long RowId, string Parent, long FkId)>();
|
||||||
while (await reader.ReadAsync()) {
|
while (await reader.ReadAsync()) {
|
||||||
var table = reader.GetString(0);
|
var table = reader.GetString(0);
|
||||||
var rowid = reader.GetInt64(1);
|
var rowid = reader.GetInt64(1);
|
||||||
@@ -146,7 +176,11 @@ namespace Elwig.Helpers {
|
|||||||
var fkid = reader.GetInt64(3);
|
var fkid = reader.GetInt64(3);
|
||||||
list.Add((table, rowid, parent, fkid));
|
list.Add((table, rowid, parent, fkid));
|
||||||
}
|
}
|
||||||
return [.. list];
|
|
||||||
|
if (list.Count > 0) {
|
||||||
|
throw new InvalidDataException($"Foreign key violations ({list.Count}):\n" + string.Join("\n", list.Take(50)
|
||||||
|
.Select(v => $"{v.Table} - {v.RowId} - {v.Parent} - {v.FkId}")));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IEnumerable<T> Join<T>(this IEnumerable<T> src, Func<T> separatorFactory) {
|
public static IEnumerable<T> Join<T>(this IEnumerable<T> src, Func<T> separatorFactory) {
|
||||||
@@ -159,17 +193,25 @@ namespace Elwig.Helpers {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
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, Brush? color = null) {
|
||||||
var tb = new TextBlock() {
|
var tb = new TextBlock() {
|
||||||
Text = text,
|
Text = text,
|
||||||
TextAlignment = alignRight ? TextAlignment.Right : alignCenter ? TextAlignment.Center : TextAlignment.Left,
|
TextAlignment = alignRight ? TextAlignment.Right : alignCenter ? TextAlignment.Center : TextAlignment.Left,
|
||||||
Margin = new(0, 12 * row, 0, 0),
|
Margin = new(0, 12 * row, 0, 0),
|
||||||
FontWeight = bold ? FontWeights.Bold : FontWeights.Normal,
|
FontWeight = bold ? FontWeights.Bold : FontWeights.Normal,
|
||||||
};
|
};
|
||||||
|
if (color != null) tb.Foreground = color;
|
||||||
tb.SetValue(Grid.ColumnProperty, col);
|
tb.SetValue(Grid.ColumnProperty, col);
|
||||||
tb.SetValue(Grid.ColumnSpanProperty, colSpan);
|
tb.SetValue(Grid.ColumnSpanProperty, colSpan);
|
||||||
grid.Children.Add(tb);
|
grid.Children.Add(tb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static (int Year, int Week) GetYearAndWeek(this DateTime date) {
|
||||||
|
return (ISOWeek.GetYear(date), ISOWeek.GetWeekOfYear(date));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static (int Year, int Tertial) GetYearAndTertial(this DateTime date) {
|
||||||
|
return (date.Month <= 7 ? date.Year - 1 : date.Year, date.Month == 12 || date.Month <= 3 ? 2 : date.Month <= 7 ? 3 : 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,303 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace Elwig.Helpers {
|
||||||
|
public static partial class Normalizer {
|
||||||
|
|
||||||
|
[GeneratedRegex(@"(?=(?:(?:bundes)?straße|gasse|weg|platz|allee|ring|zeile?|steig|hof|markt|kai|ufer|brücke|tor|stiege|promenade|gang|siedlung)\b)|[\s-]+", RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase)]
|
||||||
|
private static partial Regex GeneratedStreetNameWordsRegex();
|
||||||
|
private static readonly Regex StreetNameWordsRegex = GeneratedStreetNameWordsRegex();
|
||||||
|
|
||||||
|
private static readonly HashSet<string> StreetTypes = [
|
||||||
|
"Straße", "Gasse", "Weg", "Platz", "Allee", "Ring", "Zeile", "Zeil", "Steig", "Hof",
|
||||||
|
"Markt", "Kai", "Ufer", "Brücke", "Tor", "Stiege", "Promenade", "Gang", "Siedlung"];
|
||||||
|
|
||||||
|
private static readonly HashSet<string> StreetArticles = ["der", "die", "das", "des", "dem", "den"];
|
||||||
|
|
||||||
|
private static readonly HashSet<string> StreetPrepositions = [
|
||||||
|
"an", "am", "auf", "aus", "bei", "beim", "hinter", "hinterm", "in", "im", "ins", "nach",
|
||||||
|
"neben", "über", "unter", "von", "vom", "van", "vor", "zu", "zum", "zur", "zwischen",
|
||||||
|
"durch", "mit"];
|
||||||
|
|
||||||
|
private static readonly HashSet<string> StreetNumbers = [ "Zwei", "Drei", "Vier", "Fünf", "Sechs", "Sieben" ];
|
||||||
|
|
||||||
|
private static readonly HashSet<string> StreetAdjectives = [
|
||||||
|
"alter", "alte", "alten", "altem", "altes",
|
||||||
|
"äußere", "äußere", "äußeren", "äußerem", "äußeres",
|
||||||
|
// "breiter", "breite", "breiten", "breitem", "breites",
|
||||||
|
"dritter", "dritte", "dritten", "drittem", "drittes",
|
||||||
|
"erster", "erste", "ersten", "erstem", "erstes",
|
||||||
|
"großer", "große", "großen", "großem", "großes",
|
||||||
|
"hoher", "hohe", "hohen", "hohem", "hohes",
|
||||||
|
"innerer", "innere", "inneren", "innerem", "inneres",
|
||||||
|
"kleiner", "kleine", "kleinen", "kleinem", "kleines",
|
||||||
|
"kurzer", "kurze", "kurzen", "kurzem", "kurzes",
|
||||||
|
"langer", "lange", "langen", "langem", "langes",
|
||||||
|
"linker", "linke", "linken", "linkem", "linkes",
|
||||||
|
"mittlerer", "mittlere", "mittleren", "mittlerem", "mittleres",
|
||||||
|
"neuer", "neue", "neuen", "neuem", "neues",
|
||||||
|
"oberer", "obere", "oberen", "oberem", "oberes",
|
||||||
|
"rechter", "rechte", "rechten", "rechtem", "rechtes",
|
||||||
|
"schmaler", "schmale", "schmalen", "schmalem", "schmales",
|
||||||
|
"schöner", "schöne", "schönen", "schönem", "schönes",
|
||||||
|
"unterer", "untere", "unteren", "unterem", "unteres",
|
||||||
|
"hinterer", "hintere", "hinteren", "hinterem", "hinteres",
|
||||||
|
"vorderer", "vordere", "vorderen", "vorderem", "vorderes",
|
||||||
|
"runder", "runde", "runden", "rundem", "rundes",
|
||||||
|
"kalter", "kalte", "kalten", "kaltem", "kaltes"];
|
||||||
|
|
||||||
|
private static readonly HashSet<string> StreetLastNames = [
|
||||||
|
"Habsburger", "Lothringer", "Leitzenberger", "Luyderer", "Preiner", "Radinger", "Seefelder", "Staribacher", "Gschmeidler",
|
||||||
|
"Hannover", "Münster", "Salzgitter", "Speyer", "Trier"];
|
||||||
|
|
||||||
|
private static readonly HashSet<string> StreetPersonTitles = [
|
||||||
|
"St.", "Familie",
|
||||||
|
"Dr.", "DDr.", "Hofrat", "Baurat", "Kommerzialrat", "Dir.", "Ing.", "Prof.", "Mag.", "DI", "OSR", "Präsident",
|
||||||
|
"Landeshauptmann", "LH", "Bürgermeister", "Bgm.", "Minister",
|
||||||
|
"Kaiser", "Kaiserin", "König", "Königin", "Erzherzog", "Erzherzogin", "Herzog", "Fürst", "Graf", "Gräfin", "Markgraf", "Kronprinz", "Prinz", "Ritter", "Freiherr", "Lord",
|
||||||
|
"Abt", "Bischof", "Propst", "Dechant", "Kardinal", "Monsignore", "Pfarrer", "Pater", "Prälat",
|
||||||
|
"Oberst"];
|
||||||
|
|
||||||
|
private static readonly HashSet<string> StreetGivenNames = [
|
||||||
|
"Adalbert", "Adam", "Adele", "Adelheid", "Adolf", "Adolph", "Adrian", "Albert", "Albrecht", "Alexander", "Alfons", "Alfred", "Alois", "Aloisia",
|
||||||
|
"Andreas", "Andrea", "Andre", "Anna", "Anton", "Arnold", "Arthur", "August", "Augustin", "Augustine", "Agnes", "Angelika", "Ada", "Adelheid", "Anni", "Anita",
|
||||||
|
"Barbara", "Beate", "Beatrix", "Benedikt", "Bernhard", "Berta", "Bertha", "Berthold", "Brüder", "Bruno", "Brigitte",
|
||||||
|
"Camillo", "Carl", "Caspar", "Catharina", "Christian", "Christine", "Christof", "Christoph", "Clara", "Clemens", "Conrad", "Claus", "Camillo", "Claudia",
|
||||||
|
"Daniel", "Dietmar", "Dietrich",
|
||||||
|
"Edgar", "Edi", "Edith", "Edmund", "Egon", "Elsa", "Eduard", "Emmerich", "Erhard", "Erich", "Ernst", "Erwin", "Eugen", "Ewald", "Eberhard",
|
||||||
|
"Elisabeth", "Emanuel", "Emerich", "Emil", "Emma", "Engelbert", "Elias",
|
||||||
|
"Franz", "Ferdinand", "Friedrich", "Felix", "Florian", "Fritz", "Franziska", "Fred",
|
||||||
|
"Georg", "Gregor", "Gustav", "Gabriel", "Gebrüder", "Gabriele", "Gerhard", "Gerhart", "Gertrude", "Gottfried", "Gottlieb", "Grete",
|
||||||
|
"Günther", "Günter",
|
||||||
|
"Hans", "Hanns", "Heinrich", "Heinz", "Helmut", "Helmuth", "Hermann", "Herta", "Herbert", "Hubert", "Harald", "Horst", "Helene", "Helga",
|
||||||
|
"Hieronymus", "Hilde", "Hugo",
|
||||||
|
"Isabelle", "Ignaz", "Ilse", "Ingeborg", "Isidor",
|
||||||
|
"Josef", "Josefine", "Joseph", "Johann", "Johanna", "Johan", "Johannes", "Hannes", "Harry", "Jakob", "Jacob", "Jan", "Julian", "Julius", "Julia", "Jürgen",
|
||||||
|
"Karl", "Kasimir", "Konrad", "Klemens", "Klara", "Katharina", "Kurt", "Kaspar", "Klaus", "Koloman", "Konstantin", "Killian",
|
||||||
|
"Leopold", "Leo", "Lorenz", "Lothar", "Louise", "Ludmilla", "Ludwig", "Lukas", "Ladislaus", "Lambert", "Laurenz", "Liese",
|
||||||
|
"Lise", "Lilly", "Lina", "Lothar", "Lotte", "Luise", "Leonhard", "Lotte", "Martha",
|
||||||
|
"Maria", "Marie", "Michael", "Martin", "Max", "Maximilian", "Manuel", "Manuela", "Moritz", "Marianne", "Manfred", "Marc",
|
||||||
|
"Mathias", "Matthias", "Matthäus",
|
||||||
|
"Margarete", "Margarethe",
|
||||||
|
"Nico", "Niko", "Niklas", "Niclas", "Nikolaus", "Norbert",
|
||||||
|
"Otto", "Ottokar", "Oskar", "Olga", "Oswald", "Othmar",
|
||||||
|
"Paul", "Pauline", "Patrick", "Pepi", "Peter", "Philipp", "Philip", "Petrus",
|
||||||
|
"Robert", "Rudolf", "Richard", "Ruprecht", "Raffael", "Rolf", "Roman", "Rosa", "Rosalia", "Rupert", "Raimund",
|
||||||
|
"Sigmund", "Siegfried", "Simon", "Stanislaus", "Stefan", "Stephan", "Sepp", "Samuel", "Sebastian", "Susi",
|
||||||
|
"Theodor", "Thomas", "Theresia", "Thaddäus", "Theo", "Theophil", "Tina", "Titus", "Toni", "Trude",
|
||||||
|
"Ullrich", "Ulrich", "Udo",
|
||||||
|
"Viktor", "Vinzenz", "Victor",
|
||||||
|
"Wolfgang", "Willibald", "Wilhelm", "Willhelm", "Wilhelmine", "Walter", "Walther", "Wenzel", "Werner", "Willi",
|
||||||
|
"Zacharias"];
|
||||||
|
|
||||||
|
private static readonly HashSet<string> LocalityNames = [
|
||||||
|
"Groß-Enzersdorf",
|
||||||
|
"Groß Burgstall", "Klein Eberharts", "Klein-Engersdorf", "Groß-Enzersdorf", "Klein-Erlauf",
|
||||||
|
"Groß Gerungs", "Klein Gundholz", "Klein-Harras", "Klein-Heinrichschlag", "Groß-Höbarten",
|
||||||
|
"Klein-Jetzelsdorf", "Klein-Mariazell", "Groß Meinharts", "Klein-Meiseldorf", "Groß-Neusiedl", "Klein-Neusiedl", "Klein-Pöchlarn",
|
||||||
|
"Groß-Radischen", "Klein-Radischen", "Groß Raßberg", "Klein Reinprechts", "Klein-Reinprechtsdorf", "Groß-Reipersdorf", "Klein-Ruprechts",
|
||||||
|
"Groß-Schollach", "Klein-Schollach", "Groß-Schweinbarth", "Groß-Siegharts", "Klein-Siegharts", "Groß Sierning",
|
||||||
|
"Klein-Ulrichschlag", "Klein Weinberg", "Klein Wetzles", "Klein-Wien",
|
||||||
|
];
|
||||||
|
|
||||||
|
private static bool IsGivenName(this string word) {
|
||||||
|
return StreetGivenNames.Contains(word);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsFamilyName(this string word) {
|
||||||
|
if (StreetLastNames.Contains(word))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsPersonalName(this string word) {
|
||||||
|
return word.IsGivenName() || word.IsFamilyName();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsGeographicalDerivativeName(this string word) {
|
||||||
|
if (!word.EndsWith("er") || word.IsPersonalName() || word == "Weißer")
|
||||||
|
return false;
|
||||||
|
return word.StartsWith("St. ") || word.StartsWith("Ober ") || word.StartsWith("Unter ") || word.StartsWith("Maria") ||
|
||||||
|
word.EndsWith("sdorfer") || word.EndsWith("ndorfer") || word.EndsWith("ldorfer") ||
|
||||||
|
word.EndsWith("felder") ||
|
||||||
|
word.EndsWith("sthaler") || word.EndsWith("nthaler") || word.EndsWith("lthaler") ||
|
||||||
|
word.EndsWith("dauer") || word.EndsWith("lauer") || word.EndsWith("mauer") || word.EndsWith("nauer") || word.EndsWith("ßauer") ||
|
||||||
|
word.EndsWith("lbacher") || word.EndsWith("nbacher") || word.EndsWith("ßbacher") ||
|
||||||
|
word.EndsWith("ringer") || word.EndsWith("singer") ||
|
||||||
|
word.EndsWith("sbrunner") || word.EndsWith("nbrunner") || word.EndsWith("lbrunner") || word.EndsWith("abrunner") || word.EndsWith("ingbrunner") ||
|
||||||
|
word.EndsWith("sburger") || word.EndsWith("nburger") || word.EndsWith("mburger") || word.EndsWith("lburger") || word.EndsWith("neuburger") ||
|
||||||
|
word.EndsWith("berger") ||
|
||||||
|
word.EndsWith("winkler") ||
|
||||||
|
word.EndsWith("lsteiner") || word.EndsWith("nsteiner") ||
|
||||||
|
word.EndsWith("städter") ||
|
||||||
|
word.EndsWith("stättner") || word.EndsWith("stettner") ||
|
||||||
|
word.EndsWith("brücker") ||
|
||||||
|
word.EndsWith("further") || word.EndsWith("furter") ||
|
||||||
|
word.EndsWith("aaer") ||
|
||||||
|
word.EndsWith("seer") || word.EndsWith("leer") ||
|
||||||
|
word.EndsWith("tzner") ||
|
||||||
|
word.EndsWith("zeller") ||
|
||||||
|
word.EndsWith("rther") ||
|
||||||
|
word.EndsWith("sdner") ||
|
||||||
|
word.EndsWith("gerner") || word.EndsWith("berner") ||
|
||||||
|
word.EndsWith("frieder") ||
|
||||||
|
word.EndsWith("litzer") || word.EndsWith("mitzer") || word.EndsWith("eutzer") ||
|
||||||
|
word.EndsWith("loner") ||
|
||||||
|
word.EndsWith("skirchner") || word.EndsWith("nkirchner") || word.EndsWith("ingkirchner") ||
|
||||||
|
word.EndsWith("ziger") ||
|
||||||
|
word.EndsWith("ließer") ||
|
||||||
|
word.EndsWith("gerer") ||
|
||||||
|
word.EndsWith("kreuzer") ||
|
||||||
|
word == "Wiener" || word == "Brünner" || word == "Znaimer" || word == "Triester" || word == "Prager" || word == "Berliner" || word == "Basler" ||
|
||||||
|
word == "Retzer" || word == "Tullner" || word == "Badner" ||
|
||||||
|
word == "Gruber" || word == "Sulzer" || word == "Harraser" || word == "Dörfleser" || word == "Neusiedler" ||
|
||||||
|
word == "Dornauer" || word == "Siebenhauser" || word == "Alser" ||
|
||||||
|
word == "Bockenheimer";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string NormalizeAddress(string address, string? locality = null) {
|
||||||
|
var idx = address.IndexOf(',');
|
||||||
|
if (idx >= 0) address = address[..idx];
|
||||||
|
var (name, nr) = Utils.SplitAddress(address);
|
||||||
|
return (NormalizeStreetName(name, locality) + " " + nr).Trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string NormalizeStreetName(string name, string? locality = null) {
|
||||||
|
name = name.Trim().ToLowerInvariant();
|
||||||
|
if (name == "") {
|
||||||
|
return "";
|
||||||
|
} else if (name == "nr.") {
|
||||||
|
if (locality == null)
|
||||||
|
return "Nr.";
|
||||||
|
name = locality.Trim().ToLowerInvariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
name = name.Replace("hautp", "haupt")
|
||||||
|
.Replace("leop.", "leopold ").Replace("ferd.", "ferdinand ").Replace("gottfr.", "gottfried ")
|
||||||
|
.Replace("heinr.", "heinrich").Replace("joh.", "johann ").Replace("jos.", "josef ")
|
||||||
|
.Replace("msgr.", "monsignore ").Replace("pf.", "pfarrer ")
|
||||||
|
.Replace("präs.", "präsident ");
|
||||||
|
name = name.Replace("str.", "straße").Replace("strasse", "straße")
|
||||||
|
.Replace("bruecke", "brücke").Replace("pl.", "platz")
|
||||||
|
.Replace("gr.", "groß").Replace("kl.", "klein")
|
||||||
|
.Replace("sankt-", "st.").Replace("sankt ", "st.")
|
||||||
|
.Replace("wr.", "wiener ")
|
||||||
|
.Replace(".", ". ");
|
||||||
|
List<string> words = [.. StreetNameWordsRegex.Split(name)
|
||||||
|
.Where(w => !string.IsNullOrWhiteSpace(w))
|
||||||
|
.Select(w => StreetArticles.Contains(w) || StreetPrepositions.Contains(w) ? w : string.Concat(w[0..1].ToUpper(), w.AsSpan(1)))
|
||||||
|
.Select(w => w == "Ddr." ? "DDr." : w == "Lh" || w == "Osr" ? w.ToUpper() : w)
|
||||||
|
];
|
||||||
|
if (words[0] == "Di") words[0] = "DI";
|
||||||
|
|
||||||
|
var temp = "|" + string.Join('|', words) + "|";
|
||||||
|
temp = temp.Replace("|Dipl.|Ing.|", "|DI|").Replace("|Dipl|Ing.|", "|DI|")
|
||||||
|
.Replace("|Kaiser|Ebersdorf|", "|Kaiser-Ebersdorf|")
|
||||||
|
.Replace("|Kalk|Deutz|", "|Kalk-Deutz|").Replace("|Kalk|Deutzer|", "|Kalk-Deutzer|")
|
||||||
|
.Replace("|Hohe|Wand|", "|Hohe Wand|").Replace("|Hohen|Wand|", "|Hohen Wand|").Replace("|Hohewand|", "|Hohe Wand|")
|
||||||
|
.Replace("|Alten|Markt|", "|Altenmarkt|")
|
||||||
|
.Replace("|Kirch|Hof|", "|Kirchhof|").Replace("|Bisc|Hof|", "|Bischof|")
|
||||||
|
.Replace("|Wiener|Neustadt|", "|Wiener Neustadt|").Replace("|Wiener|Neustädter|", "|Wiener Neustädter|")
|
||||||
|
.Replace("|St.|Pölten|", "|St. Pölten|").Replace("|St.|Pöltner|", "|St. Pöltner|")
|
||||||
|
.Replace("|Gross|", "|Groß|")
|
||||||
|
.Replace("|Nr|", "|Nr.|").Replace("|Und|", "|und|");
|
||||||
|
words = [.. temp.Trim('|').Split('|')];
|
||||||
|
|
||||||
|
if (words.Count > 1 && (words[0] == "Groß" || words[0] == "Klein") && !StreetTypes.Contains(words[1])) {
|
||||||
|
var w = words[0] + words[1].ToLowerInvariant();
|
||||||
|
words.RemoveRange(0, 2);
|
||||||
|
words.Insert(0, w);
|
||||||
|
}
|
||||||
|
if (words[0].StartsWith("Groß") || words[0].StartsWith("Klein")) {
|
||||||
|
var repl = LocalityNames.FirstOrDefault(n => n.Replace(" ", "").Replace("-", "").Equals(words[0], StringComparison.InvariantCultureIgnoreCase));
|
||||||
|
if (repl != null) words[0] = repl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (words.Count > 2 && words[^2] == "in") {
|
||||||
|
// remove suffix "in ..."
|
||||||
|
words.RemoveRange(words.Count - 2, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
char sep = name.Contains('-') ? '-' : ' ';
|
||||||
|
if (words.Count <= 1) {
|
||||||
|
// single word
|
||||||
|
} else if (StreetTypes.Contains(words[0]) && !StreetTypes.Contains(words[^1])) {
|
||||||
|
// "Straße der ..." / "Straße des ..."
|
||||||
|
sep = ' ';
|
||||||
|
} else if (StreetTypes.Contains(words[^1])) {
|
||||||
|
// "... Straße" / "...straße"
|
||||||
|
var type = words[^1];
|
||||||
|
var isCompound = true;
|
||||||
|
var isAdjective = StreetAdjectives.Contains(words[^2].ToLowerInvariant());
|
||||||
|
var isGeographical = false;
|
||||||
|
var isPerson = false;
|
||||||
|
|
||||||
|
var geo = words.FindLastIndex(IsGeographicalDerivativeName);
|
||||||
|
if (geo >= 0 && geo < words.Count - 2 && words[^2] != "Haupt" && words[^2] != "Bundes" && words[^2] != "Keller") {
|
||||||
|
isPerson = true;
|
||||||
|
isGeographical = true;
|
||||||
|
} else if (words.Any(w => w.Contains(' ') && !w.IsGeographicalDerivativeName())) {
|
||||||
|
isPerson = true;
|
||||||
|
isGeographical = true;
|
||||||
|
} else if (StreetNumbers.Contains(words[0])) {
|
||||||
|
isPerson = true;
|
||||||
|
isGeographical = true;
|
||||||
|
} else if (!StreetPrepositions.Contains(words[0]) && !StreetArticles.Contains(words[0]) && words.FindIndex(StreetPrepositions.Contains) > 0) {
|
||||||
|
isPerson = true;
|
||||||
|
isGeographical = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (words.Count(w => w.Contains('.')) >= 2 || words.Contains("van") || words.Contains("von") || words.Contains("St.") ||
|
||||||
|
StreetPersonTitles.Contains(words[0]) || words.Any(w => w.IsGivenName()))
|
||||||
|
{
|
||||||
|
isPerson = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isPerson && isAdjective || StreetArticles.Contains(words[^2]) || StreetPrepositions.Contains(words[^2])) {
|
||||||
|
isCompound = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isPerson && words[^2].EndsWith("er") && !StreetLastNames.Contains(words[^2])) {
|
||||||
|
isGeographical = IsGeographicalDerivativeName(words[^2]);
|
||||||
|
} else if (words.Count >= 3 && words.Contains("Bad")) {
|
||||||
|
isPerson = true;
|
||||||
|
isGeographical = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
sep = isPerson ? '-' : ' ';
|
||||||
|
|
||||||
|
if (isPerson && words.Count == 2 && !isGeographical) {
|
||||||
|
isPerson = false;
|
||||||
|
isCompound = true;
|
||||||
|
}
|
||||||
|
if (isGeographical || isPerson) {
|
||||||
|
isCompound = false;
|
||||||
|
}
|
||||||
|
if (isCompound) {
|
||||||
|
var w = words[^2] + type.ToLowerInvariant();
|
||||||
|
words.RemoveRange(words.Count - 2, 2);
|
||||||
|
words.Add(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isPerson) {
|
||||||
|
words = [.. words.Select(w => w.Replace(' ', '-'))];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// unknown
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sep == '-' && StreetPrepositions.Contains(words[0]) && words[0] != "von" && words[0] != "van") {
|
||||||
|
sep = ' ';
|
||||||
|
int i;
|
||||||
|
for (i = 0; StreetPrepositions.Contains(words[i]) && i < words.Count; i++);
|
||||||
|
var word = string.Join('-', words.Skip(i));
|
||||||
|
words = [.. words.Take(i).Append(word)];
|
||||||
|
}
|
||||||
|
|
||||||
|
var norm = string.Join(sep, words);
|
||||||
|
return string.Concat(norm[0..1].ToUpperInvariant(), norm.AsSpan(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,21 +1,17 @@
|
|||||||
using Elwig.Services;
|
using Elwig.Services;
|
||||||
using Elwig.Windows;
|
using Elwig.Windows;
|
||||||
using System;
|
using System;
|
||||||
using System.Drawing.Printing;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Elwig.Helpers.Printing {
|
namespace Elwig.Helpers.Printing {
|
||||||
public static class Pdf {
|
public static class Pdf {
|
||||||
|
|
||||||
public static Task Init(Action? evtHandler = null) {
|
public static void Init(Action? evtHandler = null) {
|
||||||
PdfiumNative.FPDF_InitLibrary();
|
PdfiumNative.FPDF_InitLibrary();
|
||||||
evtHandler?.Invoke();
|
evtHandler?.Invoke();
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Task Cleanup() {
|
public static void Cleanup() {
|
||||||
PdfiumNative.FPDF_DestroyLibrary();
|
PdfiumNative.FPDF_DestroyLibrary();
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Show(TempFile file, string title) {
|
public static void Show(TempFile file, string title) {
|
||||||
@@ -32,24 +28,13 @@ namespace Elwig.Helpers.Printing {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task Print(string path, int copies = 1, bool doublePaged = false) {
|
public static void Print(string path, int copies = 1, bool doublePaged = false) {
|
||||||
await Print(path, new() {
|
|
||||||
Copies = (short)copies,
|
|
||||||
Collate = true,
|
|
||||||
Duplex = doublePaged ? Duplex.Vertical : Duplex.Simplex,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Task Print(string path, PrinterSettings settings) {
|
|
||||||
try {
|
try {
|
||||||
using var printDoc = new PdfPrintDocument(path) {
|
var printer = new PdfPrinter();
|
||||||
PrinterSettings = settings,
|
printer.Print(path, copies, doublePaged);
|
||||||
};
|
|
||||||
printDoc.Print();
|
|
||||||
} catch (Exception exc) {
|
} catch (Exception exc) {
|
||||||
InteractionService.ShowException("Fehler beim Drucken", "Beim Drucken ist ein Fehler aufgetreten", exc);
|
InteractionService.ShowException("Fehler beim Drucken", "Beim Drucken ist ein Fehler aufgetreten", exc);
|
||||||
}
|
}
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.Drawing.Imaging;
|
|
||||||
using System.Drawing.Printing;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace Elwig.Helpers.Printing {
|
|
||||||
public class PdfPrintDocument : PrintDocument {
|
|
||||||
|
|
||||||
private readonly IntPtr _handle;
|
|
||||||
private readonly int _pageCount;
|
|
||||||
private readonly double _dpi;
|
|
||||||
|
|
||||||
private int _currentPage;
|
|
||||||
|
|
||||||
public PdfPrintDocument(string path, string? password = null, double dpi = 300.0) :
|
|
||||||
base() {
|
|
||||||
_handle = PdfiumNative.FPDF_LoadDocument(path, password);
|
|
||||||
_pageCount = PdfiumNative.FPDF_GetPageCount(_handle);
|
|
||||||
_dpi = dpi;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Dispose(bool disposing) {
|
|
||||||
PdfiumNative.FPDF_CloseDocument(_handle);
|
|
||||||
base.Dispose(disposing);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnBeginPrint(PrintEventArgs evt) {
|
|
||||||
_currentPage = (PrinterSettings.FromPage != 0) ? (PrinterSettings.FromPage - 1) : 0;
|
|
||||||
base.OnBeginPrint(evt);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnPrintPage(PrintPageEventArgs evt) {
|
|
||||||
if (_currentPage < _pageCount) {
|
|
||||||
IntPtr page = PdfiumNative.FPDF_LoadPage(_handle, _currentPage);
|
|
||||||
double width = PdfiumNative.FPDF_GetPageWidth(page);
|
|
||||||
double height = PdfiumNative.FPDF_GetPageHeight(page);
|
|
||||||
int pixelWidth = (int)(width / 72.0 * _dpi);
|
|
||||||
int pixelHeight = (int)(height / 72.0 * _dpi);
|
|
||||||
|
|
||||||
IntPtr bitmap = PdfiumNative.FPDFBitmap_Create(pixelWidth, pixelHeight, 1);
|
|
||||||
PdfiumNative.FPDF_RenderPageBitmap(bitmap, page, 0, 0, pixelWidth, pixelHeight, 0, 0);
|
|
||||||
|
|
||||||
IntPtr buffer = PdfiumNative.FPDFBitmap_GetBuffer(bitmap);
|
|
||||||
int stride = PdfiumNative.FPDFBitmap_GetStride(bitmap);
|
|
||||||
using (var bmp = new Bitmap(pixelWidth, pixelHeight, stride, PixelFormat.Format32bppArgb, buffer)) {
|
|
||||||
evt.Graphics?.DrawImage(bmp, evt.PageBounds);
|
|
||||||
}
|
|
||||||
_currentPage++;
|
|
||||||
|
|
||||||
PdfiumNative.FPDFBitmap_Destroy(bitmap);
|
|
||||||
PdfiumNative.FPDF_ClosePage(page);
|
|
||||||
}
|
|
||||||
evt.HasMorePages = _currentPage < ((PrinterSettings.ToPage == 0) ? _pageCount : Math.Min(PrinterSettings.ToPage, _pageCount));
|
|
||||||
base.OnPrintPage(evt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal partial class PdfiumNative {
|
|
||||||
[LibraryImport("pdfium.dll")]
|
|
||||||
public static partial void FPDF_InitLibrary();
|
|
||||||
|
|
||||||
[LibraryImport("pdfium.dll")]
|
|
||||||
public static partial void FPDF_DestroyLibrary();
|
|
||||||
|
|
||||||
[LibraryImport("pdfium.dll", StringMarshalling = StringMarshalling.Utf8)]
|
|
||||||
public static partial IntPtr FPDF_LoadDocument(string filePath, string? password);
|
|
||||||
|
|
||||||
[LibraryImport("pdfium.dll")]
|
|
||||||
public static partial void FPDF_CloseDocument(IntPtr document);
|
|
||||||
|
|
||||||
[LibraryImport("pdfium.dll")]
|
|
||||||
public static partial int FPDF_GetPageCount(IntPtr document);
|
|
||||||
|
|
||||||
[LibraryImport("pdfium.dll")]
|
|
||||||
public static partial IntPtr FPDF_LoadPage(IntPtr document, int pageIndex);
|
|
||||||
|
|
||||||
[LibraryImport("pdfium.dll")]
|
|
||||||
public static partial void FPDF_ClosePage(IntPtr page);
|
|
||||||
|
|
||||||
[LibraryImport("pdfium.dll")]
|
|
||||||
public static partial double FPDF_GetPageWidth(IntPtr page);
|
|
||||||
|
|
||||||
[LibraryImport("pdfium.dll")]
|
|
||||||
public static partial double FPDF_GetPageHeight(IntPtr page);
|
|
||||||
|
|
||||||
[LibraryImport("pdfium.dll")]
|
|
||||||
public static partial IntPtr FPDFBitmap_Create(int width, int height, int alpha);
|
|
||||||
|
|
||||||
[LibraryImport("pdfium.dll")]
|
|
||||||
public static partial void FPDFBitmap_Destroy(IntPtr bitmap);
|
|
||||||
|
|
||||||
[LibraryImport("pdfium.dll")]
|
|
||||||
public static partial IntPtr FPDFBitmap_GetBuffer(IntPtr bitmap);
|
|
||||||
|
|
||||||
[LibraryImport("pdfium.dll")]
|
|
||||||
public static partial int FPDFBitmap_GetStride(IntPtr bitmap);
|
|
||||||
|
|
||||||
[LibraryImport("pdfium.dll")]
|
|
||||||
public static partial void FPDF_RenderPageBitmap(IntPtr bitmap, IntPtr page, int start_x, int start_y, int size_x, int size_y, int rotate, int flags);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Printing;
|
||||||
|
|
||||||
|
namespace Elwig.Helpers.Printing {
|
||||||
|
public class PdfPrinter {
|
||||||
|
|
||||||
|
public string PrinterName { get; init; }
|
||||||
|
|
||||||
|
public PdfPrinter(string? printerName = null) {
|
||||||
|
PrinterName = printerName ?? GetDefaultPrinterName() ?? throw new InvalidOperationException("No default Windows printer is configured.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Print(string pdfPath, int copies = 1, bool doublePaged = false) {
|
||||||
|
if (!File.Exists(pdfPath)) throw new FileNotFoundException("PDF file not found.", pdfPath);
|
||||||
|
|
||||||
|
IntPtr document = PdfiumNative.FPDF_LoadDocument(pdfPath, null);
|
||||||
|
if (document == IntPtr.Zero) throw new InvalidOperationException("PDFium could not open the PDF.");
|
||||||
|
|
||||||
|
try {
|
||||||
|
int pageCount = PdfiumNative.FPDF_GetPageCount(document);
|
||||||
|
if (pageCount <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
using var printer = new Win32Printer.Printer(PrinterName);
|
||||||
|
printer.TrySetDuplex(doublePaged ? Duplexing.TwoSidedLongEdge : Duplexing.OneSided);
|
||||||
|
printer.StartDocument(Path.GetFileName(pdfPath));
|
||||||
|
bool documentStarted = true;
|
||||||
|
try {
|
||||||
|
for (int i = 0; i < copies; i++) {
|
||||||
|
for (int j = 0; j < pageCount; j++) {
|
||||||
|
PrintPage(document, printer, j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printer.EndDocument();
|
||||||
|
documentStarted = false;
|
||||||
|
} finally {
|
||||||
|
if (documentStarted) printer.AbortDocument();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
PdfiumNative.FPDF_CloseDocument(document);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void PrintPage(IntPtr document, Win32Printer.Printer printer, int pageIndex) {
|
||||||
|
if (!PdfiumNative.FPDF_GetPageSizeByIndex(document, pageIndex, out double pageWidthPt, out double pageHeightPt)) {
|
||||||
|
throw new InvalidOperationException($"Unable to obtain PDF page {pageIndex} size.");
|
||||||
|
}
|
||||||
|
|
||||||
|
IntPtr page = PdfiumNative.FPDF_LoadPage(document, pageIndex);
|
||||||
|
if (page == IntPtr.Zero)
|
||||||
|
throw new InvalidOperationException($"Unable to load PDF page {pageIndex}.");
|
||||||
|
|
||||||
|
try {
|
||||||
|
int renderWidth = (int)Math.Round(pageWidthPt / 72.0 * printer.DpiX);
|
||||||
|
int renderHeight = (int)Math.Round(pageHeightPt / 72.0 * printer.DpiY);
|
||||||
|
int offsetX = (printer.PrintableWidth - renderWidth) / 2;
|
||||||
|
int offsetY = (printer.PrintableHeight - renderHeight) / 2;
|
||||||
|
|
||||||
|
printer.StartPage();
|
||||||
|
try {
|
||||||
|
PdfiumNative.FPDF_RenderPage(printer.Hdc, page, offsetX, offsetY, renderWidth, renderHeight, 0, PdfiumNative.FPDF_PRINTING | PdfiumNative.FPDF_ANNOT);
|
||||||
|
} finally {
|
||||||
|
printer.EndPage();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
PdfiumNative.FPDF_ClosePage(page);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string? GetDefaultPrinterName() {
|
||||||
|
using var key = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows NT\CurrentVersion\Windows");
|
||||||
|
string? printer = key?.GetValue("Device") as string;
|
||||||
|
if (string.IsNullOrWhiteSpace(printer))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// Device has the form:
|
||||||
|
// Printer Name,winspool,PORT
|
||||||
|
int comma = printer.IndexOf(',');
|
||||||
|
return comma >= 0 ? printer[..comma] : printer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Elwig.Helpers.Printing {
|
||||||
|
internal partial class PdfiumNative {
|
||||||
|
|
||||||
|
public const int FPDF_ANNOT = 0x01;
|
||||||
|
public const int FPDF_PRINTING = 0x800;
|
||||||
|
|
||||||
|
[LibraryImport("pdfium.dll")]
|
||||||
|
public static partial void FPDF_InitLibrary();
|
||||||
|
|
||||||
|
[LibraryImport("pdfium.dll")]
|
||||||
|
public static partial void FPDF_DestroyLibrary();
|
||||||
|
|
||||||
|
[LibraryImport("pdfium.dll", StringMarshalling = StringMarshalling.Utf8)]
|
||||||
|
public static partial IntPtr FPDF_LoadDocument(string filePath, string? password);
|
||||||
|
|
||||||
|
[LibraryImport("pdfium.dll")]
|
||||||
|
public static partial void FPDF_CloseDocument(IntPtr document);
|
||||||
|
|
||||||
|
[LibraryImport("pdfium.dll")]
|
||||||
|
public static partial int FPDF_GetPageCount(IntPtr document);
|
||||||
|
|
||||||
|
[LibraryImport("pdfium.dll")]
|
||||||
|
public static partial IntPtr FPDF_LoadPage(IntPtr document, int pageIndex);
|
||||||
|
|
||||||
|
[LibraryImport("pdfium.dll")]
|
||||||
|
public static partial void FPDF_ClosePage(IntPtr page);
|
||||||
|
|
||||||
|
[LibraryImport("pdfium.dll")]
|
||||||
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
|
public static partial bool FPDF_GetPageSizeByIndex(IntPtr document, int pageIndex, out double width, out double height);
|
||||||
|
|
||||||
|
[LibraryImport("pdfium.dll")]
|
||||||
|
public static partial void FPDF_RenderPage(IntPtr hdc, IntPtr page, int startX, int startY, int sizeX, int sizeY, int rotate, int flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,239 @@
|
|||||||
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Printing;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Elwig.Helpers.Printing {
|
||||||
|
public partial class Win32Printer {
|
||||||
|
|
||||||
|
private const int DM_OUT_BUFFER = 2;
|
||||||
|
|
||||||
|
private const int HORZRES = 8;
|
||||||
|
private const int VERTRES = 10;
|
||||||
|
private const int LOGPIXELSX = 88;
|
||||||
|
private const int LOGPIXELSY = 90;
|
||||||
|
private const int PHYSICALWIDTH = 110;
|
||||||
|
private const int PHYSICALHEIGHT = 111;
|
||||||
|
private const int PHYSICALOFFSETX = 112;
|
||||||
|
private const int PHYSICALOFFSETY = 113;
|
||||||
|
|
||||||
|
private const int DM_DUPLEX = 0x1000;
|
||||||
|
private const short DMDUP_SIMPLEX = 1;
|
||||||
|
private const short DMDUP_VERTICAL = 2;
|
||||||
|
private const short DMDUP_HORIZONTAL = 3;
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||||
|
private struct DOCINFO {
|
||||||
|
public int cbSize;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.LPWStr)]
|
||||||
|
public string? lpszDocName;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.LPWStr)]
|
||||||
|
public string? lpszOutput;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.LPWStr)]
|
||||||
|
public string? lpszDatatype;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||||
|
private struct DEVMODE {
|
||||||
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
|
||||||
|
public string dmDeviceName;
|
||||||
|
|
||||||
|
public short dmSpecVersion;
|
||||||
|
public short dmDriverVersion;
|
||||||
|
public short dmSize;
|
||||||
|
public short dmDriverExtra;
|
||||||
|
public int dmFields;
|
||||||
|
|
||||||
|
public short dmOrientation;
|
||||||
|
public short dmPaperSize;
|
||||||
|
public short dmPaperLength;
|
||||||
|
public short dmPaperWidth;
|
||||||
|
public short dmScale;
|
||||||
|
public short dmCopies;
|
||||||
|
public short dmDefaultSource;
|
||||||
|
public short dmPrintQuality;
|
||||||
|
public short dmColor;
|
||||||
|
public short dmDuplex;
|
||||||
|
public short dmYResolution;
|
||||||
|
public short dmTTOption;
|
||||||
|
public short dmCollate;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
|
||||||
|
public string dmFormName;
|
||||||
|
|
||||||
|
public short dmLogPixels;
|
||||||
|
public int dmBitsPerPel;
|
||||||
|
public int dmPelsWidth;
|
||||||
|
public int dmPelsHeight;
|
||||||
|
public int dmDisplayFlags;
|
||||||
|
public int dmDisplayFrequency;
|
||||||
|
public int dmICMMethod;
|
||||||
|
public int dmICMIntent;
|
||||||
|
public int dmMediaType;
|
||||||
|
public int dmDitherType;
|
||||||
|
public int dmReserved1;
|
||||||
|
public int dmReserved2;
|
||||||
|
public int dmPanningWidth;
|
||||||
|
public int dmPanningHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport("winspool.drv", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||||
|
private static extern bool OpenPrinter(string pPrinterName, out IntPtr phPrinter, IntPtr pDefault);
|
||||||
|
|
||||||
|
[DllImport("winspool.drv", SetLastError = true)]
|
||||||
|
private static extern bool ClosePrinter(IntPtr hPrinter);
|
||||||
|
|
||||||
|
[DllImport("winspool.drv", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||||
|
private static extern int DocumentProperties(IntPtr hwnd, IntPtr hPrinter, string pDeviceName, IntPtr pDevModeOutput, IntPtr pDevModeInput, int fMode);
|
||||||
|
|
||||||
|
[DllImport("gdi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||||
|
private static extern IntPtr CreateDC(string? pDriver, string? pDevice, string? pOutput, IntPtr pInitData);
|
||||||
|
|
||||||
|
[DllImport("gdi32.dll", SetLastError = true)]
|
||||||
|
private static extern bool DeleteDC(IntPtr hdc);
|
||||||
|
|
||||||
|
[DllImport("gdi32.dll", SetLastError = true)]
|
||||||
|
private static extern int GetDeviceCaps(IntPtr hdc, int index);
|
||||||
|
|
||||||
|
[DllImport("gdi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||||
|
private static extern int StartDoc(IntPtr hdc, ref DOCINFO lpdi);
|
||||||
|
|
||||||
|
[DllImport("gdi32.dll", SetLastError = true)]
|
||||||
|
private static extern int EndDoc(IntPtr hdc);
|
||||||
|
|
||||||
|
[DllImport("gdi32.dll", SetLastError = true)]
|
||||||
|
private static extern int AbortDoc(IntPtr hdc);
|
||||||
|
|
||||||
|
[DllImport("gdi32.dll", SetLastError = true)]
|
||||||
|
private static extern int StartPage(IntPtr hdc);
|
||||||
|
|
||||||
|
[DllImport("gdi32.dll", SetLastError = true)]
|
||||||
|
private static extern int EndPage(IntPtr hdc);
|
||||||
|
|
||||||
|
[DllImport("kernel32.dll", SetLastError = true)]
|
||||||
|
private static extern IntPtr GlobalAlloc(uint uFlags, UIntPtr dwBytes);
|
||||||
|
|
||||||
|
[DllImport("kernel32.dll", SetLastError = true)]
|
||||||
|
private static extern IntPtr GlobalFree(IntPtr hMem);
|
||||||
|
|
||||||
|
[DllImport("kernel32.dll")]
|
||||||
|
private static extern IntPtr GlobalLock(IntPtr hMem);
|
||||||
|
|
||||||
|
[DllImport("kernel32.dll")]
|
||||||
|
private static extern bool GlobalUnlock(IntPtr hMem);
|
||||||
|
|
||||||
|
public class Printer : IDisposable {
|
||||||
|
private readonly string _printerName;
|
||||||
|
private readonly IntPtr _printerHandle;
|
||||||
|
private readonly IntPtr _devMode;
|
||||||
|
private readonly IntPtr _hdc;
|
||||||
|
|
||||||
|
public IntPtr Hdc => _hdc;
|
||||||
|
|
||||||
|
public int PrintableWidth => GetDeviceCaps(_hdc, HORZRES);
|
||||||
|
public int PrintableHeight => GetDeviceCaps(_hdc, VERTRES);
|
||||||
|
public int DpiX => GetDeviceCaps(_hdc, LOGPIXELSX);
|
||||||
|
public int DpiY => GetDeviceCaps(_hdc, LOGPIXELSY);
|
||||||
|
public int PhysicalWidth => GetDeviceCaps(_hdc, PHYSICALWIDTH);
|
||||||
|
public int PhysicalHeight => GetDeviceCaps(_hdc, PHYSICALHEIGHT);
|
||||||
|
public int PhysicalOffsetX => GetDeviceCaps(_hdc, PHYSICALOFFSETX);
|
||||||
|
public int PhysicalOffsetY => GetDeviceCaps(_hdc, PHYSICALOFFSETY);
|
||||||
|
|
||||||
|
public Printer(string printerName) {
|
||||||
|
_printerName = printerName;
|
||||||
|
|
||||||
|
if (!OpenPrinter(_printerName, out _printerHandle, IntPtr.Zero)) {
|
||||||
|
throw new Win32Exception(Marshal.GetLastWin32Error(), $"Unable to open printer '{printerName}'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
_devMode = CreateDevMode();
|
||||||
|
_hdc = CreateDC(null, _printerName, null, _devMode);
|
||||||
|
if (_hdc == IntPtr.Zero)
|
||||||
|
throw new Win32Exception(Marshal.GetLastWin32Error(), $"Unable to create printer DC for '{_printerName}'.");
|
||||||
|
} catch {
|
||||||
|
if (_devMode != IntPtr.Zero) Marshal.FreeHGlobal(_devMode);
|
||||||
|
ClosePrinter(_printerHandle);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TrySetDuplex(Duplexing duplex) {
|
||||||
|
var devMode = Marshal.PtrToStructure<DEVMODE>(_devMode);
|
||||||
|
switch (duplex) {
|
||||||
|
case Duplexing.OneSided: devMode.dmDuplex = DMDUP_SIMPLEX; break;
|
||||||
|
case Duplexing.TwoSidedShortEdge: devMode.dmDuplex = DMDUP_HORIZONTAL; break;
|
||||||
|
case Duplexing.TwoSidedLongEdge: devMode.dmDuplex = DMDUP_VERTICAL; break;
|
||||||
|
}
|
||||||
|
if ((devMode.dmFields & DM_DUPLEX) != 0) {
|
||||||
|
Marshal.StructureToPtr(devMode, _devMode, false);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
devMode.dmFields |= DM_DUPLEX;
|
||||||
|
Marshal.StructureToPtr(devMode, _devMode, false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IntPtr CreateDevMode() {
|
||||||
|
int size = DocumentProperties(IntPtr.Zero, _printerHandle, _printerName, IntPtr.Zero, IntPtr.Zero, 0);
|
||||||
|
if (size <= 0)
|
||||||
|
throw new Win32Exception(Marshal.GetLastWin32Error(), "DocumentProperties failed.");
|
||||||
|
|
||||||
|
IntPtr devMode = Marshal.AllocHGlobal(size);
|
||||||
|
int result = DocumentProperties(IntPtr.Zero, _printerHandle, _printerName, devMode, IntPtr.Zero, DM_OUT_BUFFER);
|
||||||
|
if (result < 0) {
|
||||||
|
Marshal.FreeHGlobal(devMode);
|
||||||
|
throw new Win32Exception(Marshal.GetLastWin32Error(), "Unable to obtain printer DEVMODE.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return devMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StartDocument(string documentName) {
|
||||||
|
var docInfo = new DOCINFO {
|
||||||
|
cbSize = Marshal.SizeOf<DOCINFO>(),
|
||||||
|
lpszDocName = documentName,
|
||||||
|
lpszDatatype = null,
|
||||||
|
lpszOutput = null
|
||||||
|
};
|
||||||
|
|
||||||
|
if (StartDoc(_hdc, ref docInfo) <= 0)
|
||||||
|
throw new Win32Exception(Marshal.GetLastWin32Error(), "StartDoc failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StartPage() {
|
||||||
|
if (Win32Printer.StartPage(_hdc) <= 0)
|
||||||
|
throw new Win32Exception(Marshal.GetLastWin32Error(), "StartPage failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EndPage() {
|
||||||
|
if (Win32Printer.EndPage(_hdc) <= 0)
|
||||||
|
throw new Win32Exception(Marshal.GetLastWin32Error(), "EndPage failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EndDocument() {
|
||||||
|
if (EndDoc(_hdc) <= 0)
|
||||||
|
throw new Win32Exception( Marshal.GetLastWin32Error(), "EndDoc failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AbortDocument() {
|
||||||
|
AbortDoc(_hdc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose() {
|
||||||
|
if (_hdc != IntPtr.Zero)
|
||||||
|
DeleteDC(_hdc);
|
||||||
|
|
||||||
|
if (_devMode != IntPtr.Zero)
|
||||||
|
Marshal.FreeHGlobal(_devMode);
|
||||||
|
|
||||||
|
if (_printerHandle != IntPtr.Zero)
|
||||||
|
ClosePrinter(_printerHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+52
-15
@@ -45,7 +45,6 @@ namespace Elwig.Helpers {
|
|||||||
public static int CurrentNextSeason => DateTime.Now.Year - (DateTime.Now.Month <= 3 ? 1 : 0);
|
public static int CurrentNextSeason => DateTime.Now.Year - (DateTime.Now.Month <= 3 ? 1 : 0);
|
||||||
public static int CurrentLastSeason => DateTime.Now.Year - (DateTime.Now.Month <= 6 ? 1 : 0);
|
public static int CurrentLastSeason => DateTime.Now.Year - (DateTime.Now.Month <= 6 ? 1 : 0);
|
||||||
public static int FollowingSeason => DateTime.Now.Year + (DateTime.Now.Month >= 11 ? 1 : 0);
|
public static int FollowingSeason => DateTime.Now.Year + (DateTime.Now.Month >= 11 ? 1 : 0);
|
||||||
public static DateTime Today => (DateTime.Now.Hour >= 3) ? DateTime.Today : DateTime.Today.AddDays(-1);
|
|
||||||
|
|
||||||
[GeneratedRegex("^serial://([A-Za-z0-9]+):([0-9]+)(,([5-9]),([NOEMSnoems]),(0|1|1\\.5|2|))?$", RegexOptions.Compiled)]
|
[GeneratedRegex("^serial://([A-Za-z0-9]+):([0-9]+)(,([5-9]),([NOEMSnoems]),(0|1|1\\.5|2|))?$", RegexOptions.Compiled)]
|
||||||
private static partial Regex GeneratedSerialRegex();
|
private static partial Regex GeneratedSerialRegex();
|
||||||
@@ -304,6 +303,11 @@ namespace Elwig.Helpers {
|
|||||||
return d.ShowDialog() == true ? (d.Weight, d.Reason) : null;
|
return d.ShowDialog() == true ? (d.Weight, d.Reason) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int? ShowTareCorrectionDialog(int? actualTare, int? targetTare = null) {
|
||||||
|
var d = new TareCorrectionDialog(actualTare, targetTare);
|
||||||
|
return d.ShowDialog() == true ? d.TargetTare - d.ActualTare : null;
|
||||||
|
}
|
||||||
|
|
||||||
public static (string?, int[])? ShowDeliverySplittingDialog(Delivery delivery) {
|
public static (string?, int[])? ShowDeliverySplittingDialog(Delivery delivery) {
|
||||||
var d = new DeliverySplittingDialog(delivery);
|
var d = new DeliverySplittingDialog(delivery);
|
||||||
return d.ShowDialog() == true ? (d.MgNr?.ToString() ?? d.LsNr, d.Weights ?? []) : null;
|
return d.ShowDialog() == true ? (d.MgNr?.ToString() ?? d.LsNr, d.Weights ?? []) : null;
|
||||||
@@ -319,7 +323,7 @@ namespace Elwig.Helpers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public class Footer {
|
public class Footer {
|
||||||
private readonly List<List<object>> Items = [[]];
|
private readonly List<List<List<object>>> Items = [[[]]];
|
||||||
private readonly string LineBreak;
|
private readonly string LineBreak;
|
||||||
private readonly string Separator;
|
private readonly string Separator;
|
||||||
|
|
||||||
@@ -330,7 +334,7 @@ namespace Elwig.Helpers {
|
|||||||
|
|
||||||
public Footer Item(object? text) {
|
public Footer Item(object? text) {
|
||||||
if (text == null) return this;
|
if (text == null) return this;
|
||||||
Items[^1].Add(text);
|
Items[^1][^1].Add(text);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -338,13 +342,38 @@ namespace Elwig.Helpers {
|
|||||||
return text == null ? this : Item($"{name}: {text}");
|
return text == null ? this : Item($"{name}: {text}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Footer NextGroup() {
|
||||||
|
Items[^1].Add([]);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public Footer NextLine() {
|
public Footer NextLine() {
|
||||||
Items.Add([]);
|
Items.Add([[]]);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Footer RebalanceLines() {
|
||||||
|
for (int i = 0; i < Items.Count - 1; i++) {
|
||||||
|
var groups = Items[i];
|
||||||
|
var nextGroups = Items[i + 1];
|
||||||
|
if (groups.Count <= 1) continue;
|
||||||
|
var g = groups[^1];
|
||||||
|
var gl = g.Sum(i => (i is Text txt ? txt.GetText().Length : i.ToString()?.Length ?? 0) + Separator.Length);
|
||||||
|
var l1a = groups.SelectMany(g => g).Sum(i => (i is Text txt ? txt.GetText().Length : i.ToString()?.Length ?? 0) + Separator.Length) - Separator.Length;
|
||||||
|
var l2a = nextGroups.SelectMany(g => g).Sum(i => (i is Text txt ? txt.GetText().Length : i.ToString()?.Length ?? 0) + Separator.Length) - Separator.Length;
|
||||||
|
var l1b = l1a - gl;
|
||||||
|
var l2b = l2a + gl;
|
||||||
|
if (Math.Abs(l1b - l2b) <= Math.Abs(l1a - l2a)) {
|
||||||
|
Items[i].Remove(g);
|
||||||
|
Items[i + 1].Insert(0, g);
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString() {
|
public override string ToString() {
|
||||||
return string.Join(LineBreak, Items.Select(l => string.Join(Separator, l.ToString())));
|
return string.Join(LineBreak, Items.Select(l => string.Join(Separator, l.SelectMany(g => g).ToString())));
|
||||||
}
|
}
|
||||||
|
|
||||||
public IList<ILeafElement> ToLeafElements() {
|
public IList<ILeafElement> ToLeafElements() {
|
||||||
@@ -353,10 +382,12 @@ namespace Elwig.Helpers {
|
|||||||
foreach (var line in Items) {
|
foreach (var line in Items) {
|
||||||
if (!first1) l.Add(new Text(LineBreak));
|
if (!first1) l.Add(new Text(LineBreak));
|
||||||
var first2 = true;
|
var first2 = true;
|
||||||
foreach (var item in line) {
|
foreach (var group in line) {
|
||||||
if (!first2) l.Add(new Text(Separator));
|
foreach (var item in group) {
|
||||||
l.Add(item as ILeafElement ?? new Text(item.ToString() ?? ""));
|
if (!first2) l.Add(new Text(Separator));
|
||||||
first2 = false;
|
l.Add(item as ILeafElement ?? new Text(item.ToString() ?? ""));
|
||||||
|
first2 = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
first1 = false;
|
first1 = false;
|
||||||
}
|
}
|
||||||
@@ -516,7 +547,7 @@ namespace Elwig.Helpers {
|
|||||||
public static async Task<SmtpClient?> GetSmtpClient() {
|
public static async Task<SmtpClient?> GetSmtpClient() {
|
||||||
if (App.Config.Smtp == null)
|
if (App.Config.Smtp == null)
|
||||||
return null;
|
return null;
|
||||||
var (host, port, mode, username, password, _) = App.Config.Smtp.Value;
|
var (host, port, mode, username, password, _, _) = App.Config.Smtp.Value;
|
||||||
var client = new SmtpClient();
|
var client = new SmtpClient();
|
||||||
await client.ConnectAsync(host, port, mode == "starttls" ? SecureSocketOptions.StartTls : SecureSocketOptions.None);
|
await client.ConnectAsync(host, port, mode == "starttls" ? SecureSocketOptions.StartTls : SecureSocketOptions.None);
|
||||||
await client.AuthenticateAsync(username, password);
|
await client.AuthenticateAsync(username, password);
|
||||||
@@ -536,6 +567,7 @@ namespace Elwig.Helpers {
|
|||||||
msg.From.Add(new MailboxAddress(App.Client.NameFull, App.Config.Smtp.Value.From));
|
msg.From.Add(new MailboxAddress(App.Client.NameFull, App.Config.Smtp.Value.From));
|
||||||
msg.To.AddRange(member.EmailAddresses.OrderBy(a => a.Nr).Select(a => new MailboxAddress(member.AdministrativeName, a.Address)));
|
msg.To.AddRange(member.EmailAddresses.OrderBy(a => a.Nr).Select(a => new MailboxAddress(member.AdministrativeName, a.Address)));
|
||||||
msg.Subject = subject;
|
msg.Subject = subject;
|
||||||
|
msg.Date = DateTime.Now;
|
||||||
var body = new Multipart("mixed") {
|
var body = new Multipart("mixed") {
|
||||||
new TextPart("plain") { Text = text }
|
new TextPart("plain") { Text = text }
|
||||||
};
|
};
|
||||||
@@ -546,10 +578,10 @@ namespace Elwig.Helpers {
|
|||||||
msg.Body = body;
|
msg.Body = body;
|
||||||
await client!.SendAsync(msg);
|
await client!.SendAsync(msg);
|
||||||
await AddSentMails([(
|
await AddSentMails([(
|
||||||
"email", member.MgNr, member.AdministrativeName,
|
"email", member.MgNr, member.AdministrativeName,
|
||||||
member.EmailAddresses.OrderBy(a => a.Nr).Select(a => a.Address).ToArray(),
|
member.EmailAddresses.OrderBy(a => a.Nr).Select(a => a.Address).ToArray(),
|
||||||
subject, docs.Select(d => d.Title).ToArray()
|
subject, docs.Select(d => d.Title).ToArray()
|
||||||
)]);
|
)]);
|
||||||
} catch (Exception exc) {
|
} catch (Exception exc) {
|
||||||
InteractionService.ShowException(exc);
|
InteractionService.ShowException(exc);
|
||||||
return false;
|
return false;
|
||||||
@@ -670,7 +702,7 @@ namespace Elwig.Helpers {
|
|||||||
p[2],
|
p[2],
|
||||||
int.Parse(p[3]),
|
int.Parse(p[3]),
|
||||||
p[4],
|
p[4],
|
||||||
p[5].Split(',').Select(a => a.Replace(" | ", "\n")).ToArray(),
|
[.. p[5].Split(',').Select(a => a.Replace(" | ", "\n"))],
|
||||||
p[6],
|
p[6],
|
||||||
p[7].Split(',')
|
p[7].Split(',')
|
||||||
));
|
));
|
||||||
@@ -712,5 +744,10 @@ namespace Elwig.Helpers {
|
|||||||
var filename = Path.Combine(App.MailsPath, $"{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{NormalizeFileName(subject)}.txt");
|
var filename = Path.Combine(App.MailsPath, $"{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{NormalizeFileName(subject)}.txt");
|
||||||
await File.WriteAllTextAsync(filename, $"# {subject}\r\n# Vorgesehene Empfänger: {recipients}\r\n\r\n" + body, Utils.UTF8);
|
await File.WriteAllTextAsync(filename, $"# {subject}\r\n# Vorgesehene Empfänger: {recipients}\r\n\r\n" + body, Utils.UTF8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string GetTitle(string window, IEnumerable<string> filterNames, IEnumerable<string> filter) {
|
||||||
|
var f = string.Join(" / ", filterNames.Union(filter.Select(f => $"\"{f}\"")));
|
||||||
|
return window + (f.Length == 0 ? "" : ": " + f) + " - Elwig";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -623,6 +623,37 @@ namespace Elwig.Helpers {
|
|||||||
return new(true, null);
|
return new(true, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ValidationResult CheckOrganicOperatorId(TextBox input, bool required) {
|
||||||
|
string text = "";
|
||||||
|
int pos = input.CaretIndex;
|
||||||
|
for (int i = 0, v = 0; i < input.Text.Length; i++) {
|
||||||
|
char ch = input.Text[i];
|
||||||
|
if (char.IsAsciiDigit(ch)) {
|
||||||
|
if (v == 3 && text[^1] != '-')
|
||||||
|
text += "-";
|
||||||
|
v++;
|
||||||
|
text += ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == input.CaretIndex - 1) {
|
||||||
|
pos = text.Length;
|
||||||
|
} else if (v >= 10) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input.Text = text;
|
||||||
|
input.CaretIndex = pos;
|
||||||
|
|
||||||
|
if (text.Length == 0) {
|
||||||
|
return required ? new(false, "OOC-ID ist nicht optional") : new(true, null);
|
||||||
|
} else if (!text.StartsWith("040-") || text.Length != 11) {
|
||||||
|
return new(false, "OOC-ID ist ungültig");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new(true, null);
|
||||||
|
}
|
||||||
|
|
||||||
public static ValidationResult CheckOrganicAuthorityCode(TextBox input, bool required) {
|
public static ValidationResult CheckOrganicAuthorityCode(TextBox input, bool required) {
|
||||||
string text = "";
|
string text = "";
|
||||||
int pos = input.CaretIndex;
|
int pos = input.CaretIndex;
|
||||||
@@ -631,15 +662,18 @@ namespace Elwig.Helpers {
|
|||||||
if (v < 2 && char.IsAsciiLetter(ch)) {
|
if (v < 2 && char.IsAsciiLetter(ch)) {
|
||||||
v++;
|
v++;
|
||||||
text += ch;
|
text += ch;
|
||||||
} else if ((v == 2 || v == 6) && ch == '-') {
|
} else if ((v == 2 || v == 5) && ch == '-' && text[^1] != '-') {
|
||||||
v++;
|
|
||||||
text += ch;
|
text += ch;
|
||||||
} else if (v >= 2 && char.IsLetterOrDigit(ch)) {
|
} else if (v >= 2 && v <= 4 && char.IsLetter(ch)) {
|
||||||
|
if (v == 2 && text[^1] != '-')
|
||||||
|
text += "-";
|
||||||
if (text.StartsWith("AT")) {
|
if (text.StartsWith("AT")) {
|
||||||
if (v == 3 && ch == 'B' || v == 4 && ch == 'I' || v == 5 && ch == 'O') {
|
if (v == 2 && ch == 'B' || v == 3 && ch == 'I' || v == 4 && ch == 'O') {
|
||||||
v++;
|
v++;
|
||||||
text += ch;
|
text += ch;
|
||||||
} else if (v > 6 && char.IsAsciiDigit(ch)) {
|
}
|
||||||
|
} else if (text.StartsWith("DE")) {
|
||||||
|
if (v == 2 && ch == 'Ö' || v == 3 && ch == 'K' || v == 4 && ch == 'O') {
|
||||||
v++;
|
v++;
|
||||||
text += ch;
|
text += ch;
|
||||||
}
|
}
|
||||||
@@ -647,11 +681,16 @@ namespace Elwig.Helpers {
|
|||||||
v++;
|
v++;
|
||||||
text += ch;
|
text += ch;
|
||||||
}
|
}
|
||||||
|
} else if (v >= 5 && v <= 7 && char.IsAsciiDigit(ch)) {
|
||||||
|
if (v == 5 && text[^1] != '-')
|
||||||
|
text += "-";
|
||||||
|
v++;
|
||||||
|
text += ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i == input.CaretIndex - 1) {
|
if (i == input.CaretIndex - 1) {
|
||||||
pos = text.Length;
|
pos = text.Length;
|
||||||
} else if (text.StartsWith("AT") && v >= 10) {
|
} else if ((text.StartsWith("AT") || text.StartsWith("DE")) && v >= 10) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -662,7 +701,7 @@ namespace Elwig.Helpers {
|
|||||||
if (text.Length == 0)
|
if (text.Length == 0)
|
||||||
return required ? new(false, "Bio-Kontrollstellen-Code ist nicht optional") : new(true, null);
|
return required ? new(false, "Bio-Kontrollstellen-Code ist nicht optional") : new(true, null);
|
||||||
|
|
||||||
if (text.StartsWith("AT")) {
|
if (text.StartsWith("AT") || text.StartsWith("DE")) {
|
||||||
if (text.Length != 10) {
|
if (text.Length != 10) {
|
||||||
return new(false, "Bio-Kontrollstellen-Code ist ungültig");
|
return new(false, "Bio-Kontrollstellen-Code ist ungültig");
|
||||||
}
|
}
|
||||||
@@ -672,5 +711,25 @@ namespace Elwig.Helpers {
|
|||||||
|
|
||||||
return new(true, null);
|
return new(true, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ValidationResult CheckAddress(TextBox input, bool required, string? locality = null) {
|
||||||
|
var text = input.Text;
|
||||||
|
var (name, nr) = Utils.SplitAddress(text);
|
||||||
|
if (!string.IsNullOrWhiteSpace(nr)) {
|
||||||
|
var street = Normalizer.NormalizeStreetName(name.Replace(",", ""), locality);
|
||||||
|
var idx = input.CaretIndex;
|
||||||
|
input.Text = $"{street} {nr}".Trim();
|
||||||
|
if (idx >= (text.Length - nr.Length)) {
|
||||||
|
input.CaretIndex = street.Length + (idx - (text.Length - nr.Length)) + 1;
|
||||||
|
} else if (idx > 0) {
|
||||||
|
input.CaretIndex = idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (text.Length == 0)
|
||||||
|
return required ? new(false, "Adresse ist nicht optional") : new(true, null);
|
||||||
|
|
||||||
|
return new(true, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9,9 +9,8 @@ namespace Elwig.Helpers.Weighing {
|
|||||||
public class AveryEventScale : Scale, IEventScale, IDisposable {
|
public class AveryEventScale : Scale, IEventScale, IDisposable {
|
||||||
|
|
||||||
public string Manufacturer => "Avery";
|
public string Manufacturer => "Avery";
|
||||||
public int InternalScaleNr => 1;
|
|
||||||
public string Model { get; private set; }
|
public string Model { get; private set; }
|
||||||
public string ScaleId { get; private set; }
|
public string ScaleTerminalId { get; private set; }
|
||||||
public bool IsReady { get; private set; }
|
public bool IsReady { get; private set; }
|
||||||
public bool HasFillingClearance { get; private set; }
|
public bool HasFillingClearance { get; private set; }
|
||||||
|
|
||||||
@@ -19,13 +18,11 @@ namespace Elwig.Helpers.Weighing {
|
|||||||
|
|
||||||
private bool IsRunning = true;
|
private bool IsRunning = true;
|
||||||
private readonly Thread BackgroundThread;
|
private readonly Thread BackgroundThread;
|
||||||
private readonly string Connection;
|
|
||||||
|
|
||||||
public AveryEventScale(string id, string model, string cnx, string? log = null, bool required = true) :
|
public AveryEventScale(string id, string model, string cnx, string? log = null, bool required = true) :
|
||||||
base(cnx, null, null, null, log, true, !required) {
|
base(cnx, null, null, null, log, true, !required) {
|
||||||
ScaleId = id;
|
ScaleTerminalId = id;
|
||||||
Model = model;
|
Model = model;
|
||||||
Connection = cnx;
|
|
||||||
IsReady = true;
|
IsReady = true;
|
||||||
HasFillingClearance = false;
|
HasFillingClearance = false;
|
||||||
Stream.WriteTimeout = -1;
|
Stream.WriteTimeout = -1;
|
||||||
|
|||||||
+17
-17
@@ -5,18 +5,17 @@ using System.Text;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Elwig.Helpers.Weighing {
|
namespace Elwig.Helpers.Weighing {
|
||||||
public class GassnerScale : Scale, ICommandScale {
|
public class GassnerEnqScale : Scale, ICommandScale {
|
||||||
|
|
||||||
public string Manufacturer => "Gassner";
|
public string Manufacturer => "Gassner";
|
||||||
public int InternalScaleNr => 1;
|
|
||||||
public string Model { get; private set; }
|
public string Model { get; private set; }
|
||||||
public string ScaleId { get; private set; }
|
public string ScaleTerminalId { get; private set; }
|
||||||
public bool IsReady { get; private set; }
|
public bool IsReady { get; private set; }
|
||||||
public bool HasFillingClearance { get; private set; }
|
public bool HasFillingClearance { get; private set; }
|
||||||
|
|
||||||
public GassnerScale(string id, string model, string cnx, string? empty = null, string? filling = null, int? limit = null, string? log = null) :
|
public GassnerEnqScale(string id, string model, string cnx, string? empty = null, string? filling = null, int? limit = null, string? log = null) :
|
||||||
base(cnx, empty, filling, limit, log) {
|
base(cnx, empty, filling, limit, log) {
|
||||||
ScaleId = id;
|
ScaleTerminalId = id;
|
||||||
Model = model;
|
Model = model;
|
||||||
IsReady = true;
|
IsReady = true;
|
||||||
HasFillingClearance = false;
|
HasFillingClearance = false;
|
||||||
@@ -24,10 +23,9 @@ namespace Elwig.Helpers.Weighing {
|
|||||||
Stream.ReadTimeout = 11000;
|
Stream.ReadTimeout = 11000;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Task SendCommand(char command) => SendCommand(Convert.ToByte(command));
|
protected Task SendCommand(string command) => SendCommand(Encoding.ASCII.GetBytes(command));
|
||||||
|
|
||||||
protected async Task SendCommand(byte command) {
|
protected async Task SendCommand(byte[] cmd) {
|
||||||
byte[] cmd = [command];
|
|
||||||
await Stream.WriteAsync(cmd);
|
await Stream.WriteAsync(cmd);
|
||||||
if (LogPath != null) await File.AppendAllTextAsync(LogPath, Encoding.ASCII.GetString(cmd));
|
if (LogPath != null) await File.AppendAllTextAsync(LogPath, Encoding.ASCII.GetString(cmd));
|
||||||
}
|
}
|
||||||
@@ -53,15 +51,15 @@ namespace Elwig.Helpers.Weighing {
|
|||||||
return line[1..^1];
|
return line[1..^1];
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async Task<WeighingResult> Weigh(bool incIdentNr, bool retry = true) {
|
protected async Task<WeighingResult> Weigh(int? internalScaleNr, bool incIdentNr, bool retry = true) {
|
||||||
string record;
|
string record;
|
||||||
try {
|
try {
|
||||||
await SendCommand(incIdentNr ? '\x05' : '?');
|
await SendCommand(incIdentNr ? "\x05" : "?");
|
||||||
record = await ReceiveResponse();
|
record = await ReceiveResponse();
|
||||||
} catch (IOException) {
|
} catch (IOException) {
|
||||||
if (!retry || Tcp == null) throw;
|
if (!retry || Tcp == null) throw;
|
||||||
ReconnectTcp();
|
ReconnectTcp();
|
||||||
return await Weigh(incIdentNr, false);
|
return await Weigh(internalScaleNr, incIdentNr, false);
|
||||||
}
|
}
|
||||||
if (record.Length != 45)
|
if (record.Length != 45)
|
||||||
throw new FormatException("Invalid response from scale: Received record has invalid size");
|
throw new FormatException("Invalid response from scale: Received record has invalid size");
|
||||||
@@ -80,6 +78,7 @@ namespace Elwig.Helpers.Weighing {
|
|||||||
GrossWeight = int.Parse(brutto),
|
GrossWeight = int.Parse(brutto),
|
||||||
TareWeight = int.Parse(tara),
|
TareWeight = int.Parse(tara),
|
||||||
NetWeight = int.Parse(netto),
|
NetWeight = int.Parse(netto),
|
||||||
|
ScaleId = scaleNr,
|
||||||
WeighingId = identNr,
|
WeighingId = identNr,
|
||||||
FullWeighingId = identNr,
|
FullWeighingId = identNr,
|
||||||
Date = DateOnly.TryParseExact(date, "yyyyMMdd", out var d) ? d : null,
|
Date = DateOnly.TryParseExact(date, "yyyyMMdd", out var d) ? d : null,
|
||||||
@@ -87,12 +86,12 @@ namespace Elwig.Helpers.Weighing {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<WeighingResult> Weigh() {
|
public async Task<WeighingResult> Weigh(int? scaleNr = null) {
|
||||||
return await Weigh(true);
|
return await Weigh(scaleNr, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<WeighingResult> GetCurrentWeight() {
|
public async Task<WeighingResult> GetCurrentWeight(int? scaleNr = null) {
|
||||||
return await Weigh(false);
|
return await Weigh(scaleNr, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Empty() {
|
public async Task Empty() {
|
||||||
@@ -126,8 +125,9 @@ namespace Elwig.Helpers.Weighing {
|
|||||||
await SetFillingClearance(false);
|
await SetFillingClearance(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task SetDateAndTime(DateTime dateTime) {
|
public async Task SetDateAndTime(DateTime dateTime) {
|
||||||
throw new NotImplementedException("Für Waagen vom Typ 'Gassner' ist diese Funktion noch nicht implementiert");
|
await SendCommand($"C{dateTime:yyyyMMddHHmmss}\r");
|
||||||
|
await ReceiveResponse();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10,13 +10,13 @@ namespace Elwig.Helpers.Weighing {
|
|||||||
/// Get the current weight on the scale without performing a weighing process
|
/// Get the current weight on the scale without performing a weighing process
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Result of the weighing process (probably without a weighing id)</returns>
|
/// <returns>Result of the weighing process (probably without a weighing id)</returns>
|
||||||
Task<WeighingResult> GetCurrentWeight();
|
Task<WeighingResult> GetCurrentWeight(int? scaleNr = null);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Perform a weighing process
|
/// Perform a weighing process
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Result of the weighing process (including a weighing id)</returns>
|
/// <returns>Result of the weighing process (including a weighing id)</returns>
|
||||||
Task<WeighingResult> Weigh();
|
Task<WeighingResult> Weigh(int? scaleNr = null);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Empty the scale container or grant clearance to do so
|
/// Empty the scale container or grant clearance to do so
|
||||||
|
|||||||
@@ -18,12 +18,7 @@ namespace Elwig.Helpers.Weighing {
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Unique identificator of the scale
|
/// Unique identificator of the scale
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string ScaleId { get; }
|
string ScaleTerminalId { get; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Internal identifying number of the scale in its system
|
|
||||||
/// </summary>
|
|
||||||
int InternalScaleNr { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates if the scale is currently processing a request or not
|
/// Indicates if the scale is currently processing a request or not
|
||||||
|
|||||||
@@ -5,8 +5,7 @@ namespace Elwig.Helpers.Weighing {
|
|||||||
|
|
||||||
public string Manufacturer => "NONE";
|
public string Manufacturer => "NONE";
|
||||||
public string Model => "NONE";
|
public string Model => "NONE";
|
||||||
public string ScaleId => id;
|
public string ScaleTerminalId => id;
|
||||||
public int InternalScaleNr => 0;
|
|
||||||
public bool IsReady => false;
|
public bool IsReady => false;
|
||||||
public bool HasFillingClearance => false;
|
public bool HasFillingClearance => false;
|
||||||
public int? WeightLimit => null;
|
public int? WeightLimit => null;
|
||||||
|
|||||||
@@ -28,10 +28,10 @@ namespace Elwig.Helpers.Weighing {
|
|||||||
int? limit = config.Limit != null ? int.Parse(config.Limit) : null;
|
int? limit = config.Limit != null ? int.Parse(config.Limit) : null;
|
||||||
if (config.Type == "SysTec-IT") {
|
if (config.Type == "SysTec-IT") {
|
||||||
return new SysTecITScale(config.Id, config.Model!, config.Connection!, config.Empty, config.Filling, limit, config.Log);
|
return new SysTecITScale(config.Id, config.Model!, config.Connection!, config.Empty, config.Filling, limit, config.Log);
|
||||||
} else if (config.Type == "Avery-Async") {
|
} else if (config.Type == "Gassner-Enq" || config.Type == "Gassner") {
|
||||||
|
return new GassnerEnqScale(config.Id, config.Model!, config.Connection!, config.Empty, config.Filling, limit, config.Log);
|
||||||
|
} else if (config.Type == "Avery-Event" || config.Type == "Avery-Async") {
|
||||||
return new AveryEventScale(config.Id, config.Model!, config.Connection!, config.Log, config.Required);
|
return new AveryEventScale(config.Id, config.Model!, config.Connection!, config.Log, config.Required);
|
||||||
} else if (config.Type == "Gassner") {
|
|
||||||
return new GassnerScale(config.Id, config.Model!, config.Connection!, config.Empty, config.Filling, limit, config.Log);
|
|
||||||
} else {
|
} else {
|
||||||
throw new ArgumentException($"Invalid scale type: \"{config.Type}\"");
|
throw new ArgumentException($"Invalid scale type: \"{config.Type}\"");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,15 +8,14 @@ namespace Elwig.Helpers.Weighing {
|
|||||||
public class SysTecITScale : Scale, ICommandScale {
|
public class SysTecITScale : Scale, ICommandScale {
|
||||||
|
|
||||||
public string Manufacturer => "SysTec";
|
public string Manufacturer => "SysTec";
|
||||||
public int InternalScaleNr => 1;
|
|
||||||
public string Model { get; private set; }
|
public string Model { get; private set; }
|
||||||
public string ScaleId { get; private set; }
|
public string ScaleTerminalId { get; private set; }
|
||||||
public bool IsReady { get; private set; }
|
public bool IsReady { get; private set; }
|
||||||
public bool HasFillingClearance { get; private set; }
|
public bool HasFillingClearance { get; private set; }
|
||||||
|
|
||||||
public SysTecITScale(string id, string model, string cnx, string? empty = null, string? filling = null, int? limit = null, string? log = null) :
|
public SysTecITScale(string id, string model, string cnx, string? empty = null, string? filling = null, int? limit = null, string? log = null) :
|
||||||
base(cnx, empty, filling, limit, log) {
|
base(cnx, empty, filling, limit, log) {
|
||||||
ScaleId = id;
|
ScaleTerminalId = id;
|
||||||
Model = model;
|
Model = model;
|
||||||
IsReady = true;
|
IsReady = true;
|
||||||
HasFillingClearance = false;
|
HasFillingClearance = false;
|
||||||
@@ -74,15 +73,15 @@ namespace Elwig.Helpers.Weighing {
|
|||||||
return line[1..^3];
|
return line[1..^3];
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async Task<WeighingResult> Weigh(bool incIdentNr, bool retry = true) {
|
protected async Task<WeighingResult> Weigh(int internalScalNr, bool incIdentNr, bool retry = true) {
|
||||||
string record;
|
string record;
|
||||||
try {
|
try {
|
||||||
await SendCommand(incIdentNr ? $"RN{InternalScaleNr}" : $"RM{InternalScaleNr}");
|
await SendCommand(incIdentNr ? $"RN{internalScalNr}" : $"RM{internalScalNr}");
|
||||||
record = await ReceiveResponse();
|
record = await ReceiveResponse();
|
||||||
} catch (IOException) {
|
} catch (IOException) {
|
||||||
if (!retry || Tcp == null) throw;
|
if (!retry || Tcp == null) throw;
|
||||||
ReconnectTcp();
|
ReconnectTcp();
|
||||||
return await Weigh(incIdentNr, false);
|
return await Weigh(internalScalNr, incIdentNr, false);
|
||||||
}
|
}
|
||||||
if (record.Length != 62)
|
if (record.Length != 62)
|
||||||
throw new FormatException("Invalid response from scale: Received record has invalid size");
|
throw new FormatException("Invalid response from scale: Received record has invalid size");
|
||||||
@@ -114,6 +113,7 @@ namespace Elwig.Helpers.Weighing {
|
|||||||
GrossWeight = int.Parse(brutto),
|
GrossWeight = int.Parse(brutto),
|
||||||
TareWeight = int.Parse(tara),
|
TareWeight = int.Parse(tara),
|
||||||
NetWeight = int.Parse(netto),
|
NetWeight = int.Parse(netto),
|
||||||
|
ScaleId = scaleNr,
|
||||||
WeighingId = identNr,
|
WeighingId = identNr,
|
||||||
FullWeighingId = identNr != null ? $"{parsedDate:yyyy-MM-dd}/{identNr}" : null,
|
FullWeighingId = identNr != null ? $"{parsedDate:yyyy-MM-dd}/{identNr}" : null,
|
||||||
Date = parsedDate,
|
Date = parsedDate,
|
||||||
@@ -121,12 +121,12 @@ namespace Elwig.Helpers.Weighing {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<WeighingResult> Weigh() {
|
public async Task<WeighingResult> Weigh(int? scaleNr = 1) {
|
||||||
return await Weigh(true);
|
return await Weigh(scaleNr ?? 1, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<WeighingResult> GetCurrentWeight() {
|
public async Task<WeighingResult> GetCurrentWeight(int? scaleNr = 1) {
|
||||||
return await Weigh(false);
|
return await Weigh(scaleNr ?? 1, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Empty() {
|
public async Task Empty() {
|
||||||
|
|||||||
@@ -21,6 +21,11 @@ namespace Elwig.Helpers.Weighing {
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public int? NetWeight;
|
public int? NetWeight;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reported id of the scale
|
||||||
|
/// </summary>
|
||||||
|
public string? ScaleId;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Weighing id (or IdentNr) provided by the scale
|
/// Weighing id (or IdentNr) provided by the scale
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -44,11 +49,12 @@ namespace Elwig.Helpers.Weighing {
|
|||||||
/// <returns><[GrossWeight-TaraWeight=]NetWeight/WeighingId/Date/Time></returns>
|
/// <returns><[GrossWeight-TaraWeight=]NetWeight/WeighingId/Date/Time></returns>
|
||||||
public override readonly string ToString() {
|
public override readonly string ToString() {
|
||||||
var w = NetWeight != null ? (GrossWeight != null && TareWeight != null ? $"{GrossWeight}-{TareWeight}=" : "") + $"{NetWeight}kg" : "";
|
var w = NetWeight != null ? (GrossWeight != null && TareWeight != null ? $"{GrossWeight}-{TareWeight}=" : "") + $"{NetWeight}kg" : "";
|
||||||
return $"<{w}/{WeighingId}/{Date:yyyy-MM-dd}/{Time:HH:mm}>";
|
return $"<{w}/{WeighingId}/{Date:yyyy-MM-dd}/{Time:HH:mm:ss}>";
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly JsonObject ToJson() {
|
public readonly JsonObject ToJson() {
|
||||||
var obj = new JsonObject();
|
var obj = new JsonObject();
|
||||||
|
if (ScaleId != null) obj["scale"] = ScaleId;
|
||||||
if (FullWeighingId != null) obj["id"] = FullWeighingId;
|
if (FullWeighingId != null) obj["id"] = FullWeighingId;
|
||||||
if (WeighingId != null) obj["nr"] = int.Parse(WeighingId);
|
if (WeighingId != null) obj["nr"] = int.Parse(WeighingId);
|
||||||
if (Date != null) obj["date"] = $"{Date:yyyy-MM-dd}";
|
if (Date != null) obj["date"] = $"{Date:yyyy-MM-dd}";
|
||||||
|
|||||||
@@ -0,0 +1,105 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Elwig.Models.Dtos {
|
||||||
|
class MemberAreaComTotalsData : DataTable<MemberAreaComTotalsRow> {
|
||||||
|
|
||||||
|
private static readonly (string, string, string?, int)[] FieldNames = [
|
||||||
|
("MgNr", "MgNr.", null, 12),
|
||||||
|
("Name1", "Name", null, 40),
|
||||||
|
("Name2", "Vorname", null, 40),
|
||||||
|
("Address", "Adresse", null, 60),
|
||||||
|
("Plz", "PLZ", null, 10),
|
||||||
|
("Locality", "Ort", null, 60),
|
||||||
|
("SortIds", "Sorte", null, 12),
|
||||||
|
("AttrIds", "Attribut", null, 16),
|
||||||
|
("Areas", "Fläche", "m²", 22),
|
||||||
|
("DeliveryObligations", "Lieferpflicht", "kg", 22),
|
||||||
|
("DeliveryRights", "Lieferrecht", "kg", 22),
|
||||||
|
];
|
||||||
|
|
||||||
|
public MemberAreaComTotalsData(IEnumerable<MemberAreaComTotalsRow> rows, int year) :
|
||||||
|
base($"Gebundene Fläche", $"Gebundene Fläche pro Mitglied {year}", rows, FieldNames) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<MemberAreaComTotalsData> ForSeason(DbSet<MemberAreaComTotalsRowSingle> table, int year) {
|
||||||
|
return new MemberAreaComTotalsData(
|
||||||
|
(await FromDbSet(table, year)).GroupBy(
|
||||||
|
r => r.MgNr,
|
||||||
|
(k, g) => new MemberAreaComTotalsRow(g)
|
||||||
|
), year);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task<IEnumerable<MemberAreaComTotalsRowSingle>> FromDbSet(DbSet<MemberAreaComTotalsRowSingle> table, int year) {
|
||||||
|
return await table.FromSql($"""
|
||||||
|
SELECT m.mgnr, m.name AS name_1,
|
||||||
|
COALESCE(m.prefix || ' ', '') || m.given_name ||
|
||||||
|
COALESCE(' ' || m.middle_names, '') || COALESCE(' ' || m.suffix, '') AS name_2,
|
||||||
|
p.plz, o.name AS ort, m.address,
|
||||||
|
c.bucket, c.area, c.min_kg, c.max_kg
|
||||||
|
FROM v_area_commitment_bucket_strict c
|
||||||
|
LEFT JOIN member m ON m.mgnr = c.mgnr
|
||||||
|
LEFT JOIN AT_plz_dest p ON p.id = m.postal_dest
|
||||||
|
LEFT JOIN AT_ort o ON o.okz = p.okz
|
||||||
|
WHERE c.year = {year}
|
||||||
|
ORDER BY m.mgnr, c.bucket
|
||||||
|
""").ToListAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MemberAreaComTotalsRow {
|
||||||
|
public int MgNr;
|
||||||
|
public string Name1;
|
||||||
|
public string? Name2;
|
||||||
|
public string Address;
|
||||||
|
public int Plz;
|
||||||
|
public string Locality;
|
||||||
|
public string[] SortIds;
|
||||||
|
public string[] AttrIds;
|
||||||
|
public int[] Areas;
|
||||||
|
public int[] DeliveryObligations;
|
||||||
|
public int[] DeliveryRights;
|
||||||
|
|
||||||
|
public MemberAreaComTotalsRow(IEnumerable<MemberAreaComTotalsRowSingle> rows) {
|
||||||
|
var f = rows.First();
|
||||||
|
MgNr = f.MgNr;
|
||||||
|
Name1 = f.Name1;
|
||||||
|
Name2 = f.Name2;
|
||||||
|
Address = f.Address;
|
||||||
|
Plz = f.Plz;
|
||||||
|
Locality = f.Locality.Split(",")[0];
|
||||||
|
SortIds = [.. rows.Select(r => r.VtrgId[..2])];
|
||||||
|
AttrIds = [.. rows.Select(r => r.VtrgId[2..])];
|
||||||
|
Areas = [.. rows.Select(r => r.Area)];
|
||||||
|
DeliveryObligations = [.. rows.Select(r => r.MinKg)];
|
||||||
|
DeliveryRights = [.. rows.Select(r => r.MaxKg)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Keyless]
|
||||||
|
public class MemberAreaComTotalsRowSingle {
|
||||||
|
[Column("mgnr")]
|
||||||
|
public int MgNr { get; set; }
|
||||||
|
[Column("name_1")]
|
||||||
|
public required string Name1 { get; set; }
|
||||||
|
[Column("name_2")]
|
||||||
|
public string? Name2 { get; set; }
|
||||||
|
[Column("address")]
|
||||||
|
public required string Address { get; set; }
|
||||||
|
[Column("plz")]
|
||||||
|
public int Plz { get; set; }
|
||||||
|
[Column("ort")]
|
||||||
|
public required string Locality { get; set; }
|
||||||
|
[Column("bucket")]
|
||||||
|
public required string VtrgId { get; set; }
|
||||||
|
[Column("area")]
|
||||||
|
public int Area { get; set; }
|
||||||
|
[Column("min_kg")]
|
||||||
|
public int MinKg { get; set; }
|
||||||
|
[Column("max_kg")]
|
||||||
|
public int MaxKg { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,73 +14,49 @@ 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),
|
||||||
("SortIds", "Sorte", null, 12),
|
("SortId", "Sorte", null, 12),
|
||||||
("AttrIds", "Attribut", null, 16),
|
("AttrId", "Attribut", null, 16),
|
||||||
("Areas", "Fläche", "m²", 22),
|
("CultId", "Bewirt.", null, 16),
|
||||||
("DeliveryObligations", "Lieferpflicht", "kg", 22),
|
("GstNr", "Parzelle(n)", null, 25),
|
||||||
("DeliveryRights", "Lieferrecht", "kg", 22),
|
("Area", "Fläche", "m²", 22),
|
||||||
|
("MinKg", "Lieferpflicht", "kg", 22),
|
||||||
|
("MaxKg", "Lieferrecht", "kg", 22),
|
||||||
];
|
];
|
||||||
|
|
||||||
public MemberAreaComsData(IEnumerable<MemberAreaComsRow> rows, int year) :
|
public MemberAreaComsData(IEnumerable<MemberAreaComsRow> rows, int year) :
|
||||||
base($"Flächenbindungen", $"Flächenbindungen pro Mitglied {year}", rows, FieldNames) {
|
base($"Flächenbindungen", $"Flächenbindungen pro Mitglied {year}", rows, FieldNames) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<MemberAreaComsData> ForSeason(DbSet<MemberAreaComsRowSingle> table, int year) {
|
public static async Task<MemberAreaComsData> ForSeason(DbSet<MemberAreaComsRow> table, int year) {
|
||||||
return new MemberAreaComsData(
|
return new MemberAreaComsData(await FromDbSet(table, year), year);
|
||||||
(await FromDbSet(table, year)).GroupBy(
|
|
||||||
r => r.MgNr,
|
|
||||||
(k, g) => new MemberAreaComsRow(g)
|
|
||||||
), year);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<IEnumerable<MemberAreaComsRowSingle>> FromDbSet(DbSet<MemberAreaComsRowSingle> table, int year) {
|
private static async Task<IEnumerable<MemberAreaComsRow>> FromDbSet(DbSet<MemberAreaComsRow> table, int year) {
|
||||||
return await table.FromSql($"""
|
return 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,
|
p.plz, o.name AS ort, m.address,
|
||||||
c.bucket, c.area, c.min_kg, c.max_kg
|
t.sortid, t.attrid, c.cultid,
|
||||||
FROM v_area_commitment_bucket_strict c
|
c.gstnr, c.area,
|
||||||
|
CAST(ROUND(area * COALESCE(t.min_kg_per_ha, 0) / 10000.0, 0) AS INTEGER) AS min_kg,
|
||||||
|
CAST(ROUND(area * MIN(COALESCE(a.max_kg_per_ha, s.max_kg_per_ha), s.max_kg_per_ha) / 10000.0, 0) AS INTEGER) AS max_kg
|
||||||
|
FROM v_virtual_season s, area_commitment c
|
||||||
|
JOIN area_commitment_type t ON t.vtrgid = c.vtrgid
|
||||||
|
LEFT JOIN wine_attribute a ON a.attrid = t.attrid
|
||||||
LEFT JOIN member m ON m.mgnr = c.mgnr
|
LEFT JOIN member m ON m.mgnr = c.mgnr
|
||||||
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
|
||||||
WHERE c.year = {year}
|
WHERE s.year = {year} AND
|
||||||
ORDER BY m.mgnr, c.bucket
|
(year_from IS NULL OR year_from <= s.year) AND
|
||||||
|
(year_to IS NULL OR year_to >= s.year)
|
||||||
|
ORDER BY c.mgnr, t.sortid, t.attrid, c.cultid, c.gstnr;
|
||||||
""").ToListAsync();
|
""").ToListAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class MemberAreaComsRow {
|
|
||||||
public int MgNr;
|
|
||||||
public string Name1;
|
|
||||||
public string? Name2;
|
|
||||||
public string Address;
|
|
||||||
public int Plz;
|
|
||||||
public string Locality;
|
|
||||||
public string[] SortIds;
|
|
||||||
public string[] AttrIds;
|
|
||||||
public int[] Areas;
|
|
||||||
public int[] DeliveryObligations;
|
|
||||||
public int[] DeliveryRights;
|
|
||||||
|
|
||||||
public MemberAreaComsRow(IEnumerable<MemberAreaComsRowSingle> rows) {
|
|
||||||
var f = rows.First();
|
|
||||||
MgNr = f.MgNr;
|
|
||||||
Name1 = f.Name1;
|
|
||||||
Name2 = f.Name2;
|
|
||||||
Address = f.Address;
|
|
||||||
Plz = f.Plz;
|
|
||||||
Locality = f.Locality.Split(",")[0];
|
|
||||||
SortIds = rows.Select(r => r.VtrgId[..2]).ToArray();
|
|
||||||
AttrIds = rows.Select(r => r.VtrgId[2..]).ToArray();
|
|
||||||
Areas = rows.Select(r => r.Area).ToArray();
|
|
||||||
DeliveryObligations = rows.Select(r => r.MinKg).ToArray();
|
|
||||||
DeliveryRights = rows.Select(r => r.MaxKg).ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Keyless]
|
[Keyless]
|
||||||
public class MemberAreaComsRowSingle {
|
public class MemberAreaComsRow {
|
||||||
[Column("mgnr")]
|
[Column("mgnr")]
|
||||||
public int MgNr { get; set; }
|
public int MgNr { get; set; }
|
||||||
[Column("name_1")]
|
[Column("name_1")]
|
||||||
@@ -93,8 +69,14 @@ namespace Elwig.Models.Dtos {
|
|||||||
public int Plz { get; set; }
|
public int Plz { get; set; }
|
||||||
[Column("ort")]
|
[Column("ort")]
|
||||||
public required string Locality { get; set; }
|
public required string Locality { get; set; }
|
||||||
[Column("bucket")]
|
[Column("sortid")]
|
||||||
public required string VtrgId { get; set; }
|
public required string SortId { get; set; }
|
||||||
|
[Column("attrid")]
|
||||||
|
public string? AttrId { get; set; }
|
||||||
|
[Column("cultid")]
|
||||||
|
public string? CultId { get; set; }
|
||||||
|
[Column("gstnr")]
|
||||||
|
public required string GstNr { get; set; }
|
||||||
[Column("area")]
|
[Column("area")]
|
||||||
public int Area { get; set; }
|
public int Area { get; set; }
|
||||||
[Column("min_kg")]
|
[Column("min_kg")]
|
||||||
|
|||||||
@@ -118,26 +118,28 @@ namespace Elwig.Models.Entities {
|
|||||||
[Column("acid")]
|
[Column("acid")]
|
||||||
public double? Acid { get; set; }
|
public double? Acid { get; set; }
|
||||||
|
|
||||||
[Column("scale_id")]
|
[Column("scale_terminal")]
|
||||||
public string? ScaleId { get; set; }
|
public string? ScaleTerminalId { get; set; }
|
||||||
|
|
||||||
[Column("weighing_data")]
|
[Column("weighing_data")]
|
||||||
public string? WeighingData { get; set; }
|
public string? WeighingData { get; set; }
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public (string? Id, int? Gross, int? Tare, int? Net, DateOnly? Date, TimeOnly? Time) WeighingInfo {
|
public (string? ScaleId, string? Id, int? Gross, int? Tare, int? TareCorrection, int? Net, DateOnly? Date, TimeOnly? Time) WeighingInfo {
|
||||||
get {
|
get {
|
||||||
try {
|
try {
|
||||||
var obj = JsonNode.Parse(WeighingData!)!.AsObject();
|
var obj = JsonNode.Parse(WeighingData!)!.AsObject();
|
||||||
return (
|
return (
|
||||||
|
obj["scale"]?.AsValue().GetValue<string>(),
|
||||||
obj["id"]?.AsValue().GetValue<string>(),
|
obj["id"]?.AsValue().GetValue<string>(),
|
||||||
obj["gross_weight"]?.AsValue().GetValue<int>(),
|
obj["gross_weight"]?.AsValue().GetValue<int>(),
|
||||||
obj["tare_weight"]?.AsValue().GetValue<int>(),
|
obj["tare_weight"]?.AsValue().GetValue<int>(),
|
||||||
|
obj["tare_correction"]?.AsValue().GetValue<int>(),
|
||||||
obj["net_weight"]?.AsValue().GetValue<int>(),
|
obj["net_weight"]?.AsValue().GetValue<int>(),
|
||||||
DateOnly.TryParseExact(obj["date"]?.AsValue().GetValue<string>(), "yyyy-MM-dd", out var d) ? d : null,
|
DateOnly.TryParseExact(obj["date"]?.AsValue().GetValue<string>(), "yyyy-MM-dd", out var d) ? d : null,
|
||||||
TimeOnly.TryParseExact(obj["time"]?.AsValue().GetValue<string>(), ["HH:mm:ss", "HH:mm"], out var t) ? t : null
|
TimeOnly.TryParseExact(obj["time"]?.AsValue().GetValue<string>(), ["HH:mm:ss", "HH:mm"], out var t) ? t : null
|
||||||
);
|
);
|
||||||
} catch {
|
} catch {
|
||||||
return (null, null, null, null, null, null);
|
return (null, null, null, null, null, null, null, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ namespace Elwig.Models.Entities {
|
|||||||
|
|
||||||
[Column("cultid")]
|
[Column("cultid")]
|
||||||
public string? CultId { get; set; }
|
public string? CultId { get; set; }
|
||||||
|
[NotMapped]
|
||||||
|
public bool IsOrganic => Cultivation?.IsOrganic ?? false;
|
||||||
|
|
||||||
[Column("max_weight")]
|
[Column("max_weight")]
|
||||||
public int? MaxWeight { get; set; }
|
public int? MaxWeight { get; set; }
|
||||||
|
|||||||
@@ -96,6 +96,12 @@ namespace Elwig.Models.Entities {
|
|||||||
[Column("ustid_nr")]
|
[Column("ustid_nr")]
|
||||||
public string? UstIdNr { get; set; }
|
public string? UstIdNr { get; set; }
|
||||||
|
|
||||||
|
[Column("ooc_id")]
|
||||||
|
public string? OrganicOperatorId { get; set; }
|
||||||
|
|
||||||
|
[Column("org_auth_code")]
|
||||||
|
public string? OrganicAuthorityCode { get; set; }
|
||||||
|
|
||||||
[Column("juridical_pers")]
|
[Column("juridical_pers")]
|
||||||
public bool IsJuridicalPerson { get; set; }
|
public bool IsJuridicalPerson { get; set; }
|
||||||
|
|
||||||
|
|||||||
@@ -76,7 +76,10 @@ namespace Elwig.Models.Entities {
|
|||||||
[Column("shares")]
|
[Column("shares")]
|
||||||
public int Shares { get; set; }
|
public int Shares { get; set; }
|
||||||
|
|
||||||
[Column("signed")]
|
[Column("signed_company")]
|
||||||
|
public bool CompanyHasSigned { get; set; }
|
||||||
|
|
||||||
|
[Column("signed_member")]
|
||||||
public bool MemberHasSigned { get; set; }
|
public bool MemberHasSigned { get; set; }
|
||||||
|
|
||||||
[Column("value_per_share")]
|
[Column("value_per_share")]
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ namespace Elwig.Models.Entities {
|
|||||||
[Column("name")]
|
[Column("name")]
|
||||||
public required string Name { get; set; }
|
public required string Name { get; set; }
|
||||||
|
|
||||||
|
[Column("organic")]
|
||||||
|
public bool IsOrganic { get; set; }
|
||||||
|
|
||||||
[Column("description")]
|
[Column("description")]
|
||||||
public string? Description { get; set; }
|
public string? Description { get; set; }
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
-- schema version 40 to 41
|
||||||
|
|
||||||
|
PRAGMA writable_schema = ON;
|
||||||
|
|
||||||
|
UPDATE sqlite_schema SET sql = REPLACE(sql, 'scale_id ', 'scale_terminal')
|
||||||
|
WHERE type = 'table' AND name = 'delivery_part';
|
||||||
|
|
||||||
|
DROP VIEW v_bki_delivery;
|
||||||
|
DROP VIEW v_bki_member;
|
||||||
|
|
||||||
|
CREATE VIEW v_bki_member AS
|
||||||
|
SELECT s.year, m.mgnr, m.lfbis_nr, m.name,
|
||||||
|
(COALESCE(m.prefix || ' ', '') || m.given_name || COALESCE(' ' || m.middle_names, '') || COALESCE(' ' || m.suffix, '')) AS other_names,
|
||||||
|
a.name AS billing_name, COALESCE(a.address, m.address) AS address,
|
||||||
|
COALESCE(a.country, m.country) AS country, COALESCE(a.postal_dest, m.postal_dest) AS postal_dest,
|
||||||
|
m.volllieferant AS vollablieferer,
|
||||||
|
SUM(COALESCE(IIF((c.year_from IS NULL OR c.year_from <= s.year) AND (c.year_to IS NULL OR c.year_to >= s.year), c.area, NULL), 0)) AS area
|
||||||
|
FROM season s, member m
|
||||||
|
LEFT JOIN member_billing_address a ON a.mgnr = m.mgnr
|
||||||
|
LEFT JOIN area_commitment c ON c.mgnr = m.mgnr
|
||||||
|
GROUP BY s.year, m.mgnr;
|
||||||
|
|
||||||
|
CREATE VIEW v_bki_delivery AS
|
||||||
|
SELECT m.lfbis_nr, m.name, m.other_names, m.billing_name,
|
||||||
|
m.address, plz.plz, IIF(INSTR(o.name, ',') = 0, o.name, SUBSTR(o.name, 1, INSTR(o.name, ',') - 1)) AS ort,
|
||||||
|
d.date, d.weight, v.type, v.sortid, d.qualid, d.year, d.hkid, d.kmw, d.oe,
|
||||||
|
m.vollablieferer, m.area
|
||||||
|
FROM v_delivery d
|
||||||
|
JOIN v_bki_member m ON (m.year, m.mgnr) = (d.year, d.mgnr)
|
||||||
|
JOIN postal_dest pd ON (pd.country, pd.id) = (m.country, m.postal_dest)
|
||||||
|
LEFT JOIN AT_plz_dest ap ON (ap.country, ap.id) = (pd.country, pd.id)
|
||||||
|
LEFT JOIN AT_plz plz ON plz.plz = ap.plz
|
||||||
|
LEFT JOIN AT_ort o ON o.okz = ap.okz
|
||||||
|
JOIN wine_variety v ON v.sortid = d.sortid
|
||||||
|
ORDER BY d.date, d.time;
|
||||||
|
|
||||||
|
PRAGMA writable_schema = OFF;
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
-- schema version 41 to 42
|
||||||
|
|
||||||
|
ALTER TABLE member ADD COLUMN ooc_id TEXT CHECK (ooc_id REGEXP '^[0-9]{3}-[0-9]{7}$') DEFAULT NULL;
|
||||||
|
ALTER TABLE member ADD COLUMN org_auth_code TEXT CHECK (org_auth_code REGEXP '^[A-Z]{2}-[A-ZÖØ]{3}-[0-9]{2,3}(-[A-Z]{2})?$') DEFAULT NULL;
|
||||||
|
|
||||||
|
ALTER TABLE wine_cultivation ADD COLUMN organic INTEGER NOT NULL CHECK (organic IN (TRUE, FALSE)) DEFAULT FALSE;
|
||||||
|
|
||||||
|
ALTER TABLE member_history RENAME COLUMN signed TO signed_member;
|
||||||
|
ALTER TABLE member_history ADD COLUMN signed_company INTEGER NOT NULL CHECK (signed_company IN (TRUE, FALSE)) DEFAULT FALSE;
|
||||||
|
|
||||||
|
|
||||||
|
UPDATE client_parameter SET value = '0' WHERE param = 'ENABLE_TIME_TRIGGERS';
|
||||||
|
|
||||||
|
UPDATE member SET org_auth_code = UPPER(SUBSTR(a.name, -11, 10))
|
||||||
|
FROM member m JOIN member_billing_address a ON a.mgnr = m.mgnr
|
||||||
|
WHERE m.mgnr = member.mgnr AND a.name LIKE '%AT-BIO-___)';
|
||||||
|
UPDATE member SET org_auth_code = UPPER(suffix) WHERE suffix LIKE 'AT-BIO-___';
|
||||||
|
|
||||||
|
UPDATE wine_cultivation SET organic = TRUE WHERE name LIKE '%bio%' OR name LIKE '%org%' OR description LIKE '%AT-BIO-%';
|
||||||
|
UPDATE wine_cultivation SET description = NULL WHERE description LIKE '%AT-BIO-%';
|
||||||
|
UPDATE wine_cultivation SET description = 'Biologische Produktion' WHERE organic;
|
||||||
|
|
||||||
|
UPDATE delivery_schedule SET cultid = (SELECT cultid FROM wine_cultivation WHERE organic LIMIT 1) WHERE description LIKE '%Bio%';
|
||||||
|
|
||||||
|
UPDATE client_parameter SET param = 'CLIENT_ORGANIC_AUTHORITYCODE' WHERE param = 'CLIENT_ORGANIC_AUTHORITY';
|
||||||
|
|
||||||
|
|
||||||
|
UPDATE member_telephone_number SET comment = NULL WHERE comment = '';
|
||||||
|
UPDATE member_email_address SET comment = NULL WHERE comment = '';
|
||||||
|
|
||||||
|
UPDATE member SET address = 'Untere Weißgerberstraße' WHERE address = 'U. Weißgasse Straße';
|
||||||
|
UPDATE member SET address = 'Edgar-Penzig-Franz-Straße' WHERE address = 'Edgar-Penzing-Franz-Straße';
|
||||||
|
|
||||||
|
UPDATE member
|
||||||
|
SET address = NORMALIZE_ADDRESS(address, (SELECT o.name FROM AT_plz_dest p JOIN AT_ort o ON o.okz = p.okz WHERE p.id = member.postal_dest))
|
||||||
|
WHERE address != NORMALIZE_ADDRESS(address, (SELECT o.name FROM AT_plz_dest p JOIN AT_ort o ON o.okz = p.okz WHERE p.id = member.postal_dest));
|
||||||
|
UPDATE member_billing_address
|
||||||
|
SET address = NORMALIZE_ADDRESS(address, (SELECT o.name FROM AT_plz_dest p JOIN AT_ort o ON o.okz = p.okz WHERE p.id = member_billing_address.postal_dest))
|
||||||
|
WHERE address != NORMALIZE_ADDRESS(address, (SELECT o.name FROM AT_plz_dest p JOIN AT_ort o ON o.okz = p.okz WHERE p.id = member_billing_address.postal_dest));
|
||||||
|
|
||||||
|
UPDATE client_parameter SET value = '1' WHERE param = 'ENABLE_TIME_TRIGGERS';
|
||||||
@@ -43,6 +43,8 @@ namespace Elwig.Services {
|
|||||||
public static async Task<(List<string>, IQueryable<AreaComContract>, 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);
|
||||||
|
filterNames.Add(vm.FilterMember.AdministrativeName);
|
||||||
|
|
||||||
if (vm.FilterSeason is int season) {
|
if (vm.FilterSeason is int season) {
|
||||||
areaComQuery = Utils.ActiveAreaCommitments(areaComQuery, season);
|
areaComQuery = Utils.ActiveAreaCommitments(areaComQuery, season);
|
||||||
filterNames.Add($"laufend {season}");
|
filterNames.Add($"laufend {season}");
|
||||||
|
|||||||
@@ -0,0 +1,133 @@
|
|||||||
|
using Elwig.Helpers;
|
||||||
|
using Elwig.Helpers.Export;
|
||||||
|
using Microsoft.Win32;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
namespace Elwig.Services {
|
||||||
|
public static class BackupService {
|
||||||
|
|
||||||
|
public static bool IsAnyBackupUpToDate {
|
||||||
|
get {
|
||||||
|
var lastDbWrite = File.GetLastWriteTime(App.Config.DatabaseFile);
|
||||||
|
lastDbWrite += new TimeSpan(0, 0, -1);
|
||||||
|
return Directory.GetFiles(App.Config.BackupPath, "????-??-??_??-??-??.*.zip")
|
||||||
|
.Any(n => DateTime.ParseExact(Path.GetFileName(n)[..19], "yyyy-MM-dd_HH-mm-ss", CultureInfo.InvariantCulture, DateTimeStyles.None) >= lastDbWrite);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task TryDatabaseBackup() {
|
||||||
|
if (IsAnyBackupUpToDate) return;
|
||||||
|
await BackupDatabase();
|
||||||
|
PruneBackups();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task BackupDatabase() {
|
||||||
|
await Database.ExportSql(Path.Combine(App.Config.BackupPath, $"{File.GetLastWriteTime(App.Config.DatabaseFile):yyyy-MM-dd_HH-mm-ss}.sql.zip"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void PruneBackups() {
|
||||||
|
var retain = new HashSet<string>();
|
||||||
|
var backups = Directory.GetFiles(App.Config.BackupPath, "????-??-??_??-??-??.*.zip")
|
||||||
|
.Select(n => (FileName: n, Timestamp: DateTime.ParseExact(Path.GetFileName(n)[..19], "yyyy-MM-dd_HH-mm-ss", CultureInfo.InvariantCulture, DateTimeStyles.None)))
|
||||||
|
.OrderByDescending(t => t.Timestamp).ToArray();
|
||||||
|
|
||||||
|
DateTime now;
|
||||||
|
|
||||||
|
// retain hourly backups
|
||||||
|
now = DateTime.Now;
|
||||||
|
for (int i = 0; i < App.Config.BackupRetainHours; i++, now = now.AddHours(-1)) {
|
||||||
|
foreach (var b in backups) {
|
||||||
|
if (b.Timestamp.Date == now.Date && b.Timestamp.Hour == now.Hour) {
|
||||||
|
retain.Add(b.FileName);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// retain daily backups
|
||||||
|
now = DateTime.Now;
|
||||||
|
for (int i = 0; i < App.Config.BackupRetainDays; i++, now = now.AddDays(-1)) {
|
||||||
|
foreach (var b in backups) {
|
||||||
|
if (b.Timestamp.Date == now.Date) {
|
||||||
|
retain.Add(b.FileName);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// retain weekly backups
|
||||||
|
now = DateTime.Now;
|
||||||
|
for (int i = 0; i < App.Config.BackupRetainWeeks; i++, now = now.AddDays(-7)) {
|
||||||
|
foreach (var b in backups) {
|
||||||
|
if (b.Timestamp.GetYearAndWeek() == now.GetYearAndWeek()) {
|
||||||
|
retain.Add(b.FileName);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// retain monthly backups
|
||||||
|
now = DateTime.Now;
|
||||||
|
for (int i = 0; i < App.Config.BackupRetainMonths; i++, now = now.AddMonths(-1)) {
|
||||||
|
foreach (var b in backups) {
|
||||||
|
if (b.Timestamp.Year == now.Year && b.Timestamp.Month == now.Month) {
|
||||||
|
retain.Add(b.FileName);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// retain tertial backups
|
||||||
|
now = new DateTime(DateTime.Now.Year + 1, 3, 1);
|
||||||
|
for (int i = 0; i < 600; i++, now = now.AddMonths(-4)) {
|
||||||
|
foreach (var b in backups) {
|
||||||
|
if (b.Timestamp.GetYearAndTertial() == now.GetYearAndTertial()) {
|
||||||
|
retain.Add(b.FileName);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete non-retained files
|
||||||
|
foreach (var b in backups) {
|
||||||
|
if (retain.Contains(b.FileName)) continue;
|
||||||
|
try {
|
||||||
|
File.Delete(b.FileName);
|
||||||
|
} catch { }
|
||||||
|
}
|
||||||
|
// delete temp files
|
||||||
|
foreach (var f in Directory.GetFiles(App.Config.BackupPath, "*.tmp")) {
|
||||||
|
try {
|
||||||
|
File.Delete(f);
|
||||||
|
} catch { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task RestoreDatabase() {
|
||||||
|
try {
|
||||||
|
var d = new OpenFileDialog() {
|
||||||
|
Title = "Datenbank wiederherstellen - Elwig",
|
||||||
|
DefaultDirectory = App.Config.BackupPath,
|
||||||
|
InitialDirectory = App.Config.BackupPath,
|
||||||
|
DefaultExt = "sql.zip",
|
||||||
|
Filter = "SQLite-Datenbank (*.sqlite3, *.sqlite3.zip, *.sql, *.sql.zip)|*.sqlite3;*.sqlite3.zip;*.sql;*.sql.zip",
|
||||||
|
};
|
||||||
|
if (d.ShowDialog() == true) {
|
||||||
|
if (!InteractionService.AskContinue("Datenbank wiederherstellen", "Soll die Datenbank wirklich unwiederruflich durch die wiederhergestellte Version ersetzt werden?"))
|
||||||
|
return;
|
||||||
|
Mouse.OverrideCursor = Cursors.Wait;
|
||||||
|
await App.ReplaceDatabase(d.FileName);
|
||||||
|
}
|
||||||
|
} catch (Exception exc) {
|
||||||
|
InteractionService.ShowException(exc);
|
||||||
|
}
|
||||||
|
Mouse.OverrideCursor = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -45,7 +45,8 @@ namespace Elwig.Services {
|
|||||||
deliveryAncmtQuery = deliveryAncmtQuery.Where(a => a.Year == s.Year && a.DsNr == s.DsNr);
|
deliveryAncmtQuery = deliveryAncmtQuery.Where(a => a.Year == s.Year && a.DsNr == s.DsNr);
|
||||||
filterNames.Add($"{s.Date:dd.MM.yyyy} – {s.Branch.Name} – {s.Description}");
|
filterNames.Add($"{s.Date:dd.MM.yyyy} – {s.Branch.Name} – {s.Description}");
|
||||||
} else {
|
} else {
|
||||||
deliveryAncmtQuery = deliveryAncmtQuery.Where(a => a.Year == vm.FilterSeason && (!vm.FilterOnlyUpcoming || a.Schedule.DateString.CompareTo(Utils.Today.ToString("yyyy-MM-dd")) >= 0));
|
var today = DateTime.Today;
|
||||||
|
deliveryAncmtQuery = deliveryAncmtQuery.Where(a => a.Year == vm.FilterSeason && (!vm.FilterOnlyUpcoming || a.Schedule.DateString.CompareTo(today.ToString("yyyy-MM-dd")) >= 0));
|
||||||
filterNames.Add($"{vm.FilterSeason}");
|
filterNames.Add($"{vm.FilterSeason}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,8 +49,9 @@ namespace Elwig.Services {
|
|||||||
filterNames.Add($"{vm.FilterSeason}");
|
filterNames.Add($"{vm.FilterSeason}");
|
||||||
}
|
}
|
||||||
if (vm.FilterOnlyUpcoming) {
|
if (vm.FilterOnlyUpcoming) {
|
||||||
deliveryScheduleQuery = deliveryScheduleQuery.Where(s => s.DateString.CompareTo(Utils.Today.ToString("yyyy-MM-dd")) >= 0);
|
var today = DateTime.Today;
|
||||||
filterNames.Add($"ab {Utils.Today:dd.MM.yyyy}");
|
deliveryScheduleQuery = deliveryScheduleQuery.Where(s => s.DateString.CompareTo(today.ToString("yyyy-MM-dd")) >= 0);
|
||||||
|
filterNames.Add($"ab {today:dd.MM.yyyy}");
|
||||||
}
|
}
|
||||||
|
|
||||||
var filterVar = new List<string>();
|
var filterVar = new List<string>();
|
||||||
|
|||||||
@@ -1,19 +1,21 @@
|
|||||||
using Elwig.Documents;
|
using Elwig.Documents;
|
||||||
using Elwig.Helpers.Export;
|
|
||||||
using Elwig.Helpers;
|
using Elwig.Helpers;
|
||||||
|
using Elwig.Helpers.Export;
|
||||||
using Elwig.Models.Dtos;
|
using Elwig.Models.Dtos;
|
||||||
using Elwig.Models.Entities;
|
using Elwig.Models.Entities;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System;
|
|
||||||
using Elwig.ViewModels;
|
using Elwig.ViewModels;
|
||||||
|
using iText.Commons.Internal.Runtime;
|
||||||
using LinqKit;
|
using LinqKit;
|
||||||
using System.Globalization;
|
|
||||||
using System.Linq.Expressions;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Media;
|
||||||
|
|
||||||
namespace Elwig.Services {
|
namespace Elwig.Services {
|
||||||
public static class DeliveryService {
|
public static class DeliveryService {
|
||||||
@@ -35,8 +37,13 @@ namespace Elwig.Services {
|
|||||||
|
|
||||||
vm.SortId = "";
|
vm.SortId = "";
|
||||||
vm.GradationKmwString = "";
|
vm.GradationKmwString = "";
|
||||||
vm.WeightString = "";
|
|
||||||
|
vm.Weight = null;
|
||||||
|
vm.ActualTare = null;
|
||||||
|
vm.TargetTare = null;
|
||||||
|
vm.Tare = null;
|
||||||
vm.IsManualWeighing = false;
|
vm.IsManualWeighing = false;
|
||||||
|
|
||||||
vm.PartComment = "";
|
vm.PartComment = "";
|
||||||
vm.TemperatureString = "";
|
vm.TemperatureString = "";
|
||||||
vm.AcidString = "";
|
vm.AcidString = "";
|
||||||
@@ -51,7 +58,11 @@ namespace Elwig.Services {
|
|||||||
vm.WineKg = ControlUtils.GetItemFromSourceWithPk(vm.WineKgSource, p.KgNr) as AT_Kg;
|
vm.WineKg = ControlUtils.GetItemFromSourceWithPk(vm.WineKgSource, p.KgNr) as AT_Kg;
|
||||||
vm.WineRd = ControlUtils.GetItemFromSourceWithPk(vm.WineRdSource, p.KgNr, p.RdNr) as WbRd;
|
vm.WineRd = ControlUtils.GetItemFromSourceWithPk(vm.WineRdSource, p.KgNr, p.RdNr) as WbRd;
|
||||||
vm.WineOrigin = ControlUtils.GetItemFromSourceWithPk(vm.WineOriginSource, p.HkId) as WineOrigin;
|
vm.WineOrigin = ControlUtils.GetItemFromSourceWithPk(vm.WineOriginSource, p.HkId) as WineOrigin;
|
||||||
vm.WeightString = $"{p.Weight:N0}";
|
|
||||||
|
vm.Weight = p.Weight;
|
||||||
|
vm.ActualTare = p.WeighingInfo.Tare;
|
||||||
|
vm.TargetTare = vm.ActualTare + p.WeighingInfo.TareCorrection;
|
||||||
|
vm.Tare = vm.TargetTare ?? (vm.ActualTare is int t && t != 0 ? t : null);
|
||||||
vm.IsManualWeighing = p.IsManualWeighing;
|
vm.IsManualWeighing = p.IsManualWeighing;
|
||||||
vm.IsNetWeight = p.IsNetWeight;
|
vm.IsNetWeight = p.IsNetWeight;
|
||||||
|
|
||||||
@@ -67,11 +78,50 @@ namespace Elwig.Services {
|
|||||||
vm.IsGebunden = p.IsGebunden;
|
vm.IsGebunden = p.IsGebunden;
|
||||||
vm.Unloading = p.Unloading;
|
vm.Unloading = p.Unloading;
|
||||||
|
|
||||||
vm.ScaleId = p.ScaleId;
|
vm.ScaleTerminalId = p.ScaleTerminalId;
|
||||||
vm.WeighingData = p.WeighingData;
|
vm.WeighingData = p.WeighingData;
|
||||||
vm.ManualWeighingReason = p.WeighingReason;
|
vm.ManualWeighingReason = p.WeighingReason;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static (DateTime From, DateTime To)? GetFilterToday(DateTime today, IEnumerable<DateTime> timestamps) {
|
||||||
|
var filtered = timestamps.Where(t => t >= today.AddDays(-1) && t < today.AddDays(1)).Order().ToArray();
|
||||||
|
if (filtered.Length == 0) return null;
|
||||||
|
|
||||||
|
var latest = filtered.Last();
|
||||||
|
var since = filtered.Cast<DateTime>().Reverse().Aggregate(latest, (s, c) => s.Subtract(c).TotalHours <= 6 ? c : s);
|
||||||
|
latest += new TimeSpan(0, 1, -latest.Minute, -latest.Second, -latest.Millisecond, -latest.Microsecond);
|
||||||
|
since += new TimeSpan(0, 0, -since.Minute, -since.Second, -since.Millisecond, -since.Microsecond);
|
||||||
|
|
||||||
|
if (since.Subtract(today) <= new TimeSpan(-6, 0, 0) && latest.Subtract(today) < new TimeSpan(0, 0, 0))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return (since, latest);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task<(Expression<Func<Delivery, bool>>, string)> GetFilterToday(AppDbContext ctx) {
|
||||||
|
var today = DateTime.Today;
|
||||||
|
var timestamps = (await ctx.Deliveries
|
||||||
|
.Where(d => d.DateString.CompareTo(today.AddDays(-1).ToString("yyyy-MM-dd")) >= 0)
|
||||||
|
.OrderBy(d => d.DateString).ThenBy(d => d.TimeString)
|
||||||
|
.Select(d => d.DateString + " " + d.TimeString)
|
||||||
|
.ToListAsync())
|
||||||
|
.Select(s => DateTime.TryParseExact(s, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.None, out var dt) ? (DateTime?)dt : null)
|
||||||
|
.Where(t => t.HasValue)
|
||||||
|
.Cast<DateTime>()
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
var res = GetFilterToday(today, timestamps);
|
||||||
|
if (!res.HasValue) {
|
||||||
|
return (_ => false, today.ToString("dd.MM.yyyy"));
|
||||||
|
} else {
|
||||||
|
var from = res.Value.From;
|
||||||
|
var to = res.Value.To;
|
||||||
|
return (d => (d.DateString == from.ToString("yyyy-MM-dd") && (d.TimeString == null || d.TimeString.CompareTo(from.ToString("HH:mm:ss")) >= 0)) ||
|
||||||
|
(d.DateString.CompareTo(from.ToString("yyyy-MM-dd")) > 0),
|
||||||
|
from.Date == to.Date ? from.ToString("dd.MM.yyyy") : $"{from:dd.MM.yyyy \\a\\b HH:mm} / {to:dd.MM.yyyy \\b\\i\\s HH:mm}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static async Task<(List<string>, IQueryable<Delivery>, IQueryable<DeliveryPart>, Predicate<DeliveryPart>, List<string>)> GetFilters(this DeliveryAdminViewModel vm, AppDbContext ctx) {
|
public static async Task<(List<string>, IQueryable<Delivery>, IQueryable<DeliveryPart>, Predicate<DeliveryPart>, List<string>)> GetFilters(this DeliveryAdminViewModel vm, AppDbContext ctx) {
|
||||||
List<string> filterNames = [];
|
List<string> filterNames = [];
|
||||||
IQueryable<Delivery> deliveryQuery = ctx.Deliveries;
|
IQueryable<Delivery> deliveryQuery = ctx.Deliveries;
|
||||||
@@ -84,10 +134,9 @@ namespace Elwig.Services {
|
|||||||
filterNames.Add(vm.FilterMember.AdministrativeName);
|
filterNames.Add(vm.FilterMember.AdministrativeName);
|
||||||
}
|
}
|
||||||
if (vm.FilterTodayOnly) {
|
if (vm.FilterTodayOnly) {
|
||||||
deliveryQuery = deliveryQuery
|
var (pred, name) = await GetFilterToday(ctx);
|
||||||
.Where(d => (d.DateString == Utils.Today.ToString("yyyy-MM-dd") && (d.TimeString == null || d.TimeString.CompareTo("03:00:00") > 0)) ||
|
deliveryQuery = deliveryQuery.Where(pred);
|
||||||
(d.DateString == Utils.Today.AddDays(1).ToString("yyyy-MM-dd") && (d.TimeString == null || d.TimeString.CompareTo("03:00:00") <= 0)));
|
filterNames.Add(name);
|
||||||
filterNames.Add(Utils.Today.ToString("dd.MM.yyyy"));
|
|
||||||
} else if (!vm.FilterAllSeasons) {
|
} else if (!vm.FilterAllSeasons) {
|
||||||
deliveryQuery = deliveryQuery.Where(d => d.Year == vm.FilterSeason);
|
deliveryQuery = deliveryQuery.Where(d => d.Year == vm.FilterSeason);
|
||||||
filterNames.Add($"{vm.FilterSeason}");
|
filterNames.Add($"{vm.FilterSeason}");
|
||||||
@@ -515,7 +564,7 @@ namespace Elwig.Services {
|
|||||||
|
|
||||||
Weight = vm.Weight!.Value,
|
Weight = vm.Weight!.Value,
|
||||||
IsManualWeighing = vm.IsManualWeighing,
|
IsManualWeighing = vm.IsManualWeighing,
|
||||||
ScaleId = vm.ScaleId,
|
ScaleTerminalId = vm.ScaleTerminalId,
|
||||||
WeighingData = vm.WeighingData,
|
WeighingData = vm.WeighingData,
|
||||||
WeighingReason = vm.ManualWeighingReason,
|
WeighingReason = vm.ManualWeighingReason,
|
||||||
};
|
};
|
||||||
@@ -730,10 +779,9 @@ namespace Elwig.Services {
|
|||||||
query = q;
|
query = q;
|
||||||
filterNames.AddRange(f);
|
filterNames.AddRange(f);
|
||||||
} else if (subject == ExportSubject.FromToday) {
|
} else if (subject == ExportSubject.FromToday) {
|
||||||
var date = $"{Utils.Today:yyyy-MM-dd}";
|
var (pred, name) = await GetFilterToday(ctx);
|
||||||
query = ctx.DeliveryParts
|
query = ctx.Deliveries.Where(pred).SelectMany(d => d.Parts);
|
||||||
.Where(p => p.Delivery.DateString == date);
|
filterNames.Add(name);
|
||||||
filterNames.Add($"{Utils.Today:dd.MM.yyyy}");
|
|
||||||
} else if (subject == ExportSubject.FromSeasonAndBranch) {
|
} else if (subject == ExportSubject.FromSeasonAndBranch) {
|
||||||
query = ctx.DeliveryParts
|
query = ctx.DeliveryParts
|
||||||
.Where(p => p.Year == Utils.CurrentLastSeason && p.Delivery.ZwstId == App.ZwstId);
|
.Where(p => p.Year == Utils.CurrentLastSeason && p.Delivery.ZwstId == App.ZwstId);
|
||||||
@@ -805,10 +853,9 @@ namespace Elwig.Services {
|
|||||||
query = q;
|
query = q;
|
||||||
filterNames.AddRange(f);
|
filterNames.AddRange(f);
|
||||||
} else if (subject == ExportSubject.FromToday) {
|
} else if (subject == ExportSubject.FromToday) {
|
||||||
var date = $"{Utils.Today:yyyy-MM-dd}";
|
var (pred, name) = await GetFilterToday(ctx);
|
||||||
query = ctx.DeliveryParts
|
query = ctx.Deliveries.Where(pred).SelectMany(d => d.Parts);
|
||||||
.Where(p => p.Delivery.DateString == date);
|
filterNames.Add(name);
|
||||||
filterNames.Add($"{Utils.Today:dd.MM.yyyy}");
|
|
||||||
} else {
|
} else {
|
||||||
throw new ArgumentException("Invalid value for ExportSubject");
|
throw new ArgumentException("Invalid value for ExportSubject");
|
||||||
}
|
}
|
||||||
@@ -930,30 +977,40 @@ namespace Elwig.Services {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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, string? h3, int weight, int? total1, int? total2, int total3, string? type) {
|
||||||
var bold = h2 == null;
|
var bold = h3 == null;
|
||||||
if (h1 != null) grid.AddToolTipCell(h1 + ":", row, 0, (h2 == null) ? 2 : 1, bold);
|
var color = type == "R" ? Brushes.Firebrick : type == "W" ? Brushes.ForestGreen : null;
|
||||||
if (h2 != null) grid.AddToolTipCell(h2 + ":", row, 1, 1, bold);
|
if (h1 != null) grid.AddToolTipCell(h1 + ":", row, 0, (h2 == null) ? (h3 == null) ? 3 : 2 : 1, bold: bold, color: color);
|
||||||
grid.AddToolTipCell($"{weight:N0} kg", row, 2, bold: bold, alignRight: true);
|
if (h2 != null) grid.AddToolTipCell(h2 + ":", row, 1, (h3 == null) ? 2 : 1, bold: bold, color: color);
|
||||||
|
if (h3 != null) grid.AddToolTipCell(h3 + ":", row, 2, 1, bold: bold, color: color);
|
||||||
|
grid.AddToolTipCell($"{weight:N0} kg", row, 3, bold: bold, alignRight: true, color: color);
|
||||||
if (total1 != null && total1 != 0)
|
if (total1 != null && total1 != 0)
|
||||||
grid.AddToolTipCell($"{weight * 100.0 / total1:N1} %", row, 3, bold: bold, alignRight: true);
|
grid.AddToolTipCell($"{weight * 100.0 / total1:N1} %", row, 4, bold: bold, alignRight: true, color: color);
|
||||||
if (total2 != 0)
|
if (total2 != null && total2 != 0)
|
||||||
grid.AddToolTipCell($"{weight * 100.0 / total2:N1} %", row, 4, bold: bold, alignRight: true);
|
grid.AddToolTipCell($"{weight * 100.0 / total2:N1} %", row, 5, bold: bold, alignRight: true, color: color);
|
||||||
|
if (total3 != 0)
|
||||||
|
grid.AddToolTipCell($"{weight * 100.0 / total3:N1} %", row, 6, bold: bold, alignRight: true, color: color);
|
||||||
}
|
}
|
||||||
|
|
||||||
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, string? h3, double min, double avg, double max, string? type) {
|
||||||
var bold = h2 == null;
|
var bold = h3 == null;
|
||||||
if (h1 != null) grid.AddToolTipCell(h1 + ":", row, 0, (h2 == null) ? 2 : 1, bold);
|
var color = type == "R" ? Brushes.Firebrick : type == "W" ? Brushes.ForestGreen : null;
|
||||||
if (h2 != null) grid.AddToolTipCell(h2 + ":", row, 1, bold: bold);
|
if (h1 != null) grid.AddToolTipCell(h1 + ":", row, 0, (h2 == null) ? (h3 == null) ? 3 : 2 : 1, bold: bold, color: color);
|
||||||
grid.AddToolTipCell($"{min:N1}°", row, 2, bold: bold, alignRight: true);
|
if (h2 != null) grid.AddToolTipCell(h2 + ":", row, 1, (h3 == null) ? 2 : 1, bold: bold, color: color);
|
||||||
grid.AddToolTipCell($"{avg:N1}°", row, 3, bold: bold, alignRight: true);
|
if (h3 != null) grid.AddToolTipCell(h3 + ":", row, 2, bold: bold, color: color);
|
||||||
grid.AddToolTipCell($"{max:N1}°", row, 4, bold: bold, alignRight: true);
|
grid.AddToolTipCell($"{min:N1}°", row, 3, bold: bold, alignRight: true, color: color);
|
||||||
|
grid.AddToolTipCell($"{avg:N1}°", row, 4, bold: bold, alignRight: true, color: color);
|
||||||
|
grid.AddToolTipCell($"{max:N1}°", row, 5, bold: bold, alignRight: true, color: color);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<(string WeightText, (string?, string?, int, int?, int)[] WeightGrid, string GradationText, (string?, string?, double, double, double)[] GradationGrid)> GenerateToolTipData(IQueryable<DeliveryPart> deliveryParts) {
|
private static string? GetGroupName(params string?[] parts) {
|
||||||
var wGrid = new List<(string?, string?, int, int?, int)>();
|
return parts.All(p => p == null) ? null : string.Join(" / ", parts.Where(p => p != null));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<(string WeightText, (string?, string?, string?, int, int?, int?, int, string?)[] WeightGrid, string GradationText, (string?, string?, string?, double, double, double, string?)[] GradationGrid)> GenerateToolTipData(IQueryable<DeliveryPart> deliveryParts) {
|
||||||
|
var wGrid = new List<(string?, string?, string?, int, int?, int?, int, string?)>();
|
||||||
var wText = "-";
|
var wText = "-";
|
||||||
var gGrid = new List<(string?, string?, double, double, double)>();
|
var gGrid = new List<(string?, string?, string?, double, double, double, string?)>();
|
||||||
var gText = "-";
|
var gText = "-";
|
||||||
|
|
||||||
var stat = (await deliveryParts.GroupBy(p => 0)
|
var stat = (await deliveryParts.GroupBy(p => 0)
|
||||||
@@ -968,11 +1025,11 @@ namespace Elwig.Services {
|
|||||||
.Single();
|
.Single();
|
||||||
|
|
||||||
wText = $"{stat.Weight:N0} kg";
|
wText = $"{stat.Weight:N0} kg";
|
||||||
wGrid.Add(("Menge", null, stat.Weight, null, stat.Weight));
|
wGrid.Add(("Menge", null, null, stat.Weight, null, null, stat.Weight, null));
|
||||||
|
|
||||||
if (stat.Min != null && stat.Max != null) {
|
if (stat.Min != null && stat.Max != null) {
|
||||||
gText = $"{stat.Min:N1}° / {stat.Avg:N1}° / {stat.Max:N1}°";
|
gText = $"{stat.Min:N1}° / {stat.Avg:N1}° / {stat.Max:N1}°";
|
||||||
gGrid.Add(("Gradation", null, stat.Min.Value, stat.Avg, stat.Max.Value));
|
gGrid.Add(("Gradation", null, null, stat.Min.Value, stat.Avg, stat.Max.Value, null));
|
||||||
|
|
||||||
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 })
|
||||||
@@ -989,9 +1046,10 @@ namespace Elwig.Services {
|
|||||||
.ThenBy(g => g.Cult)
|
.ThenBy(g => g.Cult)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
var sortGroups = await deliveryParts
|
var sortGroups = await deliveryParts
|
||||||
.GroupBy(p => p.SortId)
|
.GroupBy(p => new { p.SortId, p.Variety.Type })
|
||||||
.Select(g => new {
|
.Select(g => new {
|
||||||
SortId = g.Key,
|
g.Key.SortId,
|
||||||
|
g.Key.Type,
|
||||||
Weight = g.Sum(p => p.Weight),
|
Weight = g.Sum(p => p.Weight),
|
||||||
Min = g.Min(p => p.Kmw),
|
Min = g.Min(p => p.Kmw),
|
||||||
Avg = g.Sum(p => p.Kmw * p.Weight) / g.Sum(p => p.Weight),
|
Avg = g.Sum(p => p.Kmw * p.Weight) / g.Sum(p => p.Weight),
|
||||||
@@ -1004,11 +1062,13 @@ namespace Elwig.Services {
|
|||||||
.GroupBy(p => new {
|
.GroupBy(p => new {
|
||||||
Attr = p.Attribute!.Name,
|
Attr = p.Attribute!.Name,
|
||||||
Cult = p.Cultivation!.Name,
|
Cult = p.Cultivation!.Name,
|
||||||
|
p.Variety.Type,
|
||||||
p.SortId,
|
p.SortId,
|
||||||
})
|
})
|
||||||
.Select(g => new {
|
.Select(g => new {
|
||||||
g.Key.Attr,
|
g.Key.Attr,
|
||||||
g.Key.Cult,
|
g.Key.Cult,
|
||||||
|
g.Key.Type,
|
||||||
g.Key.SortId,
|
g.Key.SortId,
|
||||||
Weight = g.Sum(p => p.Weight),
|
Weight = g.Sum(p => p.Weight),
|
||||||
Min = g.Min(p => p.Kmw),
|
Min = g.Min(p => p.Kmw),
|
||||||
@@ -1018,27 +1078,62 @@ namespace Elwig.Services {
|
|||||||
.OrderByDescending(g => g.Weight)
|
.OrderByDescending(g => g.Weight)
|
||||||
.ThenBy(g => g.Attr)
|
.ThenBy(g => g.Attr)
|
||||||
.ThenBy(g => g.Cult)
|
.ThenBy(g => g.Cult)
|
||||||
|
.ThenBy(g => g.Type)
|
||||||
.ThenBy(g => g.SortId)
|
.ThenBy(g => g.SortId)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
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 = GetGroupName(attrG.Attr, attrG.Cult);
|
||||||
wGrid.Add((name, null, attrG.Weight, attrG.Weight, stat.Weight));
|
var typeGroups = groups.Where(g => g.Attr == attrG.Attr && g.Cult == attrG.Cult)
|
||||||
foreach (var g in groups.Where(g => g.Attr == attrG.Attr && g.Cult == attrG.Cult).OrderByDescending(g => g.Weight).ThenBy(g => g.SortId)) {
|
.GroupBy(g => g.Type)
|
||||||
wGrid.Add((null, g.SortId, g.Weight, attrG.Weight, stat.Weight));
|
.Select(g => new { Type = g.Key, Weight = g.Sum(p => p.Weight) })
|
||||||
|
.OrderByDescending(g => g.Weight).ThenBy(g => g.Type)
|
||||||
|
.ToList();
|
||||||
|
wGrid.Add((name, null, null, attrG.Weight, null, attrG.Weight, stat.Weight, typeGroups.Count == 1 ? typeGroups.First().Type : null));
|
||||||
|
if (typeGroups.Count == 1) {
|
||||||
|
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, null, g.SortId, g.Weight, null, attrG.Weight, stat.Weight, null));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
foreach (var t in typeGroups) {
|
||||||
|
wGrid.Add((null, t.Type == "R" ? "Rot" : "Weiß", null, t.Weight, t.Weight, attrG.Weight, stat.Weight, t.Type));
|
||||||
|
foreach (var g in groups.Where(g => g.Attr == attrG.Attr && g.Cult == attrG.Cult && g.Type == t.Type).OrderByDescending(g => g.Weight).ThenBy(g => g.SortId)) {
|
||||||
|
wGrid.Add((null, null, g.SortId, g.Weight, t.Weight, attrG.Weight, stat.Weight, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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 = GetGroupName(attrG.Attr, attrG.Cult);
|
||||||
gGrid.Add((name, null, attrG.Min, attrG.Avg, attrG.Max));
|
var typeGroups = groups.Where(g => g.Attr == attrG.Attr && g.Cult == attrG.Cult)
|
||||||
foreach (var g in groups.Where(g => g.Attr == attrG.Attr && g.Cult == attrG.Cult).OrderByDescending(g => g.Avg).ThenBy(g => g.SortId)) {
|
.GroupBy(g => g.Type)
|
||||||
gGrid.Add((null, g.SortId, g.Min, g.Avg, g.Max));
|
.Select(g => new {
|
||||||
|
Type = g.Key,
|
||||||
|
Weight = g.Sum(p => p.Weight),
|
||||||
|
Min = g.Min(p => p.Min),
|
||||||
|
Avg = g.Sum(p => p.Avg * p.Weight) / g.Sum(p => p.Weight),
|
||||||
|
Max = g.Max(p => p.Max),
|
||||||
|
})
|
||||||
|
.OrderByDescending(g => g.Weight).ThenBy(g => g.Type)
|
||||||
|
.ToList();
|
||||||
|
gGrid.Add((name, null, null, attrG.Min, attrG.Avg, attrG.Max, typeGroups.Count == 1 ? typeGroups.First().Type : null));
|
||||||
|
if (typeGroups.Count == 1) {
|
||||||
|
foreach (var g in groups.Where(g => g.Attr == attrG.Attr && g.Cult == attrG.Cult).OrderByDescending(g => g.Avg).ThenBy(g => g.SortId)) {
|
||||||
|
gGrid.Add((null, null, g.SortId, g.Min, g.Avg, g.Max, null));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
foreach (var t in typeGroups) {
|
||||||
|
gGrid.Add((null, t.Type == "R" ? "Rot" : "Weiß", null, t.Min, t.Avg, t.Max, t.Type));
|
||||||
|
foreach (var g in groups.Where(g => g.Attr == attrG.Attr && g.Cult == attrG.Cult && g.Type == t.Type).OrderByDescending(g => g.Avg).ThenBy(g => g.SortId)) {
|
||||||
|
gGrid.Add((null, null, g.SortId, g.Min, g.Avg, g.Max, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attrGroups.Count == 1) {
|
if (attrGroups.Count == 1) {
|
||||||
var g = attrGroups.First();
|
var g = attrGroups.First();
|
||||||
var name = g.Attr == null && g.Cult == null ? null : g.Attr + (g.Attr != null && g.Cult != null ? " / " : "") + g.Cult;
|
var name = GetGroupName(g.Attr, g.Cult);
|
||||||
if (name != null) {
|
if (name != null) {
|
||||||
wText += $" [{name}]";
|
wText += $" [{name}]";
|
||||||
gText += $" [{name}]";
|
gText += $" [{name}]";
|
||||||
@@ -1049,40 +1144,43 @@ namespace Elwig.Services {
|
|||||||
|
|
||||||
}
|
}
|
||||||
} else if (attrGroups.Count <= 4) {
|
} else if (attrGroups.Count <= 4) {
|
||||||
wText += $" = {string.Join(" + ", attrGroups.Select(g => $"{g.Weight:N0} kg ({(double)g.Weight / stat.Weight:0%})" + (g.Attr == null && g.Cult == null ? "" : $" [{g.Attr}{(g.Attr != null && g.Cult != null ? " / " : "")}{g.Cult}]")))}";
|
wText += $" = {string.Join(" + ", attrGroups.Select(g => $"{g.Weight:N0} kg ({(double)g.Weight / stat.Weight:0%})" + (GetGroupName(g.Attr, g.Cult) is string s ? $" [{s}]" : "")))}";
|
||||||
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}" + (GetGroupName(g.Attr, g.Cult) is string s ? $" [{s}]" : "")))}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (wText, wGrid.ToArray(), gText, gGrid.ToArray());
|
return (wText, wGrid.ToArray(), gText, gGrid.ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static (Grid WeightGrid, Grid GradationGrid) GenerateToolTip((string?, string?, int, int?, int)[] weightData, (string?, string?, double, double, double)[] gradationData) {
|
public static (Grid WeightGrid, Grid GradationGrid) GenerateToolTip((string?, string?, string?, int, int?, int?, int, string?)[] weightData, (string?, string?, string?, double, double, double, string?)[] gradationData) {
|
||||||
var wGrid = new Grid();
|
var wGrid = new Grid();
|
||||||
wGrid.ColumnDefinitions.Add(new() { Width = new(10) });
|
wGrid.ColumnDefinitions.Add(new() { Width = new(10) });
|
||||||
wGrid.ColumnDefinitions.Add(new() { Width = new(60) });
|
wGrid.ColumnDefinitions.Add(new() { Width = new(10) });
|
||||||
wGrid.ColumnDefinitions.Add(new() { Width = new(80) });
|
wGrid.ColumnDefinitions.Add(new() { Width = new(80) });
|
||||||
|
wGrid.ColumnDefinitions.Add(new() { Width = new(80) });
|
||||||
|
wGrid.ColumnDefinitions.Add(new() { Width = new(50) });
|
||||||
wGrid.ColumnDefinitions.Add(new() { Width = new(50) });
|
wGrid.ColumnDefinitions.Add(new() { Width = new(50) });
|
||||||
wGrid.ColumnDefinitions.Add(new() { Width = new(50) });
|
wGrid.ColumnDefinitions.Add(new() { Width = new(50) });
|
||||||
int rowNum = 0;
|
int rowNum = 0;
|
||||||
foreach (var row in weightData) {
|
foreach (var row in weightData) {
|
||||||
if (rowNum != 0 && row.Item2 == null) rowNum++;
|
if (rowNum != 0 && row.Item2 == null && row.Item3 == null) rowNum++;
|
||||||
AddWeightToolTipRow(wGrid, rowNum++, row.Item1, row.Item2, row.Item3, row.Item4, row.Item5);
|
AddWeightToolTipRow(wGrid, rowNum++, row.Item1, row.Item2, row.Item3, row.Item4, row.Item5, row.Item6, row.Item7, row.Item8);
|
||||||
}
|
}
|
||||||
|
|
||||||
var gGrid = new Grid();
|
var gGrid = new Grid();
|
||||||
gGrid.ColumnDefinitions.Add(new() { Width = new(10) });
|
gGrid.ColumnDefinitions.Add(new() { Width = new(10) });
|
||||||
gGrid.ColumnDefinitions.Add(new() { Width = new(60) });
|
gGrid.ColumnDefinitions.Add(new() { Width = new(10) });
|
||||||
|
gGrid.ColumnDefinitions.Add(new() { Width = new(80) });
|
||||||
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) });
|
||||||
gGrid.AddToolTipCell("Min.", 0, 2, alignCenter: true);
|
gGrid.AddToolTipCell("Min.", 0, 3, alignCenter: true);
|
||||||
gGrid.AddToolTipCell("⌀", 0, 3, alignCenter: true);
|
gGrid.AddToolTipCell("⌀", 0, 4, alignCenter: true);
|
||||||
gGrid.AddToolTipCell("Max.", 0, 4, alignCenter: true);
|
gGrid.AddToolTipCell("Max.", 0, 5, 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 && row.Item3 == null) rowNum++;
|
||||||
AddGradationToolTipRow(gGrid, rowNum++, row.Item1, row.Item2, row.Item3, row.Item4, row.Item5);
|
AddGradationToolTipRow(gGrid, rowNum++, row.Item1, row.Item2, row.Item3, row.Item4, row.Item5, row.Item6, row.Item7);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (wGrid, gGrid);
|
return (wGrid, gGrid);
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using Microsoft.Data.Sqlite;
|
||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -117,8 +118,35 @@ namespace Elwig.Services {
|
|||||||
|
|
||||||
public static void ShowException(string title, string? text, Exception exc, bool showExcType = false, bool isError = true) {
|
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 = text == null ? "" : text + (text.EndsWith('.') || text.EndsWith('!') || text.EndsWith('?') ? "" : ":") + "\n\n";
|
||||||
text += exc.Message + (showExcType ? $" ({exc.GetType().Name})" : "");
|
if ((exc.InnerException ?? exc) is SqliteException sql) {
|
||||||
if (exc.InnerException != null) text += "\n\n" + exc.InnerException.Message;
|
if (sql.SqliteErrorCode == 5 || sql.SqliteErrorCode == 6) {
|
||||||
|
// SQLITE_BUSY / SQLITE_LOCKED
|
||||||
|
text += "Die Datenbank wurde gerade von einem anderen Gerät/Prozess verwendet. Bitte noch einmal versuchen!\n\n" + sql.Message;
|
||||||
|
} else if (sql.SqliteErrorCode == 19) {
|
||||||
|
// SQLITE_CONSTRAINT
|
||||||
|
switch (sql.SqliteExtendedErrorCode) {
|
||||||
|
case 1555: // SQLITE_CONSTRAINT_PRIMARYKEY - indicating that a PRIMARY KEY constraint failed
|
||||||
|
case 2067: // SQLITE_CONSTRAINT_UNIQUE - indicating that a UNIQUE constraint failed
|
||||||
|
case 2579: // SQLITE_CONSTRAINT_ROWID - indicating that a rowid is not unique
|
||||||
|
text += "Dieser Datensatz existiert bereits!\n\n";
|
||||||
|
break;
|
||||||
|
case 787: // SQLITE_CONSTRAINT_FOREIGNKEY - indicating that a foreign key constraint failed
|
||||||
|
case 1299: // SQLITE_CONSTRAINT_NOTNULL - indicating that a NOT NULL constraint failed
|
||||||
|
case 275: // SQLITE_CONSTRAINT_CHECK - indicating that a CHECK constraint failed
|
||||||
|
case 1811: // SQLITE_CONSTRAINT_TRIGGER - indicating that a RAISE function within a trigger fired, causing the SQL statement to abort
|
||||||
|
case 531: // SQLITE_CONSTRAINT_COMMITHOOK - indicating that a commit hook callback returned non-zero that thus caused the SQL statement to be rolled back
|
||||||
|
text += "Der Datensatz ist inkonsistent!\n\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
text += sql.Message;
|
||||||
|
} else {
|
||||||
|
text += exc.Message + (showExcType ? $" ({exc.GetType().Name})" : "");
|
||||||
|
if (exc.InnerException != null) text += "\n\n" + exc.InnerException.Message;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
text += exc.Message + (showExcType ? $" ({exc.GetType().Name})" : "");
|
||||||
|
if (exc.InnerException != null) text += "\n\n" + exc.InnerException.Message;
|
||||||
|
}
|
||||||
if (isError) {
|
if (isError) {
|
||||||
ShowError(title, text);
|
ShowError(title, text);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using Elwig.Models;
|
|||||||
using Elwig.Models.Entities;
|
using Elwig.Models.Entities;
|
||||||
using Elwig.ViewModels;
|
using Elwig.ViewModels;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@@ -11,7 +12,7 @@ namespace Elwig.Services {
|
|||||||
|
|
||||||
public static async Task InitInputs(this MemberBusinessSharesViewModel vm) {
|
public static async Task InitInputs(this MemberBusinessSharesViewModel vm) {
|
||||||
using var ctx = new AppDbContext();
|
using var ctx = new AppDbContext();
|
||||||
vm.DateNoticeString = $"{Utils.Today:dd.MM.yyyy}";
|
vm.DateNoticeString = $"{DateTime.Today:dd.MM.yyyy}";
|
||||||
vm.ValuePerShare = (await ctx.Seasons.OrderBy(s => s.Year).LastOrDefaultAsync())?.BusinessShareValue;
|
vm.ValuePerShare = (await ctx.Seasons.OrderBy(s => s.Year).LastOrDefaultAsync())?.BusinessShareValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,6 +26,7 @@ namespace Elwig.Services {
|
|||||||
vm.DateEffective = h.DateEffective;
|
vm.DateEffective = h.DateEffective;
|
||||||
vm.Reason = h.Reason + (h.Reason == MemberHistory.REASON_TRANSFER ? $"_{(h.ToMgNr == mgnr ? "from" : "to")}" : "");
|
vm.Reason = h.Reason + (h.Reason == MemberHistory.REASON_TRANSFER ? $"_{(h.ToMgNr == mgnr ? "from" : "to")}" : "");
|
||||||
vm.Shares = h.Shares;
|
vm.Shares = h.Shares;
|
||||||
|
vm.CompanyHasSigned = h.CompanyHasSigned;
|
||||||
vm.MemberHasSigned = h.MemberHasSigned;
|
vm.MemberHasSigned = h.MemberHasSigned;
|
||||||
vm.ValuePerShare = h.ValuePerShare;
|
vm.ValuePerShare = h.ValuePerShare;
|
||||||
vm.OtherMgNr = h.FromMgNr != null && h.FromMgNr != mgnr ? h.FromMgNr : h.ToMgNr != null && h.ToMgNr != mgnr ? h.ToMgNr : null;
|
vm.OtherMgNr = h.FromMgNr != null && h.FromMgNr != mgnr ? h.FromMgNr : h.ToMgNr != null && h.ToMgNr != mgnr ? h.ToMgNr : null;
|
||||||
@@ -62,6 +64,7 @@ namespace Elwig.Services {
|
|||||||
Reason = vm.Reason?.Split("_")[0] ?? MemberHistory.REASON_CONVERT,
|
Reason = vm.Reason?.Split("_")[0] ?? MemberHistory.REASON_CONVERT,
|
||||||
Source = "manual",
|
Source = "manual",
|
||||||
Shares = vm.Shares ?? 0,
|
Shares = vm.Shares ?? 0,
|
||||||
|
CompanyHasSigned = vm.CompanyHasSigned,
|
||||||
MemberHasSigned = vm.MemberHasSigned,
|
MemberHasSigned = vm.MemberHasSigned,
|
||||||
ValuePerShare = vm.ValuePerShare,
|
ValuePerShare = vm.ValuePerShare,
|
||||||
CurrencyCode = vm.ValuePerShare != null ? "EUR" : null,
|
CurrencyCode = vm.ValuePerShare != null ? "EUR" : null,
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ 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.Media;
|
||||||
|
|
||||||
namespace Elwig.Services {
|
namespace Elwig.Services {
|
||||||
public static class MemberService {
|
public static class MemberService {
|
||||||
@@ -19,6 +20,7 @@ namespace Elwig.Services {
|
|||||||
};
|
};
|
||||||
|
|
||||||
public static async Task InitInputs(this MemberAdminViewModel vm) {
|
public static async Task InitInputs(this MemberAdminViewModel vm) {
|
||||||
|
vm.IsMemberSelectedOrCreating = true;
|
||||||
using var ctx = new AppDbContext();
|
using var ctx = new AppDbContext();
|
||||||
vm.MgNr = await ctx.NextMgNr();
|
vm.MgNr = await ctx.NextMgNr();
|
||||||
vm.EntryDate = DateTime.Now.ToString("dd.MM.yyyy");
|
vm.EntryDate = DateTime.Now.ToString("dd.MM.yyyy");
|
||||||
@@ -31,6 +33,7 @@ namespace Elwig.Services {
|
|||||||
|
|
||||||
public static void ClearInputs(this MemberAdminViewModel vm) {
|
public static void ClearInputs(this MemberAdminViewModel vm) {
|
||||||
vm.IsMemberSelected = false;
|
vm.IsMemberSelected = false;
|
||||||
|
vm.IsMemberSelectedOrCreating = false;
|
||||||
vm.MemberHasEmail = false;
|
vm.MemberHasEmail = false;
|
||||||
vm.MemberCanSendEmail = false;
|
vm.MemberCanSendEmail = false;
|
||||||
vm.EnableMemberReferenceButton = false;
|
vm.EnableMemberReferenceButton = false;
|
||||||
@@ -49,10 +52,15 @@ namespace Elwig.Services {
|
|||||||
vm.ModifiedAtShort = "-";
|
vm.ModifiedAtShort = "-";
|
||||||
vm.ExportedAt = "-";
|
vm.ExportedAt = "-";
|
||||||
vm.ImportedAt = "-";
|
vm.ImportedAt = "-";
|
||||||
|
vm.OrganicState = null;
|
||||||
|
vm.OrganicColor = Brushes.Black;
|
||||||
|
vm.OrganicDetails = "-";
|
||||||
|
vm.OrganicToolTip = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void FillInputs(this MemberAdminViewModel vm, Member m) {
|
public static void FillInputs(this MemberAdminViewModel vm, Member m) {
|
||||||
vm.IsMemberSelected = true;
|
vm.IsMemberSelected = true;
|
||||||
|
vm.IsMemberSelectedOrCreating = true;
|
||||||
vm.MgNr = m.MgNr;
|
vm.MgNr = m.MgNr;
|
||||||
vm.PredecessorMgNr = m.PredecessorMgNr;
|
vm.PredecessorMgNr = m.PredecessorMgNr;
|
||||||
vm.IsJuridicalPerson = m.IsJuridicalPerson;
|
vm.IsJuridicalPerson = m.IsJuridicalPerson;
|
||||||
@@ -106,6 +114,8 @@ namespace Elwig.Services {
|
|||||||
|
|
||||||
vm.UstIdNr = m.UstIdNr;
|
vm.UstIdNr = m.UstIdNr;
|
||||||
vm.LfbisNr = m.LfbisNr;
|
vm.LfbisNr = m.LfbisNr;
|
||||||
|
vm.OrganicOperatorId = m.OrganicOperatorId;
|
||||||
|
vm.OrganicAuthorityCode = m.OrganicAuthorityCode;
|
||||||
vm.IsBuchführend = m.IsBuchführend;
|
vm.IsBuchführend = m.IsBuchführend;
|
||||||
vm.IsOrganic = m.IsOrganic;
|
vm.IsOrganic = m.IsOrganic;
|
||||||
|
|
||||||
@@ -187,10 +197,9 @@ namespace Elwig.Services {
|
|||||||
.GroupBy(d => d.Year)
|
.GroupBy(d => d.Year)
|
||||||
.ToDictionaryAsync(g => g.Key, g => g.Any());
|
.ToDictionaryAsync(g => g.Key, g => g.Any());
|
||||||
|
|
||||||
if (m.MgNr != vm.MgNr)
|
|
||||||
return;
|
|
||||||
|
|
||||||
await App.MainDispatcher.BeginInvoke(() => {
|
await App.MainDispatcher.BeginInvoke(() => {
|
||||||
|
if (m.MgNr != vm.MgNr)
|
||||||
|
return;
|
||||||
var (d1Grid, _) = DeliveryService.GenerateToolTip(d1GridData, []);
|
var (d1Grid, _) = DeliveryService.GenerateToolTip(d1GridData, []);
|
||||||
var (d2Grid, _) = DeliveryService.GenerateToolTip(d2GridData, []);
|
var (d2Grid, _) = DeliveryService.GenerateToolTip(d2GridData, []);
|
||||||
var grid = AreaComService.GenerateToolTip(gridData);
|
var grid = AreaComService.GenerateToolTip(gridData);
|
||||||
@@ -203,13 +212,76 @@ namespace Elwig.Services {
|
|||||||
vm.StatusAreaCommitmentInfo = $"{Utils.CurrentLastSeason}";
|
vm.StatusAreaCommitmentInfo = $"{Utils.CurrentLastSeason}";
|
||||||
vm.StatusAreaCommitment = text;
|
vm.StatusAreaCommitment = text;
|
||||||
vm.StatusAreaCommitmentToolTip = grid;
|
vm.StatusAreaCommitmentToolTip = grid;
|
||||||
vm.MemberHasDeliveries = Enumerable.Range(0, 9999).Select(i => deliveries.GetValueOrDefault(i, false)).ToList();
|
vm.MemberHasDeliveries = [.. Enumerable.Range(0, 9999).Select(i => deliveries.GetValueOrDefault(i, false))];
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
vm.OrganicState = null;
|
||||||
|
vm.OrganicColor = Brushes.Black;
|
||||||
|
vm.OrganicToolTip = null;
|
||||||
|
if (!vm.IsOrganic) {
|
||||||
|
vm.OrganicDetails = "-";
|
||||||
|
} else {
|
||||||
|
vm.OrganicDetails = "...";
|
||||||
|
Utils.RunBackground("Bio-Zertifikatsdaten laden", async () => {
|
||||||
|
if (App.MainDispatcher == null) return;
|
||||||
|
var certs = await OrganicService.GetTracesCertificates(m);
|
||||||
|
await App.MainDispatcher.BeginInvoke(() => {
|
||||||
|
if (m.MgNr != vm.MgNr) return;
|
||||||
|
vm.FillOrganicInputs(certs.Length > 0 ? certs[0] : null);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
vm.MemberHasEmail = m.EmailAddresses.Count > 0;
|
vm.MemberHasEmail = m.EmailAddresses.Count > 0;
|
||||||
vm.MemberCanSendEmail = App.Config.Smtp != null && m.EmailAddresses.Count > 0;
|
vm.MemberCanSendEmail = App.Config.Smtp != null && m.EmailAddresses.Count > 0;
|
||||||
vm.MemberHasDeliveries = Enumerable.Range(0, 9999).Select(i => false).ToList();
|
vm.MemberHasDeliveries = [.. Enumerable.Range(0, 9999).Select(i => false)];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void FillOrganicInputs(this MemberAdminViewModel vm, OrganicService.TracesCertificate? cert) {
|
||||||
|
vm.OrganicDetails = null;
|
||||||
|
if (cert == null) {
|
||||||
|
vm.OrganicState = "Nicht gefunden";
|
||||||
|
vm.OrganicColor = Brushes.DarkRed;
|
||||||
|
vm.OrganicToolTip = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vm.OrganicToolTip = $"""
|
||||||
|
Zertifikat-Nr.: {cert.Id}
|
||||||
|
Status: {cert.Status}
|
||||||
|
Bio-KSt.: {cert.AuthorityCode}
|
||||||
|
EU Operator-ID: {cert.OperatorId}
|
||||||
|
Operator: {cert.OperatorName}
|
||||||
|
Ausgestellt am: {cert.IssuedOn:dd.MM.yyyy}
|
||||||
|
Aktualisiert am: {cert.LastStatusUpdateOn:dd.MM.yyyy}
|
||||||
|
Erlischt am: {cert.ExpiresOn:dd.MM.yyyy}
|
||||||
|
""";
|
||||||
|
if (cert.IsValidForWineProduction) {
|
||||||
|
vm.OrganicState = "Gültig";
|
||||||
|
vm.OrganicDetails = $" ({cert.ExpiresOn:MMM. yyyy})";
|
||||||
|
vm.OrganicColor = Brushes.DarkGreen;
|
||||||
|
} else if (cert.IsValid) {
|
||||||
|
vm.OrganicState = "Gültig";
|
||||||
|
vm.OrganicDetails = $" ({cert.ExpiresOn:MMM. yyyy})";
|
||||||
|
vm.OrganicColor = Brushes.OrangeRed;
|
||||||
|
} else {
|
||||||
|
vm.OrganicColor = Brushes.DarkRed;
|
||||||
|
switch (cert.Status) {
|
||||||
|
case OrganicService.TracesStatus.ISSUED:
|
||||||
|
vm.OrganicState = "Ausgestellt";
|
||||||
|
vm.OrganicDetails = $" ({cert.LastStatusUpdateOn:MMM. yyyy})"; break;
|
||||||
|
case OrganicService.TracesStatus.SUSPENDED:
|
||||||
|
vm.OrganicState = "Gesperrt";
|
||||||
|
vm.OrganicDetails = $" ({cert.LastStatusUpdateOn:MMM. yyyy})"; break;
|
||||||
|
case OrganicService.TracesStatus.EXPIRED:
|
||||||
|
vm.OrganicState = "Ausgelaufen";
|
||||||
|
vm.OrganicDetails = $" ({cert.LastStatusUpdateOn:MMM. yyyy})"; break;
|
||||||
|
case OrganicService.TracesStatus.WITHDRAWN:
|
||||||
|
vm.OrganicState = "Widerrufen";
|
||||||
|
vm.OrganicDetails = $" ({cert.LastStatusUpdateOn:MMM. yyyy})"; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<(List<string>, IQueryable<Member>, List<string>)> GetFilters(this MemberAdminViewModel vm, AppDbContext ctx) {
|
public static async Task<(List<string>, IQueryable<Member>, List<string>)> GetFilters(this MemberAdminViewModel vm, AppDbContext ctx) {
|
||||||
@@ -555,6 +627,8 @@ namespace Elwig.Services {
|
|||||||
|
|
||||||
UstIdNr = string.IsNullOrWhiteSpace(vm.UstIdNr) ? null : vm.UstIdNr,
|
UstIdNr = string.IsNullOrWhiteSpace(vm.UstIdNr) ? null : vm.UstIdNr,
|
||||||
LfbisNr = string.IsNullOrWhiteSpace(vm.LfbisNr) ? null : vm.LfbisNr,
|
LfbisNr = string.IsNullOrWhiteSpace(vm.LfbisNr) ? null : vm.LfbisNr,
|
||||||
|
OrganicOperatorId = string.IsNullOrWhiteSpace(vm.OrganicOperatorId) ? null : vm.OrganicOperatorId,
|
||||||
|
OrganicAuthorityCode = string.IsNullOrWhiteSpace(vm.OrganicAuthorityCode) ? null : vm.OrganicAuthorityCode,
|
||||||
IsBuchführend = vm.IsBuchführend,
|
IsBuchführend = vm.IsBuchführend,
|
||||||
IsOrganic = vm.IsOrganic,
|
IsOrganic = vm.IsOrganic,
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,162 @@
|
|||||||
|
using Elwig.Helpers;
|
||||||
|
using Elwig.Models.Entities;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Nodes;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Web;
|
||||||
|
|
||||||
|
namespace Elwig.Services {
|
||||||
|
public static class OrganicService {
|
||||||
|
|
||||||
|
public const string TRACES_API_URL = "https://webgate.ec.europa.eu/tracesnt/directory/publication/organic-operator/for/query";
|
||||||
|
public const string TRACES_PDF_URL_PREFIX = "https://webgate.ec.europa.eu/tracesnt/directory/publication/organic-operator/digitally-signed/";
|
||||||
|
|
||||||
|
public enum TracesStatus {
|
||||||
|
ISSUED, SUSPENDED, WITHDRAWN, EXPIRED
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum TracesActivity {
|
||||||
|
PREPARATION, EXPORT, IMPORT, STORING, PRODUCTION, DISTRIBUTION, DISTRIBUTION_PLACING_ON_THE_MARKET
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum TracesCategoryOfProduct {
|
||||||
|
UNPROCESSED_PLANT_PRODUCTS_INCLUDING_SEEDS, LIVESTOCK_AND_UNPROCESSED_LIVESTOCK_PRODUCTS, ALGAE_AND_UNPROCESSED_AQUACULTURE_PRODUCTS,
|
||||||
|
PROCESSED_AGRICULTURAL_PRODUCTS_INCLUDING_AQUACULTURE_FOR_USE_AS_FOOD, FEED, WINE, OTHER_PRODUCTS_NOT_COVERED_BY_PREVIOUS_CATEGORIES
|
||||||
|
}
|
||||||
|
|
||||||
|
public record TracesCertificate {
|
||||||
|
public required string Id { get; init; }
|
||||||
|
public required string AuthorityCode { get; init; }
|
||||||
|
public required string OperatorId { get; init; }
|
||||||
|
public required string OperatorName { get; init; }
|
||||||
|
public required TracesActivity[] Activities { get; init; }
|
||||||
|
public required TracesCategoryOfProduct[] CategoriesOfProduct { get; init; }
|
||||||
|
public required DateOnly IssuedOn { get; init; }
|
||||||
|
public required DateOnly ExpiresOn { get; init; }
|
||||||
|
public required DateOnly LastStatusUpdateOn { get; init; }
|
||||||
|
public required TracesStatus Status { get; init; }
|
||||||
|
|
||||||
|
public string PdfUrl => TRACES_PDF_URL_PREFIX + Id + ".pdf";
|
||||||
|
public bool IsValid => Status == TracesStatus.ISSUED && IssuedOn.ToDateTime(new()) <= DateTime.Today && ExpiresOn.ToDateTime(new()) >= DateTime.Today;
|
||||||
|
public bool IsValidForWineProduction => IsValid && Activities.Contains(TracesActivity.PRODUCTION) &&
|
||||||
|
(CategoriesOfProduct.Contains(TracesCategoryOfProduct.UNPROCESSED_PLANT_PRODUCTS_INCLUDING_SEEDS) || CategoriesOfProduct.Contains(TracesCategoryOfProduct.WINE));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly Dictionary<int, (DateTime Timestamp, TracesCertificate[] Certificates)> _memberCerts = [];
|
||||||
|
|
||||||
|
public async static Task<TracesCertificate[]> GetTracesCertificates(Member m, bool? tryNameAndAddress = null) {
|
||||||
|
if (_memberCerts.TryGetValue(m.MgNr, out var entry) && entry.Timestamp >= DateTime.Now.AddDays(-1))
|
||||||
|
return entry.Certificates;
|
||||||
|
var certs = await FetchTracesCertificates(m, tryNameAndAddress);
|
||||||
|
_memberCerts[m.MgNr] = (DateTime.Now, certs);
|
||||||
|
return certs;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async static Task<JsonArray> TryFetchTracesCertificates(Dictionary<string, string> query) {
|
||||||
|
var q = HttpUtility.ParseQueryString("");
|
||||||
|
q.Add("sort", "-issuedOn");
|
||||||
|
q.Add("countryCode", "AT");
|
||||||
|
foreach (var (k, v) in query) {
|
||||||
|
q.Add(k, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
using var client = Utils.GetHttpClient();
|
||||||
|
using var res = await client.GetAsync($"{TRACES_API_URL}?{q}");
|
||||||
|
res.EnsureSuccessStatusCode();
|
||||||
|
var resJson = JsonNode.Parse(await res.Content.ReadAsStringAsync());
|
||||||
|
return resJson?.AsArray() ?? throw new JsonException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Task<TracesCertificate[]> FetchTracesCertificates(Member m, bool? tryNameAndAddress = null) {
|
||||||
|
return FetchTracesCertificates(m.OrganicOperatorId, m.LfbisNr,
|
||||||
|
(tryNameAndAddress ?? m.IsOrganic) ? m.BillingAddress is BillingAddr a ?
|
||||||
|
(a.FullName, a.Address, $"{a.PostalDest.AtPlz?.Plz}") :
|
||||||
|
(m.FullName, m.Address, $"{m.PostalDest.AtPlz?.Plz}") :
|
||||||
|
null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async static Task<TracesCertificate[]> FetchTracesCertificates(string? oocId = null, string? lfbisNr = null, (string Name, string Address, string PostalCode)? address = null) {
|
||||||
|
bool searchedByName = false;
|
||||||
|
JsonArray jsonCerts = [];
|
||||||
|
|
||||||
|
if (jsonCerts.Count == 0 && oocId != null) {
|
||||||
|
jsonCerts = await TryFetchTracesCertificates(new Dictionary<string, string> {
|
||||||
|
{ "operatorIdentifierType", "ooc_identifier" },
|
||||||
|
{ "operatorIdentifierSearchOperator", "STRICT" },
|
||||||
|
{ "operatorIdentifier", oocId },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jsonCerts.Count == 0 && lfbisNr != null) {
|
||||||
|
jsonCerts = await TryFetchTracesCertificates(new Dictionary<string, string> {
|
||||||
|
{ "operatorIdentifierType", "comp_reg" },
|
||||||
|
{ "operatorIdentifierSearchOperator", "STRICT" },
|
||||||
|
{ "operatorIdentifier", lfbisNr.TrimStart('0') },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jsonCerts.Count == 0 && address != null) {
|
||||||
|
var query = $"{Regex.Replace(address.Value.Name, @"\(.*?\)", "")} {address.Value.Address}";
|
||||||
|
jsonCerts = await TryFetchTracesCertificates(new Dictionary<string, string> {
|
||||||
|
{ "operatorPostalCode", address.Value.PostalCode },
|
||||||
|
{ "query", query.Length > 40 ? query[..query.LastIndexOf(' ', 40)] : query },
|
||||||
|
});
|
||||||
|
searchedByName = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jsonCerts.Count == 0)
|
||||||
|
return [];
|
||||||
|
|
||||||
|
TracesCertificate[] certs = [.. jsonCerts.Select(j => new TracesCertificate {
|
||||||
|
Id = j!["reference"]?.GetValue<string>() ?? throw new Exception(),
|
||||||
|
AuthorityCode = j["issuingBody"]?["code"]?.GetValue<string>() ?? throw new Exception(),
|
||||||
|
OperatorId = j["operatorIdentifier"]?.GetValue<string>() ?? throw new Exception(),
|
||||||
|
OperatorName = j["operator"]?["name"]?.GetValue<string>() ?? throw new Exception(),
|
||||||
|
Activities = [.. j["activities"]?.AsArray().Select(a => Enum.Parse<TracesActivity>(a?["id"]?.GetValue<string>().ToUpper().Replace("_IMPORT", "IMPORT") ?? throw new Exception())) ?? []],
|
||||||
|
CategoriesOfProduct = [.. j["categoriesOfProduct"]?.AsArray().Select(c => Enum.Parse<TracesCategoryOfProduct>(c?["id"]?.GetValue<string>() ?? throw new Exception())) ?? []],
|
||||||
|
IssuedOn = DateOnly.FromDateTime(DateTime.ParseExact(j["issuedOn"]?.GetValue<string>() ?? throw new Exception(), "yyyy-MM-ddTHH:mm:ss.fffK", CultureInfo.InvariantCulture, DateTimeStyles.None)),
|
||||||
|
ExpiresOn = DateOnly.ParseExact(j["expiresOn"]?.GetValue<string>() ?? throw new Exception(), "yyyy-MM-dd"),
|
||||||
|
LastStatusUpdateOn = DateOnly.FromDateTime(DateTime.ParseExact(j["lastStatusUpdateDateTime"]?.GetValue<string>() ?? throw new Exception(), "yyyy-MM-ddTHH:mm:ss.fffK", CultureInfo.InvariantCulture, DateTimeStyles.None)),
|
||||||
|
Status = Enum.Parse<TracesStatus>(j["status"]?["id"]?.GetValue<string>() ?? throw new Exception()),
|
||||||
|
})];
|
||||||
|
|
||||||
|
return (!searchedByName || certs.Where(c => c.Status == TracesStatus.ISSUED).Select(c => c.OperatorId).ToHashSet().Count == 1) ? certs : [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string? GetTracesSearchUrl(Member m, bool? tryNameAndAddress = null) {
|
||||||
|
return GetTracesSearchUrl(m.OrganicOperatorId, m.LfbisNr,
|
||||||
|
(tryNameAndAddress ?? m.IsOrganic) ? m.BillingAddress is BillingAddr a ?
|
||||||
|
(a.FullName, a.Address, $"{a.PostalDest.AtPlz?.Plz}") :
|
||||||
|
(m.FullName, m.Address, $"{m.PostalDest.AtPlz?.Plz}") :
|
||||||
|
null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string? GetTracesSearchUrl(string? oocId = null, string? lfbisNr = null, (string Name, string Address, string PostalCode)? address = null) {
|
||||||
|
var baseUrl = "https://webgate.ec.europa.eu/tracesnt/directory/publication/organic-operator/index";
|
||||||
|
if (oocId != null) {
|
||||||
|
return $"{baseUrl}#!?countryCode=AT&operatorIdentifierType=ooc_identifier&operatorIdentifierSearchOperator=STRICT&operatorIdentifier={oocId}&states=ISSUED";
|
||||||
|
} else if (lfbisNr != null) {
|
||||||
|
return $"{baseUrl}#!?countryCode=AT&operatorIdentifierType=comp_reg&operatorIdentifierSearchOperator=STRICT&operatorIdentifier={lfbisNr.TrimStart('0')}&states=ISSUED";
|
||||||
|
} else if (address != null) {
|
||||||
|
return $"{baseUrl}#!?countryCode=AT&operatorPostalCode={address?.PostalCode}&query={address?.Name.Replace(' ', '+')}+{address?.Address.Replace(' ', '+')}&states=ISSUED";
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string? GetEasyCertSearchUrl(string lfbisNr) {
|
||||||
|
var baseUrl = "https://www.easy-cert.com/htm/suchergebnis.htm";
|
||||||
|
return $"{baseUrl}?CountryCode=AT&CustomerNumber={lfbisNr.TrimStart('0')}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string? GetBiocSearchUrl(string lfbisNr) {
|
||||||
|
var baseUrl = "https://www.bioc.info/search/producersearchresult";
|
||||||
|
return $"{baseUrl}?producerSearch[country]=a1e51f85-27b5-a1e3-65f7-561569884d38&producerSearch[operatorId]={lfbisNr.TrimStart('0')}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -214,7 +214,7 @@ namespace Elwig.Services {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task Download(string url, string username, string password) {
|
public static async Task Download(string url, string username, string password, bool confirmImports) {
|
||||||
try {
|
try {
|
||||||
var import = await GetFilesToImport(url, username, password);
|
var import = await GetFilesToImport(url, username, password);
|
||||||
var paths = new List<string>();
|
var paths = new List<string>();
|
||||||
@@ -226,7 +226,7 @@ namespace Elwig.Services {
|
|||||||
paths.Add(filename);
|
paths.Add(filename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await ElwigData.Import(paths, ElwigData.ImportMode.FromBranches);
|
await ElwigData.Import(paths, confirmImports ? ElwigData.ImportMode.Interactively : ElwigData.ImportMode.FromBranches);
|
||||||
} catch (HttpRequestException exc) {
|
} catch (HttpRequestException exc) {
|
||||||
InteractionService.ShowException("Daten herunterladen", "Eventuell Internetverbindung prüfen!", exc);
|
InteractionService.ShowException("Daten herunterladen", "Eventuell Internetverbindung prüfen!", exc);
|
||||||
} catch (TaskCanceledException exc) {
|
} catch (TaskCanceledException exc) {
|
||||||
@@ -264,5 +264,14 @@ namespace Elwig.Services {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async Task<bool> ChangesAvailable(AppDbContext ctx, string url, string username, string password, int? year = null) {
|
||||||
|
try {
|
||||||
|
year ??= Utils.CurrentLastSeason;
|
||||||
|
return await ctx.Deliveries.Where(d => d.ZwstId == App.ZwstId && d.Year == year).Where(ChangedDeliveries).AnyAsync() || (Utils.HasInternetConnectivity() && (await GetFilesToImport(url, username, password)).Count > 0);
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -25,7 +25,7 @@ namespace Elwig.ViewModels {
|
|||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private string? _manualWeighingReason;
|
private string? _manualWeighingReason;
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private string? _scaleId;
|
private string? _scaleTerminalId;
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private string? _weighingData;
|
private string? _weighingData;
|
||||||
|
|
||||||
@@ -120,6 +120,14 @@ namespace Elwig.ViewModels {
|
|||||||
set => WeightString = $"{value:N0}";
|
set => WeightString = $"{value:N0}";
|
||||||
}
|
}
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
|
private string? _tareString = "-";
|
||||||
|
public int? Tare {
|
||||||
|
get => int.TryParse(TareString?.Replace(Utils.GroupSeparator, "").Replace(" kg", ""), out var w) ? w : null;
|
||||||
|
set => TareString = value == null ? "-" : $"{value:N0} kg{(TargetTare != null ? "*" : "")}";
|
||||||
|
}
|
||||||
|
public int? ActualTare;
|
||||||
|
public int? TargetTare;
|
||||||
|
[ObservableProperty]
|
||||||
private bool _isManualWeighing;
|
private bool _isManualWeighing;
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private bool? _isNetWeightValue = false;
|
private bool? _isNetWeightValue = false;
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ using System.Windows.Controls;
|
|||||||
namespace Elwig.ViewModels {
|
namespace Elwig.ViewModels {
|
||||||
public partial class DeliveryAncmtAdminViewModel : ObservableObject {
|
public partial class DeliveryAncmtAdminViewModel : ObservableObject {
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _title = "Anmeldungen - Elwig";
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private string? _searchQuery = "";
|
private string? _searchQuery = "";
|
||||||
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) ?? []];
|
||||||
|
|||||||
@@ -6,11 +6,14 @@ 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;
|
using System.Windows.Media;
|
||||||
|
|
||||||
namespace Elwig.ViewModels {
|
namespace Elwig.ViewModels {
|
||||||
public partial class MemberAdminViewModel : ObservableObject {
|
public partial class MemberAdminViewModel : ObservableObject {
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _title = "Mitglieder - Elwig";
|
||||||
|
|
||||||
public int? TransferPredecessorAreaComs = null;
|
public int? TransferPredecessorAreaComs = null;
|
||||||
public int? CancelAreaComs = null;
|
public int? CancelAreaComs = null;
|
||||||
|
|
||||||
@@ -31,6 +34,8 @@ namespace Elwig.ViewModels {
|
|||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private bool _isMemberSelected;
|
private bool _isMemberSelected;
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
|
private bool _isMemberSelectedOrCreating;
|
||||||
|
[ObservableProperty]
|
||||||
private bool _memberHasEmail;
|
private bool _memberHasEmail;
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private bool _memberCanSendEmail;
|
private bool _memberCanSendEmail;
|
||||||
@@ -116,10 +121,23 @@ namespace Elwig.ViewModels {
|
|||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private string? _lfbisNr;
|
private string? _lfbisNr;
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
|
private string? _organicOperatorId;
|
||||||
|
[ObservableProperty]
|
||||||
|
private string? _organicAuthorityCode;
|
||||||
|
[ObservableProperty]
|
||||||
private bool _isBuchführend;
|
private bool _isBuchführend;
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private bool _isOrganic;
|
private bool _isOrganic;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string? _organicState;
|
||||||
|
[ObservableProperty]
|
||||||
|
private string? _organicDetails = "-";
|
||||||
|
[ObservableProperty]
|
||||||
|
private Brush? _organicColor = Brushes.Black;
|
||||||
|
[ObservableProperty]
|
||||||
|
private string? _organicToolTip;
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private string? _entryDate;
|
private string? _entryDate;
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
|
|||||||
@@ -52,6 +52,8 @@ namespace Elwig.ViewModels {
|
|||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private bool _deduct;
|
private bool _deduct;
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
|
private bool _companyHasSigned;
|
||||||
|
[ObservableProperty]
|
||||||
private bool _memberHasSigned;
|
private bool _memberHasSigned;
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private string? _valuePerShareString;
|
private string? _valuePerShareString;
|
||||||
|
|||||||
@@ -108,12 +108,20 @@ namespace Elwig.Windows {
|
|||||||
LockInputs();
|
LockInputs();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void TryClose() {
|
||||||
|
var evt = new CancelEventArgs();
|
||||||
|
OnClosing(this, evt);
|
||||||
|
if (!evt.Cancel) Close();
|
||||||
|
}
|
||||||
|
|
||||||
private void OnClosing(object? sender, CancelEventArgs evt) {
|
private void OnClosing(object? sender, CancelEventArgs evt) {
|
||||||
if ((IsCreating || IsEditing) && HasChanged) {
|
if (!IsClosing && (IsCreating || IsEditing) && HasChanged) {
|
||||||
if (!InteractionService.AskConfirmation("Schließen bestätigen", "Soll das Fenster wirklich geschlossen werden?")) {
|
try {
|
||||||
evt.Cancel = true;
|
if (!InteractionService.AskConfirmation("Schließen bestätigen", "Soll das Fenster wirklich geschlossen werden?")) {
|
||||||
return;
|
evt.Cancel = true;
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
} catch { }
|
||||||
}
|
}
|
||||||
IsClosing = true;
|
IsClosing = true;
|
||||||
}
|
}
|
||||||
@@ -434,7 +442,7 @@ namespace Elwig.Windows {
|
|||||||
UpdateButtons();
|
UpdateButtons();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void TextBox_TextChanged(object sender, RoutedEventArgs? evt) {
|
protected void TextBox_TextChanged(object sender, TextChangedEventArgs? evt) {
|
||||||
var input = (Control)sender;
|
var input = (Control)sender;
|
||||||
var tb = input as TextBox;
|
var tb = input as TextBox;
|
||||||
if (SenderIsRequired(input) && tb?.Text.Length == 0) {
|
if (SenderIsRequired(input) && tb?.Text.Length == 0) {
|
||||||
@@ -576,6 +584,14 @@ namespace Elwig.Windows {
|
|||||||
InputLostFocus((TextBox)sender, Validator.CheckLfbisNr);
|
InputLostFocus((TextBox)sender, Validator.CheckLfbisNr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void OrganicOperatorIdInput_TextChanged(object sender, TextChangedEventArgs? evt) {
|
||||||
|
InputTextChanged((TextBox)sender, Validator.CheckOrganicOperatorId);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void OrganicOperatorIdInput_LostFocus(object sender, RoutedEventArgs? evt) {
|
||||||
|
InputLostFocus((TextBox)sender, Validator.CheckOrganicOperatorId);
|
||||||
|
}
|
||||||
|
|
||||||
protected void OrganicAuthorityCodeInput_TextChanged(object sender, TextChangedEventArgs? evt) {
|
protected void OrganicAuthorityCodeInput_TextChanged(object sender, TextChangedEventArgs? evt) {
|
||||||
InputTextChanged((TextBox)sender, Validator.CheckOrganicAuthorityCode);
|
InputTextChanged((TextBox)sender, Validator.CheckOrganicAuthorityCode);
|
||||||
}
|
}
|
||||||
@@ -595,5 +611,13 @@ namespace Elwig.Windows {
|
|||||||
protected void AreaComTypeDetailsButton_Click(object sender, RoutedEventArgs? evt) {
|
protected void AreaComTypeDetailsButton_Click(object sender, RoutedEventArgs? evt) {
|
||||||
App.FocusBaseDataAreaComType();
|
App.FocusBaseDataAreaComType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void AddressInput_TextChanged(object sender, TextChangedEventArgs? evt) {
|
||||||
|
if ((IsCreating || IsEditing) && sender is TextBox b) {
|
||||||
|
InputTextChanged(b, (i, r) => Validator.CheckAddress(i, r));
|
||||||
|
} else {
|
||||||
|
TextBox_TextChanged(sender, evt);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -23,7 +23,6 @@ namespace Elwig.Windows {
|
|||||||
CommandBindings.Add(new CommandBinding(CtrlF, FocusSearchInput));
|
CommandBindings.Add(new CommandBinding(CtrlF, FocusSearchInput));
|
||||||
using var ctx = new AppDbContext();
|
using var ctx = new AppDbContext();
|
||||||
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";
|
|
||||||
ExemptInputs = [
|
ExemptInputs = [
|
||||||
AreaCommitmentList, RevisionList,
|
AreaCommitmentList, RevisionList,
|
||||||
NewAreaCommitmentButton, EditAreaCommitmentButton, DeleteAreaCommitmentButton, SaveButton,
|
NewAreaCommitmentButton, EditAreaCommitmentButton, DeleteAreaCommitmentButton, SaveButton,
|
||||||
@@ -51,9 +50,9 @@ namespace Elwig.Windows {
|
|||||||
var cursor = Mouse.OverrideCursor != null;
|
var cursor = Mouse.OverrideCursor != null;
|
||||||
if (!cursor) Mouse.OverrideCursor = Cursors.Wait;
|
if (!cursor) Mouse.OverrideCursor = Cursors.Wait;
|
||||||
var query = (vm.SearchQuery, vm.FilterSeason);
|
var query = (vm.SearchQuery, vm.FilterSeason);
|
||||||
var (filter, contracts, areaComs, areaComCount, stat) = await Task.Run(async () => {
|
var (filterNames, filter, contracts, areaComs, areaComCount, stat) = await Task.Run(async () => {
|
||||||
using var ctx = new AppDbContext();
|
using var ctx = new AppDbContext();
|
||||||
var (_, contractQuery, areaComQuery, filter) = await vm.GetFilters(ctx);
|
var (filterNames, contractQuery, areaComQuery, filter) = await vm.GetFilters(ctx);
|
||||||
var contracts = await contractQuery
|
var contracts = await contractQuery
|
||||||
.Include(c => c.Revisions).ThenInclude(a => a.Member)
|
.Include(c => c.Revisions).ThenInclude(a => a.Member)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
@@ -73,11 +72,12 @@ namespace Elwig.Windows {
|
|||||||
var season = await ctx.FetchSeasons().FirstOrDefaultAsync();
|
var season = await ctx.FetchSeasons().FirstOrDefaultAsync();
|
||||||
var stat = await AreaComService.GenerateToolTipData(areaComQuery, season?.MaxKgPerHa ?? 10_000);
|
var stat = await AreaComService.GenerateToolTipData(areaComQuery, season?.MaxKgPerHa ?? 10_000);
|
||||||
|
|
||||||
return (filter, contracts, areaComs, areaComCount, stat);
|
return (filterNames, filter, contracts, areaComs, areaComCount, stat);
|
||||||
});
|
});
|
||||||
if (!cursor) Mouse.OverrideCursor = null;
|
if (!cursor) Mouse.OverrideCursor = null;
|
||||||
if (query != (ViewModel.SearchQuery, ViewModel.FilterSeason)) return;
|
if (query != (ViewModel.SearchQuery, ViewModel.FilterSeason)) return;
|
||||||
|
|
||||||
|
ViewModel.Title = Utils.GetTitle("Flächenbindungen", filterNames, filter);
|
||||||
ControlUtils.RenewItemsSource(AreaCommitmentList, contracts,
|
ControlUtils.RenewItemsSource(AreaCommitmentList, contracts,
|
||||||
AreaCommitmentList_SelectionChanged, ViewModel.TextFilter.Count > 0 ? ControlUtils.RenewSourceDefault.IfOnly : ControlUtils.RenewSourceDefault.None, !updateSort);
|
AreaCommitmentList_SelectionChanged, ViewModel.TextFilter.Count > 0 ? ControlUtils.RenewSourceDefault.IfOnly : ControlUtils.RenewSourceDefault.None, !updateSort);
|
||||||
RefreshInputs();
|
RefreshInputs();
|
||||||
@@ -164,7 +164,6 @@ namespace Elwig.Windows {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ViewModel.FilterMember = m;
|
ViewModel.FilterMember = m;
|
||||||
ViewModel.Title = $"Flächenbindungen - {ViewModel.FilterMember.AdministrativeName} - Elwig";
|
|
||||||
|
|
||||||
ControlUtils.RenewItemsSource(KgInput, await ctx.WbKgs
|
ControlUtils.RenewItemsSource(KgInput, await ctx.WbKgs
|
||||||
.Include(k => k.AtKg.WbKg!.Rds)
|
.Include(k => k.AtKg.WbKg!.Rds)
|
||||||
|
|||||||
@@ -90,7 +90,7 @@
|
|||||||
<Label Content="Adresse:"
|
<Label Content="Adresse:"
|
||||||
VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="0" Margin="10,160,0,10"/>
|
VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="0" Margin="10,160,0,10"/>
|
||||||
<TextBox x:Name="ClientAddressInput"
|
<TextBox x:Name="ClientAddressInput"
|
||||||
TextChanged="TextBox_TextChanged"
|
TextChanged="AddressInput_TextChanged"
|
||||||
VerticalAlignment="Top" HorizontalAlignment="Stretch" Grid.Column="1" Margin="0,160,10,10"/>
|
VerticalAlignment="Top" HorizontalAlignment="Stretch" Grid.Column="1" Margin="0,160,10,10"/>
|
||||||
|
|
||||||
<Label Content="PLZ/Ort:"
|
<Label Content="PLZ/Ort:"
|
||||||
@@ -109,24 +109,30 @@
|
|||||||
<TextBox x:Name="ClientBicInput" Margin="0,250,10,0" Grid.Column="1"
|
<TextBox x:Name="ClientBicInput" Margin="0,250,10,0" Grid.Column="1"
|
||||||
TextChanged="BicInput_TextChanged" LostFocus="BicInput_LostFocus"/>
|
TextChanged="BicInput_TextChanged" LostFocus="BicInput_LostFocus"/>
|
||||||
|
|
||||||
<Label Content="UID:"
|
|
||||||
VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="2" Margin="10,100,0,10"/>
|
|
||||||
<TextBox x:Name="ClientUstIdNrInput"
|
|
||||||
VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="3" Margin="0,100,10,10" Width="96"
|
|
||||||
TextChanged="UstIdNrInput_TextChanged" LostFocus="UstIdNrInput_LostFocus"/>
|
|
||||||
|
|
||||||
<Label Content="Betriebs-Nr.:"
|
<Label Content="Betriebs-Nr.:"
|
||||||
VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="2" Margin="10,130,0,10"/>
|
VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="2" Margin="10,100,0,10"/>
|
||||||
<TextBox x:Name="ClientLfbisNrInput"
|
<TextBox x:Name="ClientLfbisNrInput"
|
||||||
VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="3" Margin="0,130,10,10" Width="64"
|
VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="3" Margin="0,100,10,10" Width="64"
|
||||||
TextChanged="LfbisNrInput_TextChanged" LostFocus="LfbisNrInput_LostFocus"/>
|
TextChanged="LfbisNrInput_TextChanged" LostFocus="LfbisNrInput_LostFocus"/>
|
||||||
|
|
||||||
<Label Content="Bio-Kontrollstelle:"
|
<Label Content="UID:"
|
||||||
VerticalAlignment="Top" HorizontalAlignment="Right" Grid.Column="3" Margin="10,130,110,10"/>
|
VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="2" Margin="10,130,0,10"/>
|
||||||
<TextBox x:Name="ClientOrganicAuthorityInput"
|
<TextBox x:Name="ClientUstIdNrInput"
|
||||||
VerticalAlignment="Top" HorizontalAlignment="Right" Grid.Column="3" Margin="10,130,10,10" Width="90"
|
VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="3" Margin="0,130,10,10" Width="96"
|
||||||
|
TextChanged="UstIdNrInput_TextChanged" LostFocus="UstIdNrInput_LostFocus"/>
|
||||||
|
|
||||||
|
<Label Content="Bio-KSt.:" ToolTip="Bio-Konstrollstelle"
|
||||||
|
VerticalAlignment="Top" HorizontalAlignment="Right" Grid.Column="3" Margin="10,100,110,10"/>
|
||||||
|
<TextBox x:Name="ClientOrganicAuthorityCodeInput"
|
||||||
|
VerticalAlignment="Top" HorizontalAlignment="Right" Grid.Column="3" Margin="10,100,10,10" Width="91"
|
||||||
TextChanged="OrganicAuthorityCodeInput_TextChanged" LostFocus="OrganicAuthorityCodeInput_LostFocus"/>
|
TextChanged="OrganicAuthorityCodeInput_TextChanged" LostFocus="OrganicAuthorityCodeInput_LostFocus"/>
|
||||||
|
|
||||||
|
<Label Content="OOC-ID:" ToolTip="Bio-EU-Operator-ID / Organic Operator Certificate ID"
|
||||||
|
VerticalAlignment="Top" HorizontalAlignment="Right" Grid.Column="3" Margin="10,130,110,10"/>
|
||||||
|
<TextBox x:Name="ClientOrganicOperatorIdInput"
|
||||||
|
VerticalAlignment="Top" HorizontalAlignment="Right" Grid.Column="3" Margin="10,130,10,10" Width="91"
|
||||||
|
TextChanged="OrganicOperatorIdInput_TextChanged" LostFocus="OrganicOperatorIdInput_LostFocus"/>
|
||||||
|
|
||||||
<Label Content="Telefon-Nr.:"
|
<Label Content="Telefon-Nr.:"
|
||||||
VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="2" Margin="10,160,0,10"/>
|
VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="2" Margin="10,160,0,10"/>
|
||||||
<TextBox x:Name="ClientPhoneNrInput" Margin="0,160,10,10" Grid.Column="3"
|
<TextBox x:Name="ClientPhoneNrInput" Margin="0,160,10,10" Grid.Column="3"
|
||||||
@@ -320,6 +326,10 @@
|
|||||||
<Label Content="Beschreibung:" Margin="10,70,0,10"/>
|
<Label Content="Beschreibung:" Margin="10,70,0,10"/>
|
||||||
<TextBox x:Name="WineCultivationDescriptionInput" Grid.Column="1" Margin="0,70,10,10"
|
<TextBox x:Name="WineCultivationDescriptionInput" Grid.Column="1" Margin="0,70,10,10"
|
||||||
TextChanged="WineCultivation_Changed"/>
|
TextChanged="WineCultivation_Changed"/>
|
||||||
|
|
||||||
|
<CheckBox x:Name="WineCultivationOrganicInput" Content="Bio" Grid.Column="1" Margin="0,105,10,10"
|
||||||
|
Checked="WineCultivation_Changed" Unchecked="WineCultivation_Changed"
|
||||||
|
HorizontalAlignment="Left" VerticalAlignment="Top"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
|
|||||||
@@ -47,26 +47,26 @@ namespace Elwig.Windows {
|
|||||||
if (!_actChanged || _actList == null || _acts == null || _actIds == null)
|
if (!_actChanged || _actList == null || _acts == null || _actIds == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
foreach (var (vtrgid, _) in _acts.Where(a => a.Value == null)) {
|
// delete
|
||||||
ctx.Remove(ctx.AreaCommitmentTypes.Find(vtrgid)!);
|
var delete = _acts.Where(a => a.Value == null).Select(a => a.Key).ToList();
|
||||||
}
|
await ctx.AreaCommitmentTypes.Where(v => delete.Contains(v.VtrgId)).ExecuteDeleteAsync();
|
||||||
foreach (var (attr, old) in _actIds) {
|
|
||||||
attr.VtrgId = old;
|
|
||||||
}
|
|
||||||
foreach (var (old, vtrgid) in _acts.Where(a => a.Value != null)) {
|
|
||||||
ctx.Update(ctx.AreaCommitmentTypes.Find(old)!);
|
|
||||||
}
|
|
||||||
await ctx.SaveChangesAsync();
|
|
||||||
|
|
||||||
foreach (var (old, vtrgid) in _acts.Where(a => a.Value != null)) {
|
// update
|
||||||
|
ctx.UpdateRange(_actList
|
||||||
|
.Where(_actIds.ContainsKey)
|
||||||
|
.Select(t => {
|
||||||
|
t.VtrgId = _actIds[t];
|
||||||
|
ctx.Entry(t).State = EntityState.Added;
|
||||||
|
return t;
|
||||||
|
}));
|
||||||
|
await ctx.SaveChangesAsync();
|
||||||
|
foreach (var (old, vtrgid) in _acts.Where(a => a.Value != null && a.Key != a.Value)) {
|
||||||
await ctx.Database.ExecuteSqlAsync($"UPDATE area_commitment_type SET vtrgid = {vtrgid} WHERE vtrgid = {old}");
|
await ctx.Database.ExecuteSqlAsync($"UPDATE area_commitment_type SET vtrgid = {vtrgid} WHERE vtrgid = {old}");
|
||||||
}
|
}
|
||||||
await ctx.SaveChangesAsync();
|
|
||||||
|
|
||||||
foreach (var type in _actList.Where(a => !_actIds.ContainsKey(a))) {
|
// insert
|
||||||
if (type.VtrgId == null) continue;
|
ctx.AddRange(_actList
|
||||||
ctx.Add(type);
|
.Where(t => !_actIds.ContainsKey(t) && t.VtrgId != null));
|
||||||
}
|
|
||||||
await ctx.SaveChangesAsync();
|
await ctx.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,7 +125,7 @@ namespace Elwig.Windows {
|
|||||||
var id = AreaCommitmentTypeIdInput.Text;
|
var id = AreaCommitmentTypeIdInput.Text;
|
||||||
if (old != null) _acts[old] = id;
|
if (old != null) _acts[old] = id;
|
||||||
attr.VtrgId = id;
|
attr.VtrgId = id;
|
||||||
attr.SortId = v?.SortId;
|
attr.SortId = v?.SortId ?? "";
|
||||||
attr.AttrId = a?.AttrId;
|
attr.AttrId = a?.AttrId;
|
||||||
attr.MinKgPerHa = AreaCommitmentTypeMinKgPerHaInput.Text.Length > 0 ? int.Parse(AreaCommitmentTypeMinKgPerHaInput.Text) : null;
|
attr.MinKgPerHa = AreaCommitmentTypeMinKgPerHaInput.Text.Length > 0 ? int.Parse(AreaCommitmentTypeMinKgPerHaInput.Text) : null;
|
||||||
attr.PenaltyPerKg = AreaCommitmentTypePenaltyPerKgInput.Text.Length > 0 ? decimal.Parse(AreaCommitmentTypePenaltyPerKgInput.Text) : null;
|
attr.PenaltyPerKg = AreaCommitmentTypePenaltyPerKgInput.Text.Length > 0 ? decimal.Parse(AreaCommitmentTypePenaltyPerKgInput.Text) : null;
|
||||||
|
|||||||
@@ -41,25 +41,26 @@ namespace Elwig.Windows {
|
|||||||
if (!_branchChanged || _branchList == null || _branches == null || _branchIds == null)
|
if (!_branchChanged || _branchList == null || _branches == null || _branchIds == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// delete
|
||||||
var deleteZwstIds = _branches.Where(b => b.Value == null).Select(b => b.Key).ToList();
|
var deleteZwstIds = _branches.Where(b => b.Value == null).Select(b => b.Key).ToList();
|
||||||
await ctx.Branches.Where(b => deleteZwstIds.Contains(b.ZwstId)).ExecuteDeleteAsync();
|
await ctx.Branches.Where(b => deleteZwstIds.Contains(b.ZwstId)).ExecuteDeleteAsync();
|
||||||
|
|
||||||
foreach (var (branch, old) in _branchIds) {
|
// update
|
||||||
branch.ZwstId = old;
|
ctx.UpdateRange(_branchList
|
||||||
}
|
.Where(_branchIds.ContainsKey)
|
||||||
foreach (var (old, zwstid) in _branches.Where(b => b.Value != null)) {
|
.Select(b => {
|
||||||
ctx.Update(ctx.Branches.Find(old)!);
|
b.ZwstId = _branchIds[b];
|
||||||
}
|
ctx.Entry(b).State = EntityState.Added;
|
||||||
|
return b;
|
||||||
|
}));
|
||||||
await ctx.SaveChangesAsync();
|
await ctx.SaveChangesAsync();
|
||||||
|
foreach (var (old, zwstid) in _branches.Where(b => b.Value != null && b.Key != b.Value)) {
|
||||||
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}");
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var branch in _branchList.Where(b => !_branchIds.ContainsKey(b))) {
|
// insert
|
||||||
if (branch.ZwstId == null) continue;
|
ctx.AddRange(_branchList
|
||||||
ctx.Add(branch);
|
.Where(b => !_branchIds.ContainsKey(b) && b.ZwstId != null));
|
||||||
}
|
|
||||||
await ctx.SaveChangesAsync();
|
await ctx.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,30 +48,30 @@ namespace Elwig.Windows {
|
|||||||
if (!_modChanged || _modList == null || _mods == null || _modIds == null)
|
if (!_modChanged || _modList == null || _mods == null || _modIds == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
var year = (SeasonList.SelectedItem as Season)?.Year;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
foreach (var mod in _modList) mod.Ordering = ++i;
|
foreach (var mod in _modList) mod.Ordering = ++i;
|
||||||
|
|
||||||
var year = (SeasonList.SelectedItem as Season)?.Year;
|
// delete
|
||||||
foreach (var (modid, _) in _mods.Where(m => m.Value == null)) {
|
var deleteModIds = _mods.Where(b => b.Value == null).Select(b => b.Key).ToList();
|
||||||
ctx.Remove(ctx.Modifiers.Find(year, modid)!);
|
await ctx.Modifiers.Where(b => b.Year == year && deleteModIds.Contains(b.ModId)).ExecuteDeleteAsync();
|
||||||
}
|
|
||||||
foreach (var (mod, old) in _modIds) {
|
|
||||||
mod.ModId = old;
|
|
||||||
}
|
|
||||||
foreach (var (old, modid) in _mods.Where(m => m.Value != null)) {
|
|
||||||
ctx.Update(ctx.Modifiers.Find(year, old)!);
|
|
||||||
}
|
|
||||||
await ctx.SaveChangesAsync();
|
|
||||||
|
|
||||||
|
// update
|
||||||
|
ctx.UpdateRange(_modList
|
||||||
|
.Where(_modIds.ContainsKey)
|
||||||
|
.Select(m => {
|
||||||
|
m.ModId = _modIds[m];
|
||||||
|
ctx.Entry(m).State = EntityState.Added;
|
||||||
|
return m;
|
||||||
|
}));
|
||||||
|
await ctx.SaveChangesAsync();
|
||||||
foreach (var (old, modid) in _mods.Where(m => m.Value != null)) {
|
foreach (var (old, modid) in _mods.Where(m => m.Value != null)) {
|
||||||
await ctx.Database.ExecuteSqlAsync($"UPDATE modifier SET modid = {modid} WHERE (year, modid) = ({year}, {old})");
|
await ctx.Database.ExecuteSqlAsync($"UPDATE modifier SET modid = {modid} WHERE (year, modid) = ({year}, {old})");
|
||||||
}
|
}
|
||||||
await ctx.SaveChangesAsync();
|
|
||||||
|
|
||||||
foreach (var mod in _modList.Where(m => !_modIds.ContainsKey(m))) {
|
// insert
|
||||||
if (mod.ModId == null) continue;
|
ctx.AddRange(_modList
|
||||||
await ctx.AddAsync(mod);
|
.Where(m => !_modIds.ContainsKey(m) && m.ModId != null));
|
||||||
}
|
|
||||||
await ctx.SaveChangesAsync();
|
await ctx.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,26 +41,28 @@ namespace Elwig.Windows {
|
|||||||
if (!_attrChanged || _attrList == null || _attrs == null || _attrIds == null)
|
if (!_attrChanged || _attrList == null || _attrs == null || _attrIds == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// delete
|
||||||
var deleteAttrIds = _attrs.Where(a => a.Value == null).Select(a => a.Key).ToList();
|
var deleteAttrIds = _attrs.Where(a => a.Value == null).Select(a => a.Key).ToList();
|
||||||
await ctx.WineAttributes.Where(a => deleteAttrIds.Contains(a.AttrId)).ExecuteDeleteAsync();
|
await ctx.WineAttributes.Where(a => deleteAttrIds.Contains(a.AttrId)).ExecuteDeleteAsync();
|
||||||
foreach (var (attr, old) in _attrIds) {
|
|
||||||
attr.AttrId = old;
|
|
||||||
}
|
|
||||||
foreach (var (old, attrid) in _attrs.Where(a => a.Value != null)) {
|
|
||||||
ctx.Update(ctx.WineAttributes.Find(old)!);
|
|
||||||
}
|
|
||||||
await ctx.SaveChangesAsync();
|
|
||||||
|
|
||||||
|
// update
|
||||||
|
ctx.UpdateRange(_attrList
|
||||||
|
.Where(_attrIds.ContainsKey)
|
||||||
|
.Select(a => {
|
||||||
|
a.AttrId = _attrIds[a];
|
||||||
|
ctx.Entry(a).State = EntityState.Added;
|
||||||
|
return a;
|
||||||
|
}));
|
||||||
|
await ctx.SaveChangesAsync();
|
||||||
foreach (var (old, attrid) in _attrs.Where(a => a.Value != null)) {
|
foreach (var (old, attrid) in _attrs.Where(a => a.Value != null)) {
|
||||||
await ctx.Database.ExecuteSqlAsync($"UPDATE wine_attribute SET attrid = {attrid} WHERE attrid = {old}");
|
await ctx.Database.ExecuteSqlAsync($"UPDATE wine_attribute SET attrid = {attrid} WHERE attrid = {old}");
|
||||||
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.ExecuteSqlAsync($"UPDATE payment_variant SET data = REPLACE(REPLACE(data, {$"/{old}\""}, {$"/{attrid}\""}), {$"/{old}-"}, {$"/{attrid}-"})");
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var attr in _attrList.Where(a => !_attrIds.ContainsKey(a))) {
|
// insert
|
||||||
if (attr.AttrId == null) continue;
|
ctx.AddRange(_attrList
|
||||||
ctx.Add(attr);
|
.Where(a => !_attrIds.ContainsKey(a) && a.AttrId != null));
|
||||||
}
|
|
||||||
await ctx.SaveChangesAsync();
|
await ctx.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,25 +41,27 @@ namespace Elwig.Windows {
|
|||||||
if (!_cultChanged || _cultList == null || _cults == null || _cultIds == null)
|
if (!_cultChanged || _cultList == null || _cults == null || _cultIds == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// delete
|
||||||
var deleteCultIds = _cults.Where(c => c.Value == null).Select(c => c.Key).ToList();
|
var deleteCultIds = _cults.Where(c => c.Value == null).Select(c => c.Key).ToList();
|
||||||
await ctx.WineCultivations.Where(c => deleteCultIds.Contains(c.CultId)).ExecuteDeleteAsync();
|
await ctx.WineCultivations.Where(c => deleteCultIds.Contains(c.CultId)).ExecuteDeleteAsync();
|
||||||
foreach (var (cult, old) in _cultIds) {
|
|
||||||
cult.CultId = old;
|
|
||||||
}
|
|
||||||
foreach (var (old, cultid) in _cults.Where(c => c.Value != null)) {
|
|
||||||
ctx.Update(ctx.WineCultivations.Find(old)!);
|
|
||||||
}
|
|
||||||
await ctx.SaveChangesAsync();
|
|
||||||
|
|
||||||
|
// update
|
||||||
|
ctx.UpdateRange(_cultList
|
||||||
|
.Where(_cultIds.ContainsKey)
|
||||||
|
.Select(c => {
|
||||||
|
c.CultId = _cultIds[c];
|
||||||
|
ctx.Entry(c).State = EntityState.Added;
|
||||||
|
return c;
|
||||||
|
}));
|
||||||
|
await ctx.SaveChangesAsync();
|
||||||
foreach (var (old, cultid) in _cults.Where(c => c.Value != null)) {
|
foreach (var (old, cultid) in _cults.Where(c => c.Value != null)) {
|
||||||
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.ExecuteSqlAsync($"UPDATE payment_variant SET data = REPLACE(data, {$"-{old}\""}, {$"-{cultid}\""})");
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var cult in _cultList.Where(c => !_cultIds.ContainsKey(c))) {
|
// insert
|
||||||
if (cult.CultId == null) continue;
|
ctx.AddRange(_cultList
|
||||||
ctx.Add(cult);
|
.Where(c => !_cultIds.ContainsKey(c) && c.CultId != null));
|
||||||
}
|
|
||||||
await ctx.SaveChangesAsync();
|
await ctx.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,10 +72,12 @@ namespace Elwig.Windows {
|
|||||||
WineCultivationIdInput.Text = "";
|
WineCultivationIdInput.Text = "";
|
||||||
WineCultivationNameInput.Text = "";
|
WineCultivationNameInput.Text = "";
|
||||||
WineCultivationDescriptionInput.Text = "";
|
WineCultivationDescriptionInput.Text = "";
|
||||||
|
WineCultivationOrganicInput.IsChecked = false;
|
||||||
} else {
|
} else {
|
||||||
WineCultivationIdInput.Text = cult.CultId;
|
WineCultivationIdInput.Text = cult.CultId;
|
||||||
WineCultivationNameInput.Text = cult.Name;
|
WineCultivationNameInput.Text = cult.Name;
|
||||||
WineCultivationDescriptionInput.Text = cult.Description;
|
WineCultivationDescriptionInput.Text = cult.Description;
|
||||||
|
WineCultivationOrganicInput.IsChecked = cult.IsOrganic;
|
||||||
}
|
}
|
||||||
_cultUpdate = false;
|
_cultUpdate = false;
|
||||||
}
|
}
|
||||||
@@ -103,7 +107,8 @@ namespace Elwig.Windows {
|
|||||||
_cultChanged = _cultChanged ||
|
_cultChanged = _cultChanged ||
|
||||||
WineCultivationIdInput.Text != cult.CultId ||
|
WineCultivationIdInput.Text != cult.CultId ||
|
||||||
WineCultivationNameInput.Text != cult.Name ||
|
WineCultivationNameInput.Text != cult.Name ||
|
||||||
WineCultivationDescriptionInput.Text != (cult.Description ?? "");
|
WineCultivationDescriptionInput.Text != (cult.Description ?? "") ||
|
||||||
|
WineCultivationOrganicInput.IsChecked != cult.IsOrganic;
|
||||||
|
|
||||||
var old = _cultIds.GetValueOrDefault(cult);
|
var old = _cultIds.GetValueOrDefault(cult);
|
||||||
var id = WineCultivationIdInput.Text ?? "";
|
var id = WineCultivationIdInput.Text ?? "";
|
||||||
@@ -111,7 +116,8 @@ namespace Elwig.Windows {
|
|||||||
cult.CultId = id;
|
cult.CultId = id;
|
||||||
cult.Name = WineCultivationNameInput.Text ?? "";
|
cult.Name = WineCultivationNameInput.Text ?? "";
|
||||||
cult.Description = WineCultivationDescriptionInput.Text ?? "";
|
cult.Description = WineCultivationDescriptionInput.Text ?? "";
|
||||||
if (cult.Description.Length == 0) cult.Description = null;
|
cult.IsOrganic = WineCultivationOrganicInput.IsChecked ?? false;
|
||||||
|
if (string.IsNullOrWhiteSpace(cult.Description)) cult.Description = null;
|
||||||
|
|
||||||
CollectionViewSource.GetDefaultView(_cultList).Refresh();
|
CollectionViewSource.GetDefaultView(_cultList).Refresh();
|
||||||
UpdateButtons();
|
UpdateButtons();
|
||||||
|
|||||||
@@ -12,8 +12,6 @@ using System.Windows.Input;
|
|||||||
namespace Elwig.Windows {
|
namespace Elwig.Windows {
|
||||||
public partial class BaseDataWindow : AdministrationWindow {
|
public partial class BaseDataWindow : AdministrationWindow {
|
||||||
|
|
||||||
protected AppDbContext? EditContext;
|
|
||||||
|
|
||||||
public BaseDataWindow() {
|
public BaseDataWindow() {
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
RequiredInputs = [
|
RequiredInputs = [
|
||||||
@@ -27,7 +25,7 @@ namespace Elwig.Windows {
|
|||||||
BranchAddressInput, BranchPhoneNrInput, BranchFaxNrInput, BranchMobileNrInput,
|
BranchAddressInput, BranchPhoneNrInput, BranchFaxNrInput, BranchMobileNrInput,
|
||||||
WineAttributeIdInput, WineAttributeNameInput, WineAttributeActiveInput,
|
WineAttributeIdInput, WineAttributeNameInput, WineAttributeActiveInput,
|
||||||
WineAttributeMaxKgPerHaInput, WineAttributeStrictInput, WineAttributeFillLowerInput,
|
WineAttributeMaxKgPerHaInput, WineAttributeStrictInput, WineAttributeFillLowerInput,
|
||||||
WineCultivationIdInput, WineCultivationNameInput, WineCultivationDescriptionInput,
|
WineCultivationIdInput, WineCultivationNameInput, WineCultivationDescriptionInput, WineCultivationOrganicInput,
|
||||||
AreaCommitmentTypeIdInput, AreaCommitmentTypeWineVariantInput, AreaCommitmentTypeWineAttributeInput,
|
AreaCommitmentTypeIdInput, AreaCommitmentTypeWineVariantInput, AreaCommitmentTypeWineAttributeInput,
|
||||||
AreaCommitmentTypeMinKgPerHaInput, AreaCommitmentTypePenaltyPerKgInput,
|
AreaCommitmentTypeMinKgPerHaInput, AreaCommitmentTypePenaltyPerKgInput,
|
||||||
AreaCommitmentTypePenaltyInput, AreaCommitmentTypePenaltyNoneInput,
|
AreaCommitmentTypePenaltyInput, AreaCommitmentTypePenaltyNoneInput,
|
||||||
@@ -69,6 +67,7 @@ namespace Elwig.Windows {
|
|||||||
WineCultivationIdInput.IsReadOnly = true;
|
WineCultivationIdInput.IsReadOnly = true;
|
||||||
WineCultivationNameInput.IsReadOnly = true;
|
WineCultivationNameInput.IsReadOnly = true;
|
||||||
WineCultivationDescriptionInput.IsReadOnly = true;
|
WineCultivationDescriptionInput.IsReadOnly = true;
|
||||||
|
WineCultivationOrganicInput.IsEnabled = false;
|
||||||
|
|
||||||
AreaCommitmentTypeWineVariantInput.IsEnabled = false;
|
AreaCommitmentTypeWineVariantInput.IsEnabled = false;
|
||||||
AreaCommitmentTypeWineAttributeInput.IsEnabled = false;
|
AreaCommitmentTypeWineAttributeInput.IsEnabled = false;
|
||||||
@@ -117,6 +116,7 @@ namespace Elwig.Windows {
|
|||||||
WineCultivationIdInput.IsReadOnly = false;
|
WineCultivationIdInput.IsReadOnly = false;
|
||||||
WineCultivationNameInput.IsReadOnly = false;
|
WineCultivationNameInput.IsReadOnly = false;
|
||||||
WineCultivationDescriptionInput.IsReadOnly = false;
|
WineCultivationDescriptionInput.IsReadOnly = false;
|
||||||
|
WineCultivationOrganicInput.IsEnabled = true;
|
||||||
|
|
||||||
AreaCommitmentTypeWineVariantInput.IsEnabled = true;
|
AreaCommitmentTypeWineVariantInput.IsEnabled = true;
|
||||||
AreaCommitmentTypeWineAttributeInput.IsEnabled = true;
|
AreaCommitmentTypeWineAttributeInput.IsEnabled = true;
|
||||||
@@ -189,31 +189,30 @@ namespace Elwig.Windows {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async Task InitEditing() {
|
private async Task InitEditing() {
|
||||||
EditContext = new AppDbContext();
|
using var ctx = new AppDbContext();
|
||||||
await BranchesInitEditing(EditContext);
|
await BranchesInitEditing(ctx);
|
||||||
await WineAttributesInitEditing(EditContext);
|
await WineAttributesInitEditing(ctx);
|
||||||
await WineCultivationsInitEditing(EditContext);
|
await WineCultivationsInitEditing(ctx);
|
||||||
await AreaCommitmentTypesInitEditing(EditContext);
|
await AreaCommitmentTypesInitEditing(ctx);
|
||||||
await SeasonsInitEditing(EditContext);
|
await SeasonsInitEditing(ctx);
|
||||||
await ModifiersInitEditing(EditContext);
|
await ModifiersInitEditing(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task Save() {
|
private async Task Save() {
|
||||||
await UpdateClientParameters(App.Client);
|
await UpdateClientParameters(App.Client);
|
||||||
await UpdateParameters(Utils.CurrentLastSeason);
|
await UpdateParameters(Utils.CurrentLastSeason);
|
||||||
using var tx = await EditContext!.Database.BeginTransactionAsync();
|
using var ctx = new AppDbContext();
|
||||||
await BranchesSave(EditContext!);
|
using var tx = await ctx.Database.BeginTransactionAsync();
|
||||||
await WineAttributesSave(EditContext!);
|
await BranchesSave(ctx);
|
||||||
await WineCultivationsSave(EditContext!);
|
await WineAttributesSave(ctx);
|
||||||
await AreaCommitmentTypesSave(EditContext!);
|
await WineCultivationsSave(ctx);
|
||||||
await SeasonsSave(EditContext!);
|
await AreaCommitmentTypesSave(ctx);
|
||||||
await ModifiersSave(EditContext!);
|
await SeasonsSave(ctx);
|
||||||
|
await ModifiersSave(ctx);
|
||||||
await tx.CommitAsync();
|
await tx.CommitAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task FinishEditing() {
|
private async Task FinishEditing() {
|
||||||
EditContext?.Dispose();
|
|
||||||
EditContext = null;
|
|
||||||
using var ctx = new AppDbContext();
|
using var ctx = new AppDbContext();
|
||||||
await BranchesFinishEditing(ctx);
|
await BranchesFinishEditing(ctx);
|
||||||
await WineAttributesFinishEditing(ctx);
|
await WineAttributesFinishEditing(ctx);
|
||||||
@@ -332,7 +331,8 @@ namespace Elwig.Windows {
|
|||||||
ClientBicInput.Text = p.Bic;
|
ClientBicInput.Text = p.Bic;
|
||||||
ClientUstIdNrInput.Text = p.UstIdNr;
|
ClientUstIdNrInput.Text = p.UstIdNr;
|
||||||
ClientLfbisNrInput.Text = p.LfbisNr;
|
ClientLfbisNrInput.Text = p.LfbisNr;
|
||||||
ClientOrganicAuthorityInput.Text = p.OrganicAuthority;
|
ClientOrganicOperatorIdInput.Text = p.OrganicOperatorId;
|
||||||
|
ClientOrganicAuthorityCodeInput.Text = p.OrganicAuthorityCode;
|
||||||
ClientPhoneNrInput.Text = p.PhoneNr;
|
ClientPhoneNrInput.Text = p.PhoneNr;
|
||||||
ClientFaxNrInput.Text = p.FaxNr;
|
ClientFaxNrInput.Text = p.FaxNr;
|
||||||
ClientEmailAddressInput.Text = p.EmailAddress;
|
ClientEmailAddressInput.Text = p.EmailAddress;
|
||||||
@@ -372,7 +372,8 @@ namespace Elwig.Windows {
|
|||||||
p.Bic = string.IsNullOrWhiteSpace(ClientBicInput.Text) ? null : ClientBicInput.Text;
|
p.Bic = string.IsNullOrWhiteSpace(ClientBicInput.Text) ? null : ClientBicInput.Text;
|
||||||
p.UstIdNr = string.IsNullOrWhiteSpace(ClientUstIdNrInput.Text) ? null : ClientUstIdNrInput.Text;
|
p.UstIdNr = string.IsNullOrWhiteSpace(ClientUstIdNrInput.Text) ? null : ClientUstIdNrInput.Text;
|
||||||
p.LfbisNr = string.IsNullOrWhiteSpace(ClientLfbisNrInput.Text) ? null : ClientLfbisNrInput.Text;
|
p.LfbisNr = string.IsNullOrWhiteSpace(ClientLfbisNrInput.Text) ? null : ClientLfbisNrInput.Text;
|
||||||
p.OrganicAuthority = string.IsNullOrWhiteSpace(ClientOrganicAuthorityInput.Text) ? null : ClientOrganicAuthorityInput.Text;
|
p.OrganicOperatorId = string.IsNullOrWhiteSpace(ClientOrganicOperatorIdInput.Text) ? null : ClientOrganicOperatorIdInput.Text;
|
||||||
|
p.OrganicAuthorityCode = string.IsNullOrWhiteSpace(ClientOrganicAuthorityCodeInput.Text) ? null : ClientOrganicAuthorityCodeInput.Text;
|
||||||
p.PhoneNr = string.IsNullOrWhiteSpace(ClientPhoneNrInput.Text) ? null : ClientPhoneNrInput.Text;
|
p.PhoneNr = string.IsNullOrWhiteSpace(ClientPhoneNrInput.Text) ? null : ClientPhoneNrInput.Text;
|
||||||
p.FaxNr = string.IsNullOrWhiteSpace(ClientFaxNrInput.Text) ? null : ClientFaxNrInput.Text;
|
p.FaxNr = string.IsNullOrWhiteSpace(ClientFaxNrInput.Text) ? null : ClientFaxNrInput.Text;
|
||||||
p.EmailAddress = string.IsNullOrWhiteSpace(ClientEmailAddressInput.Text) ? null : ClientEmailAddressInput.Text;
|
p.EmailAddress = string.IsNullOrWhiteSpace(ClientEmailAddressInput.Text) ? null : ClientEmailAddressInput.Text;
|
||||||
|
|||||||
@@ -398,7 +398,8 @@
|
|||||||
<Grid Grid.Row="1" Grid.Column="2">
|
<Grid Grid.Row="1" Grid.Column="2">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="0.625*"/>
|
<RowDefinition Height="0.625*"/>
|
||||||
<RowDefinition Height="0.875*"/>
|
<RowDefinition Height="0.8125*"/>
|
||||||
|
<RowDefinition Height="0.0625*"/>
|
||||||
<RowDefinition Height="0.875*"/>
|
<RowDefinition Height="0.875*"/>
|
||||||
<RowDefinition Height="0.25*"/>
|
<RowDefinition Height="0.25*"/>
|
||||||
<RowDefinition Height="*"/>
|
<RowDefinition Height="*"/>
|
||||||
@@ -434,7 +435,7 @@
|
|||||||
</Grid>
|
</Grid>
|
||||||
</GroupBox>
|
</GroupBox>
|
||||||
|
|
||||||
<GroupBox Header="Lieferung" Grid.Column="0" Grid.Row="1" Grid.RowSpan="3" Margin="5,5,5,5">
|
<GroupBox Header="Lieferung" Grid.Column="0" Grid.Row="1" Grid.RowSpan="4" Margin="5,5,5,5">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="100"/>
|
<ColumnDefinition Width="100"/>
|
||||||
@@ -517,6 +518,7 @@
|
|||||||
<ComboBox x:Name="CultivationInput" SelectedItem="{Binding WineCultObj, Mode=TwoWay}" ItemsSource="{Binding WineCultSource, Mode=TwoWay}"
|
<ComboBox x:Name="CultivationInput" SelectedItem="{Binding WineCultObj, Mode=TwoWay}" ItemsSource="{Binding WineCultSource, Mode=TwoWay}"
|
||||||
Grid.Row="1" Grid.Column="2" Margin="0,40,10,10"
|
Grid.Row="1" Grid.Column="2" Margin="0,40,10,10"
|
||||||
DisplayMemberPath="Name"
|
DisplayMemberPath="Name"
|
||||||
|
SelectionChanged="CultivationInput_SelectionChanged"
|
||||||
KeyUp="Input_KeyUp"/>
|
KeyUp="Input_KeyUp"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
</GroupBox>
|
</GroupBox>
|
||||||
@@ -553,7 +555,7 @@
|
|||||||
</Grid>
|
</Grid>
|
||||||
</GroupBox>
|
</GroupBox>
|
||||||
|
|
||||||
<GroupBox Header="Menge" Grid.Column="1" Grid.Row="2" Margin="5,5,5,5">
|
<GroupBox Header="Menge" Grid.Column="1" Grid.Row="2" Grid.RowSpan="2" Margin="5,5,5,5">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="70"/>
|
<ColumnDefinition Width="70"/>
|
||||||
@@ -565,16 +567,23 @@
|
|||||||
TextChanged="WeightInput_TextChanged"
|
TextChanged="WeightInput_TextChanged"
|
||||||
Grid.Column="1" Width="70" Margin="0,10,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"/>
|
Grid.Column="1" Width="70" Margin="0,10,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"/>
|
||||||
|
|
||||||
|
<Label Content="Tara:" Margin="10,40,10,10"/>
|
||||||
|
<TextBlock x:Name="Tare" Text="{Binding TareString}" Width="40"
|
||||||
|
Grid.Column="1" Margin="30,44,10,10" TextAlignment="Center" HorizontalAlignment="Left" VerticalAlignment="Top"/>
|
||||||
|
|
||||||
<CheckBox x:Name="ManualWeighingInput" IsChecked="{Binding IsManualWeighing, Mode=TwoWay}"
|
<CheckBox x:Name="ManualWeighingInput" IsChecked="{Binding IsManualWeighing, Mode=TwoWay}"
|
||||||
Content="Handwiegung" IsEnabled="False"
|
Content="Handwiegung" IsEnabled="False"
|
||||||
VerticalAlignment="Top" HorizontalAlignment="Left" Margin="10,45,10,10" Grid.Column="0" Grid.ColumnSpan="2"
|
VerticalAlignment="Top" HorizontalAlignment="Left" Margin="10,75,10,10" Grid.Column="0" Grid.ColumnSpan="2"
|
||||||
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"/>
|
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"/>
|
||||||
|
|
||||||
<CheckBox x:Name="GerebeltGewogenInput" IsChecked="{Binding IsNetWeightValue, Mode=TwoWay}"
|
<CheckBox x:Name="GerebeltGewogenInput" IsChecked="{Binding IsNetWeightValue, Mode=TwoWay}"
|
||||||
Content="Gerebelt gewogen" IsThreeState="True"
|
Content="Gerebelt gewogen" IsThreeState="True"
|
||||||
VerticalAlignment="Top" HorizontalAlignment="Left" Margin="10,75,10,10" Grid.Column="0" Grid.ColumnSpan="2"
|
VerticalAlignment="Top" HorizontalAlignment="Left" Margin="10,100,10,10" Grid.Column="0" Grid.ColumnSpan="2"
|
||||||
Checked="GerebeltGewogenInput_Changed" Unchecked="GerebeltGewogenInput_Changed" Indeterminate="GerebeltGewogenInput_Changed"/>
|
Checked="GerebeltGewogenInput_Changed" Unchecked="GerebeltGewogenInput_Changed" Indeterminate="GerebeltGewogenInput_Changed"/>
|
||||||
|
|
||||||
|
<Button x:Name="CorrectTareButton" Content="Tara korrigieren" Width="120" Visibility="Hidden"
|
||||||
|
Click="CorrectTareButton_Click"
|
||||||
|
VerticalAlignment="Top" HorizontalAlignment="Right" Margin="10,10,10,10" Grid.Column="2"/>
|
||||||
<Button x:Name="WeighingAButton" Content="Wiegen A" Width="120"
|
<Button x:Name="WeighingAButton" Content="Wiegen A" Width="120"
|
||||||
Click="WeighingButton_Click"
|
Click="WeighingButton_Click"
|
||||||
VerticalAlignment="Top" HorizontalAlignment="Right" Margin="10,10,10,10" Grid.Column="2"/>
|
VerticalAlignment="Top" HorizontalAlignment="Right" Margin="10,10,10,10" Grid.Column="2"/>
|
||||||
@@ -593,7 +602,7 @@
|
|||||||
</Grid>
|
</Grid>
|
||||||
</GroupBox>
|
</GroupBox>
|
||||||
|
|
||||||
<GroupBox Header="Sonstiges" Grid.Column="1" Grid.Row="3" Grid.RowSpan="2" Margin="5,5,5,10">
|
<GroupBox Header="Sonstiges" Grid.Column="1" Grid.Row="4" Grid.RowSpan="2" Margin="5,5,5,10">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="100"/>
|
<ColumnDefinition Width="100"/>
|
||||||
@@ -646,7 +655,7 @@
|
|||||||
</Grid>
|
</Grid>
|
||||||
</GroupBox>
|
</GroupBox>
|
||||||
|
|
||||||
<GroupBox Header="Herkunft" Grid.Column="0" Grid.Row="4" Margin="5,5,5,10">
|
<GroupBox Header="Herkunft" Grid.Column="0" Grid.Row="5" Margin="5,5,5,10">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="100"/>
|
<ColumnDefinition Width="100"/>
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ using Microsoft.EntityFrameworkCore;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text.Json.Nodes;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
@@ -85,10 +86,10 @@ namespace Elwig.Windows {
|
|||||||
if (n < 3) WeighingCButton.Visibility = Visibility.Hidden;
|
if (n < 3) WeighingCButton.Visibility = Visibility.Hidden;
|
||||||
if (n < 4) WeighingDButton.Visibility = Visibility.Hidden;
|
if (n < 4) WeighingDButton.Visibility = Visibility.Hidden;
|
||||||
if (n == 1) WeighingAButton.Content = "Wiegen";
|
if (n == 1) WeighingAButton.Content = "Wiegen";
|
||||||
if (n > 1) WeighingAButton.Content = $"Wiegen {App.CommandScales[0].ScaleId}";
|
if (n > 1) WeighingAButton.Content = $"Wiegen {App.CommandScales[0].ScaleTerminalId}";
|
||||||
if (n >= 2) WeighingBButton.Content = $"Wiegen {App.CommandScales[1].ScaleId}";
|
if (n >= 2) WeighingBButton.Content = $"Wiegen {App.CommandScales[1].ScaleTerminalId}";
|
||||||
if (n >= 3) WeighingCButton.Content = $"Wiegen {App.CommandScales[2].ScaleId}";
|
if (n >= 3) WeighingCButton.Content = $"Wiegen {App.CommandScales[2].ScaleTerminalId}";
|
||||||
if (n >= 4) WeighingDButton.Content = $"Wiegen {App.CommandScales[3].ScaleId}";
|
if (n >= 4) WeighingDButton.Content = $"Wiegen {App.CommandScales[3].ScaleTerminalId}";
|
||||||
WeighingManualButton.Margin = new Thickness(10, 10 + n * 32, 10, 10);
|
WeighingManualButton.Margin = new Thickness(10, 10 + n * 32, 10, 10);
|
||||||
foreach (var s in App.EventScales) {
|
foreach (var s in App.EventScales) {
|
||||||
s.WeighingEvent += Scale_Weighing;
|
s.WeighingEvent += Scale_Weighing;
|
||||||
@@ -103,6 +104,7 @@ namespace Elwig.Windows {
|
|||||||
WeighingBButton.Visibility = Visibility.Hidden;
|
WeighingBButton.Visibility = Visibility.Hidden;
|
||||||
WeighingCButton.Visibility = Visibility.Hidden;
|
WeighingCButton.Visibility = Visibility.Hidden;
|
||||||
WeighingDButton.Visibility = Visibility.Hidden;
|
WeighingDButton.Visibility = Visibility.Hidden;
|
||||||
|
DisableWeighingButtons();
|
||||||
}
|
}
|
||||||
|
|
||||||
Menu_Statistics_WineQuality_ModeOe.IsChecked = false;
|
Menu_Statistics_WineQuality_ModeOe.IsChecked = false;
|
||||||
@@ -126,7 +128,6 @@ namespace Elwig.Windows {
|
|||||||
this() {
|
this() {
|
||||||
using var ctx = new AppDbContext();
|
using var ctx = new AppDbContext();
|
||||||
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 = $"Lieferungen - {ViewModel.FilterMember.AdministrativeName} - Elwig";
|
|
||||||
ViewModel.EnableAllSeasons = true;
|
ViewModel.EnableAllSeasons = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,7 +140,7 @@ namespace Elwig.Windows {
|
|||||||
if (await ctx.FetchSeasons(Utils.CurrentYear).SingleOrDefaultAsync() == null) {
|
if (await ctx.FetchSeasons(Utils.CurrentYear).SingleOrDefaultAsync() == null) {
|
||||||
InteractionService.ShowWarning("Saison noch nicht erstellt",
|
InteractionService.ShowWarning("Saison noch nicht erstellt",
|
||||||
"Die Saison für das aktuelle Jahr wurde noch nicht erstellt. Neue Lieferungen können nicht abgespeichert werden.\n\n" +
|
"Die Saison für das aktuelle Jahr wurde noch nicht erstellt. Neue Lieferungen können nicht abgespeichert werden.\n\n" +
|
||||||
"(Stammdaten -> Saisons -> Neu anlegen...)");
|
"(Stammdaten \u2192 Saisons \u2192 Neu anlegen...)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -366,7 +367,7 @@ namespace Elwig.Windows {
|
|||||||
private void InitialInputs() {
|
private void InitialInputs() {
|
||||||
ViewModel.LastScaleError = null;
|
ViewModel.LastScaleError = null;
|
||||||
ViewModel.WeighingData = null;
|
ViewModel.WeighingData = null;
|
||||||
ViewModel.ScaleId = null;
|
ViewModel.ScaleTerminalId = null;
|
||||||
ViewModel.ManualWeighingReason = null;
|
ViewModel.ManualWeighingReason = null;
|
||||||
|
|
||||||
ClearOriginalValues();
|
ClearOriginalValues();
|
||||||
@@ -419,9 +420,9 @@ namespace Elwig.Windows {
|
|||||||
var cursor = Mouse.OverrideCursor != null;
|
var cursor = Mouse.OverrideCursor != null;
|
||||||
if (!cursor) Mouse.OverrideCursor = Cursors.Wait;
|
if (!cursor) Mouse.OverrideCursor = Cursors.Wait;
|
||||||
var query = (vm.SearchQuery, vm.FilterSeason, vm.FilterAllSeasons, vm.FilterTodayOnly);
|
var query = (vm.SearchQuery, vm.FilterSeason, vm.FilterAllSeasons, vm.FilterTodayOnly);
|
||||||
var (filter, deliveries, deliveryPartsNum, varieties, members, stat) = await Task.Run(async () => {
|
var (filterNames, 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 vm.GetFilters(ctx);
|
var (filterNames, 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.Variety)
|
||||||
@@ -450,11 +451,13 @@ namespace Elwig.Windows {
|
|||||||
var members = await deliveryQuery.Select(d => d.Member).Distinct().IgnoreAutoIncludes().ToListAsync();
|
var members = await deliveryQuery.Select(d => d.Member).Distinct().IgnoreAutoIncludes().ToListAsync();
|
||||||
var stat = await DeliveryService.GenerateToolTipData(deliveryPartsQuery);
|
var stat = await DeliveryService.GenerateToolTipData(deliveryPartsQuery);
|
||||||
|
|
||||||
return (filter, deliveries, deliveryPartsNum, varieties, members, stat);
|
return (filterNames, filter, deliveries, deliveryPartsNum, varieties, members, stat);
|
||||||
});
|
});
|
||||||
if (!cursor) Mouse.OverrideCursor = null;
|
if (!cursor) Mouse.OverrideCursor = null;
|
||||||
if (query != (ViewModel.SearchQuery, ViewModel.FilterSeason, ViewModel.FilterAllSeasons, ViewModel.FilterTodayOnly)) return;
|
if (query != (ViewModel.SearchQuery, ViewModel.FilterSeason, ViewModel.FilterAllSeasons, ViewModel.FilterTodayOnly)) return;
|
||||||
|
|
||||||
|
if (!ViewModel.IsReceipt)
|
||||||
|
ViewModel.Title = Utils.GetTitle("Lieferungen", filterNames, filter);
|
||||||
ControlUtils.RenewItemsSource(DeliveryList, deliveries,
|
ControlUtils.RenewItemsSource(DeliveryList, deliveries,
|
||||||
DeliveryList_SelectionChanged, ViewModel.TextFilter.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();
|
||||||
@@ -488,7 +491,6 @@ namespace Elwig.Windows {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ViewModel.FilterMember = m;
|
ViewModel.FilterMember = m;
|
||||||
ViewModel.Title = $"Lieferungen - {ViewModel.FilterMember.AdministrativeName} - Elwig";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int year = 0;
|
int year = 0;
|
||||||
@@ -612,14 +614,34 @@ namespace Elwig.Windows {
|
|||||||
ClearOriginalValues();
|
ClearOriginalValues();
|
||||||
ClearDefaultValues();
|
ClearDefaultValues();
|
||||||
ViewModel.FillInputs(p);
|
ViewModel.FillInputs(p);
|
||||||
|
CorrectTareButton.Visibility = !ViewModel.IsReceipt && ((ViewModel.ActualTare is int t && t != 0) || ViewModel.IsUnloadingBox) ? Visibility.Visible : Visibility.Hidden;
|
||||||
FinishInputFilling();
|
FinishInputFilling();
|
||||||
}
|
}
|
||||||
|
|
||||||
new protected void ClearInputs(bool validate = false) {
|
new protected void ClearInputs(bool validate = false) {
|
||||||
ViewModel.ClearInputs();
|
ViewModel.ClearInputs();
|
||||||
|
CorrectTareButton.Visibility = Visibility.Hidden;
|
||||||
base.ClearInputs(validate);
|
base.ClearInputs(validate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void CorrectTareButton_Click(object sender, RoutedEventArgs evt) {
|
||||||
|
var lastCorrection = (ViewModel.TargetTare ?? ViewModel.ActualTare ?? 0) - (ViewModel.ActualTare ?? 0);
|
||||||
|
var correction = Utils.ShowTareCorrectionDialog(ViewModel.ActualTare, ViewModel.TargetTare);
|
||||||
|
if (correction == null) return;
|
||||||
|
ViewModel.Weight += lastCorrection - correction;
|
||||||
|
if (ViewModel.WeighingData is string s) {
|
||||||
|
ViewModel.TargetTare = correction == 0 ? null : (ViewModel.ActualTare ?? 0) + correction;
|
||||||
|
ViewModel.Tare = ViewModel.TargetTare ?? ViewModel.ActualTare;
|
||||||
|
var obj = JsonNode.Parse(s)!.AsObject();
|
||||||
|
if (correction == 0) {
|
||||||
|
obj.Remove("tare_correction");
|
||||||
|
} else {
|
||||||
|
obj["tare_correction"] = correction;
|
||||||
|
}
|
||||||
|
ViewModel.WeighingData = obj.ToJsonString(Utils.JsonOpts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void WeighingButton_Click(object sender, RoutedEventArgs evt) {
|
private void WeighingButton_Click(object sender, RoutedEventArgs evt) {
|
||||||
int index = Array.IndexOf(WeighingButtons, sender as Button);
|
int index = Array.IndexOf(WeighingButtons, sender as Button);
|
||||||
if (index >= 0) WeighingButton_Click(index);
|
if (index >= 0) WeighingButton_Click(index);
|
||||||
@@ -651,13 +673,19 @@ namespace Elwig.Windows {
|
|||||||
private void OnWeighingResult(IScale scale, WeighingResult res) {
|
private void OnWeighingResult(IScale scale, WeighingResult res) {
|
||||||
if ((res.NetWeight ?? 0) > 0 && res.FullWeighingId != null) {
|
if ((res.NetWeight ?? 0) > 0 && res.FullWeighingId != null) {
|
||||||
ViewModel.Weight = res.NetWeight;
|
ViewModel.Weight = res.NetWeight;
|
||||||
ViewModel.ScaleId = scale.ScaleId;
|
ViewModel.ActualTare = res.TareWeight;
|
||||||
|
ViewModel.TargetTare = null;
|
||||||
|
ViewModel.Tare = ViewModel.ActualTare is int t && t != 0 ? t : null;
|
||||||
|
ViewModel.ScaleTerminalId = scale.ScaleTerminalId;
|
||||||
ViewModel.WeighingData = res.ToJson().ToJsonString();
|
ViewModel.WeighingData = res.ToJson().ToJsonString();
|
||||||
ViewModel.ManualWeighingReason = null;
|
ViewModel.ManualWeighingReason = null;
|
||||||
ManualWeighingInput.IsChecked = false;
|
ManualWeighingInput.IsChecked = false;
|
||||||
} else {
|
} else {
|
||||||
ViewModel.Weight = null;
|
ViewModel.Weight = null;
|
||||||
ViewModel.ScaleId = null;
|
ViewModel.ActualTare = null;
|
||||||
|
ViewModel.TargetTare = null;
|
||||||
|
ViewModel.Tare = null;
|
||||||
|
ViewModel.ScaleTerminalId = null;
|
||||||
ViewModel.WeighingData = null;
|
ViewModel.WeighingData = null;
|
||||||
}
|
}
|
||||||
ViewModel.LastScaleError = null;
|
ViewModel.LastScaleError = null;
|
||||||
@@ -685,7 +713,7 @@ namespace Elwig.Windows {
|
|||||||
private async void TodayOnlyInput_Changed(object sender, RoutedEventArgs evt) {
|
private async void TodayOnlyInput_Changed(object sender, RoutedEventArgs evt) {
|
||||||
if (!HasContextLoaded) return;
|
if (!HasContextLoaded) return;
|
||||||
if (TodayOnlyInput.IsChecked == true && AllSeasonsInput.IsChecked == false) {
|
if (TodayOnlyInput.IsChecked == true && AllSeasonsInput.IsChecked == false) {
|
||||||
ViewModel.FilterSeason = Utils.Today.Year;
|
ViewModel.FilterSeason = DateTime.Today.Year;
|
||||||
ViewModel.FilterTodayOnly = true;
|
ViewModel.FilterTodayOnly = true;
|
||||||
}
|
}
|
||||||
await RefreshList();
|
await RefreshList();
|
||||||
@@ -746,12 +774,12 @@ namespace Elwig.Windows {
|
|||||||
MgNrInput.CaretIndex = caret;
|
MgNrInput.CaretIndex = caret;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MgNrInput_LostFocus(object sender, RoutedEventArgs evt) {
|
private async void MgNrInput_LostFocus(object sender, RoutedEventArgs evt) {
|
||||||
var valid = InputLostFocus((TextBox)sender, Validator.CheckMgNr);
|
var valid = InputLostFocus((TextBox)sender, Validator.CheckMgNr);
|
||||||
ControlUtils.SelectItemWithPk(MemberInput, valid ? ViewModel.MgNr : null);
|
ControlUtils.SelectItemWithPk(MemberInput, valid ? ViewModel.MgNr : null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MemberInput_SelectionChanged(object? sender, SelectionChangedEventArgs? evt) {
|
private async void MemberInput_SelectionChanged(object? sender, SelectionChangedEventArgs? evt) {
|
||||||
var m = MemberInput.SelectedItem as Member;
|
var m = MemberInput.SelectedItem as Member;
|
||||||
ViewModel.MgNr = m?.MgNr;
|
ViewModel.MgNr = m?.MgNr;
|
||||||
ViewModel.MemberAddress = m?.FullAddress;
|
ViewModel.MemberAddress = m?.FullAddress;
|
||||||
@@ -768,15 +796,20 @@ namespace Elwig.Windows {
|
|||||||
SetDefaultValue(WineKgInput);
|
SetDefaultValue(WineKgInput);
|
||||||
ComboBox_SelectionChanged(WineKgInput, null);
|
ComboBox_SelectionChanged(WineKgInput, null);
|
||||||
}
|
}
|
||||||
|
if (IsCreating && Mouse.OverrideCursor == null)
|
||||||
|
await CheckOrganic();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EmptyScale() {
|
private void EmptyScale() {
|
||||||
var scale = App.Scales.Where(s => s.ScaleId == ViewModel.ScaleId).FirstOrDefault();
|
var scale = App.Scales.Where(s => s.ScaleTerminalId == ViewModel.ScaleTerminalId).FirstOrDefault();
|
||||||
if (scale is not ICommandScale cs) return;
|
if (scale is not ICommandScale cs) return;
|
||||||
cs.Empty();
|
cs.Empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void NewDeliveryPartButton_Click(object sender, RoutedEventArgs evt) {
|
private async void NewDeliveryPartButton_Click(object sender, RoutedEventArgs evt) {
|
||||||
|
if (!await CheckOrganic(true))
|
||||||
|
return;
|
||||||
|
|
||||||
FinishButton.IsEnabled = false;
|
FinishButton.IsEnabled = false;
|
||||||
NewDeliveryPartButton.IsEnabled = false;
|
NewDeliveryPartButton.IsEnabled = false;
|
||||||
Mouse.OverrideCursor = Cursors.Wait;
|
Mouse.OverrideCursor = Cursors.Wait;
|
||||||
@@ -796,7 +829,7 @@ namespace Elwig.Windows {
|
|||||||
} catch (Exception exc) {
|
} catch (Exception exc) {
|
||||||
InteractionService.ShowDbException("Lieferung aktualisieren", exc);
|
InteractionService.ShowDbException("Lieferung aktualisieren", exc);
|
||||||
FinishButton.IsEnabled = true;
|
FinishButton.IsEnabled = true;
|
||||||
SaveButton.IsEnabled = true;
|
NewDeliveryPartButton.IsEnabled = true;
|
||||||
Mouse.OverrideCursor = null;
|
Mouse.OverrideCursor = null;
|
||||||
DeliveryPartList.IsEnabled = true;
|
DeliveryPartList.IsEnabled = true;
|
||||||
return;
|
return;
|
||||||
@@ -805,14 +838,18 @@ namespace Elwig.Windows {
|
|||||||
EmptyScale();
|
EmptyScale();
|
||||||
|
|
||||||
await EnsureContextRenewed();
|
await EnsureContextRenewed();
|
||||||
Mouse.OverrideCursor = null;
|
|
||||||
ControlUtils.SelectItemWithPk(DeliveryList, p?.Year, p?.DId);
|
ControlUtils.SelectItemWithPk(DeliveryList, p?.Year, p?.DId);
|
||||||
DeliveryPartList.SelectedItem = null;
|
DeliveryPartList.SelectedItem = null;
|
||||||
DeliveryPartList.ScrollIntoView(DeliveryPartList.ItemsSource.Cast<object>().LastOrDefault());
|
DeliveryPartList.ScrollIntoView(DeliveryPartList.ItemsSource.Cast<object>().LastOrDefault());
|
||||||
InitialInputs();
|
InitialInputs();
|
||||||
|
|
||||||
|
Mouse.OverrideCursor = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void FinishButton_Click(object sender, RoutedEventArgs evt) {
|
private async void FinishButton_Click(object sender, RoutedEventArgs evt) {
|
||||||
|
if (!await CheckOrganic(true))
|
||||||
|
return;
|
||||||
|
|
||||||
FinishButton.IsEnabled = false;
|
FinishButton.IsEnabled = false;
|
||||||
NewDeliveryPartButton.IsEnabled = false;
|
NewDeliveryPartButton.IsEnabled = false;
|
||||||
Mouse.OverrideCursor = Cursors.Wait;
|
Mouse.OverrideCursor = Cursors.Wait;
|
||||||
@@ -832,7 +869,7 @@ namespace Elwig.Windows {
|
|||||||
} catch (Exception exc) {
|
} catch (Exception exc) {
|
||||||
InteractionService.ShowDbException("Lieferung aktualisieren", exc);
|
InteractionService.ShowDbException("Lieferung aktualisieren", exc);
|
||||||
FinishButton.IsEnabled = true;
|
FinishButton.IsEnabled = true;
|
||||||
SaveButton.IsEnabled = true;
|
NewDeliveryPartButton.IsEnabled = true;
|
||||||
Mouse.OverrideCursor = null;
|
Mouse.OverrideCursor = null;
|
||||||
DeliveryPartList.IsEnabled = true;
|
DeliveryPartList.IsEnabled = true;
|
||||||
return;
|
return;
|
||||||
@@ -953,7 +990,7 @@ namespace Elwig.Windows {
|
|||||||
ViewModel.Weight = res?.Item1;
|
ViewModel.Weight = res?.Item1;
|
||||||
ManualWeighingInput.IsChecked = true;
|
ManualWeighingInput.IsChecked = true;
|
||||||
ViewModel.ManualWeighingReason = res?.Item2;
|
ViewModel.ManualWeighingReason = res?.Item2;
|
||||||
ViewModel.ScaleId = null;
|
ViewModel.ScaleTerminalId = null;
|
||||||
ViewModel.WeighingData = null;
|
ViewModel.WeighingData = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -971,6 +1008,8 @@ namespace Elwig.Windows {
|
|||||||
DeliveryList.IsEnabled = false;
|
DeliveryList.IsEnabled = false;
|
||||||
DeliveryPartList.IsEnabled = false;
|
DeliveryPartList.IsEnabled = false;
|
||||||
|
|
||||||
|
if (!ViewModel.IsReceipt)
|
||||||
|
EnableWeighingButtons();
|
||||||
HideNewEditDeleteButtons();
|
HideNewEditDeleteButtons();
|
||||||
ShowSaveResetCancelButtons();
|
ShowSaveResetCancelButtons();
|
||||||
UnlockInputs();
|
UnlockInputs();
|
||||||
@@ -1008,6 +1047,9 @@ namespace Elwig.Windows {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async void SaveButton_Click(object? sender, RoutedEventArgs? evt) {
|
private async void SaveButton_Click(object? sender, RoutedEventArgs? evt) {
|
||||||
|
if (!await CheckOrganic(true))
|
||||||
|
return;
|
||||||
|
|
||||||
SaveButton.IsEnabled = false;
|
SaveButton.IsEnabled = false;
|
||||||
Mouse.OverrideCursor = Cursors.Wait;
|
Mouse.OverrideCursor = Cursors.Wait;
|
||||||
|
|
||||||
@@ -1034,6 +1076,8 @@ namespace Elwig.Windows {
|
|||||||
DeliveryList.IsEnabled = true;
|
DeliveryList.IsEnabled = true;
|
||||||
DeliveryPartList.IsEnabled = true;
|
DeliveryPartList.IsEnabled = true;
|
||||||
|
|
||||||
|
if (!ViewModel.IsReceipt)
|
||||||
|
DisableWeighingButtons();
|
||||||
HideSaveResetCancelButtons();
|
HideSaveResetCancelButtons();
|
||||||
ShowNewEditDeleteButtons();
|
ShowNewEditDeleteButtons();
|
||||||
LockInputs();
|
LockInputs();
|
||||||
@@ -1067,6 +1111,8 @@ namespace Elwig.Windows {
|
|||||||
DeliveryList.IsEnabled = true;
|
DeliveryList.IsEnabled = true;
|
||||||
DeliveryPartList.IsEnabled = true;
|
DeliveryPartList.IsEnabled = true;
|
||||||
|
|
||||||
|
if (!ViewModel.IsReceipt)
|
||||||
|
DisableWeighingButtons();
|
||||||
HideSaveResetCancelButtons();
|
HideSaveResetCancelButtons();
|
||||||
ShowNewEditDeleteButtons();
|
ShowNewEditDeleteButtons();
|
||||||
RefreshInputs();
|
RefreshInputs();
|
||||||
@@ -1171,6 +1217,7 @@ namespace Elwig.Windows {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void DisableWeighingButtons() {
|
private void DisableWeighingButtons() {
|
||||||
|
CorrectTareButton.IsEnabled = false;
|
||||||
WeighingManualButton.IsEnabled = false;
|
WeighingManualButton.IsEnabled = false;
|
||||||
WeighingAButton.IsEnabled = false;
|
WeighingAButton.IsEnabled = false;
|
||||||
WeighingBButton.IsEnabled = false;
|
WeighingBButton.IsEnabled = false;
|
||||||
@@ -1179,6 +1226,7 @@ namespace Elwig.Windows {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void EnableWeighingButtons() {
|
private void EnableWeighingButtons() {
|
||||||
|
CorrectTareButton.IsEnabled = true;
|
||||||
WeighingManualButton.IsEnabled = true;
|
WeighingManualButton.IsEnabled = true;
|
||||||
var n = App.CommandScales.Count;
|
var n = App.CommandScales.Count;
|
||||||
WeighingAButton.IsEnabled = n > 0 && App.CommandScales[0].IsReady;
|
WeighingAButton.IsEnabled = n > 0 && App.CommandScales[0].IsReady;
|
||||||
@@ -1373,13 +1421,15 @@ namespace Elwig.Windows {
|
|||||||
|
|
||||||
private void UnloadingInput_Checked(object sender, RoutedEventArgs evt) {
|
private void UnloadingInput_Checked(object sender, RoutedEventArgs evt) {
|
||||||
if (!IsEditing && !IsCreating) return;
|
if (!IsEditing && !IsCreating) return;
|
||||||
|
if (!ViewModel.IsReceipt)
|
||||||
|
CorrectTareButton.Visibility = (ViewModel.ActualTare is int t && t != 0) || ViewModel.IsUnloadingBox ? Visibility.Visible : Visibility.Hidden;
|
||||||
var mod = ViewModel.Modifiers.ToList();
|
var mod = ViewModel.Modifiers.ToList();
|
||||||
var source = ViewModel.ModifiersSource.ToList();
|
var source = ViewModel.ModifiersSource.ToList();
|
||||||
if (App.Client.IsMatzen) {
|
if (App.Client.IsMatzen) {
|
||||||
var kl = mod.Where(m => m.Name.StartsWith("Klasse ")).Select(m => m.ModId).LastOrDefault("_")[0];
|
var kl = mod.Where(m => m.Name.StartsWith("Klasse ")).Select(m => m.ModId).LastOrDefault("_")[0];
|
||||||
if (ViewModel.IsUnloadingPumped && (kl == 'A' || kl == '_')) {
|
if (ViewModel.IsUnloadingPumped && (kl == 'A' || kl == '_')) {
|
||||||
kl = 'B';
|
kl = 'B';
|
||||||
} else if (ViewModel.IsUnloadingDumper && kl == '_') {
|
} else if (ViewModel.IsUnloadingDumper && (kl == 'B' || kl == '_')) {
|
||||||
kl = 'A';
|
kl = 'A';
|
||||||
} else {
|
} else {
|
||||||
kl = '_';
|
kl = '_';
|
||||||
@@ -1501,5 +1551,43 @@ namespace Elwig.Windows {
|
|||||||
if (MemberInput.SelectedItem is not Member m) return;
|
if (MemberInput.SelectedItem is not Member m) return;
|
||||||
App.FocusMember(m.MgNr);
|
App.FocusMember(m.MgNr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async void CultivationInput_SelectionChanged(object sender, RoutedEventArgs evt) {
|
||||||
|
if (IsCreating && Mouse.OverrideCursor == null)
|
||||||
|
await CheckOrganic();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<bool> CheckOrganic(bool confirm = false) {
|
||||||
|
if (MemberInput.SelectedValue is not Member m || CultivationInput.SelectedItem is not WineCult c) {
|
||||||
|
return true;
|
||||||
|
} else if (c.IsOrganic) {
|
||||||
|
if (m.IsOrganic) {
|
||||||
|
var valid = true;
|
||||||
|
if (IsCreating) {
|
||||||
|
try {
|
||||||
|
var certs = await OrganicService.GetTracesCertificates(m);
|
||||||
|
valid = certs.Length > 0 && certs[0].IsValidForWineProduction;
|
||||||
|
} catch { }
|
||||||
|
}
|
||||||
|
if (valid)
|
||||||
|
return true;
|
||||||
|
if (confirm) {
|
||||||
|
return InteractionService.AskConfirmation("Kein gültiges Bio-Zertifikat", "Soll die Bio-Lieferung wirklich gespeichert werden, obwohl für das Mitglied kein gültiges Bio-Zertifikat gefunden werden konnte?");
|
||||||
|
} else {
|
||||||
|
InteractionService.ShowWarning("Kein gültiges Bio-Zertifikat", "Achtung! Für diesen Bio-Betrieb konnte kein gültiges Bio-Zertifikat gefunden werden!");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
if (confirm) {
|
||||||
|
return InteractionService.AskConfirmation("Kein Bio-Betrieb", "Soll die Bio-Lieferung wirklich gespeichert werden, obwohl das Mitglied keinen Bio-Betrieb hat?");
|
||||||
|
} else {
|
||||||
|
InteractionService.ShowWarning("Kein Bio-Betrieb", "Achtung! Bio-Lieferung ohne Bio-Betrieb!");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,7 +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="{Binding Title}" Height="700" Width="980" MinWidth="600" MinHeight="400">
|
||||||
<Window.DataContext>
|
<Window.DataContext>
|
||||||
<vm:DeliveryAncmtAdminViewModel/>
|
<vm:DeliveryAncmtAdminViewModel/>
|
||||||
</Window.DataContext>
|
</Window.DataContext>
|
||||||
|
|||||||
@@ -91,8 +91,9 @@ namespace Elwig.Windows {
|
|||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
list.ForEach(v => v.Schedule.AnnouncedWeightOverride = v.AnnouncedWeight);
|
list.ForEach(v => v.Schedule.AnnouncedWeightOverride = v.AnnouncedWeight);
|
||||||
var deliverySchedules = list.Select(v => v.Schedule).ToList();
|
var deliverySchedules = list.Select(v => v.Schedule).ToList();
|
||||||
|
var today = DateTime.Today;
|
||||||
ControlUtils.RenewItemsSource(DeliveryScheduleList, deliverySchedules
|
ControlUtils.RenewItemsSource(DeliveryScheduleList, deliverySchedules
|
||||||
.Where(s => !ViewModel.FilterOnlyUpcoming || s.DateString.CompareTo(Utils.Today.ToString("yyyy-MM-dd")) >= 0)
|
.Where(s => !ViewModel.FilterOnlyUpcoming || s.DateString.CompareTo(today.ToString("yyyy-MM-dd")) >= 0)
|
||||||
.ToList(), DeliveryScheduleList_SelectionChanged, ViewModel.FilterFromAllSchedules ? ControlUtils.RenewSourceDefault.None : ControlUtils.RenewSourceDefault.First);
|
.ToList(), DeliveryScheduleList_SelectionChanged, ViewModel.FilterFromAllSchedules ? ControlUtils.RenewSourceDefault.None : ControlUtils.RenewSourceDefault.First);
|
||||||
ControlUtils.RenewItemsSource(DeliveryScheduleInput, deliverySchedules, DeliveryScheduleInput_SelectionChanged);
|
ControlUtils.RenewItemsSource(DeliveryScheduleInput, deliverySchedules, DeliveryScheduleInput_SelectionChanged);
|
||||||
}
|
}
|
||||||
@@ -102,9 +103,9 @@ namespace Elwig.Windows {
|
|||||||
var cursor = Mouse.OverrideCursor != null;
|
var cursor = Mouse.OverrideCursor != null;
|
||||||
if (!cursor) Mouse.OverrideCursor = Cursors.Wait;
|
if (!cursor) Mouse.OverrideCursor = Cursors.Wait;
|
||||||
var query = (vm.SearchQuery, vm.FilterSeason, vm.FilterOnlyUpcoming, vm.FilterOnlyUpcoming);
|
var query = (vm.SearchQuery, vm.FilterSeason, vm.FilterOnlyUpcoming, vm.FilterOnlyUpcoming);
|
||||||
var (filter, deliveryAncmts, stat) = await Task.Run(async () => {
|
var (filterNames, filter, deliveryAncmts, stat) = await Task.Run(async () => {
|
||||||
using var ctx = new AppDbContext();
|
using var ctx = new AppDbContext();
|
||||||
var (_, deliveryAncmtQuery, filter) = await vm.GetFilters(ctx);
|
var (filterNames, deliveryAncmtQuery, filter) = await vm.GetFilters(ctx);
|
||||||
var deliveryAncmts = await deliveryAncmtQuery.ToListAsync();
|
var deliveryAncmts = await deliveryAncmtQuery.ToListAsync();
|
||||||
|
|
||||||
if (filter.Count > 0 && deliveryAncmts.Count > 0) {
|
if (filter.Count > 0 && deliveryAncmts.Count > 0) {
|
||||||
@@ -129,11 +130,12 @@ namespace Elwig.Windows {
|
|||||||
|
|
||||||
var stat = await DeliveryAncmtService.GenerateToolTipData(deliveryAncmtQuery);
|
var stat = await DeliveryAncmtService.GenerateToolTipData(deliveryAncmtQuery);
|
||||||
|
|
||||||
return (filter, deliveryAncmts, stat);
|
return (filterNames, filter, deliveryAncmts, stat);
|
||||||
});
|
});
|
||||||
if (!cursor) Mouse.OverrideCursor = null;
|
if (!cursor) Mouse.OverrideCursor = null;
|
||||||
if (query != (ViewModel.SearchQuery, ViewModel.FilterSeason, ViewModel.FilterOnlyUpcoming, ViewModel.FilterOnlyUpcoming)) return;
|
if (query != (ViewModel.SearchQuery, ViewModel.FilterSeason, ViewModel.FilterOnlyUpcoming, ViewModel.FilterOnlyUpcoming)) return;
|
||||||
|
|
||||||
|
ViewModel.Title = Utils.GetTitle("Anmeldungen", filterNames, filter);
|
||||||
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)
|
||||||
@@ -206,8 +208,28 @@ namespace Elwig.Windows {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DeliveryScheduleInput_SelectionChanged(object sender, RoutedEventArgs evt) {
|
private bool CheckOrganic(bool confirm = false) {
|
||||||
|
if (DeliveryScheduleInput.SelectedItem is not DeliverySchedule s || MemberInput.SelectedItem is not Member m) {
|
||||||
|
return true;
|
||||||
|
} else if (s.IsOrganic) {
|
||||||
|
if (m.IsOrganic) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
if (confirm) {
|
||||||
|
return InteractionService.AskConfirmation("Kein Bio-Betrieb", "Soll die Bio-Anmeldung wirklich gespeichert werden, obwohl das Mitglied keinen Bio-Betrieb hat?");
|
||||||
|
} else {
|
||||||
|
InteractionService.ShowWarning("Kein Bio-Betrieb", "Achtung! Bio-Anmeldung ohne Bio-Betrieb!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DeliveryScheduleInput_SelectionChanged(object sender, RoutedEventArgs evt) {
|
||||||
|
if (IsEditing || IsCreating)
|
||||||
|
CheckOrganic();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void OnlyUpcomingInput_Changed(object sender, RoutedEventArgs evt) {
|
private async void OnlyUpcomingInput_Changed(object sender, RoutedEventArgs evt) {
|
||||||
@@ -256,6 +278,8 @@ namespace Elwig.Windows {
|
|||||||
var m = MemberInput.SelectedItem as Member;
|
var m = MemberInput.SelectedItem as Member;
|
||||||
ViewModel.MgNr = m?.MgNr;
|
ViewModel.MgNr = m?.MgNr;
|
||||||
ViewModel.MemberAddress = m?.FullAddress;
|
ViewModel.MemberAddress = m?.FullAddress;
|
||||||
|
if (IsCreating)
|
||||||
|
CheckOrganic();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void ShortcutNew() {
|
protected override void ShortcutNew() {
|
||||||
@@ -332,6 +356,9 @@ namespace Elwig.Windows {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async void SaveButton_Click(object? sender, RoutedEventArgs? evt) {
|
private async void SaveButton_Click(object? sender, RoutedEventArgs? evt) {
|
||||||
|
if (!CheckOrganic(true))
|
||||||
|
return;
|
||||||
|
|
||||||
Mouse.OverrideCursor = Cursors.Wait;
|
Mouse.OverrideCursor = Cursors.Wait;
|
||||||
SaveButton.IsEnabled = false;
|
SaveButton.IsEnabled = false;
|
||||||
|
|
||||||
|
|||||||
@@ -108,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.OrderByDescending(s => s.Year).FirstOrDefault()?.Year ?? Utils.Today.Year;
|
Year = year ?? ctx.Seasons.OrderByDescending(s => s.Year).FirstOrDefault()?.Year ?? DateTime.Today.Year;
|
||||||
Title = $"Rundschreiben - Lese {Year} - Elwig";
|
Title = $"Rundschreiben - Lese {Year} - Elwig";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,7 +150,7 @@ namespace Elwig.Windows {
|
|||||||
PostalSender1.Text = App.Client.Sender1;
|
PostalSender1.Text = App.Client.Sender1;
|
||||||
PostalSender2.Text = App.Client.Sender2;
|
PostalSender2.Text = App.Client.Sender2;
|
||||||
PostalLocation.Text = App.BranchLocation;
|
PostalLocation.Text = App.BranchLocation;
|
||||||
PostalDate.Text = $"{Utils.Today:dd.MM.yyyy}";
|
PostalDate.Text = $"{DateTime.Today:dd.MM.yyyy}";
|
||||||
EmailSubjectInput.Text = App.Client.TextEmailSubject ?? "Rundschreiben";
|
EmailSubjectInput.Text = App.Client.TextEmailSubject ?? "Rundschreiben";
|
||||||
EmailBodyInput.Text = App.Client.TextEmailBody ?? "Sehr geehrtes Mitglied,\n\nim Anhang finden Sie das aktuelle Rundschreiben.\n\nIhre Winzergenossenschaft\n";
|
EmailBodyInput.Text = App.Client.TextEmailBody ?? "Sehr geehrtes Mitglied,\n\nim Anhang finden Sie das aktuelle Rundschreiben.\n\nIhre Winzergenossenschaft\n";
|
||||||
}
|
}
|
||||||
@@ -438,7 +438,7 @@ namespace Elwig.Windows {
|
|||||||
|
|
||||||
private void Date_LostFocus(object sender, RoutedEventArgs evt) {
|
private void Date_LostFocus(object sender, RoutedEventArgs evt) {
|
||||||
var res = Validator.CheckDate((TextBox)sender, true);
|
var res = Validator.CheckDate((TextBox)sender, true);
|
||||||
if (!res.IsValid) ((TextBox)sender).Text = $"{Utils.Today:dd.MM.yyyy}";
|
if (!res.IsValid) ((TextBox)sender).Text = $"{DateTime.Today:dd.MM.yyyy}";
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task UpdateRecipients(AppDbContext ctx) {
|
private async Task UpdateRecipients(AppDbContext ctx) {
|
||||||
@@ -937,6 +937,7 @@ namespace Elwig.Windows {
|
|||||||
Mouse.OverrideCursor = Cursors.Wait;
|
Mouse.OverrideCursor = Cursors.Wait;
|
||||||
var subject = EmailSubjectInput.Text;
|
var subject = EmailSubjectInput.Text;
|
||||||
var text = EmailBodyInput.Text;
|
var text = EmailBodyInput.Text;
|
||||||
|
var date = DateTime.Now;
|
||||||
await Task.Run(async () => {
|
await Task.Run(async () => {
|
||||||
await Utils.AddSentMailBody(subject, text, EmailDocuments.Count);
|
await Utils.AddSentMailBody(subject, text, EmailDocuments.Count);
|
||||||
foreach (var (m, docs) in EmailDocuments) {
|
foreach (var (m, docs) in EmailDocuments) {
|
||||||
@@ -944,6 +945,7 @@ namespace Elwig.Windows {
|
|||||||
msg.From.Add(new MailboxAddress(App.Client.NameFull, App.Config.Smtp.Value.From));
|
msg.From.Add(new MailboxAddress(App.Client.NameFull, App.Config.Smtp.Value.From));
|
||||||
msg.To.AddRange(m.EmailAddresses.OrderBy(a => a.Nr).Select(a => new MailboxAddress(m.AdministrativeName, a.Address)));
|
msg.To.AddRange(m.EmailAddresses.OrderBy(a => a.Nr).Select(a => new MailboxAddress(m.AdministrativeName, a.Address)));
|
||||||
msg.Subject = subject;
|
msg.Subject = subject;
|
||||||
|
msg.Date = date;
|
||||||
var body = new Multipart("mixed") {
|
var body = new Multipart("mixed") {
|
||||||
new TextPart("plain") { Text = text }
|
new TextPart("plain") { Text = text }
|
||||||
};
|
};
|
||||||
@@ -958,6 +960,7 @@ namespace Elwig.Windows {
|
|||||||
m.EmailAddresses.OrderBy(a => a.Nr).Select(a => a.Address).ToArray(),
|
m.EmailAddresses.OrderBy(a => a.Nr).Select(a => a.Address).ToArray(),
|
||||||
subject, docs.Select(d => d.Title).ToArray()
|
subject, docs.Select(d => d.Title).ToArray()
|
||||||
)]);
|
)]);
|
||||||
|
await Task.Delay((int)(App.Config.SmtpWait * 1000));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -52,20 +52,21 @@ namespace Elwig.Windows {
|
|||||||
|
|
||||||
private void Window_Closing(object sender, CancelEventArgs evt) {
|
private void Window_Closing(object sender, CancelEventArgs evt) {
|
||||||
if (App.NumWindows > 1 && !App.ForceShutdown) {
|
if (App.NumWindows > 1 && !App.ForceShutdown) {
|
||||||
foreach (var w in App.Current.Windows.Cast<Window>().Where(w => ((w as AdministrationWindow)?.IsEditing ?? false) || ((w as AdministrationWindow)?.IsCreating ?? false))) {
|
foreach (var w in Application.Current.Windows.Cast<Window>().Where(w => w is AdministrationWindow adm && (adm.IsEditing || adm.IsCreating))) {
|
||||||
try {
|
try {
|
||||||
w.Close();
|
w.Close();
|
||||||
} catch { }
|
} catch { }
|
||||||
}
|
}
|
||||||
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) {
|
||||||
if (!InteractionService.AskConfirmation("Elwig beenden", "Es sind noch weitere Fenster geöffnet.\nSollen alle Fenster geschlossen werden?")) {
|
var areAdminWindowsOpen = Application.Current.Windows.Cast<Window>().Any(w => w is AdministrationWindow adm && (adm.IsEditing || adm.IsCreating));
|
||||||
|
if (areAdminWindowsOpen && !InteractionService.AskConfirmation("Elwig beenden", "Es sind noch weitere Fenster geöffnet.\nSollen alle Fenster geschlossen werden?")) {
|
||||||
evt.Cancel = true;
|
evt.Cancel = true;
|
||||||
} else {
|
return;
|
||||||
Application.Current.Shutdown();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
App.CurrentApp.ShutdownGracefully();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Menu_Help_About_Click(object sender, RoutedEventArgs evt) {
|
private void Menu_Help_About_Click(object sender, RoutedEventArgs evt) {
|
||||||
@@ -162,7 +163,7 @@ namespace Elwig.Windows {
|
|||||||
|
|
||||||
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 filename = InteractionService.SaveFile("Datenbank-Sicherung", $"database_{Utils.Today:yyyy-MM-dd}", "sql.zip");
|
var filename = InteractionService.SaveFile("Datenbank-Sicherung", $"database_{DateTime.Today:yyyy-MM-dd}", "sql.zip");
|
||||||
if (filename != null) {
|
if (filename != null) {
|
||||||
if (!filename.EndsWith(".sql.zip")) filename += ".sql.zip";
|
if (!filename.EndsWith(".sql.zip")) filename += ".sql.zip";
|
||||||
Mouse.OverrideCursor = Cursors.Wait;
|
Mouse.OverrideCursor = Cursors.Wait;
|
||||||
@@ -177,22 +178,7 @@ namespace Elwig.Windows {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async void Menu_Database_Restore_Click(object sender, RoutedEventArgs evt) {
|
private async void Menu_Database_Restore_Click(object sender, RoutedEventArgs evt) {
|
||||||
try {
|
await BackupService.RestoreDatabase();
|
||||||
var d = new OpenFileDialog() {
|
|
||||||
Title = "Datenbank wiederherstellen - Elwig",
|
|
||||||
DefaultExt = "sql.zip",
|
|
||||||
Filter = "SQLite-Datenbank (*.sqlite3, *.sqlite3.zip, *.sql, *.sql.zip)|*.sqlite3;*.sqlite3.zip;*.sql;*.sql.zip",
|
|
||||||
};
|
|
||||||
if (d.ShowDialog() == true) {
|
|
||||||
if (!InteractionService.AskContinue("Datenbank wiederherstellen", "Soll die Datenbank wirklich unwiederruflich durch die wiederhergestellte Version ersetzt werden?"))
|
|
||||||
return;
|
|
||||||
Mouse.OverrideCursor = Cursors.Wait;
|
|
||||||
await App.ReplaceDatabase(d.FileName);
|
|
||||||
}
|
|
||||||
} catch (Exception exc) {
|
|
||||||
InteractionService.ShowException(exc);
|
|
||||||
}
|
|
||||||
Mouse.OverrideCursor = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void SyncButton_Click(object sender, RoutedEventArgs evt) {
|
private async void SyncButton_Click(object sender, RoutedEventArgs evt) {
|
||||||
@@ -200,8 +186,13 @@ namespace Elwig.Windows {
|
|||||||
return;
|
return;
|
||||||
Mouse.OverrideCursor = Cursors.Wait;
|
Mouse.OverrideCursor = Cursors.Wait;
|
||||||
await Task.Run(async () => {
|
await Task.Run(async () => {
|
||||||
await SyncService.Download(App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
|
if (App.Config.SyncMain) {
|
||||||
await SyncService.UploadModified(App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
|
await SyncService.Download(App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword, true);
|
||||||
|
await SyncService.UploadModified(App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
|
||||||
|
} else {
|
||||||
|
await SyncService.Download(App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword, false);
|
||||||
|
await SyncService.UploadBranchDeliveries(App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
Mouse.OverrideCursor = null;
|
Mouse.OverrideCursor = null;
|
||||||
}
|
}
|
||||||
@@ -211,7 +202,7 @@ namespace Elwig.Windows {
|
|||||||
return;
|
return;
|
||||||
Mouse.OverrideCursor = Cursors.Wait;
|
Mouse.OverrideCursor = Cursors.Wait;
|
||||||
await Task.Run(async () => {
|
await Task.Run(async () => {
|
||||||
await SyncService.Download(App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
|
await SyncService.Download(App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword, App.Config.SyncMain);
|
||||||
});
|
});
|
||||||
Mouse.OverrideCursor = null;
|
Mouse.OverrideCursor = null;
|
||||||
}
|
}
|
||||||
@@ -229,6 +220,10 @@ namespace Elwig.Windows {
|
|||||||
private async void Menu_Sync_UploadModified_Click(object sender, RoutedEventArgs evt) {
|
private async void Menu_Sync_UploadModified_Click(object sender, RoutedEventArgs evt) {
|
||||||
if (App.Config.SyncUrl == null)
|
if (App.Config.SyncUrl == null)
|
||||||
return;
|
return;
|
||||||
|
if (!App.Config.SyncMain) {
|
||||||
|
InteractionService.ShowInformation("Mitglieder und Lieferungen hochladen", "Hochladen nicht möglich: Dieses Gerät ist nicht das Hauptgerät!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
Mouse.OverrideCursor = Cursors.Wait;
|
Mouse.OverrideCursor = Cursors.Wait;
|
||||||
await Task.Run(async () => {
|
await Task.Run(async () => {
|
||||||
await SyncService.UploadModified(App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
|
await SyncService.UploadModified(App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
|
||||||
@@ -296,6 +291,11 @@ namespace Elwig.Windows {
|
|||||||
if (App.Config.SyncUrl == null)
|
if (App.Config.SyncUrl == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (!App.Config.SyncMain) {
|
||||||
|
InteractionService.ShowInformation("Datenbank hochladen", "Hochladen nicht möglich: Dieses Gerät ist nicht das Hauptgerät!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!InteractionService.AskContinue("Datenbank hochladen", "Sind Sie wirklich sicher, dass Sie die Datenbank dieses\nGerätes hochladen möchten? Das sollte nur vom Hauptgerät aus passieren!"))
|
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!"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -367,7 +367,11 @@ namespace Elwig.Windows {
|
|||||||
await Task.Delay(delay);
|
await Task.Delay(delay);
|
||||||
var ch = false;
|
var ch = false;
|
||||||
using (var ctx = new AppDbContext()) {
|
using (var ctx = new AppDbContext()) {
|
||||||
ch = await SyncService.ChangesAvailable(ctx, App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
|
if (App.Config.SyncMain) {
|
||||||
|
ch = await SyncService.ChangesAvailable(ctx, App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
|
||||||
|
} else {
|
||||||
|
ch = await SyncService.ChangesAvailable(ctx, App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword, default);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
await App.MainDispatcher.BeginInvoke(() => {
|
await App.MainDispatcher.BeginInvoke(() => {
|
||||||
if (ch) {
|
if (ch) {
|
||||||
@@ -520,9 +524,11 @@ namespace Elwig.Windows {
|
|||||||
App.HintContextChange();
|
App.HintContextChange();
|
||||||
|
|
||||||
using var ctx = new AppDbContext();
|
using var ctx = new AppDbContext();
|
||||||
var tbl = await MemberAreaComsData.ForSeason(ctx.MemberAreaComsRows, year);
|
var tbl1 = await MemberAreaComTotalsData.ForSeason(ctx.MemberAreaComTotalsRows, year);
|
||||||
|
var tbl2 = await MemberAreaComsData.ForSeason(ctx.MemberAreaComsRows, year);
|
||||||
using var ods = new OdsFile(filename);
|
using var ods = new OdsFile(filename);
|
||||||
await ods.AddTable(tbl);
|
await ods.AddTable(tbl1);
|
||||||
|
await ods.AddTable(tbl2);
|
||||||
} catch (Exception exc) {
|
} catch (Exception exc) {
|
||||||
InteractionService.ShowException(exc);
|
InteractionService.ShowException(exc);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +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="{Binding Title}" Height="700" Width="1250" MinHeight="650" MinWidth="1150">
|
||||||
<Window.DataContext>
|
<Window.DataContext>
|
||||||
<vm:MemberAdminViewModel/>
|
<vm:MemberAdminViewModel/>
|
||||||
</Window.DataContext>
|
</Window.DataContext>
|
||||||
@@ -371,7 +371,7 @@
|
|||||||
<Label Content="Adresse:" Margin="10,130,0,0"/>
|
<Label Content="Adresse:" Margin="10,130,0,0"/>
|
||||||
<TextBox x:Name="AddressInput" Text="{Binding Address, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
<TextBox x:Name="AddressInput" Text="{Binding Address, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||||
Margin="0,130,10,0" Grid.Column="1" Grid.ColumnSpan="3"
|
Margin="0,130,10,0" Grid.Column="1" Grid.ColumnSpan="3"
|
||||||
TextChanged="TextBox_TextChanged"/>
|
TextChanged="AddressInput_TextChanged"/>
|
||||||
|
|
||||||
<Label Content="PLZ/Ort:" Margin="10,160,0,0" Grid.Column="0"/>
|
<Label Content="PLZ/Ort:" Margin="10,160,0,0" Grid.Column="0"/>
|
||||||
<TextBox x:Name="PlzInput" Margin="0,160,0,0" Text="{Binding PlzString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
<TextBox x:Name="PlzInput" Margin="0,160,0,0" Text="{Binding PlzString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||||
@@ -379,6 +379,7 @@
|
|||||||
TextChanged="PlzInput_TextChanged" LostFocus="PlzInput_LostFocus" Tag="PLZ"/>
|
TextChanged="PlzInput_TextChanged" LostFocus="PlzInput_LostFocus" Tag="PLZ"/>
|
||||||
<ComboBox x:Name="OrtInput" SelectedItem="{Binding Ort, Mode=TwoWay}" ItemsSource="{Binding OrtSource, Mode=TwoWay}"
|
<ComboBox x:Name="OrtInput" SelectedItem="{Binding Ort, Mode=TwoWay}" ItemsSource="{Binding OrtSource, Mode=TwoWay}"
|
||||||
ItemTemplate="{StaticResource PostalDestTemplate}" TextSearch.TextPath="Ort.Name"
|
ItemTemplate="{StaticResource PostalDestTemplate}" TextSearch.TextPath="Ort.Name"
|
||||||
|
SelectionChanged="OrtInput_SelectionChanged"
|
||||||
Margin="47,160,10,0" Grid.Column="1" Grid.ColumnSpan="3"/>
|
Margin="47,160,10,0" Grid.Column="1" Grid.ColumnSpan="3"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
</GroupBox>
|
</GroupBox>
|
||||||
@@ -547,35 +548,48 @@
|
|||||||
<GroupBox Header="Betrieb" Grid.Column="1" Grid.Row="0" Grid.RowSpan="1" Margin="5,5,5,5">
|
<GroupBox Header="Betrieb" Grid.Column="1" Grid.Row="0" Grid.RowSpan="1" Margin="5,5,5,5">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="90"/>
|
<ColumnDefinition Width="85"/>
|
||||||
<ColumnDefinition Width="150"/>
|
<ColumnDefinition Width="69"/>
|
||||||
<ColumnDefinition/>
|
<ColumnDefinition Width="*"/>
|
||||||
|
<ColumnDefinition Width="55"/>
|
||||||
|
<ColumnDefinition Width="101"/>
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
<Label Content="UID:" Margin="10,10,0,0" Grid.Column="0"/>
|
<Label Content="Betriebs-Nr.:" Margin="10,10,0,0" Grid.Column="0"/>
|
||||||
|
<TextBox x:Name="LfbisNrInput" Text="{Binding LfbisNr, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||||
|
Margin="0,10,5,0" Grid.Column="1" Width="64" HorizontalAlignment="Left" TextAlignment="Right"
|
||||||
|
TextChanged="LfbisNrInput_TextChanged" LostFocus="LfbisNrInput_LostFocus"/>
|
||||||
|
|
||||||
|
<Label Content="UID:" Margin="10,40,0,0" Grid.Column="0" ToolTip="USt-IdNr. / Umsatzsteuer-Identifikationsnummer"/>
|
||||||
<TextBox x:Name="UstIdNrInput" Text="{Binding UstIdNr, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
<TextBox x:Name="UstIdNrInput" Text="{Binding UstIdNr, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||||
Margin="0,10,10,0" Grid.Column="1" Width="96" HorizontalAlignment="Left"
|
Margin="0,40,5,0" Grid.Column="0" Grid.ColumnSpan="2" Width="96" HorizontalAlignment="Right"
|
||||||
TextChanged="UstIdNrInput_TextChanged" LostFocus="UstIdNrInput_LostFocus"/>
|
TextChanged="UstIdNrInput_TextChanged" LostFocus="UstIdNrInput_LostFocus"/>
|
||||||
|
|
||||||
<Label Content="Betriebs-Nr.:" Margin="10,40,0,0" Grid.Column="0"/>
|
<CheckBox x:Name="OrganicInput" Content="Bio" IsChecked="{Binding IsOrganic, Mode=TwoWay}" IsEnabled="False"
|
||||||
<TextBox x:Name="LfbisNrInput" Text="{Binding LfbisNr, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
Checked="OrganicInput_Changed" Unchecked="OrganicInput_Changed"
|
||||||
Margin="0,40,10,0" Grid.Column="1" Width="64" HorizontalAlignment="Left" TextAlignment="Right"
|
Grid.Column="2" HorizontalAlignment="Left" Margin="5,15,0,0" VerticalAlignment="Top"/>
|
||||||
TextChanged="LfbisNrInput_TextChanged" LostFocus="LfbisNrInput_LostFocus"/>
|
|
||||||
|
|
||||||
<CheckBox x:Name="BuchführendInput" Content="Buchführend" IsChecked="{Binding IsBuchführend, Mode=TwoWay}" IsEnabled="False"
|
<CheckBox x:Name="BuchführendInput" Content="Buchführend" IsChecked="{Binding IsBuchführend, Mode=TwoWay}" IsEnabled="False"
|
||||||
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"
|
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"
|
||||||
Grid.Column="2" HorizontalAlignment="Left" Margin="10,15,0,0" VerticalAlignment="Top"/>
|
Grid.Column="2" HorizontalAlignment="Left" Margin="5,45,0,0" VerticalAlignment="Top"/>
|
||||||
|
|
||||||
<CheckBox x:Name="OrganicInput" Content="Bio" IsChecked="{Binding IsOrganic, Mode=TwoWay}" IsEnabled="False"
|
<Label Content="Kontrollstelle:" Margin="0,10,5,0" Grid.Column="2" Grid.ColumnSpan="2" HorizontalAlignment="Right" ToolTip="Bio-Kontrollstelle"/>
|
||||||
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"
|
<TextBox x:Name="OrganicAuthorityCodeInput" Text="{Binding OrganicAuthorityCode, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||||
Grid.Column="2" HorizontalAlignment="Left" Margin="10,45,0,0" VerticalAlignment="Top"/>
|
Margin="0,10,10,0" Grid.Column="4" Width="91" HorizontalAlignment="Left"
|
||||||
<Button x:Name="OrganicButton" Content="easy-cert.com" IsEnabled="{Binding IsMemberSelected}"
|
TextChanged="OrganicAuthorityCodeInput_TextChanged" LostFocus="OrganicAuthorityCodeInput_LostFocus"/>
|
||||||
Height="25" FontSize="12"
|
|
||||||
Click="OrganicButton_Click"
|
<Label Content="OOC-ID:" Margin="0,40,0,0" Grid.Column="3" HorizontalAlignment="Left" ToolTip="Bio-EU-Operator-ID / Organic Operator Certificate ID"/>
|
||||||
Grid.Column="2" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="60,40,0,0"/>
|
<TextBox x:Name="OrganicOperatorIdInput" Text="{Binding OrganicOperatorId, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||||
|
Margin="0,40,10,0" Grid.Column="4" Width="91" HorizontalAlignment="Left"
|
||||||
|
TextChanged="OrganicOperatorIdInput_TextChanged" LostFocus="OrganicOperatorIdInput_LostFocus"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
</GroupBox>
|
</GroupBox>
|
||||||
<GroupBox Header="Rechnungsadresse (optional)" Grid.Column="1" Grid.Row="1" Grid.RowSpan="2" Margin="5,5,5,5">
|
<GroupBox Grid.Column="1" Grid.Row="1" Grid.RowSpan="2" Margin="5,5,5,5">
|
||||||
|
<GroupBox.Header>
|
||||||
|
<TextBlock>Rechnungsadresse (optional)
|
||||||
|
<Run FontSize="10">für Lieferschein, Anlfrg.-Bstng., Tr.-Gutschr.</Run>
|
||||||
|
</TextBlock>
|
||||||
|
</GroupBox.Header>
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="65"/>
|
<ColumnDefinition Width="65"/>
|
||||||
@@ -590,7 +604,7 @@
|
|||||||
<Label Content="Adresse:" Margin="10,40,0,0" Grid.Column="0"/>
|
<Label Content="Adresse:" Margin="10,40,0,0" Grid.Column="0"/>
|
||||||
<TextBox x:Name="BillingAddressInput" Text="{Binding BillingAddress, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
<TextBox x:Name="BillingAddressInput" Text="{Binding BillingAddress, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||||
Margin="0,40,10,0" Grid.Column="1"
|
Margin="0,40,10,0" Grid.Column="1"
|
||||||
TextChanged="TextBox_TextChanged"/>
|
TextChanged="AddressInput_TextChanged"/>
|
||||||
|
|
||||||
<Label Content="PLZ/Ort:" Margin="10,70,0,0" Grid.Column="0"/>
|
<Label Content="PLZ/Ort:" Margin="10,70,0,0" Grid.Column="0"/>
|
||||||
<TextBox x:Name="BillingPlzInput" Text="{Binding BillingPlzString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
<TextBox x:Name="BillingPlzInput" Text="{Binding BillingPlzString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||||
@@ -598,6 +612,7 @@
|
|||||||
TextChanged="PlzInput_TextChanged" LostFocus="PlzInput_LostFocus" Tag="PLZ"/>
|
TextChanged="PlzInput_TextChanged" LostFocus="PlzInput_LostFocus" Tag="PLZ"/>
|
||||||
<ComboBox x:Name="BillingOrtInput" SelectedItem="{Binding BillingOrt, Mode=TwoWay}" ItemsSource="{Binding BillingOrtSource, Mode=TwoWay}"
|
<ComboBox x:Name="BillingOrtInput" SelectedItem="{Binding BillingOrt, Mode=TwoWay}" ItemsSource="{Binding BillingOrtSource, Mode=TwoWay}"
|
||||||
ItemTemplate="{StaticResource PostalDestTemplate}" TextSearch.TextPath="Ort.Name"
|
ItemTemplate="{StaticResource PostalDestTemplate}" TextSearch.TextPath="Ort.Name"
|
||||||
|
SelectionChanged="OrtInput_SelectionChanged"
|
||||||
Margin="47,70,10,0" Grid.Column="1"/>
|
Margin="47,70,10,0" Grid.Column="1"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
</GroupBox>
|
</GroupBox>
|
||||||
@@ -605,7 +620,8 @@
|
|||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="120"/>
|
<ColumnDefinition Width="120"/>
|
||||||
<ColumnDefinition Width="120"/>
|
<ColumnDefinition Width="90"/>
|
||||||
|
<ColumnDefinition Width="90"/>
|
||||||
<ColumnDefinition/>
|
<ColumnDefinition/>
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
@@ -619,7 +635,7 @@
|
|||||||
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="BH-Konto:" Margin="10,70,0,0" Grid.Column="0"/>
|
<Label Content="BH-Konto:" Margin="10,70,0,0" Grid.Column="0" ToolTip="Buchhaltungskonto"/>
|
||||||
<TextBox x:Name="AccountingNrInput" Text="{Binding AccountingNr, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
<TextBox x:Name="AccountingNrInput" Text="{Binding AccountingNr, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||||
Margin="0,70,10,0" Width="63" Grid.Column="1" HorizontalAlignment="Left"
|
Margin="0,70,10,0" Width="63" Grid.Column="1" HorizontalAlignment="Left"
|
||||||
TextChanged="TextBox_TextChanged"/>
|
TextChanged="TextBox_TextChanged"/>
|
||||||
@@ -642,46 +658,64 @@
|
|||||||
|
|
||||||
<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="0,15,0,0" VerticalAlignment="Top"/>
|
||||||
|
|
||||||
<CheckBox x:Name="VollLieferantInput" Content="Volllieferant" IsChecked="{Binding IsVollLieferant, Mode=TwoWay}" IsEnabled="False"
|
<CheckBox x:Name="VollLieferantInput" Content="Volllieferant" IsChecked="{Binding IsVollLieferant, Mode=TwoWay}" IsEnabled="False"
|
||||||
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"
|
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"
|
||||||
Grid.Column="2" HorizontalAlignment="Left" Margin="10,45,0,0" VerticalAlignment="Top"/>
|
Grid.Column="2" HorizontalAlignment="Left" Margin="0,45,0,0" VerticalAlignment="Top"/>
|
||||||
|
|
||||||
<CheckBox x:Name="FunkionärInput" Content="Funktionär" IsChecked="{Binding IsFunktionär, Mode=TwoWay}" IsEnabled="False"
|
<CheckBox x:Name="FunkionärInput" Content="Funktionär" IsChecked="{Binding IsFunktionär, Mode=TwoWay}" IsEnabled="False"
|
||||||
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"
|
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"
|
||||||
Grid.Column="2" HorizontalAlignment="Left" Margin="10,75,0,0" VerticalAlignment="Top"/>
|
Grid.Column="2" HorizontalAlignment="Left" Margin="0,75,0,0" VerticalAlignment="Top"/>
|
||||||
|
|
||||||
|
<Label Content="Bio-Zertifikate:" Margin="0,-2.5,20,0" Grid.Column="3" HorizontalAlignment="Right"/>
|
||||||
|
<Button x:Name="OrganicTracesButton" IsEnabled="{Binding IsMemberSelectedOrCreating}" ToolTip="{Binding OrganicToolTip}"
|
||||||
|
Click="OrganicTracesButton_Click"
|
||||||
|
HorizontalAlignment="Right" Margin="0,20,10,0" Width="100" Padding="0" Height="35" VerticalAlignment="Top" Grid.Column="2" Grid.ColumnSpan="2" HorizontalContentAlignment="Stretch">
|
||||||
|
<StackPanel Orientation="Vertical">
|
||||||
|
<TextBlock FontSize="12" TextAlignment="Center" VerticalAlignment="Top" Margin="0,0,0,-3">EU TRACES</TextBlock>
|
||||||
|
<TextBlock FontSize="10" TextAlignment="Center" VerticalAlignment="Bottom" Margin="0,0,0,0">
|
||||||
|
<Run Text="{Binding OrganicState}" FontWeight="Bold" Foreground="{Binding OrganicColor}"/><Run Text="{Binding OrganicDetails}"/>
|
||||||
|
</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
<Button x:Name="OrganicEasyCertButton" IsEnabled="{Binding IsMemberSelectedOrCreating}" Content="Easy-Cert"
|
||||||
|
Click="OrganicEasyCertButton_Click"
|
||||||
|
HorizontalAlignment="Right" Margin="0,60,10,0" Width="100" Height="30" VerticalAlignment="Top" Grid.Column="2" Grid.ColumnSpan="2"/>
|
||||||
|
<Button x:Name="OrganicBiocButton" IsEnabled="{Binding IsMemberSelectedOrCreating}" Content="BioC"
|
||||||
|
Click="OrganicBiocButton_Click"
|
||||||
|
HorizontalAlignment="Right" Margin="0,95,10,0" Width="100" Height="30" VerticalAlignment="Top" Grid.Column="2" Grid.ColumnSpan="2"/>
|
||||||
|
|
||||||
<Label Content="Stamm-Zwst.:" Margin="10,130,0,0" Grid.Column="0"/>
|
<Label Content="Stamm-Zwst.:" Margin="10,130,0,0" Grid.Column="0"/>
|
||||||
<ComboBox x:Name="BranchInput" SelectedItem="{Binding Branch, Mode=TwoWay}" ItemsSource="{Binding BranchSource, Mode=TwoWay}"
|
<ComboBox x:Name="BranchInput" SelectedItem="{Binding Branch, Mode=TwoWay}" ItemsSource="{Binding BranchSource, Mode=TwoWay}"
|
||||||
DisplayMemberPath="Name" TextSearch.TextPath="Name"
|
DisplayMemberPath="Name" TextSearch.TextPath="Name"
|
||||||
Margin="0,130,10,0" Grid.Column="1" Grid.ColumnSpan="2"/>
|
Margin="0,130,10,0" Grid.Column="1" Grid.ColumnSpan="3"/>
|
||||||
|
|
||||||
<Label Content="Stammgemeinde:" Margin="10,160,0,0" Grid.Column="0"/>
|
<Label Content="Stammgemeinde:" Margin="10,160,0,0" Grid.Column="0"/>
|
||||||
<ComboBox x:Name="DefaultKgInput" SelectedItem="{Binding DefaultKg, Mode=TwoWay}" ItemsSource="{Binding DefaultKgSource, Mode=TwoWay}"
|
<ComboBox x:Name="DefaultKgInput" SelectedItem="{Binding DefaultKg, Mode=TwoWay}" ItemsSource="{Binding DefaultKgSource, Mode=TwoWay}"
|
||||||
DisplayMemberPath="Name" TextSearch.TextPath="Name"
|
DisplayMemberPath="Name" TextSearch.TextPath="Name"
|
||||||
Margin="0,160,40,10" Grid.Column="1" Grid.ColumnSpan="2"/>
|
Margin="0,160,40,10" Grid.Column="1" Grid.ColumnSpan="3"/>
|
||||||
<Button x:Name="KgDetailsButton" Content="" FontFamily="Segoe MDL2 Assets" FontSize="14" Padding="0,1,0,0"
|
<Button x:Name="KgDetailsButton" Content="" FontFamily="Segoe MDL2 Assets" FontSize="14" Padding="0,1,0,0"
|
||||||
Click="KgDetailsButton_Click"
|
Click="KgDetailsButton_Click"
|
||||||
Grid.Column="2" VerticalAlignment="Top" HorizontalAlignment="Right" Width="25" Height="25" Margin="10,160,10,10"/>
|
Grid.Column="3" VerticalAlignment="Top" HorizontalAlignment="Right" Width="25" Height="25" Margin="10,160,10,10"/>
|
||||||
|
|
||||||
<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" FontSize="12"
|
Margin="0,190,10,70" Grid.Column="1" Grid.ColumnSpan="3" 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"/>
|
||||||
|
|
||||||
<Label Content="Kontaktart:" Margin="10,10,0,40" Grid.Column="0" VerticalAlignment="Bottom"/>
|
<Label Content="Kontaktart:" Margin="10,10,0,40" Grid.Column="0" VerticalAlignment="Bottom"/>
|
||||||
<CheckBox x:Name="ContactPostalInput" Content="Post" IsChecked="{Binding ContactViaPost, Mode=TwoWay}" IsEnabled="False"
|
<CheckBox x:Name="ContactPostalInput" Content="Post" IsChecked="{Binding ContactViaPost, Mode=TwoWay}" IsEnabled="False"
|
||||||
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"
|
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"
|
||||||
HorizontalAlignment="Left" Margin="0,0,0,45" VerticalAlignment="Bottom" Grid.Column="1" Grid.ColumnSpan="2"/>
|
HorizontalAlignment="Left" Margin="0,0,0,45" VerticalAlignment="Bottom" Grid.Column="1" Grid.ColumnSpan="3"/>
|
||||||
<CheckBox x:Name="ContactEmailInput" Content="E-Mail" IsChecked="{Binding ContactViaEmail, Mode=TwoWay}" IsEnabled="False"
|
<CheckBox x:Name="ContactEmailInput" Content="E-Mail" IsChecked="{Binding ContactViaEmail, Mode=TwoWay}" IsEnabled="False"
|
||||||
Checked="ContactEmailInput_Changed" Unchecked="ContactEmailInput_Changed"
|
Checked="ContactEmailInput_Changed" Unchecked="ContactEmailInput_Changed"
|
||||||
HorizontalAlignment="Left" Margin="60,0,0,45" VerticalAlignment="Bottom" Grid.Column="1" Grid.ColumnSpan="2"/>
|
HorizontalAlignment="Left" Margin="60,0,0,45" VerticalAlignment="Bottom" Grid.Column="1" Grid.ColumnSpan="3"/>
|
||||||
|
|
||||||
<Label Content="Zuletzt geändert:" Margin="10,10,0,10" Grid.Column="0" VerticalAlignment="Bottom"/>
|
<Label Content="Zuletzt geändert:" Margin="10,10,0,10" Grid.Column="0" VerticalAlignment="Bottom"/>
|
||||||
<TextBlock x:Name="LastModified" Text="{Binding ModifiedAtShort}"
|
<TextBlock x:Name="LastModified" Text="{Binding ModifiedAtShort}"
|
||||||
Margin="0,10,0,15" Grid.Column="1" TextWrapping="NoWrap" VerticalAlignment="Bottom">
|
Margin="0,10,0,15" Grid.Column="1" Grid.ColumnSpan="2" TextWrapping="NoWrap" VerticalAlignment="Bottom">
|
||||||
<TextBlock.ToolTip>
|
<TextBlock.ToolTip>
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
@@ -706,12 +740,24 @@
|
|||||||
</TextBlock.ToolTip>
|
</TextBlock.ToolTip>
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
|
|
||||||
<Button x:Name="DeliveryButton" Content="Lieferungen" IsEnabled="{Binding IsMemberSelected}"
|
<Button x:Name="DeliveryButton" IsEnabled="{Binding IsMemberSelected}"
|
||||||
Click="DeliveryButton_Click"
|
Click="DeliveryButton_Click"
|
||||||
HorizontalAlignment="Right" Margin="10,00,10,37" Width="150" VerticalAlignment="Bottom" Grid.ColumnSpan="3"/>
|
HorizontalAlignment="Right" Margin="10,00,10,37" Width="160" VerticalAlignment="Bottom" Grid.ColumnSpan="4" HorizontalContentAlignment="Stretch">
|
||||||
<Button x:Name="AreaCommitmentButton" Content="Flächenbindungen" IsEnabled="{Binding IsMemberSelected}"
|
<Grid>
|
||||||
|
<TextBlock Margin="0,0,10,0" TextAlignment="Center">Lieferungen</TextBlock>
|
||||||
|
<TextBlock FontFamily="Segoe MDL2 Assets" FontSize="16" Text=""
|
||||||
|
TextAlignment="Left" HorizontalAlignment="Right" Padding="0,1.5,0,0" Margin="0,0,0,0"/>
|
||||||
|
</Grid>
|
||||||
|
</Button>
|
||||||
|
<Button x:Name="AreaCommitmentButton" IsEnabled="{Binding IsMemberSelected}"
|
||||||
Click="AreaCommitmentButton_Click"
|
Click="AreaCommitmentButton_Click"
|
||||||
HorizontalAlignment="Right" Margin="10,10,10,5" Width="150" VerticalAlignment="Bottom" Grid.ColumnSpan="3"/>
|
HorizontalAlignment="Right" Margin="10,10,10,5" Width="160" VerticalAlignment="Bottom" Grid.ColumnSpan="4" HorizontalContentAlignment="Stretch">
|
||||||
|
<Grid>
|
||||||
|
<TextBlock Margin="0,0,15,0" TextAlignment="Center">Flächenbindungen</TextBlock>
|
||||||
|
<TextBlock FontFamily="Segoe MDL2 Assets" FontSize="16" Text=""
|
||||||
|
TextAlignment="Left" HorizontalAlignment="Right" Padding="0,1.5,0,0" Margin="0,0,0,0"/>
|
||||||
|
</Grid>
|
||||||
|
</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
</GroupBox>
|
</GroupBox>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||
@@ -147,9 +147,9 @@ namespace Elwig.Windows {
|
|||||||
var cursor = Mouse.OverrideCursor != null;
|
var cursor = Mouse.OverrideCursor != null;
|
||||||
if (!cursor) Mouse.OverrideCursor = Cursors.Wait;
|
if (!cursor) Mouse.OverrideCursor = Cursors.Wait;
|
||||||
var query = (vm.SearchQuery, vm.ShowOnlyActiveMembers);
|
var query = (vm.SearchQuery, vm.ShowOnlyActiveMembers);
|
||||||
var (members, stat) = await Task.Run(async () => {
|
var (filterNames, members, stat, filter) = await Task.Run(async () => {
|
||||||
using var ctx = new AppDbContext();
|
using var ctx = new AppDbContext();
|
||||||
var (_, memberQuery, filter) = await vm.GetFilters(ctx);
|
var (filterNames, memberQuery, filter) = await vm.GetFilters(ctx);
|
||||||
var members = await memberQuery
|
var members = await memberQuery
|
||||||
.Include(m => m.EmailAddresses)
|
.Include(m => m.EmailAddresses)
|
||||||
.Include(m => m.TelephoneNumbers)
|
.Include(m => m.TelephoneNumbers)
|
||||||
@@ -184,11 +184,12 @@ namespace Elwig.Windows {
|
|||||||
SharesActive = g.Sum(m => m.Shares + m.SharesRed + m.SharesWhite),
|
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();
|
}).ToListAsync()).Select(g => (g.Count, g.Shares, g.SharesRed, g.SharesWhite, g.SharesDormant, g.SharesTotal, g.SharesActive)).ToList();
|
||||||
|
|
||||||
return (members, stat[0]);
|
return (filterNames, members, stat[0], filter);
|
||||||
});
|
});
|
||||||
if (!cursor) Mouse.OverrideCursor = null;
|
if (!cursor) Mouse.OverrideCursor = null;
|
||||||
if (query != (ViewModel.SearchQuery, ViewModel.ShowOnlyActiveMembers)) return;
|
if (query != (ViewModel.SearchQuery, ViewModel.ShowOnlyActiveMembers)) return;
|
||||||
|
|
||||||
|
ViewModel.Title = Utils.GetTitle("Mitglieder", filterNames, filter);
|
||||||
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)
|
||||||
@@ -502,6 +503,8 @@ namespace Elwig.Windows {
|
|||||||
UnlockInputs();
|
UnlockInputs();
|
||||||
UpdateContactInfoVisibility(true);
|
UpdateContactInfoVisibility(true);
|
||||||
ViewModel.EnableSearchInputs = false;
|
ViewModel.EnableSearchInputs = false;
|
||||||
|
|
||||||
|
UpdateOrganic();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void ShortcutDelete() {
|
protected override void ShortcutDelete() {
|
||||||
@@ -965,23 +968,13 @@ namespace Elwig.Windows {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OrganicButton_Click(object sender, RoutedEventArgs evt) {
|
|
||||||
if (ViewModel.SelectedMember is not Member m) return;
|
|
||||||
var url = "https://www.easy-cert.com/htm/suchergebnis.htm?" +
|
|
||||||
//$"CustomerNumber={m.LfbisNr}&" +
|
|
||||||
$"Name={(m.BillingAddress?.FullName ?? m.FullName).Replace(' ', '+')}&" +
|
|
||||||
$"PostalCode={(m.BillingAddress?.PostalDest ?? m.PostalDest).AtPlz?.Plz}";
|
|
||||||
Process.Start(new ProcessStartInfo(url) {
|
|
||||||
UseShellExecute = true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MemberReferenceButton_Click(object sender, RoutedEventArgs evt) {
|
private void MemberReferenceButton_Click(object sender, RoutedEventArgs evt) {
|
||||||
if (ViewModel.SelectedMember is not Member m || m.PredecessorMgNr == null) return;
|
if (ViewModel.SelectedMember is not Member m || m.PredecessorMgNr == null) return;
|
||||||
FocusMember((int)m.PredecessorMgNr);
|
FocusMember((int)m.PredecessorMgNr);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void ActiveInput_Changed(object sender, RoutedEventArgs evt) {
|
private async void ActiveInput_Changed(object sender, RoutedEventArgs evt) {
|
||||||
|
CheckBox_Changed(sender, evt);
|
||||||
if (MemberList.SelectedItem is not Member m)
|
if (MemberList.SelectedItem is not Member m)
|
||||||
return;
|
return;
|
||||||
if ((IsEditing || IsCreating) && ViewModel.IsActive == false && ViewModel.MgNr is int mgnr) {
|
if ((IsEditing || IsCreating) && ViewModel.IsActive == false && ViewModel.MgNr is int mgnr) {
|
||||||
@@ -996,7 +989,6 @@ namespace Elwig.Windows {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CheckBox_Changed(sender, evt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void JuridicalPersonInput_Changed(object sender, RoutedEventArgs evt) {
|
private void JuridicalPersonInput_Changed(object sender, RoutedEventArgs evt) {
|
||||||
@@ -1019,5 +1011,100 @@ namespace Elwig.Windows {
|
|||||||
ValidateRequiredInputs();
|
ValidateRequiredInputs();
|
||||||
UpdateButtons();
|
UpdateButtons();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
new protected void AddressInput_TextChanged(object sender, TextChangedEventArgs? evt) {
|
||||||
|
if ((IsCreating || IsEditing) && sender is TextBox b) {
|
||||||
|
InputTextChanged(b, (i, r) => Validator.CheckAddress(i, r, b == BillingAddressInput ? ViewModel.BillingOrt?.Ort.Name : ViewModel.Ort?.Ort.Name));
|
||||||
|
} else {
|
||||||
|
TextBox_TextChanged(sender, evt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OrtInput_SelectionChanged(object sender, SelectionChangedEventArgs? evt) {
|
||||||
|
if (!IsCreating && !IsEditing)
|
||||||
|
return;
|
||||||
|
if (sender == BillingOrtInput) {
|
||||||
|
InputTextChanged(BillingAddressInput, (i, r) => Validator.CheckAddress(i, r, ViewModel.BillingOrt?.Ort.Name));
|
||||||
|
} else {
|
||||||
|
InputTextChanged(AddressInput, (i, r) => Validator.CheckAddress(i, r, ViewModel.Ort?.Ort.Name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OrganicInput_Changed(object sender, RoutedEventArgs evt) {
|
||||||
|
CheckBox_Changed(sender, evt);
|
||||||
|
if (IsEditing || IsCreating) {
|
||||||
|
UpdateOrganic();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private new void LfbisNrInput_TextChanged(object sender, TextChangedEventArgs evt) {
|
||||||
|
base.LfbisNrInput_TextChanged(sender, evt);
|
||||||
|
if (IsEditing || IsCreating) {
|
||||||
|
UpdateOrganic();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateOrganic() {
|
||||||
|
if (!ViewModel.IsOrganic || string.IsNullOrWhiteSpace(ViewModel.LfbisNr) || !GetInputValid(LfbisNrInput)) {
|
||||||
|
ViewModel.OrganicState = null;
|
||||||
|
ViewModel.OrganicColor = Brushes.Black;
|
||||||
|
ViewModel.OrganicDetails = "-";
|
||||||
|
ViewModel.OrganicToolTip = null;
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
ViewModel.OrganicState = null;
|
||||||
|
ViewModel.OrganicColor = Brushes.Black;
|
||||||
|
ViewModel.OrganicToolTip = null;
|
||||||
|
ViewModel.OrganicDetails = "...";
|
||||||
|
var lfbisNr = ViewModel.LfbisNr;
|
||||||
|
Utils.RunBackground("Bio-Zertifikatsdaten laden", async () => {
|
||||||
|
if (App.MainDispatcher == null) return;
|
||||||
|
var certs = await OrganicService.FetchTracesCertificates(lfbisNr: lfbisNr);
|
||||||
|
await App.MainDispatcher.BeginInvoke(() => {
|
||||||
|
if (certs.Length == 0) {
|
||||||
|
ViewModel.FillOrganicInputs(null);
|
||||||
|
} else {
|
||||||
|
var cert = certs[0];
|
||||||
|
ViewModel.FillOrganicInputs(cert);
|
||||||
|
ViewModel.OrganicAuthorityCode = cert.AuthorityCode;
|
||||||
|
ViewModel.OrganicOperatorId = cert.OperatorId;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OrganicTracesButton_Click(object sender, RoutedEventArgs evt) {
|
||||||
|
string? url = null;
|
||||||
|
if ((IsCreating || IsEditing) && !string.IsNullOrWhiteSpace(ViewModel.LfbisNr) && GetInputValid(LfbisNrInput)) {
|
||||||
|
url = OrganicService.GetTracesSearchUrl(lfbisNr: ViewModel.LfbisNr);
|
||||||
|
} else if (ViewModel.SelectedMember is Member m) {
|
||||||
|
url = OrganicService.GetTracesSearchUrl(m);
|
||||||
|
}
|
||||||
|
if (url != null)
|
||||||
|
Process.Start(new ProcessStartInfo(url) { UseShellExecute = true });
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OrganicEasyCertButton_Click(object sender, RoutedEventArgs evt) {
|
||||||
|
string? url = null;
|
||||||
|
if ((IsCreating || IsEditing) && !string.IsNullOrWhiteSpace(ViewModel.LfbisNr) && GetInputValid(LfbisNrInput)) {
|
||||||
|
url = OrganicService.GetEasyCertSearchUrl(ViewModel.LfbisNr);
|
||||||
|
} else if (ViewModel.SelectedMember is Member m && m.LfbisNr != null) {
|
||||||
|
url = OrganicService.GetEasyCertSearchUrl(m.LfbisNr);
|
||||||
|
}
|
||||||
|
if (url != null)
|
||||||
|
Process.Start(new ProcessStartInfo(url) { UseShellExecute = true });
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OrganicBiocButton_Click(object sender, RoutedEventArgs evt) {
|
||||||
|
string? url = null;
|
||||||
|
if ((IsCreating || IsEditing) && !string.IsNullOrWhiteSpace(ViewModel.LfbisNr) && GetInputValid(LfbisNrInput)) {
|
||||||
|
url = OrganicService.GetBiocSearchUrl(ViewModel.LfbisNr);
|
||||||
|
} else if (ViewModel.SelectedMember is Member m && m.LfbisNr != null) {
|
||||||
|
url = OrganicService.GetBiocSearchUrl(m.LfbisNr);
|
||||||
|
}
|
||||||
|
if (url != null)
|
||||||
|
Process.Start(new ProcessStartInfo(url) { UseShellExecute = true });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -173,8 +173,11 @@
|
|||||||
Margin="0,100,10,0" Width="78" Grid.Column="1" HorizontalAlignment="Left" TextAlignment="Right"
|
Margin="0,100,10,0" Width="78" Grid.Column="1" HorizontalAlignment="Left" TextAlignment="Right"
|
||||||
TextChanged="DateNoticeInput_TextChanged" LostFocus="DateInput_LostFocus"/>
|
TextChanged="DateNoticeInput_TextChanged" LostFocus="DateInput_LostFocus"/>
|
||||||
|
|
||||||
|
<CheckBox x:Name="HasCompanySignedInput" IsChecked="{Binding CompanyHasSigned, Mode=TwoWay}" Content="Von WG unterfertigt"
|
||||||
|
Margin="88,105,10,0" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Top"
|
||||||
|
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"/>
|
||||||
<CheckBox x:Name="HasMemberSignedInput" IsChecked="{Binding MemberHasSigned, Mode=TwoWay}" Content="Von Mg. unterfertigt"
|
<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"
|
Margin="88,135,10,0" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Top"
|
||||||
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"/>
|
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"/>
|
||||||
|
|
||||||
<Label Content="Wirksam:" Margin="10,130,0,0" Grid.Column="0"/>
|
<Label Content="Wirksam:" Margin="10,130,0,0" Grid.Column="0"/>
|
||||||
|
|||||||
@@ -198,7 +198,7 @@ namespace Elwig.Windows {
|
|||||||
|
|
||||||
int mgnr;
|
int mgnr;
|
||||||
try {
|
try {
|
||||||
mgnr = await ViewModel.UpdateMemberHistory(ViewModel.SelectedHistoryEntry?.HistNr, IsEditing || ViewModel.DateNotice >= DateOnly.FromDateTime(Utils.Today).AddDays(-14));
|
mgnr = await ViewModel.UpdateMemberHistory(ViewModel.SelectedHistoryEntry?.HistNr, IsEditing || ViewModel.DateNotice >= DateOnly.FromDateTime(DateTime.Today).AddDays(-14));
|
||||||
App.HintContextChange();
|
App.HintContextChange();
|
||||||
} catch (Exception exc) {
|
} catch (Exception exc) {
|
||||||
InteractionService.ShowDbException("Geschäftsanteilbewegung aktualisieren", exc);
|
InteractionService.ShowDbException("Geschäftsanteilbewegung aktualisieren", exc);
|
||||||
|
|||||||
@@ -7,7 +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="Auszahlungsvarianten - Elwig" Height="480" Width="850" MinHeight="400" MinWidth="850">
|
Title="Auszahlungsvarianten - Elwig" Height="480" Width="850" MinHeight="430" MinWidth="850">
|
||||||
<Window.DataContext>
|
<Window.DataContext>
|
||||||
<vm:PaymentVariantsViewModel/>
|
<vm:PaymentVariantsViewModel/>
|
||||||
</Window.DataContext>
|
</Window.DataContext>
|
||||||
@@ -195,11 +195,10 @@
|
|||||||
Content="Benutzerdefinierte Zu-/Abschläge pro Mitglied"
|
Content="Benutzerdefinierte Zu-/Abschläge pro Mitglied"
|
||||||
Margin="110,175,10,10" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Top"
|
Margin="110,175,10,10" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Top"
|
||||||
Checked="ConsiderCustomInput_Changed" Unchecked="ConsiderCustomInput_Changed"/>
|
Checked="ConsiderCustomInput_Changed" Unchecked="ConsiderCustomInput_Changed"/>
|
||||||
<Label Content="" FontFamily="Segoe MDL2 Assets" FontSize="16" Grid.Row="0" Grid.Column="1" Margin="108,195,10,10"/>
|
|
||||||
|
|
||||||
<Grid Grid.Column="0" Grid.ColumnSpan="2" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="50,200,10,10">
|
<Grid Grid.Column="0" Grid.ColumnSpan="2" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="50,200,10,10">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="110"/>
|
<ColumnDefinition Width="130"/>
|
||||||
<ColumnDefinition Width="27"/>
|
<ColumnDefinition Width="27"/>
|
||||||
<ColumnDefinition Width="110"/>
|
<ColumnDefinition Width="110"/>
|
||||||
<ColumnDefinition Width="27"/>
|
<ColumnDefinition Width="27"/>
|
||||||
@@ -207,7 +206,7 @@
|
|||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="27"/>
|
<RowDefinition Height="27"/>
|
||||||
<RowDefinition Height="5"/>
|
<RowDefinition Height="37"/>
|
||||||
<RowDefinition Height="27"/>
|
<RowDefinition Height="27"/>
|
||||||
<RowDefinition Height="5"/>
|
<RowDefinition Height="5"/>
|
||||||
<RowDefinition Height="27"/>
|
<RowDefinition Height="27"/>
|
||||||
@@ -227,11 +226,23 @@
|
|||||||
</Grid.Resources>
|
</Grid.Resources>
|
||||||
|
|
||||||
<Button x:Name="EditButton" IsEnabled="{Binding IsPaymentVariantSelected}"
|
<Button x:Name="EditButton" IsEnabled="{Binding IsPaymentVariantSelected}"
|
||||||
Content="{Binding EditText}" Grid.Column="0" Grid.Row="2"
|
Grid.Column="0" Grid.Row="2" HorizontalContentAlignment="Stretch"
|
||||||
Click="EditButton_Click"/>
|
Click="EditButton_Click">
|
||||||
|
<Grid>
|
||||||
|
<TextBlock Margin="0,0,13,0" TextAlignment="Center" Text="{Binding EditText}"/>
|
||||||
|
<TextBlock FontFamily="Segoe MDL2 Assets" FontSize="16" Text=""
|
||||||
|
TextAlignment="Left" HorizontalAlignment="Right" Padding="0,1.5,0,0" Margin="0,0,5,0"/>
|
||||||
|
</Grid>
|
||||||
|
</Button>
|
||||||
<Label Content="" FontFamily="Segoe MDL2 Assets" FontSize="16" Grid.Row="2" Grid.Column="1"/>
|
<Label Content="" FontFamily="Segoe MDL2 Assets" FontSize="16" Grid.Row="2" Grid.Column="1"/>
|
||||||
<Button x:Name="ModifierButton" Content="Zu-/Abschläge" Grid.Column="0" Grid.Row="4"
|
<Button x:Name="ModifierButton" Grid.Column="0" Grid.Row="4" HorizontalContentAlignment="Stretch"
|
||||||
Click="ModifierButton_Click"/>
|
Click="ModifierButton_Click">
|
||||||
|
<Grid>
|
||||||
|
<TextBlock Margin="0,0,15,0" TextAlignment="Center">Zu-/Abschläge</TextBlock>
|
||||||
|
<TextBlock FontFamily="Segoe MDL2 Assets" FontSize="16" Text=""
|
||||||
|
TextAlignment="Left" HorizontalAlignment="Right" Padding="0,1.5,0,0" Margin="0,0,5,0"/>
|
||||||
|
</Grid>
|
||||||
|
</Button>
|
||||||
<Label Content="" FontFamily="Segoe MDL2 Assets" FontSize="16" Grid.Row="4" Grid.Column="1" RenderTransformOrigin="0.5,0.5" >
|
<Label Content="" FontFamily="Segoe MDL2 Assets" FontSize="16" Grid.Row="4" Grid.Column="1" RenderTransformOrigin="0.5,0.5" >
|
||||||
<Label.RenderTransform>
|
<Label.RenderTransform>
|
||||||
<TransformGroup>
|
<TransformGroup>
|
||||||
@@ -244,8 +255,14 @@
|
|||||||
Content="Berechnen" Grid.Column="2" Grid.Row="2"
|
Content="Berechnen" Grid.Column="2" Grid.Row="2"
|
||||||
Click="CalculateButton_Click"/>
|
Click="CalculateButton_Click"/>
|
||||||
<Label Content="{Binding Arrow}" FontFamily="Segoe MDL2 Assets" FontSize="16" Grid.Row="2" Grid.Column="3"/>
|
<Label Content="{Binding Arrow}" FontFamily="Segoe MDL2 Assets" FontSize="16" Grid.Row="2" Grid.Column="3"/>
|
||||||
<Button x:Name="PaymentAdjustmentButton" Content="Anpassen" Grid.Column="2" Grid.Row="4"
|
<Button x:Name="PaymentAdjustmentButton" Grid.Column="2" Grid.Row="4" HorizontalContentAlignment="Stretch"
|
||||||
Click="PaymentAdjustmentButton_Click"/>
|
Click="PaymentAdjustmentButton_Click">
|
||||||
|
<Grid>
|
||||||
|
<TextBlock Margin="0,0,13,0" TextAlignment="Center">Anpassen</TextBlock>
|
||||||
|
<TextBlock FontFamily="Segoe MDL2 Assets" FontSize="16" Text=""
|
||||||
|
TextAlignment="Left" HorizontalAlignment="Right" Padding="0,1.5,0,0" Margin="0,0,5,0"/>
|
||||||
|
</Grid>
|
||||||
|
</Button>
|
||||||
<Label Content="{Binding Arrow}" FontFamily="Segoe MDL2 Assets" FontSize="16" Grid.Row="4" Grid.Column="3" RenderTransformOrigin="0.5,0.5" >
|
<Label Content="{Binding Arrow}" FontFamily="Segoe MDL2 Assets" FontSize="16" Grid.Row="4" Grid.Column="3" RenderTransformOrigin="0.5,0.5" >
|
||||||
<Label.RenderTransform>
|
<Label.RenderTransform>
|
||||||
<TransformGroup>
|
<TransformGroup>
|
||||||
@@ -261,7 +278,7 @@
|
|||||||
Content="Freigeben" Grid.Column="4" Grid.Row="2"
|
Content="Freigeben" Grid.Column="4" Grid.Row="2"
|
||||||
Click="RevertButton_Click"/>
|
Click="RevertButton_Click"/>
|
||||||
<Button x:Name="SaveButton" IsEnabled="{Binding SaveIsEnabled}"
|
<Button x:Name="SaveButton" IsEnabled="{Binding SaveIsEnabled}"
|
||||||
Content="Speichern" Grid.Column="4" Grid.Row="0"
|
Content="Speichern" Grid.Column="2" Grid.Row="0"
|
||||||
Click="SaveButton_Click"/>
|
Click="SaveButton_Click"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using Elwig.Services;
|
|||||||
using Elwig.ViewModels;
|
using Elwig.ViewModels;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
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;
|
||||||
@@ -239,15 +240,27 @@ namespace Elwig.Windows {
|
|||||||
private async void SaveButton_Click(object sender, RoutedEventArgs evt) {
|
private async void SaveButton_Click(object sender, RoutedEventArgs evt) {
|
||||||
if (PaymentVariantList.SelectedItem is not PaymentVar v || ViewModel.BillingData == null)
|
if (PaymentVariantList.SelectedItem is not PaymentVar v || ViewModel.BillingData == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Mouse.OverrideCursor = Cursors.Wait;
|
Mouse.OverrideCursor = Cursors.Wait;
|
||||||
try {
|
try {
|
||||||
await ViewModel.UpdatePaymentVariant(v.Year, v.AvNr);
|
await ViewModel.UpdatePaymentVariant(v.Year, v.AvNr);
|
||||||
App.HintContextChange();
|
|
||||||
} catch (Exception exc) {
|
} catch (Exception exc) {
|
||||||
await ForceContextReload();
|
await ForceContextReload();
|
||||||
InteractionService.ShowDbException("Auszahlungsvariante aktualisieren", exc);
|
InteractionService.ShowDbException("Auszahlungsvariante aktualisieren", exc);
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
await Task.Run(async () => {
|
||||||
|
var b = await BillingVariant.Create(v.Year, v.AvNr);
|
||||||
|
await b.Calculate(false);
|
||||||
|
});
|
||||||
|
} catch (KeyNotFoundException exc) {
|
||||||
|
InteractionService.ShowInformation("Noch nicht alle Preise festgelegt", exc.Message);
|
||||||
|
} catch (Exception exc) {
|
||||||
|
InteractionService.ShowException("Berechnungsfehler", exc);
|
||||||
|
}
|
||||||
|
App.HintContextChange();
|
||||||
Mouse.OverrideCursor = null;
|
Mouse.OverrideCursor = null;
|
||||||
|
|
||||||
await EnsureContextRenewed();
|
await EnsureContextRenewed();
|
||||||
CommentInput_TextChanged(null, null);
|
CommentInput_TextChanged(null, null);
|
||||||
DateInput_TextChanged(null, null);
|
DateInput_TextChanged(null, null);
|
||||||
|
|||||||
@@ -13,5 +13,6 @@ Data and configuration folder
|
|||||||
C:\ProgramData\Elwig\
|
C:\ProgramData\Elwig\
|
||||||
- config.ini : main configuration file
|
- config.ini : main configuration file
|
||||||
- database.sqlite3 : stores all data
|
- database.sqlite3 : stores all data
|
||||||
|
- backups\ : (automatic) backups of the database
|
||||||
- imported.txt : list of all imported *.elwig.zip files to not automatically import them again
|
- imported.txt : list of all imported *.elwig.zip files to not automatically import them again
|
||||||
- mails\ : sent/outgoing email log
|
- mails\ : sent/outgoing email log
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
; Only needed, if more than one branch is stored in database
|
; Only needed, if more than one branch is stored in database
|
||||||
;branch = Zweigstelle
|
;branch = Zweigstelle
|
||||||
;debug = true
|
;debug = true
|
||||||
|
;weighing = gross ; gross/net/box
|
||||||
|
|
||||||
[database]
|
[database]
|
||||||
; Relative or absolute path to database file
|
; Relative or absolute path to database file
|
||||||
@@ -10,6 +11,14 @@ file = database.sqlite3
|
|||||||
; Enables database logging
|
; Enables database logging
|
||||||
;log = db.log
|
;log = db.log
|
||||||
|
|
||||||
|
[backup]
|
||||||
|
;auto = false
|
||||||
|
;path = backups
|
||||||
|
;retain_hours = 36
|
||||||
|
;retain_days = 8
|
||||||
|
;retain_weeks = 6
|
||||||
|
;retain_months = 18
|
||||||
|
|
||||||
[update]
|
[update]
|
||||||
url = https://elwig.at/files/elwig/latest
|
url = https://elwig.at/files/elwig/latest
|
||||||
auto = true
|
auto = true
|
||||||
@@ -26,6 +35,7 @@ auto = true
|
|||||||
;username = ""
|
;username = ""
|
||||||
;password = ""
|
;password = ""
|
||||||
;from = mail@wg.at
|
;from = mail@wg.at
|
||||||
|
;wait = 0.5
|
||||||
|
|
||||||
;[scale.1]
|
;[scale.1]
|
||||||
;type = SysTec-IT
|
;type = SysTec-IT
|
||||||
@@ -37,6 +47,8 @@ auto = true
|
|||||||
;limit = 3500
|
;limit = 3500
|
||||||
; Enables scale logging
|
; Enables scale logging
|
||||||
;log = waage.log
|
;log = waage.log
|
||||||
|
; Opt-out of auto time synchronization at startup
|
||||||
|
;synctime = false
|
||||||
|
|
||||||
;[scale.B]
|
;[scale.B]
|
||||||
;type = Avery-Async
|
;type = Avery-Async
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ About
|
|||||||
**Product:** Elwig
|
**Product:** Elwig
|
||||||
**Description:** Electronic Management for Vintners' Cooperatives
|
**Description:** Electronic Management for Vintners' Cooperatives
|
||||||
**Type:** ERP system
|
**Type:** ERP system
|
||||||
**Version:** 1.1.0.0 ([Changelog](./CHANGELOG.md))
|
**Version:** 1.1.2.2 ([Changelog](./CHANGELOG.md))
|
||||||
**License:** [GNU General Public License 3.0 (GPLv3)](./LICENSE)
|
**License:** [GNU General Public License 3.0 (GPLv3)](./LICENSE)
|
||||||
**Website:** https://elwig.at/
|
**Website:** https://elwig.at/
|
||||||
**Source code:** https://git.necronda.net/winzer/elwig
|
**Source code:** https://git.necronda.net/winzer/elwig
|
||||||
@@ -33,7 +33,7 @@ Packaging: [WiX Toolset](https://www.firegiant.com/wixtoolset/)
|
|||||||
**Produkt:** Elwig
|
**Produkt:** Elwig
|
||||||
**Beschreibung:** Elektronische Winzergenossenschaftsverwaltung
|
**Beschreibung:** Elektronische Winzergenossenschaftsverwaltung
|
||||||
**Typ:** Warenwirtschaftssystem (ERP-System)
|
**Typ:** Warenwirtschaftssystem (ERP-System)
|
||||||
**Version:** 1.1.0.0 ([Änderungsprotokoll](./CHANGELOG.md))
|
**Version:** 1.1.2.2 ([Änderungsprotokoll](./CHANGELOG.md))
|
||||||
**Lizenz:** [GNU General Public License 3.0 (GPLv3)](./LICENSE)
|
**Lizenz:** [GNU General Public License 3.0 (GPLv3)](./LICENSE)
|
||||||
**Website:** https://elwig.at/
|
**Website:** https://elwig.at/
|
||||||
**Quellcode:** https://git.necronda.net/winzer/elwig
|
**Quellcode:** https://git.necronda.net/winzer/elwig
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ namespace Tests.E2ETests {
|
|||||||
Session.App.FindElement(By.Name("Rundschreiben")).Click();
|
Session.App.FindElement(By.Name("Rundschreiben")).Click();
|
||||||
Thread.Sleep(Utils.WINDOW_OPEN_SLEEP);
|
Thread.Sleep(Utils.WINDOW_OPEN_SLEEP);
|
||||||
var window = Session.CreateWindowDriver("MailWindow");
|
var window = Session.CreateWindowDriver("MailWindow");
|
||||||
Assert.That(window.Title, Is.EqualTo($"Rundschreiben - Lese {Elwig.Helpers.Utils.Today.Year} - Elwig"));
|
Assert.That(window.Title, Is.EqualTo($"Rundschreiben - Lese {DateTime.Today.Year} - Elwig"));
|
||||||
window.Close();
|
window.Close();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,12 +84,12 @@ namespace Tests.E2ETests {
|
|||||||
Window.FindElement(By.WpfId("SearchInput")).SendKeys("9999");
|
Window.FindElement(By.WpfId("SearchInput")).SendKeys("9999");
|
||||||
Thread.Sleep(500);
|
Thread.Sleep(500);
|
||||||
var memberListRow = Window.FindElement(By.WpfId("MemberList")).FindElement(By.ClassName("DataGridRow"));
|
var memberListRow = Window.FindElement(By.WpfId("MemberList")).FindElement(By.ClassName("DataGridRow"));
|
||||||
Assert.Multiple(() => {
|
using (Assert.EnterMultipleScope()) {
|
||||||
Assert.That(memberListRow, Is.Not.Null);
|
Assert.That(memberListRow, Is.Not.Null);
|
||||||
Assert.That(memberListRow.FindElement(By.Name("9999 ")), Is.Not.Null);
|
Assert.That(memberListRow.FindElement(By.Name("9999 ")), Is.Not.Null);
|
||||||
Assert.That(memberListRow.FindElement(By.Name("Norbert")), Is.Not.Null);
|
Assert.That(memberListRow.FindElement(By.Name("Norbert")), Is.Not.Null);
|
||||||
Assert.That(memberListRow.FindElement(By.Name("Neuling")), Is.Not.Null);
|
Assert.That(memberListRow.FindElement(By.Name("Neuling")), Is.Not.Null);
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@@ -128,12 +128,12 @@ namespace Tests.E2ETests {
|
|||||||
Assert.That(memberListRows, Has.Count.EqualTo(1));
|
Assert.That(memberListRows, Has.Count.EqualTo(1));
|
||||||
|
|
||||||
var memberListRow = memberListRows.First();
|
var memberListRow = memberListRows.First();
|
||||||
Assert.Multiple(() => {
|
using (Assert.EnterMultipleScope()) {
|
||||||
Assert.That(memberListRow, Is.Not.Null);
|
Assert.That(memberListRow, Is.Not.Null);
|
||||||
Assert.That(memberListRow.FindElement(By.Name("9999 ")), Is.Not.Null);
|
Assert.That(memberListRow.FindElement(By.Name("9999 ")), Is.Not.Null);
|
||||||
Assert.That(memberListRow.FindElement(By.Name("Norbert")), Is.Not.Null);
|
Assert.That(memberListRow.FindElement(By.Name("Norbert")), Is.Not.Null);
|
||||||
Assert.That(memberListRow.FindElement(By.Name("Neuling")), Is.Not.Null);
|
Assert.That(memberListRow.FindElement(By.Name("Neuling")), Is.Not.Null);
|
||||||
});
|
}
|
||||||
|
|
||||||
Window.FindElement(By.WpfId("DeleteMemberButton")).Click();
|
Window.FindElement(By.WpfId("DeleteMemberButton")).Click();
|
||||||
var dialog = Session.CreateWindowDriver("DeleteMemberDialog");
|
var dialog = Session.CreateWindowDriver("DeleteMemberDialog");
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
-- inserts for HelperTests.BillingTest
|
-- inserts for HelperTests.BillingTest
|
||||||
|
|
||||||
INSERT INTO wine_cultivation (cultid, name, description) VALUES
|
INSERT INTO wine_cultivation (cultid, name, description, organic) VALUES
|
||||||
('KIP', 'KIP', 'Kontrollierte Integrierte Produktion'),
|
('KIP', 'KIP', 'Kontrollierte Integrierte Produktion', FALSE),
|
||||||
('B', 'Bio', 'AT-BIO-302');
|
('B', 'Bio', 'Biologische Produktion', TRUE);
|
||||||
|
|
||||||
INSERT INTO wine_attribute (attrid, name, active, max_kg_per_ha, strict, fill_lower) VALUES
|
INSERT INTO wine_attribute (attrid, name, active, max_kg_per_ha, strict, fill_lower) VALUES
|
||||||
('K', 'Kabinett', TRUE, NULL, FALSE, 0),
|
('K', 'Kabinett', TRUE, NULL, FALSE, 0),
|
||||||
@@ -45,7 +45,7 @@ INSERT INTO delivery (mgnr, year, did, date, time, zwstid, lnr) VALUES
|
|||||||
(101, 2020, 1, '2020-10-01', NULL, 'X', 1),
|
(101, 2020, 1, '2020-10-01', NULL, 'X', 1),
|
||||||
(101, 2020, 2, '2020-10-01', NULL, 'X', 2),
|
(101, 2020, 2, '2020-10-01', NULL, 'X', 2),
|
||||||
(101, 2020, 3, '2020-10-01', NULL, 'X', 3);
|
(101, 2020, 3, '2020-10-01', NULL, 'X', 3);
|
||||||
INSERT INTO delivery_part (year, did, dpnr, sortid, attrid, cultid, weight, kmw, qualid, hkid, kgnr, net_weight, manual_weighing, spl_check, scale_id, weighing_data, weighing_reason) VALUES
|
INSERT INTO delivery_part (year, did, dpnr, sortid, attrid, cultid, weight, kmw, qualid, hkid, kgnr, net_weight, manual_weighing, spl_check, scale_terminal, weighing_data, weighing_reason) VALUES
|
||||||
(2020, 1, 1, 'GV', 'K', NULL, 4000, 17, 'KAB', 'WLNO', 06109, TRUE, FALSE, FALSE, NULL, NULL, NULL),
|
(2020, 1, 1, 'GV', 'K', NULL, 4000, 17, 'KAB', 'WLNO', 06109, TRUE, FALSE, FALSE, NULL, NULL, NULL),
|
||||||
(2020, 1, 2, 'GV', NULL, NULL, 4000, 16, 'QUW', 'WLNO', 06109, TRUE, FALSE, FALSE, NULL, NULL, NULL),
|
(2020, 1, 2, 'GV', NULL, NULL, 4000, 16, 'QUW', 'WLNO', 06109, TRUE, FALSE, FALSE, NULL, NULL, NULL),
|
||||||
(2020, 2, 1, 'GV', NULL, 'B', 4000, 15, 'QUW', 'WLNO', 06109, TRUE, FALSE, FALSE, NULL, NULL, NULL),
|
(2020, 2, 1, 'GV', NULL, 'B', 4000, 15, 'QUW', 'WLNO', 06109, TRUE, FALSE, FALSE, NULL, NULL, NULL),
|
||||||
@@ -60,7 +60,7 @@ INSERT INTO delivery (mgnr, year, did, date, time, zwstid, lnr) VALUES
|
|||||||
(101, 2021, 1, '2021-10-01', NULL, 'X', 1),
|
(101, 2021, 1, '2021-10-01', NULL, 'X', 1),
|
||||||
(101, 2021, 2, '2021-10-01', NULL, 'X', 2),
|
(101, 2021, 2, '2021-10-01', NULL, 'X', 2),
|
||||||
(101, 2021, 3, '2021-10-01', NULL, 'X', 3);
|
(101, 2021, 3, '2021-10-01', NULL, 'X', 3);
|
||||||
INSERT INTO delivery_part (year, did, dpnr, sortid, attrid, cultid, weight, kmw, qualid, hkid, kgnr, gebunden, net_weight, manual_weighing, spl_check, scale_id, weighing_data, weighing_reason) VALUES
|
INSERT INTO delivery_part (year, did, dpnr, sortid, attrid, cultid, weight, kmw, qualid, hkid, kgnr, gebunden, net_weight, manual_weighing, spl_check, scale_terminal, weighing_data, weighing_reason) VALUES
|
||||||
(2021, 1, 1, 'GV', 'K', NULL, 4000, 17, 'KAB', 'WLNO', 06109, TRUE, TRUE, FALSE, FALSE, NULL, NULL, NULL),
|
(2021, 1, 1, 'GV', 'K', NULL, 4000, 17, 'KAB', 'WLNO', 06109, TRUE, TRUE, FALSE, FALSE, NULL, NULL, NULL),
|
||||||
(2021, 1, 2, 'GV', NULL, NULL, 4000, 16, 'QUW', 'WLNO', 06109, FALSE, TRUE, FALSE, FALSE, NULL, NULL, NULL),
|
(2021, 1, 2, 'GV', NULL, NULL, 4000, 16, 'QUW', 'WLNO', 06109, FALSE, TRUE, FALSE, FALSE, NULL, NULL, NULL),
|
||||||
(2021, 2, 1, 'GV', NULL, 'B', 4000, 15, 'QUW', 'WLNO', 06109, TRUE, TRUE, FALSE, FALSE, NULL, NULL, NULL),
|
(2021, 2, 1, 'GV', NULL, 'B', 4000, 15, 'QUW', 'WLNO', 06109, TRUE, TRUE, FALSE, FALSE, NULL, NULL, NULL),
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
-- inserts for DocumentTests
|
-- inserts for DocumentTests
|
||||||
|
|
||||||
INSERT INTO wine_cultivation (cultid, name, description) VALUES
|
INSERT INTO wine_cultivation (cultid, name, description, organic) VALUES
|
||||||
('B', 'Bio', 'AT-BIO-302');
|
('B', 'Bio', 'Biologische Produktion', TRUE);
|
||||||
|
|
||||||
INSERT INTO wine_attribute (attrid, name, active, max_kg_per_ha, strict, fill_lower) VALUES
|
INSERT INTO wine_attribute (attrid, name, active, max_kg_per_ha, strict, fill_lower) VALUES
|
||||||
('K', 'Kabinett', TRUE, NULL, FALSE, 0);
|
('K', 'Kabinett', TRUE, NULL, FALSE, 0);
|
||||||
@@ -39,7 +39,7 @@ INSERT INTO delivery (mgnr, year, did, date, time, zwstid, lnr) VALUES
|
|||||||
(104, 2020, 11, '2020-10-03', '14:39:22', 'X', 2),
|
(104, 2020, 11, '2020-10-03', '14:39:22', 'X', 2),
|
||||||
(104, 2020, 12, '2020-10-03', '15:15:41', 'X', 3);
|
(104, 2020, 12, '2020-10-03', '15:15:41', 'X', 3);
|
||||||
|
|
||||||
INSERT INTO delivery_part (year, did, dpnr, sortid, attrid, cultid, weight, kmw, qualid, hkid, kgnr, net_weight, manual_weighing, spl_check, scale_id, weighing_data, weighing_reason) VALUES
|
INSERT INTO delivery_part (year, did, dpnr, sortid, attrid, cultid, weight, kmw, qualid, hkid, kgnr, net_weight, manual_weighing, spl_check, scale_terminal, weighing_data, weighing_reason) VALUES
|
||||||
(2020, 1, 1, 'GV', NULL, NULL, 3219, 15.0, 'QUW', 'WLNO', 06109, TRUE, FALSE, FALSE, '1', '{"id":"321","nr":321,"gross_weight":3219,"tare_weight":0,"net_weight":3219,"date":"2020-10-01","time":"09:02:46"}', NULL),
|
(2020, 1, 1, 'GV', NULL, NULL, 3219, 15.0, 'QUW', 'WLNO', 06109, TRUE, FALSE, FALSE, '1', '{"id":"321","nr":321,"gross_weight":3219,"tare_weight":0,"net_weight":3219,"date":"2020-10-01","time":"09:02:46"}', NULL),
|
||||||
(2020, 2, 1, 'GV', 'K', NULL, 2987, 17.5, 'KAB', 'WLNO', 06109, TRUE, FALSE, FALSE, NULL, NULL, NULL),
|
(2020, 2, 1, 'GV', 'K', NULL, 2987, 17.5, 'KAB', 'WLNO', 06109, TRUE, FALSE, FALSE, NULL, NULL, NULL),
|
||||||
(2020, 2, 2, 'GV', 'K', NULL, 1873, 17.7, 'KAB', 'WLNO', 06109, TRUE, FALSE, FALSE, NULL, NULL, NULL),
|
(2020, 2, 2, 'GV', 'K', NULL, 1873, 17.7, 'KAB', 'WLNO', 06109, TRUE, FALSE, FALSE, NULL, NULL, NULL),
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
-- inserts for E2ETests
|
-- inserts for E2ETests
|
||||||
|
|
||||||
INSERT INTO wine_cultivation (cultid, name, description) VALUES
|
INSERT INTO wine_cultivation (cultid, name, description, organic) VALUES
|
||||||
('KIP', 'KIP', 'Kontrollierte Integrierte Produktion'),
|
('KIP', 'KIP', 'Kontrollierte Integrierte Produktion', FALSE),
|
||||||
('B', 'Bio', 'AT-BIO-302');
|
('B', 'Bio', 'Biologische Produktion', TRUE);
|
||||||
|
|
||||||
INSERT INTO wine_attribute (attrid, name, active, max_kg_per_ha, strict, fill_lower) VALUES
|
INSERT INTO wine_attribute (attrid, name, active, max_kg_per_ha, strict, fill_lower) VALUES
|
||||||
('K', 'Kabinett', TRUE, NULL, FALSE, 0),
|
('K', 'Kabinett', TRUE, NULL, FALSE, 0),
|
||||||
|
|||||||
@@ -66,11 +66,11 @@ INSERT INTO wb_kg (kgnr, glnr) VALUES
|
|||||||
(15216, 2),
|
(15216, 2),
|
||||||
(15224, 2);
|
(15224, 2);
|
||||||
|
|
||||||
INSERT INTO member (mgnr, given_name, name, zwstid, volllieferant, buchführend, country, postal_dest, address, default_kgnr, iban, lfbis_nr, ustid_nr) VALUES
|
INSERT INTO member (mgnr, given_name, name, zwstid, volllieferant, buchführend, country, postal_dest, address, default_kgnr, iban, lfbis_nr, ustid_nr, org_auth_code) VALUES
|
||||||
(101, 'Max', 'Mustermann', 'X', FALSE, FALSE, 40, 222303524, 'Winzerstraße 1', 06109, 'AT811234567890123457', '0123463', NULL ),
|
(101, 'Max', 'Mustermann', 'X', FALSE, FALSE, 40, 222303524, 'Winzerstraße 1', 06109, 'AT811234567890123457', '0123463', NULL , NULL ),
|
||||||
(102, 'Wernhardt', 'Weinbauer', 'X', FALSE, FALSE, 40, 222303524, 'Winzerstraße 2', 06109, 'AT541234567890123458', '0123471', 'ATU12345684'),
|
(102, 'Wernhardt', 'Weinbauer', 'X', FALSE, FALSE, 40, 222303524, 'Winzerstraße 2', 06109, 'AT541234567890123458', '0123471', 'ATU12345684', NULL ),
|
||||||
(103, 'Matthäus', 'Musterbauer', 'X', FALSE, FALSE, 40, 212005138, 'Brünner Straße 10', 15224, 'AT271234567890123459', '0123480', NULL ),
|
(103, 'Matthäus', 'Musterbauer', 'X', FALSE, FALSE, 40, 212005138, 'Brünner Straße 10', 15224, 'AT271234567890123459', '0123480', NULL , 'AT-BIO-302'),
|
||||||
(104, 'Waltraud', 'Winzer', 'X', FALSE, TRUE , 40, 212005138, 'Wiener Straße 15', 15224, 'AT971234567890123460', '0123498', 'ATU12345693');
|
(104, 'Waltraud', 'Winzer', 'X', FALSE, TRUE , 40, 212005138, 'Wiener Straße 15', 15224, 'AT971234567890123460', '0123498', 'ATU12345693', NULL );
|
||||||
|
|
||||||
INSERT INTO member_billing_address (mgnr, name, country, postal_dest, address) VALUES
|
INSERT INTO member_billing_address (mgnr, name, country, postal_dest, address) VALUES
|
||||||
(102, 'W&B Weinbauer GesbR', 40, 222303524, 'Winzerstraße 2'),
|
(102, 'W&B Weinbauer GesbR', 40, 222303524, 'Winzerstraße 2'),
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
-- inserts for ServiceTests
|
-- inserts for ServiceTests
|
||||||
|
|
||||||
|
INSERT INTO wine_cultivation (cultid, name, description, organic) VALUES
|
||||||
INSERT INTO wine_cultivation (cultid, name, description) VALUES
|
('B', 'Bio', 'Biologische Produktion', TRUE);
|
||||||
('B', 'Bio', 'AT-BIO-302');
|
|
||||||
|
|
||||||
INSERT INTO wine_attribute (attrid, name, active, max_kg_per_ha, strict, fill_lower) VALUES
|
INSERT INTO wine_attribute (attrid, name, active, max_kg_per_ha, strict, fill_lower) VALUES
|
||||||
('K', 'Kabinett', TRUE, NULL, FALSE, 0);
|
('K', 'Kabinett', TRUE, NULL, FALSE, 0);
|
||||||
@@ -76,7 +75,7 @@ INSERT INTO delivery (mgnr, year, did, date, time, zwstid, lnr) VALUES
|
|||||||
(101, 2023, 18, '2023-10-10', NULL, 'X', 2),
|
(101, 2023, 18, '2023-10-10', NULL, 'X', 2),
|
||||||
(101, 2023, 19, '2023-10-10', NULL, 'X', 3);
|
(101, 2023, 19, '2023-10-10', NULL, 'X', 3);
|
||||||
|
|
||||||
INSERT INTO delivery_part (year, did, dpnr, sortid, attrid, cultid, weight, kmw, qualid, hkid, kgnr, net_weight, manual_weighing, spl_check, scale_id, weighing_data, weighing_reason) VALUES
|
INSERT INTO delivery_part (year, did, dpnr, sortid, attrid, cultid, weight, kmw, qualid, hkid, kgnr, net_weight, manual_weighing, spl_check, scale_terminal, weighing_data, weighing_reason) VALUES
|
||||||
(2021, 1, 1, 'GV', NULL, NULL, 3500, 15.0, 'QUW', 'WLNO', 15224, TRUE, FALSE, FALSE, NULL, NULL, NULL),
|
(2021, 1, 1, 'GV', NULL, NULL, 3500, 15.0, 'QUW', 'WLNO', 15224, TRUE, FALSE, FALSE, NULL, NULL, NULL),
|
||||||
(2021, 2, 1, 'GV', NULL, NULL, 4000, 17.0, 'KAB', 'WLNO', 15224, TRUE, FALSE, FALSE, NULL, NULL, NULL),
|
(2021, 2, 1, 'GV', NULL, NULL, 4000, 17.0, 'KAB', 'WLNO', 15224, TRUE, FALSE, FALSE, NULL, NULL, NULL),
|
||||||
(2021, 2, 2, 'GV', NULL, NULL, 4000, 16.0, 'QUW', 'WLNO', 15224, TRUE, FALSE, FALSE, NULL, NULL, NULL),
|
(2021, 2, 2, 'GV', NULL, NULL, 4000, 16.0, 'QUW', 'WLNO', 15224, TRUE, FALSE, FALSE, NULL, NULL, NULL),
|
||||||
|
|||||||
+3
-3
@@ -19,12 +19,12 @@
|
|||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.7.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.10.0" />
|
||||||
<PackageReference Include="Appium.WebDriver" Version="4.4.5" />
|
<PackageReference Include="Appium.WebDriver" Version="4.4.5" />
|
||||||
<PackageReference Include="NReco.PdfRenderer" Version="1.6.0" />
|
<PackageReference Include="NReco.PdfRenderer" Version="1.6.0" />
|
||||||
<PackageReference Include="NUnit" Version="4.6.1" />
|
<PackageReference Include="NUnit" Version="4.6.1" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="6.2.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="6.3.0" />
|
||||||
<PackageReference Include="NUnit.Analyzers" Version="4.14.0">
|
<PackageReference Include="NUnit.Analyzers" Version="4.15.0">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ namespace Tests.UnitTests.DocumentTests {
|
|||||||
"""));
|
"""));
|
||||||
Assert.That(text, Contains.Substring("0123463")); // Betriebsnummer
|
Assert.That(text, Contains.Substring("0123463")); // Betriebsnummer
|
||||||
Assert.That(text, Contains.Substring("pauschaliert"));
|
Assert.That(text, Contains.Substring("pauschaliert"));
|
||||||
Assert.That(text, Contains.Substring($"Wolkersdorf, am {Elwig.Helpers.Utils.Today:dd.MM.yyyy}"));
|
Assert.That(text, Contains.Substring($"Wolkersdorf, am {DateTime.Today:dd.MM.yyyy}"));
|
||||||
Assert.That(text, Contains.Substring("Traubengutschrift Max Mustermann – Probevariante"));
|
Assert.That(text, Contains.Substring("Traubengutschrift Max Mustermann – Probevariante"));
|
||||||
Assert.That(text, Contains.Substring("AT81 1234 5678 9012 3457"));
|
Assert.That(text, Contains.Substring("AT81 1234 5678 9012 3457"));
|
||||||
Assert.That(text, Contains.Substring("""
|
Assert.That(text, Contains.Substring("""
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ namespace Tests.UnitTests.DocumentTests {
|
|||||||
"""));
|
"""));
|
||||||
Assert.That(text, Contains.Substring("0123463")); // Betriebsnummer
|
Assert.That(text, Contains.Substring("0123463")); // Betriebsnummer
|
||||||
Assert.That(text, Contains.Substring("pauschaliert"));
|
Assert.That(text, Contains.Substring("pauschaliert"));
|
||||||
Assert.That(text, Contains.Substring($"Wolkersdorf, am {Elwig.Helpers.Utils.Today:dd.MM.yyyy}"));
|
Assert.That(text, Contains.Substring($"Wolkersdorf, am {DateTime.Today:dd.MM.yyyy}"));
|
||||||
Assert.That(text, Contains.Substring("Anlieferungsbestätigung 2020"));
|
Assert.That(text, Contains.Substring("Anlieferungsbestätigung 2020"));
|
||||||
Assert.That(text, Contains.Substring("""
|
Assert.That(text, Contains.Substring("""
|
||||||
20201001X001 1 Grüner Veltliner QUW 73 15,0 ungeb.: 3 219 3 219 ☑
|
20201001X001 1 Grüner Veltliner QUW 73 15,0 ungeb.: 3 219 3 219 ☑
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ namespace Tests.UnitTests.DocumentTests {
|
|||||||
public async Task Test_01_OneDeliveryPart() {
|
public async Task Test_01_OneDeliveryPart() {
|
||||||
using var doc = await DeliveryNote.Initialize(2020, 1);
|
using var doc = await DeliveryNote.Initialize(2020, 1);
|
||||||
var text = await Utils.GeneratePdfText(doc);
|
var text = await Utils.GeneratePdfText(doc);
|
||||||
Assert.Multiple(() => {
|
using (Assert.EnterMultipleScope()) {
|
||||||
Assert.That(text, Contains.Substring("""
|
Assert.That(text, Contains.Substring("""
|
||||||
MUSTERMANN Max
|
MUSTERMANN Max
|
||||||
Winzerstraße 1
|
Winzerstraße 1
|
||||||
@@ -23,17 +23,17 @@ namespace Tests.UnitTests.DocumentTests {
|
|||||||
1 Grüner Veltliner Qualitätswein 73 15,0 3 219
|
1 Grüner Veltliner Qualitätswein 73 15,0 3 219
|
||||||
Herkunft: Österreich / Weinland / Niederösterreich
|
Herkunft: Österreich / Weinland / Niederösterreich
|
||||||
/ Matzner Hügel / Hohenruppersdorf / KG Hohenruppersdorf
|
/ Matzner Hügel / Hohenruppersdorf / KG Hohenruppersdorf
|
||||||
Waage: 1, ID: 321 – 09:02, 01.10.2020
|
Waage/Terminal: ?/1, ID: 321 – 09:02, 01.10.2020
|
||||||
Brutto: 3 219 kg – Tara: 0 kg – Netto: 3 219 kg – gerebelt gewogen
|
Brutto: 3 219 kg – Tara: 0 kg – Netto: 3 219 kg – gerebelt gewogen
|
||||||
"""));
|
"""));
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public async Task Test_02_TwoDeliveryParts() {
|
public async Task Test_02_TwoDeliveryParts() {
|
||||||
using var doc = await DeliveryNote.Initialize(2020, 4);
|
using var doc = await DeliveryNote.Initialize(2020, 4);
|
||||||
var text = await Utils.GeneratePdfText(doc);
|
var text = await Utils.GeneratePdfText(doc);
|
||||||
Assert.Multiple(() => {
|
using (Assert.EnterMultipleScope()) {
|
||||||
Assert.That(text, Contains.Substring("""
|
Assert.That(text, Contains.Substring("""
|
||||||
W&B Weinbauer GesbR
|
W&B Weinbauer GesbR
|
||||||
WEINBAUER Wernhardt
|
WEINBAUER Wernhardt
|
||||||
@@ -49,23 +49,23 @@ namespace Tests.UnitTests.DocumentTests {
|
|||||||
1 Grüner Veltliner Qualitätswein 82 16,7 4 002
|
1 Grüner Veltliner Qualitätswein 82 16,7 4 002
|
||||||
Herkunft: Österreich / Weinland / Niederösterreich
|
Herkunft: Österreich / Weinland / Niederösterreich
|
||||||
/ Matzner Hügel / Hohenruppersdorf / KG Hohenruppersdorf
|
/ Matzner Hügel / Hohenruppersdorf / KG Hohenruppersdorf
|
||||||
Waage: ?, ID: ? (gerebelt gewogen)
|
Waage/Terminal: ?/?, ID: ? (gerebelt gewogen)
|
||||||
"""));
|
"""));
|
||||||
Assert.That(text, Contains.Substring("""
|
Assert.That(text, Contains.Substring("""
|
||||||
2 Grüner Veltliner Qualitätswein 75 15,3 481
|
2 Grüner Veltliner Qualitätswein 75 15,3 481
|
||||||
Herkunft: Österreich / Weinland / Niederösterreich
|
Herkunft: Österreich / Weinland / Niederösterreich
|
||||||
/ Matzner Hügel / Hohenruppersdorf / KG Hohenruppersdorf
|
/ Matzner Hügel / Hohenruppersdorf / KG Hohenruppersdorf
|
||||||
Waage: ?, ID: ? (gerebelt gewogen)
|
Waage/Terminal: ?/?, ID: ? (gerebelt gewogen)
|
||||||
"""));
|
"""));
|
||||||
Assert.That(text, Contains.Substring("Gesamt: 81 16,5 4 483"));
|
Assert.That(text, Contains.Substring("Gesamt: 81 16,5 4 483"));
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public async Task Test_03_DeliveryPartsWithAttribute() {
|
public async Task Test_03_DeliveryPartsWithAttribute() {
|
||||||
using var doc = await DeliveryNote.Initialize(2020, 3);
|
using var doc = await DeliveryNote.Initialize(2020, 3);
|
||||||
var text = await Utils.GeneratePdfText(doc);
|
var text = await Utils.GeneratePdfText(doc);
|
||||||
Assert.Multiple(() => {
|
using (Assert.EnterMultipleScope()) {
|
||||||
Assert.That(text, Contains.Substring("""
|
Assert.That(text, Contains.Substring("""
|
||||||
MUSTERMANN Max
|
MUSTERMANN Max
|
||||||
Winzerstraße 1
|
Winzerstraße 1
|
||||||
@@ -80,29 +80,29 @@ namespace Tests.UnitTests.DocumentTests {
|
|||||||
1 Grüner Veltliner Wein 75 15,4 2 561
|
1 Grüner Veltliner Wein 75 15,4 2 561
|
||||||
Herkunft: Österreich
|
Herkunft: Österreich
|
||||||
/ Matzner Hügel / Hohenruppersdorf / KG Hohenruppersdorf
|
/ Matzner Hügel / Hohenruppersdorf / KG Hohenruppersdorf
|
||||||
Waage: ?, ID: ? (gerebelt gewogen)
|
Waage/Terminal: ?/?, ID: ? (gerebelt gewogen)
|
||||||
"""));
|
"""));
|
||||||
Assert.That(text, Contains.Substring("""
|
Assert.That(text, Contains.Substring("""
|
||||||
2 Grüner Veltliner Kabinett Wein 87 17,6 3 129
|
2 Grüner Veltliner Kabinett Wein 87 17,6 3 129
|
||||||
Herkunft: Österreich
|
Herkunft: Österreich
|
||||||
/ Matzner Hügel / Hohenruppersdorf / KG Hohenruppersdorf
|
/ Matzner Hügel / Hohenruppersdorf / KG Hohenruppersdorf
|
||||||
Waage: ?, ID: ? (gerebelt gewogen)
|
Waage/Terminal: ?/?, ID: ? (gerebelt gewogen)
|
||||||
"""));
|
"""));
|
||||||
Assert.That(text, Contains.Substring("""
|
Assert.That(text, Contains.Substring("""
|
||||||
3 Grüner Veltliner Wein 79 16,1 1 280
|
3 Grüner Veltliner Wein 79 16,1 1 280
|
||||||
Herkunft: Österreich
|
Herkunft: Österreich
|
||||||
/ Matzner Hügel / Hohenruppersdorf / KG Hohenruppersdorf
|
/ Matzner Hügel / Hohenruppersdorf / KG Hohenruppersdorf
|
||||||
Waage: ?, ID: ? (gerebelt gewogen)
|
Waage/Terminal: ?/?, ID: ? (gerebelt gewogen)
|
||||||
"""));
|
"""));
|
||||||
Assert.That(text, Contains.Substring("Gesamt: 81 16,5 6 970"));
|
Assert.That(text, Contains.Substring("Gesamt: 81 16,5 6 970"));
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public async Task Test_04_DeliveryPartsWithCultivation() {
|
public async Task Test_04_DeliveryPartsWithCultivation() {
|
||||||
using var doc = await DeliveryNote.Initialize(2020, 7);
|
using var doc = await DeliveryNote.Initialize(2020, 7);
|
||||||
var text = await Utils.GeneratePdfText(doc);
|
var text = await Utils.GeneratePdfText(doc);
|
||||||
Assert.Multiple(() => {
|
using (Assert.EnterMultipleScope()) {
|
||||||
Assert.That(text, Contains.Substring("""
|
Assert.That(text, Contains.Substring("""
|
||||||
MUSTERBAUER Matthäus
|
MUSTERBAUER Matthäus
|
||||||
Brünner Straße 10
|
Brünner Straße 10
|
||||||
@@ -115,20 +115,20 @@ namespace Tests.UnitTests.DocumentTests {
|
|||||||
Assert.That(text, Contains.Substring("Das Mitglied erklärt, dass die gelieferte Ware dem österreichischen Weingesetz entspricht"));
|
Assert.That(text, Contains.Substring("Das Mitglied erklärt, dass die gelieferte Ware dem österreichischen Weingesetz entspricht"));
|
||||||
Assert.That(text, Contains.Substring("""
|
Assert.That(text, Contains.Substring("""
|
||||||
1 Grüner Veltliner Wein 80 16,3 3 198
|
1 Grüner Veltliner Wein 80 16,3 3 198
|
||||||
Bewirtschaftung: Bio (AT-BIO-302)
|
Bewirtschaftung: Bio (Biologische Produktion) – Kontrollstelle: AT-BIO-302
|
||||||
Herkunft: Österreich
|
Herkunft: Österreich
|
||||||
/ Wolkersdorfer Hochleithen / Wolkersdorf im Weinviertel / KG Wolkersdorf
|
/ Wolkersdorfer Hochleithen / Wolkersdorf im Weinviertel / KG Wolkersdorf
|
||||||
Waage: ?, ID: ? (gerebelt gewogen)
|
Waage/Terminal: ?/?, ID: ? (gerebelt gewogen)
|
||||||
"""));
|
"""));
|
||||||
Assert.That(text, Contains.Substring("""
|
Assert.That(text, Contains.Substring("""
|
||||||
2 Grüner Veltliner Qualitätswein 75 15,4 2 134
|
2 Grüner Veltliner Qualitätswein 75 15,4 2 134
|
||||||
Bewirtschaftung: Bio (AT-BIO-302)
|
Bewirtschaftung: Bio (Biologische Produktion) – Kontrollstelle: AT-BIO-302
|
||||||
Herkunft: Österreich / Weinland / Niederösterreich
|
Herkunft: Österreich / Weinland / Niederösterreich
|
||||||
/ Wolkersdorfer Hochleithen / Wolkersdorf im Weinviertel / KG Wolkersdorf
|
/ Wolkersdorfer Hochleithen / Wolkersdorf im Weinviertel / KG Wolkersdorf
|
||||||
Waage: ?, ID: ? (gerebelt gewogen)
|
Waage/Terminal: ?/?, ID: ? (gerebelt gewogen)
|
||||||
"""));
|
"""));
|
||||||
Assert.That(text, Contains.Substring("Gesamt: 78 15,9 5 332"));
|
Assert.That(text, Contains.Substring("Gesamt: 78 15,9 5 332"));
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@@ -152,12 +152,12 @@ namespace Tests.UnitTests.DocumentTests {
|
|||||||
Herkunft: Österreich / Weinland / Niederösterreich
|
Herkunft: Österreich / Weinland / Niederösterreich
|
||||||
/ Matzner Hügel / Hohenruppersdorf / KG Hohenruppersdorf
|
/ Matzner Hügel / Hohenruppersdorf / KG Hohenruppersdorf
|
||||||
Zu-/Abschläge: Geschädigte Trauben −10,00 %
|
Zu-/Abschläge: Geschädigte Trauben −10,00 %
|
||||||
Waage: ?, ID: ? (gerebelt gewogen)
|
Waage/Terminal: ?/?, ID: ? (gerebelt gewogen)
|
||||||
2 Grüner Veltliner Kabinett Kabinett 87 17,7 1 873
|
2 Grüner Veltliner Kabinett Kabinett 87 17,7 1 873
|
||||||
Herkunft: Österreich / Weinland / Niederösterreich
|
Herkunft: Österreich / Weinland / Niederösterreich
|
||||||
/ Matzner Hügel / Hohenruppersdorf / KG Hohenruppersdorf
|
/ Matzner Hügel / Hohenruppersdorf / KG Hohenruppersdorf
|
||||||
Zu-/Abschläge: Keine Voranmeldung −0,1000 €/kg
|
Zu-/Abschläge: Keine Voranmeldung −0,1000 €/kg
|
||||||
Waage: ?, ID: ? (gerebelt gewogen)
|
Waage/Terminal: ?/?, ID: ? (gerebelt gewogen)
|
||||||
Gesamt: 87 17,6 4 860
|
Gesamt: 87 17,6 4 860
|
||||||
"""));
|
"""));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,13 +24,13 @@ namespace Tests.UnitTests.DocumentTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[OneTimeSetUp]
|
[OneTimeSetUp]
|
||||||
public async Task SetupPrinting() {
|
public void SetupPrinting() {
|
||||||
await Pdf.Init();
|
Pdf.Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
[OneTimeTearDown]
|
[OneTimeTearDown]
|
||||||
public async Task TeardownPrinting() {
|
public void TeardownPrinting() {
|
||||||
await Pdf.Cleanup();
|
Pdf.Cleanup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
File diff suppressed because it is too large.
Load diff
Loaded 100 of 107 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user