Compare commits
3 Commits
v1.0.3.0
...
10cb23db9e
| Author | SHA1 | Date | |
|---|---|---|---|
| 10cb23db9e | |||
| a417d0f2a2 | |||
| b184d5661b |
227
CHANGELOG.md
227
CHANGELOG.md
@@ -2,229 +2,6 @@
|
|||||||
Changelog
|
Changelog
|
||||||
=========
|
=========
|
||||||
|
|
||||||
[v1.0.3.0][v1.0.3.0] (2026-01-16) {#v1.0.3.0}
|
|
||||||
---------------------------------------------
|
|
||||||
|
|
||||||
### Neue Funktionen {#v1.0.3.0-features}
|
|
||||||
|
|
||||||
* Bei Zu-/Abschlägen ist es nun möglich den konkreten Wert dieser auf Lieferscheinen nicht anzuzeigen (Stammdaten -> Saisons). (495aa8a691)
|
|
||||||
* Bei Teillieferungen kann nun die Art der Anlieferung angegeben werden: Planenwagen/Kipper, Lesewagen, Kiste(n). (bf6297f63b, 3419113dec, 6d6776f0f9)
|
|
||||||
* Im Lieferungen-Fenster (`DeliveryAdminWindow`) können nun die Gesamtmengen der gefilterten Lieferungen nach Mitglied und Sorte als Excel-Liste exportiert werden ("Liefermengen"). ([#73][i73], e97c29db43)
|
|
||||||
* Im Datenbankabfragen-Fenster (`QueryWindow`) gibt es die Möglichkeit die Ergebnisse als CSV-Datei zu exportieren. (9af498287d, 5cec5b3556)
|
|
||||||
* PDF-Dokumente wurden überarbeitet:
|
|
||||||
* Traubengutschriften können nur noch ausgedruckt bzw. verschickt werden, wenn die zugehörige Auszahlungsvariante festgesetzt ist. (b31603554a)
|
|
||||||
* Auf Dokumenten für interne Verwendung (alle außer an Mitglieder adressierte) wurden Kopf- und Fußzeile auf ein Minimum beschränkt. (f141485537)
|
|
||||||
* Das Synchronisieren zwischen Zweigstellen ist für den Benutzer nun wesentlich vereinfacht. Geänderte Daten von Mitgliedern, Flächenbindungen oder Lieferungen werden beim Synchronisieren automatsich hochgeladen bzw. heruntergeladen. ([#66][i66], 3b335a568e)
|
|
||||||
* Im Rundschreiben-Fenster (`MailWindow`) wurde ein Knopf zum Abbrechen des Generierens hinzugefügt. ([#50][i50])
|
|
||||||
|
|
||||||
### Behobene Fehler {#v1.0.3.0-bugfixes}
|
|
||||||
|
|
||||||
* Einzelne (nicht über das Rundschreiben-Fenster) verschickte E-Mails werde korrekt im Ausgangsprotokoll angeführt. (ac6d559e5d)
|
|
||||||
* Bei automatischen Datenbank-Updates sind auftretende Fehler ignoriert worden. (f228ba3019)
|
|
||||||
* Beim Aufteilen von Lieferungen sind Zu-/Abschläge nicht auf neu erstellen Teillieferungen übernommen worden. (da05a49e10)
|
|
||||||
* Das Verbinden und Trennen von Waagen mittels Serial-/COM-Port ist nun bei laufendem Programm möglich. ([#71][i71])
|
|
||||||
* In den Auszahlungsvarianten-Daten (`PaymentVariantSummary`) ist die statistische Summe der gebundenen und ungebundenen Menge ohne die Spalte _attributlos gebunden_ berechnet worden. (90def81cc5)
|
|
||||||
* Seit [v0.13.7](#v0.13.7) (2025-01-21) wurde auch bei der ersten Auszahlung der Saison ein "Bisher berücksichtigt: € 0,00" auf den Traubengutschriften angeführt. (7bea4d9ee0)
|
|
||||||
* Das Speichern der Parameter `MAIL_SEND_POSTAL` und `MAIL_SEND_EMAIL` war fehlerhaft. (01739ba42e)
|
|
||||||
* Bessere Isolation der automatisierten Dokumenten-Tests. (640dbf705e)
|
|
||||||
|
|
||||||
### Sonstiges {#v1.0.3.0-misc}
|
|
||||||
|
|
||||||
* Im Lieferungen-Fenster (`DeliveryAdminWindow`) wird bei Zu-/Abschlägen nur "Alle" angezeigt, wenn mehr als 1 ausgewählt sind. (811916a8b9)
|
|
||||||
* Im Auszahlungsvarianten-Fenster (`PaymentVariantsWindow`) wird die letzte Variante standardmäßig ausgewählt und beim Löschen wird um Bestätigung gebeten. (b6497fd422)
|
|
||||||
* Abhängigkeiten aktualisiert. (889a17b21c, 9b37330362, 3b6333a6a2, d45c3f867f, 42121fe7da)
|
|
||||||
|
|
||||||
[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
|
|
||||||
[i66]: https://git.necronda.net/winzer/elwig/issues/60
|
|
||||||
[i71]: https://git.necronda.net/winzer/elwig/issues/71
|
|
||||||
[i73]: https://git.necronda.net/winzer/elwig/issues/73
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[v1.0.2.0][v1.0.2.0] (2025-11-10) {#v1.0.2.0}
|
|
||||||
---------------------------------------------
|
|
||||||
|
|
||||||
### Neue Funktionen {#v1.0.2.0-features}
|
|
||||||
|
|
||||||
* Im Mitglieder-Fenster (`MemberAdminWindow`) können Kontaktdaten der Mitglieder als .vcf-Datei exportiert werden. (01f4480a08, 9dc225d3e4)
|
|
||||||
|
|
||||||
### Sonstiges {#v1.0.2.0-misc}
|
|
||||||
|
|
||||||
* Wenn ein Serial-/COM-Port-USB-Adapter an- oder abgesteckt wird, wird das nun automatisch erkannt. (e6367da286)
|
|
||||||
* Abhängigkeiten aktualisiert. (b10c744bf9, 0d513f7bff)
|
|
||||||
|
|
||||||
[v1.0.2.0]: https://git.necronda.net/winzer/elwig/releases/tag/v1.0.2.0
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[v1.0.1.5][v1.0.1.5] (2025-10-29) {#v1.0.1.5}
|
|
||||||
---------------------------------------------
|
|
||||||
|
|
||||||
### Behobene Fehler {#v1.0.1.5-bugfixes}
|
|
||||||
|
|
||||||
* Im Rundschreiben-Fenster (`MailWindow`) kam es zu einem Absturz, wenn man das Fenster über den "Anlieferungsbestätigung"-Knopf im Leseabschluss-Abschnitt geöffnet hat. (af98c32026)
|
|
||||||
|
|
||||||
[v1.0.1.5]: https://git.necronda.net/winzer/elwig/releases/tag/v1.0.1.5
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[v1.0.1.4][v1.0.1.4] (2025-10-28) {#v1.0.1.4}
|
|
||||||
---------------------------------------------
|
|
||||||
|
|
||||||
### Behobene Fehler {#v1.0.1.4-bugfixes}
|
|
||||||
|
|
||||||
* Im Rundschreiben-Fenster (`MailWindow`) kam es zu einem Absturz, wenn man die Zustelloptionen "Post zusenden an Mitglieder, die keine E-Mail erhalten würden" und "E-Mail zusenden an niemanden" kombiniert hat. (2de8af878b)
|
|
||||||
|
|
||||||
### Sonstiges {#v1.0.1.4-misc}
|
|
||||||
|
|
||||||
* Im Auszahlungsvariante-Fenster (`ChartWindow`) gibt es keine Fehlermeldung mehr wenn nicht für alle Sorten ein Preis definiert ist, nur noch eine Warnung. (428cd6ddc2)
|
|
||||||
|
|
||||||
[v1.0.1.4]: https://git.necronda.net/winzer/elwig/releases/tag/v1.0.1.4
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[v1.0.1.3][v1.0.1.3] (2025-10-13) {#v1.0.1.3}
|
|
||||||
---------------------------------------------
|
|
||||||
|
|
||||||
### Neue Funktionen {#v1.0.1.3-features}
|
|
||||||
|
|
||||||
* In der Liste des Lieferungen-Fenster (`DeliveryAdminWindow`) werden
|
|
||||||
* statt ausschließlich der Sorte auch Attribut und Bewirtschaftungsart angezeigt. (a0d4f19f30)
|
|
||||||
* Kommentare der Lieferungen (und Teillieferungen) angezeigt. (548aeb2ce9)
|
|
||||||
|
|
||||||
### Sonstiges {#v1.0.1.3-misc}
|
|
||||||
|
|
||||||
* Verzögerung der Überprüfung auf automatische Updates auf einige Sekunden verlängert. (67ba342c28)
|
|
||||||
* Verbesserung der Ladezeiten im Anmeldungen-Fenster (`DeliveryAncmtAdminWindow`). (7edd888aa2)
|
|
||||||
|
|
||||||
[v1.0.1.3]: https://git.necronda.net/winzer/elwig/releases/tag/v1.0.1.3
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[v1.0.1.2][v1.0.1.2] (2025-09-25) {#v1.0.1.2}
|
|
||||||
---------------------------------------------
|
|
||||||
|
|
||||||
### Behobene Fehler {#v1.0.1.2-bugfixes}
|
|
||||||
|
|
||||||
* Beim automatischen Importieren/Synchronisieren wird bei einem Fehlerfall der Benutzer verständigt, aber der Vorgang nicht abgebrochen. (9d02f18bac)
|
|
||||||
|
|
||||||
### Sonstiges {#v1.0.1.2-misc}
|
|
||||||
|
|
||||||
* Beim Sichern der Datenbank werden Meta-Informationen in der ZIP-Datei gespeichert. (c8a95422af)
|
|
||||||
|
|
||||||
[v1.0.1.2]: https://git.necronda.net/winzer/elwig/releases/tag/v1.0.1.2
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[v1.0.1.1][v1.0.1.1] (2025-09-21) {#v1.0.1.1}
|
|
||||||
---------------------------------------------
|
|
||||||
|
|
||||||
### Sonstiges {#v1.0.1.1-misc}
|
|
||||||
|
|
||||||
* Eingabe von Sorten und Qualitätsstufen im Übernahme-Fenster (`DeliveryAdminWindows`) verbessert. (e2de7a1f1c, b27b89f599)
|
|
||||||
|
|
||||||
[v1.0.1.1]: https://git.necronda.net/winzer/elwig/releases/tag/v1.0.1.1
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[v1.0.1.0][v1.0.1.0] (2025-09-18) {#v1.0.1.0}
|
|
||||||
---------------------------------------------
|
|
||||||
|
|
||||||
### Neue Funktionen {#v1.0.1.0-features}
|
|
||||||
|
|
||||||
* Neue Weinsorten gemäß Kürzelliste der Bundeskellereiinspektion hinzugefügt. (a0dcaf7b4f)
|
|
||||||
|
|
||||||
### Sonstiges {#v1.0.1.0-misc}
|
|
||||||
|
|
||||||
* HTTP-Anfragen haben jetzt das Feld `User-Agent` gesetzt. (844fc5217a)
|
|
||||||
* Auto-Update-Funktion wird auch beim Erlangen von Netzwerkverbindung ausgeführt. (8bc053053c)
|
|
||||||
|
|
||||||
[v1.0.1.0]: https://git.necronda.net/winzer/elwig/releases/tag/v1.0.1.0
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[v1.0.0.6][v1.0.0.6] (2025-09-17) {#v1.0.0.6}
|
|
||||||
---------------------------------------------
|
|
||||||
|
|
||||||
### Behobene Fehler {#v1.0.0.6-bugfixes}
|
|
||||||
|
|
||||||
* Die automatische Erkennung des Wiege-Modus hat im WKW nicht funktioniert. (463769b549)
|
|
||||||
|
|
||||||
### Sonstiges {#v1.0.0.6-misc}
|
|
||||||
|
|
||||||
* Tippfehler im Über-Fenster (`AboutWindow`) behoben. (2c383d0c55)
|
|
||||||
* `SaveFileDialog` mit Multi-File-Extensions verbessert. (9e02b15ff1)
|
|
||||||
|
|
||||||
[v1.0.0.6]: https://git.necronda.net/winzer/elwig/releases/tag/v1.0.0.6
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[v1.0.0.5][v1.0.0.5] (2025-09-15) {#v1.0.0.5}
|
|
||||||
---------------------------------------------
|
|
||||||
|
|
||||||
### Neue Funktionen {#v1.0.0.5-features}
|
|
||||||
|
|
||||||
* Die Datenbank kann im Haupt-Fenster (`MainWindow`) gesichert und wiederhergestellt werden. (f02598760f)
|
|
||||||
|
|
||||||
### Sonstiges {#v1.0.0.5-misc}
|
|
||||||
|
|
||||||
* In der WGM ist eine Auswahl eines Zu/-Abschlags im Übernahme-Fenster (`DeliveryAdminWindow`) nun erforderlich. (a9b5317e79)
|
|
||||||
* In der Konfigurationsdatei kann im `[general]` Block `weighing = gross`, `weighing = net`, oder `weighing = box` angegeben werden. (d7012ebfa1)
|
|
||||||
* Über-Fenser (`AboutWindow`) hinzugefügt. (3c9b3c2db1)
|
|
||||||
* Abhängigkeiten aktualisiert. (44dcc5e19f, 98f8907817)
|
|
||||||
|
|
||||||
[v1.0.0.5]: https://git.necronda.net/winzer/elwig/releases/tag/v1.0.0.5
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[v1.0.0.4][v1.0.0.4] (2025-09-01) {#v1.0.0.4}
|
|
||||||
---------------------------------------------
|
|
||||||
|
|
||||||
### Behobene Fehler {#v1.0.0.4-bugfixes}
|
|
||||||
|
|
||||||
* Absturz beim Verschicken von einzelnen E-Mails außerhalb des Rundschreiben-Fensters (`MailWindow`) behoben. (07f9a0f522)
|
|
||||||
|
|
||||||
### Sonstiges {#v1.0.0.4-misc}
|
|
||||||
|
|
||||||
* Ladezeit des Fehler-Protokoll-Fensters (`LogWindow`) verbessert. (4653a4f129)
|
|
||||||
* Im Übernahme-Fenster (`DeliveryAdminWindow`) ist es nun möglich die Qualitätsstufe zu verändern. (104798d4f2)
|
|
||||||
|
|
||||||
[v1.0.0.4]: https://git.necronda.net/winzer/elwig/releases/tag/v1.0.0.4
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[v1.0.0.3][v1.0.0.3] (2025-08-11) {#v1.0.0.3}
|
|
||||||
---------------------------------------------
|
|
||||||
|
|
||||||
### Neue Funktionen {#v1.0.0.3-features}
|
|
||||||
|
|
||||||
* Im Haupt-Fenster (`MainWindow`) ist es nun möglich die gesamte Datenbank zu hochzuladen bzw. herunterzuladen. ([#69][i69])
|
|
||||||
|
|
||||||
### Sonstiges {#v1.0.0.3-misc}
|
|
||||||
|
|
||||||
* Die Intigrität von Elwig-Export-Dateien (`.elwig.zip`) und anderen `.zip` Dateien wir nun überprüft. (d3157e4d48)
|
|
||||||
* Die Herkunftshierarchie wird nun auch automatisch synchronisiert (benötigt für Stamm-KG bei Mitglied, Ried/KG bei Flächenbindung, und Herkunft bei Lieferung). ([#70][i70], b6c03892b1)
|
|
||||||
* Abhängigkeiten aktualisiert. (1f165055c1, 4e2eca295d)
|
|
||||||
|
|
||||||
[v1.0.0.3]: https://git.necronda.net/winzer/elwig/releases/tag/v1.0.0.3
|
|
||||||
[i69]: https://git.necronda.net/winzer/elwig/issues/69
|
|
||||||
[i70]: https://git.necronda.net/winzer/elwig/issues/70
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[v1.0.0.2][v1.0.0.2] (2025-08-05) {#v1.0.0.2}
|
[v1.0.0.2][v1.0.0.2] (2025-08-05) {#v1.0.0.2}
|
||||||
---------------------------------------------
|
---------------------------------------------
|
||||||
|
|
||||||
@@ -232,8 +9,6 @@ Changelog
|
|||||||
|
|
||||||
* Explizit native SQLite-Bibliothek hinzugefügt. (77c3f388e7)
|
* Explizit native SQLite-Bibliothek hinzugefügt. (77c3f388e7)
|
||||||
|
|
||||||
[v1.0.0.2]: https://git.necronda.net/winzer/elwig/releases/tag/v1.0.0.2
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -245,8 +20,6 @@ Changelog
|
|||||||
* Abhängigkeiten aktualisiert. (466c8a322c)
|
* Abhängigkeiten aktualisiert. (466c8a322c)
|
||||||
* Angepasste Fehlermeldung, wenn Importieren fehlschlägt. (ab7c7404e2)
|
* Angepasste Fehlermeldung, wenn Importieren fehlschlägt. (ab7c7404e2)
|
||||||
|
|
||||||
[v1.0.0.1]: https://git.necronda.net/winzer/elwig/releases/tag/v1.0.0.1
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
<DataTemplate x:Key="WineVarietyTemplateExpanded">
|
<DataTemplate x:Key="WineVarietyTemplateExpanded">
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<TextBlock Text="{Binding SortIdFormat}" Foreground="{Binding Color}" MinWidth="36" Margin="0,0,10,0"/>
|
<TextBlock Text="{Binding SortId}" Foreground="{Binding Color}" MinWidth="36" Margin="0,0,10,0"/>
|
||||||
<TextBlock Text="{Binding Name}" Foreground="{Binding Color}"/>
|
<TextBlock Text="{Binding Name}" Foreground="{Binding Color}"/>
|
||||||
<TextBlock Text="{Binding CommentFormat}" FontSize="10" VerticalAlignment="Bottom" Margin="0,0,0,2"/>
|
<TextBlock Text="{Binding CommentFormat}" FontSize="10" VerticalAlignment="Bottom" Margin="0,0,0,2"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
@@ -55,12 +55,6 @@
|
|||||||
<TextBlock Text="{Binding ValueStr}"/>
|
<TextBlock Text="{Binding ValueStr}"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
<DataTemplate x:Key="PublicModifierTemplate">
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<TextBlock Text="{Binding Name}" MinWidth="250" Margin="0,0,10,0"/>
|
|
||||||
<TextBlock Text="{Binding PublicValueStr}"/>
|
|
||||||
</StackPanel>
|
|
||||||
</DataTemplate>
|
|
||||||
|
|
||||||
<DataTemplate x:Key="WineAttributeTemplate">
|
<DataTemplate x:Key="WineAttributeTemplate">
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ using System.Collections.Generic;
|
|||||||
using System.Data;
|
using System.Data;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.NetworkInformation;
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@@ -26,7 +25,6 @@ namespace Elwig {
|
|||||||
public static bool ForceShutdown { get; private set; } = false;
|
public static bool ForceShutdown { get; private set; } = false;
|
||||||
|
|
||||||
private readonly DispatcherTimer _autoUpdateTimer = new() { Interval = TimeSpan.FromHours(1) };
|
private readonly DispatcherTimer _autoUpdateTimer = new() { Interval = TimeSpan.FromHours(1) };
|
||||||
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");
|
||||||
public static readonly string MailsPath = Path.Combine(DataPath, "mails");
|
public static readonly string MailsPath = Path.Combine(DataPath, "mails");
|
||||||
@@ -49,10 +47,9 @@ namespace Elwig {
|
|||||||
public static string? BranchPhoneNr { get; private set; }
|
public static string? BranchPhoneNr { get; private set; }
|
||||||
public static string? BranchFaxNr { get; private set; }
|
public static string? BranchFaxNr { get; private set; }
|
||||||
public static string? BranchMobileNr { get; private set; }
|
public static string? BranchMobileNr { get; private set; }
|
||||||
|
public static IList<IScale> Scales { get; private set; }
|
||||||
public static IList<IScale> Scales { get; private set; } = [];
|
public static IList<ICommandScale> CommandScales => Scales.Where(s => s is ICommandScale).Cast<ICommandScale>().ToList();
|
||||||
public static IList<ICommandScale> CommandScales => [.. Scales.Where(s => s is ICommandScale).Cast<ICommandScale>()];
|
public static IList<IEventScale> EventScales => Scales.Where(s => s is IEventScale).Cast<IEventScale>().ToList();
|
||||||
public static IList<IEventScale> EventScales => [.. Scales.Where(s => s is IEventScale).Cast<IEventScale>()];
|
|
||||||
public static ClientParameters Client { get; set; }
|
public static ClientParameters Client { get; set; }
|
||||||
|
|
||||||
public static Dispatcher MainDispatcher { get; private set; }
|
public static Dispatcher MainDispatcher { get; private set; }
|
||||||
@@ -130,18 +127,14 @@ namespace Elwig {
|
|||||||
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 () => {
|
||||||
await Task.Delay(1000);
|
await Task.Delay(500);
|
||||||
await CheckForUpdates();
|
await CheckForUpdates();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
NetworkChange.NetworkAvailabilityChanged += OnNetworkAvailabilityChanged;
|
|
||||||
_autoUpdateTimer.Tick += new EventHandler(OnAutoUpdateTimer);
|
_autoUpdateTimer.Tick += new EventHandler(OnAutoUpdateTimer);
|
||||||
_autoUpdateTimer.Start();
|
_autoUpdateTimer.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
SerialPortWatcher.SerialPortConnected += OnSerialPortConnected;
|
|
||||||
SerialPortWatcher.SerialPortDisconnected += OnSerialPortDisconnected;
|
|
||||||
|
|
||||||
var list = new List<IScale>();
|
var list = new List<IScale>();
|
||||||
foreach (var s in Config.Scales) {
|
foreach (var s in Config.Scales) {
|
||||||
try {
|
try {
|
||||||
@@ -149,7 +142,7 @@ namespace Elwig {
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
list.Add(new InvalidScale(s.Id));
|
list.Add(new InvalidScale(s.Id));
|
||||||
if (s.Required)
|
if (s.Required)
|
||||||
MessageBox.Show($"Verbindung zu Waage {s.Id} konnte nicht hergestellt werden:\n\n{e.Message}", "Waagenfehler",
|
MessageBox.Show($"Unable to create scale {s.Id}:\n\n{e.Message}", "Scale Error",
|
||||||
MessageBoxButton.OK, MessageBoxImage.Error);
|
MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -157,7 +150,7 @@ namespace Elwig {
|
|||||||
|
|
||||||
if (Config.Branch != null) {
|
if (Config.Branch != null) {
|
||||||
if (!branches.ContainsKey(Config.Branch.ToLower())) {
|
if (!branches.ContainsKey(Config.Branch.ToLower())) {
|
||||||
MessageBox.Show("Ungültige Zweigstelle in Konfigurationsdatei!", "Ungültige Zweigstelle", MessageBoxButton.OK, MessageBoxImage.Error);
|
MessageBox.Show("Invalid branch name in config!", "Invalid Branch Config", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
Shutdown();
|
Shutdown();
|
||||||
} else {
|
} else {
|
||||||
SetBranch(branches[Config.Branch.ToLower()]);
|
SetBranch(branches[Config.Branch.ToLower()]);
|
||||||
@@ -165,20 +158,10 @@ namespace Elwig {
|
|||||||
} else if (branches.Count == 1) {
|
} else if (branches.Count == 1) {
|
||||||
SetBranch(branches.First().Value);
|
SetBranch(branches.First().Value);
|
||||||
} else {
|
} else {
|
||||||
MessageBox.Show("Erkennen der lokalen Zweigstelle nicht möglich!", "Ungültige Zweigstelle", MessageBoxButton.OK, MessageBoxImage.Error);
|
MessageBox.Show("Unable to determine local branch!", "Invalid Branch Config", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
Shutdown();
|
Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Config.WeighingMode == null) {
|
|
||||||
if (Client.IsMatzen || Client.IsWolkersdorf) {
|
|
||||||
Config.WeighingMode = WeighingMode.Net;
|
|
||||||
} else if (Client.IsHaugsdorf || Client.IsSitzendorf) {
|
|
||||||
Config.WeighingMode = WeighingMode.Box;
|
|
||||||
} else if (Client.IsBaden || Client.IsGrInzersdorf) {
|
|
||||||
Config.WeighingMode = WeighingMode.Gross;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
base.OnStartup(evt);
|
base.OnStartup(evt);
|
||||||
|
|
||||||
var window = new MainWindow();
|
var window = new MainWindow();
|
||||||
@@ -186,7 +169,6 @@ namespace Elwig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async void Application_Exit(object sender, ExitEventArgs evt) {
|
private async void Application_Exit(object sender, ExitEventArgs evt) {
|
||||||
SerialPortWatcher.Dispose();
|
|
||||||
foreach (var s in EventScales) {
|
foreach (var s in EventScales) {
|
||||||
s.Dispose();
|
s.Dispose();
|
||||||
}
|
}
|
||||||
@@ -236,63 +218,6 @@ namespace Elwig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnNetworkAvailabilityChanged(object? sender, NetworkAvailabilityEventArgs evt) {
|
|
||||||
if (!evt.IsAvailable) return;
|
|
||||||
if (Utils.HasInternetConnectivity()) {
|
|
||||||
Utils.RunBackground("Auto Updater", async () => {
|
|
||||||
await Task.Delay(2000);
|
|
||||||
await CheckForUpdates();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnSerialPortConnected(object? sender, string name) {
|
|
||||||
for (var i = 0; i < Config.Scales.Count; i++) {
|
|
||||||
var s = Config.Scales[i];
|
|
||||||
if (s.Connection?.StartsWith($"serial://{name}:") ?? false) {
|
|
||||||
if (Scales[i] is InvalidScale) {
|
|
||||||
try {
|
|
||||||
Scales[i] = Scale.FromConfig(s);
|
|
||||||
MessageBox.Show($"Verbindung zu Waage {s.Id} wieder hergestellt!", $"Waage {s.Id}", MessageBoxButton.OK, MessageBoxImage.Information);
|
|
||||||
} catch (Exception e) {
|
|
||||||
Scales[i] = new InvalidScale(s.Id);
|
|
||||||
MessageBox.Show($"Verbindung zu Waage {s.Id} konnte nicht hergestellt werden:\n\n{e.Message}", "Waagenfehler",
|
|
||||||
MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
}
|
|
||||||
} else if (Scales[i] is IEventScale) {
|
|
||||||
MessageBox.Show($"Verbindung zu Waage {s.Id} wieder hergestellt!", $"Waage {s.Id}", MessageBoxButton.OK, MessageBoxImage.Information);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
UpdateScales();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnSerialPortDisconnected(object? sender, string name) {
|
|
||||||
for (var i = 0; i < Config.Scales.Count; i++) {
|
|
||||||
var s = Config.Scales[i];
|
|
||||||
if ((s.Connection?.StartsWith($"serial://{name}:") ?? false) && Scales[i] is not InvalidScale) {
|
|
||||||
MessageBox.Show($"Verbindung zu Waage {s.Id} unterbrochen!", $"Waagen {s.Id}", MessageBoxButton.OK, MessageBoxImage.Warning);
|
|
||||||
if (Scales[i] is ICommandScale) {
|
|
||||||
try {
|
|
||||||
Scales[i].Dispose();
|
|
||||||
} catch {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
Scales[i] = new InvalidScale(s.Id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
UpdateScales();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void UpdateScales() {
|
|
||||||
foreach (Window w in CurrentApp.Windows) {
|
|
||||||
if (w is DeliveryAdminWindow t && t.ViewModel.IsReceipt) {
|
|
||||||
t.UpdateScales();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task CheckForUpdates(bool showAlert = false) {
|
public static async Task CheckForUpdates(bool showAlert = false) {
|
||||||
if (Config.UpdateUrl == null) return;
|
if (Config.UpdateUrl == null) return;
|
||||||
var latest = await Utils.GetLatestInstallerUrl(Config.UpdateUrl);
|
var latest = await Utils.GetLatestInstallerUrl(Config.UpdateUrl);
|
||||||
@@ -317,9 +242,7 @@ namespace Elwig {
|
|||||||
|
|
||||||
public static async Task ReplaceDatabase(string filename) {
|
public static async Task ReplaceDatabase(string filename) {
|
||||||
try {
|
try {
|
||||||
await Task.Run(async () => {
|
await ElwigData.ImportDatabase(filename);
|
||||||
await Database.Import(filename);
|
|
||||||
});
|
|
||||||
MessageBox.Show("Das Ersetzen war erfolgreich!\n\nBitte starten Sie Elwig neu!", "Datenbank ersetzen", MessageBoxButton.OK, MessageBoxImage.Information);
|
MessageBox.Show("Das Ersetzen war erfolgreich!\n\nBitte starten Sie Elwig neu!", "Datenbank ersetzen", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||||
ForceShutdown = true;
|
ForceShutdown = true;
|
||||||
Current.Shutdown();
|
Current.Shutdown();
|
||||||
|
|||||||
@@ -124,24 +124,19 @@ namespace Elwig.Controls {
|
|||||||
SelectItemsReverse();
|
SelectItemsReverse();
|
||||||
var dmp = !string.IsNullOrEmpty(ListDisplayMemberPath) ? ListDisplayMemberPath : !string.IsNullOrEmpty(DisplayMemberPath) ? DisplayMemberPath : null;
|
var dmp = !string.IsNullOrEmpty(ListDisplayMemberPath) ? ListDisplayMemberPath : !string.IsNullOrEmpty(DisplayMemberPath) ? DisplayMemberPath : null;
|
||||||
if (SelectedItems.Count == ItemsSource.Cast<object>().Count() && AllItemsSelectedContent != null) {
|
if (SelectedItems.Count == ItemsSource.Cast<object>().Count() && AllItemsSelectedContent != null) {
|
||||||
|
_textBox.Text = AllItemsSelectedContent;
|
||||||
AllItemsSelected = true;
|
AllItemsSelected = true;
|
||||||
} else if (SelectedItems.Count == 0) {
|
|
||||||
AllItemsSelected = false;
|
|
||||||
} else {
|
|
||||||
AllItemsSelected = null;
|
|
||||||
}
|
|
||||||
if (SelectedItems.Count > 1 && SelectedItems.Count == ItemsSource.Cast<object>().Count() && AllItemsSelectedContent != null) {
|
|
||||||
_textBox.Text = AllItemsSelectedContent;
|
|
||||||
} else if (SelectedItems.Count == 0) {
|
} else if (SelectedItems.Count == 0) {
|
||||||
_textBox.Text = "";
|
_textBox.Text = "";
|
||||||
|
AllItemsSelected = false;
|
||||||
} else {
|
} else {
|
||||||
_textBox.Text = string.Join(Delimiter,
|
_textBox.Text = string.Join(Delimiter,
|
||||||
dmp == null ? SelectedItems.Cast<object>() :
|
dmp == null ? SelectedItems.Cast<object>() :
|
||||||
SelectedItems.Cast<object>()
|
SelectedItems.Cast<object>()
|
||||||
.Select(i => i.GetType().GetProperty(dmp)?.GetValue(i))
|
.Select(i => i.GetType().GetProperty(dmp)?.GetValue(i))
|
||||||
);
|
);
|
||||||
|
AllItemsSelected = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
RaiseEvent(new SelectionChangedEventArgs(SelectionChangedEvent, evt.RemovedItems, evt.AddedItems));
|
RaiseEvent(new SelectionChangedEventArgs(SelectionChangedEvent, evt.RemovedItems, evt.AddedItems));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,16 +19,6 @@ namespace Elwig.Documents {
|
|||||||
Member = m;
|
Member = m;
|
||||||
Location = App.BranchLocation;
|
Location = App.BranchLocation;
|
||||||
IncludeSender = includeSender;
|
IncludeSender = includeSender;
|
||||||
var c = App.Client;
|
|
||||||
Header = $"<div class='name'>{c.Name}</div><div class='suffix'>{c.NameSuffix}</div><div class='type'>{c.NameTypeFull}</div>";
|
|
||||||
Footer = Utils.GenerateFooter("<br/>", " \u00b7 ")
|
|
||||||
.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.EmailAddress != null ? $"<a href=\"mailto:{c.Name} {c.NameSuffix} <{c.EmailAddress}>\">{c.EmailAddress}</a>" : null)
|
|
||||||
.Item(c.Website != null ? $"<a href=\"http://{c.Website}/\">{c.Website}</a>" : null)
|
|
||||||
.Item("Betriebs-Nr.", c.LfbisNr).Item("Bio-KSt.", c.OrganicAuthority).NextLine()
|
|
||||||
.Item("UID", c.UstIdNr).Item("BIC", c.Bic).Item("IBAN", c.Iban)
|
|
||||||
.ToString();
|
|
||||||
var uid = (m.UstIdNr ?? "-") + (m.IsBuchführend ? "" : " <i>(pauschaliert)</i>");
|
var uid = (m.UstIdNr ?? "-") + (m.IsBuchführend ? "" : " <i>(pauschaliert)</i>");
|
||||||
Aside = $"<table><colgroup><col span='1' style='width: 22.5mm;'/><col span='1' style='width: 42.5mm;'/></colgroup>" +
|
Aside = $"<table><colgroup><col span='1' style='width: 22.5mm;'/><col span='1' style='width: 42.5mm;'/></colgroup>" +
|
||||||
$"<thead><tr><th colspan='2'>Mitglied</th></tr></thead><tbody>" +
|
$"<thead><tr><th colspan='2'>Mitglied</th></tr></thead><tbody>" +
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ namespace Elwig.Documents {
|
|||||||
Data = data;
|
Data = data;
|
||||||
Payment = p;
|
Payment = p;
|
||||||
Credit = p.Credit;
|
Credit = p.Credit;
|
||||||
IsPreview = Payment == null || Credit == null;
|
|
||||||
var season = p.Variant.Season;
|
var season = p.Variant.Season;
|
||||||
if (considerCustomModifiers) {
|
if (considerCustomModifiers) {
|
||||||
CustomPayment = ctx.CustomPayments.Find(p.Year, p.MgNr);
|
CustomPayment = ctx.CustomPayments.Find(p.Year, p.MgNr);
|
||||||
@@ -49,7 +48,7 @@ namespace Elwig.Documents {
|
|||||||
if (CustomPayment?.ModComment != null) {
|
if (CustomPayment?.ModComment != null) {
|
||||||
MemberModifier = CustomPayment.ModComment;
|
MemberModifier = CustomPayment.ModComment;
|
||||||
} else if (mod != null) {
|
} else if (mod != null) {
|
||||||
MemberModifier = $"{mod.Name} ({mod.PublicValueStr})";
|
MemberModifier = $"{mod.Name} ({mod.ValueStr})";
|
||||||
} else {
|
} else {
|
||||||
MemberModifier = "Sonstige Zu-/Abschläge";
|
MemberModifier = "Sonstige Zu-/Abschläge";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
h1 {
|
h1 {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 24pt;
|
font-size: 24pt;
|
||||||
margin-top: 0;
|
margin-top: 10mm;
|
||||||
margin-bottom: 2mm;
|
margin-bottom: 2mm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
h1 {
|
h1 {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 24pt;
|
font-size: 24pt;
|
||||||
margin-top: 0;
|
margin-top: 10mm;
|
||||||
margin-bottom: 2mm;
|
margin-bottom: 2mm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
h1 {
|
h1 {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 24pt;
|
font-size: 24pt;
|
||||||
margin-top: 0;
|
margin-top: 10mm;
|
||||||
margin-bottom: 2mm;
|
margin-bottom: 2mm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,7 @@
|
|||||||
@if (part.Modifiers.Count() > 0) {
|
@if (part.Modifiers.Count() > 0) {
|
||||||
var first = true;
|
var first = true;
|
||||||
foreach (var mod in part.Modifiers) {
|
foreach (var mod in part.Modifiers) {
|
||||||
<tr class="tight @(first ? "first" : "")"><td></td><td>@Raw(first ? "<i>Zu-/Abschläge:</i>" : "")</td><td colspan="3"><b>@mod.Name</b></td><td style="white-space: pre;">@mod.PublicValueStr</td></tr>
|
<tr class="tight @(first ? "first" : "")"><td></td><td>@Raw(first ? "<i>Zu-/Abschläge:</i>" : "")</td><td colspan="3"><b>@mod.Name</b></td><td style="white-space: pre;">@mod.ValueStr</td></tr>
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Elwig.Helpers.Printing;
|
using Elwig.Helpers.Printing;
|
||||||
using MimeKit;
|
using MimeKit;
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace Elwig.Documents {
|
namespace Elwig.Documents {
|
||||||
public abstract partial class Document : IDisposable {
|
public abstract partial class Document : IDisposable {
|
||||||
@@ -19,11 +18,10 @@ namespace Elwig.Documents {
|
|||||||
protected string? _pdfPath;
|
protected string? _pdfPath;
|
||||||
protected string? PdfPath => _pdfPath ?? _pdfFile?.FilePath;
|
protected string? PdfPath => _pdfPath ?? _pdfFile?.FilePath;
|
||||||
public int? TotalPages { get; private set; }
|
public int? TotalPages { get; private set; }
|
||||||
public int? Pages => TotalPages / (IsDoublePaged ? 2 : 1);
|
public int? Pages => TotalPages / (DoublePaged ? 2 : 1);
|
||||||
|
|
||||||
public bool ShowFoldMarks = App.Config.Debug;
|
public bool ShowFoldMarks = App.Config.Debug;
|
||||||
public bool IsDoublePaged = false;
|
public bool DoublePaged = false;
|
||||||
public bool IsPreview = false;
|
|
||||||
|
|
||||||
public string DocumentsPath;
|
public string DocumentsPath;
|
||||||
public int CurrentNextSeason;
|
public int CurrentNextSeason;
|
||||||
@@ -40,8 +38,15 @@ namespace Elwig.Documents {
|
|||||||
CurrentNextSeason = Utils.CurrentNextSeason;
|
CurrentNextSeason = Utils.CurrentNextSeason;
|
||||||
Title = title;
|
Title = title;
|
||||||
Author = c.NameFull;
|
Author = c.NameFull;
|
||||||
Header = "";
|
Header = $"<div class='name'>{c.Name}</div><div class='suffix'>{c.NameSuffix}</div><div class='type'>{c.NameTypeFull}</div>";
|
||||||
Footer = Utils.GenerateFooter("<br/>", " \u00b7 ").Item(c.NameFull).ToString();
|
Footer = Utils.GenerateFooter("<br/>", " \u00b7 ")
|
||||||
|
.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.EmailAddress != null ? $"<a href=\"mailto:{c.Name} {c.NameSuffix} <{c.EmailAddress}>\">{c.EmailAddress}</a>" : null)
|
||||||
|
.Item(c.Website != null ? $"<a href=\"http://{c.Website}/\">{c.Website}</a>" : null)
|
||||||
|
.Item("Betriebs-Nr.", c.LfbisNr).Item("Bio-KSt.", c.OrganicAuthority).NextLine()
|
||||||
|
.Item("UID", c.UstIdNr).Item("BIC", c.Bic).Item("IBAN", c.Iban)
|
||||||
|
.ToString();
|
||||||
Date = DateOnly.FromDateTime(Utils.Today);
|
Date = DateOnly.FromDateTime(Utils.Today);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,7 +104,7 @@ namespace Elwig.Documents {
|
|||||||
return await Html.CompileRenderAsync(name, this); ;
|
return await Html.CompileRenderAsync(name, this); ;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Generate(CancellationToken? cancelToken = null, IProgress<double>? progress = null) {
|
public async Task Generate(IProgress<double>? progress = null) {
|
||||||
if (_pdfFile != null)
|
if (_pdfFile != null)
|
||||||
return;
|
return;
|
||||||
progress?.Report(0.0);
|
progress?.Report(0.0);
|
||||||
@@ -109,7 +114,6 @@ namespace Elwig.Documents {
|
|||||||
var pdf = new TempFile("pdf");
|
var pdf = new TempFile("pdf");
|
||||||
var tmpHtmls = new List<TempFile>();
|
var tmpHtmls = new List<TempFile>();
|
||||||
var tmpFiles = new List<string>();
|
var tmpFiles = new List<string>();
|
||||||
try {
|
|
||||||
var n = m.Documents.Count();
|
var n = m.Documents.Count();
|
||||||
int i = 0;
|
int i = 0;
|
||||||
foreach (var doc in m.Documents) {
|
foreach (var doc in m.Documents) {
|
||||||
@@ -117,8 +121,6 @@ namespace Elwig.Documents {
|
|||||||
tmpFiles.Add(doc.PdfPath!);
|
tmpFiles.Add(doc.PdfPath!);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (cancelToken?.IsCancellationRequested ?? false)
|
|
||||||
throw new OperationCanceledException("Dokumentenerzeugung abgebrochen!");
|
|
||||||
var tmpHtml = new TempFile("html");
|
var tmpHtml = new TempFile("html");
|
||||||
await File.WriteAllTextAsync(tmpHtml.FilePath, await doc.Render(), Utils.UTF8);
|
await File.WriteAllTextAsync(tmpHtml.FilePath, await doc.Render(), Utils.UTF8);
|
||||||
tmpHtmls.Add(tmpHtml);
|
tmpHtmls.Add(tmpHtml);
|
||||||
@@ -127,32 +129,21 @@ namespace Elwig.Documents {
|
|||||||
progress?.Report(GenerationProportion * 100 * i / n);
|
progress?.Report(GenerationProportion * 100 * i / n);
|
||||||
}
|
}
|
||||||
progress?.Report(GenerationProportion * 100);
|
progress?.Report(GenerationProportion * 100);
|
||||||
var pages = await Pdf.Convert(tmpFiles, pdf.FileName, IsDoublePaged, cancelToken, new Progress<double>(v => progress?.Report(GenerationProportion * 100 + v * (1 - GenerationProportion))));
|
var pages = await Pdf.Convert(tmpFiles, pdf.FileName, DoublePaged, new Progress<double>(v => progress?.Report(GenerationProportion * 100 + v * (1 - GenerationProportion))));
|
||||||
TotalPages = pages.Pages;
|
TotalPages = pages.Pages;
|
||||||
_pdfFile = pdf;
|
|
||||||
} catch {
|
|
||||||
pdf.Dispose();
|
|
||||||
throw;
|
|
||||||
} finally {
|
|
||||||
foreach (var tmp in tmpHtmls) {
|
foreach (var tmp in tmpHtmls) {
|
||||||
tmp.Dispose();
|
tmp.Dispose();
|
||||||
}
|
}
|
||||||
}
|
_pdfFile = pdf;
|
||||||
} else {
|
} else {
|
||||||
if (cancelToken?.IsCancellationRequested ?? false)
|
|
||||||
throw new OperationCanceledException("Dokumentenerzeugung abgebrochen!");
|
|
||||||
var pdf = new TempFile("pdf");
|
var pdf = new TempFile("pdf");
|
||||||
try {
|
using (var tmpHtml = new TempFile("html")) {
|
||||||
using var tmpHtml = new TempFile("html");
|
|
||||||
await File.WriteAllTextAsync(tmpHtml.FilePath, await Render(), Utils.UTF8);
|
await File.WriteAllTextAsync(tmpHtml.FilePath, await Render(), Utils.UTF8);
|
||||||
progress?.Report(50.0);
|
progress?.Report(50.0);
|
||||||
var pages = await Pdf.Convert(tmpHtml.FilePath, pdf.FilePath, IsDoublePaged, cancelToken);
|
var pages = await Pdf.Convert(tmpHtml.FilePath, pdf.FilePath, DoublePaged);
|
||||||
TotalPages = pages.Pages;
|
TotalPages = pages.Pages;
|
||||||
_pdfFile = pdf;
|
|
||||||
} catch {
|
|
||||||
pdf.Dispose();
|
|
||||||
throw;
|
|
||||||
}
|
}
|
||||||
|
_pdfFile = pdf;
|
||||||
}
|
}
|
||||||
progress?.Report(100.0);
|
progress?.Report(100.0);
|
||||||
}
|
}
|
||||||
@@ -164,7 +155,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);
|
await Pdf.Print(PdfPath, copies, DoublePaged);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Show() {
|
public void Show() {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
<link rel="stylesheet" href="file:///@Raw(Model.DocumentsPath)\Document.css" />
|
<link rel="stylesheet" href="file:///@Raw(Model.DocumentsPath)\Document.css" />
|
||||||
<link rel="stylesheet" href="file:///@Raw(Model.DocumentsPath)\Document.Page.css" />
|
<link rel="stylesheet" href="file:///@Raw(Model.DocumentsPath)\Document.Page.css" />
|
||||||
<link rel="stylesheet" href="file:///@Raw(Model.DocumentsPath)\Document.Table.css" />
|
<link rel="stylesheet" href="file:///@Raw(Model.DocumentsPath)\Document.Table.css" />
|
||||||
@if (Model.IsDoublePaged) {
|
@if (Model.DoublePaged) {
|
||||||
<style>
|
<style>
|
||||||
@@page :left {
|
@@page :left {
|
||||||
margin: 25mm 25mm 35mm 20mm;
|
margin: 25mm 25mm 35mm 20mm;
|
||||||
@@ -34,14 +34,14 @@
|
|||||||
<div class="pre-footer">
|
<div class="pre-footer">
|
||||||
<span class="date">@($"{Model.Date:dddd, d. MMMM yyyy}")</span>
|
<span class="date">@($"{Model.Date:dddd, d. MMMM yyyy}")</span>
|
||||||
<span class="doc-id">@Model.DocumentId</span>
|
<span class="doc-id">@Model.DocumentId</span>
|
||||||
<span><span class="page"></span>@Raw(Model.IsPreview ? " <b>(vorläufig)</b>" : "")</span>
|
<span class="page"></span>
|
||||||
</div>
|
</div>
|
||||||
<footer>@Raw(Model.Footer)</footer>
|
<footer>@Raw(Model.Footer)</footer>
|
||||||
</div>
|
</div>
|
||||||
@if (Model.IsDoublePaged) {
|
@if (Model.DoublePaged) {
|
||||||
<div class="footer-wrapper left">
|
<div class="footer-wrapper left">
|
||||||
<div class="pre-footer">
|
<div class="pre-footer">
|
||||||
<span>@Raw(Model.IsPreview ? "<b>(vorläufig)</b> " : "")<span class="page"></span></span>
|
<span class="page"></span>
|
||||||
<span class="doc-id">@Model.DocumentId</span>
|
<span class="doc-id">@Model.DocumentId</span>
|
||||||
<span class="date">@($"{Model.Date:dddd, d. MMMM yyyy}")</span>
|
<span class="date">@($"{Model.Date:dddd, d. MMMM yyyy}")</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
h1 {
|
h1 {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 24pt;
|
font-size: 24pt;
|
||||||
margin-top: 0;
|
margin-top: 10mm;
|
||||||
margin-bottom: 2mm;
|
margin-bottom: 2mm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ namespace Elwig.Documents {
|
|||||||
Data = data;
|
Data = data;
|
||||||
CurrencySymbol = v.Season.Currency.Symbol ?? v.Season.Currency.Code;
|
CurrencySymbol = v.Season.Currency.Symbol ?? v.Season.Currency.Code;
|
||||||
MemberNum = v.Credits.Count;
|
MemberNum = v.Credits.Count;
|
||||||
IsPreview = MemberNum == 0;
|
|
||||||
DeliveryNum = v.DeliveryPartPayments.DistinctBy(p => p.DeliveryPart.Delivery).Count();
|
DeliveryNum = v.DeliveryPartPayments.DistinctBy(p => p.DeliveryPart.Delivery).Count();
|
||||||
DeliveryPartNum = v.DeliveryPartPayments.Count;
|
DeliveryPartNum = v.DeliveryPartPayments.Count;
|
||||||
ModifierStat = AppDbContext.GetModifierStats(v.Year, v.AvNr).GetAwaiter().GetResult();
|
ModifierStat = AppDbContext.GetModifierStats(v.Year, v.AvNr).GetAwaiter().GetResult();
|
||||||
|
|||||||
@@ -164,14 +164,14 @@
|
|||||||
<td class="number">@Utils.GetSign(considered)</td>
|
<td class="number">@Utils.GetSign(considered)</td>
|
||||||
<td class="number"><span class="fleft">@Model.CurrencySymbol</span>@($"{Math.Abs(considered):N2}")</td>
|
<td class="number"><span class="fleft">@Model.CurrencySymbol</span>@($"{Math.Abs(considered):N2}")</td>
|
||||||
<th class="lborder">Menge (gebunden):</th>
|
<th class="lborder">Menge (gebunden):</th>
|
||||||
<td colspan="2" class="number">@($"{Model.Data.Rows.Sum(r => r.Geb.Weight + r.LowGeb.Weight):N0}") kg</td>
|
<td colspan="2" class="number">@($"{Model.Data.Rows.Sum(r => r.Geb.Weight):N0}") kg</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th colspan="2">Auszahlungsbetrag:</th>
|
<th colspan="2">Auszahlungsbetrag:</th>
|
||||||
<td class="number tborder"></td>
|
<td class="number tborder"></td>
|
||||||
<td class="number tborder"><span class="fleft">@Model.CurrencySymbol</span>@($"{totalSum:N2}")</td>
|
<td class="number tborder"><span class="fleft">@Model.CurrencySymbol</span>@($"{totalSum:N2}")</td>
|
||||||
<th class="lborder">Gesamtmenge:</th>
|
<th class="lborder">Gesamtmenge:</th>
|
||||||
<td colspan="2" class="number tborder">@($"{Model.Data.Rows.Sum(r => r.Ungeb.Weight + r.LowGeb.Weight + r.Geb.Weight):N0}") kg</td>
|
<td colspan="2" class="number tborder">@($"{Model.Data.Rows.Sum(r => r.Ungeb.Weight + r.Geb.Weight):N0}") kg</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
h1 {
|
h1 {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 24pt;
|
font-size: 24pt;
|
||||||
margin-top: 0;
|
margin-top: 10mm;
|
||||||
margin-bottom: 2mm;
|
margin-bottom: 2mm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
h1 {
|
h1 {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 24pt;
|
font-size: 24pt;
|
||||||
margin-top: 0;
|
margin-top: 10mm;
|
||||||
margin-bottom: 2mm;
|
margin-bottom: 2mm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,12 +2,12 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<TargetFramework>net10.0-windows</TargetFramework>
|
<TargetFramework>net8.0-windows</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<UseWPF>true</UseWPF>
|
<UseWPF>true</UseWPF>
|
||||||
<PreserveCompilationContext>true</PreserveCompilationContext>
|
<PreserveCompilationContext>true</PreserveCompilationContext>
|
||||||
<ApplicationIcon>Resources\Images\Elwig.ico</ApplicationIcon>
|
<ApplicationIcon>Resources\Images\Elwig.ico</ApplicationIcon>
|
||||||
<Version>1.0.3.0</Version>
|
<Version>1.0.0.2</Version>
|
||||||
<SatelliteResourceLanguages>de-AT</SatelliteResourceLanguages>
|
<SatelliteResourceLanguages>de-AT</SatelliteResourceLanguages>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||||
@@ -22,23 +22,22 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
||||||
<PackageReference Include="LinqKit" Version="1.3.9" />
|
<PackageReference Include="LinqKit" Version="1.3.8" />
|
||||||
<PackageReference Include="MailKit" Version="4.14.1" />
|
<PackageReference Include="MailKit" Version="4.13.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Razor.Language" Version="6.0.36" />
|
<PackageReference Include="Microsoft.AspNetCore.Razor.Language" Version="6.0.36" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="10.0.2" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="9.0.8" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.2" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.8" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Ini" Version="10.0.2" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Ini" Version="9.0.8" />
|
||||||
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.3650.58" />
|
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.3405.78" />
|
||||||
<PackageReference Include="NJsonSchema" Version="11.5.2" />
|
<PackageReference Include="NJsonSchema" Version="11.4.0" />
|
||||||
<PackageReference Include="PdfiumViewer" Version="2.13.0" />
|
<PackageReference Include="PdfiumViewer" Version="2.13.0" />
|
||||||
<PackageReference Include="PdfiumViewer.Native.x86_64.no_v8-no_xfa" Version="2018.4.8.256" />
|
<PackageReference Include="PdfiumViewer.Native.x86_64.no_v8-no_xfa" Version="2018.4.8.256" />
|
||||||
<PackageReference Include="RazorLight" Version="2.3.1" />
|
<PackageReference Include="RazorLight" Version="2.3.1" />
|
||||||
<PackageReference Include="ScottPlot.WPF" Version="5.1.57" />
|
<PackageReference Include="ScottPlot.WPF" Version="5.0.55" />
|
||||||
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="3.0.2" />
|
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="3.0.1" />
|
||||||
<PackageReference Include="System.IO.Hashing" Version="10.0.2" />
|
<PackageReference Include="System.IO.Hashing" Version="9.0.8" />
|
||||||
<PackageReference Include="System.IO.Ports" Version="10.0.2" />
|
<PackageReference Include="System.IO.Ports" Version="9.0.8" />
|
||||||
<PackageReference Include="System.Management" Version="10.0.2" />
|
<PackageReference Include="System.Text.Encoding.CodePages" Version="9.0.8" />
|
||||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="10.0.2" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ using Microsoft.Data.Sqlite;
|
|||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Elwig.Models.Dtos;
|
using Elwig.Models.Dtos;
|
||||||
|
using System.Reflection;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
|
|
||||||
namespace Elwig.Helpers {
|
namespace Elwig.Helpers {
|
||||||
@@ -66,7 +67,7 @@ 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<MemberDeliveryPerVariantRowSingle> MemberDeliveryPerVariantRows { get; private set; }
|
||||||
public DbSet<MemberAreaComsRowSingle> MemberAreaComsRows { get; private set; }
|
public DbSet<MemberAreaComsRowSingle> 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; }
|
||||||
@@ -116,6 +117,39 @@ namespace Elwig.Helpers {
|
|||||||
return cnx;
|
return cnx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async Task ExecuteBatch(SqliteConnection cnx, string sql) {
|
||||||
|
using var cmd = cnx.CreateCommand();
|
||||||
|
cmd.CommandText = sql;
|
||||||
|
await (await cmd.ExecuteReaderAsync()).CloseAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task ExecuteEmbeddedScript(SqliteConnection cnx, Assembly asm, string name) {
|
||||||
|
using var stream = asm.GetManifestResourceStream(name) ?? throw new FileNotFoundException("Unable to load embedded resource");
|
||||||
|
using var reader = new StreamReader(stream);
|
||||||
|
await ExecuteBatch(cnx, await reader.ReadToEndAsync());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<object?> ExecuteScalar(SqliteConnection cnx, string sql) {
|
||||||
|
using var cmd = cnx.CreateCommand();
|
||||||
|
cmd.CommandText = sql;
|
||||||
|
return await cmd.ExecuteScalarAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<(string Table, long RowId, string Parent, long FkId)[]> ForeignKeyCheck(SqliteConnection cnx) {
|
||||||
|
using var cmd = cnx.CreateCommand();
|
||||||
|
cmd.CommandText = "PRAGMA foreign_key_check";
|
||||||
|
using var reader = await cmd.ExecuteReaderAsync();
|
||||||
|
var list = new List<(string, long, string, long)>();
|
||||||
|
while (await reader.ReadAsync()) {
|
||||||
|
var table = reader.GetString(0);
|
||||||
|
var rowid = reader.GetInt64(1);
|
||||||
|
var parent = reader.GetString(2);
|
||||||
|
var fkid = reader.GetInt64(3);
|
||||||
|
list.Add((table, rowid, parent, fkid));
|
||||||
|
}
|
||||||
|
return [.. list];
|
||||||
|
}
|
||||||
|
|
||||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
|
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
|
||||||
optionsBuilder.UseSqlite(ConnectionString);
|
optionsBuilder.UseSqlite(ConnectionString);
|
||||||
optionsBuilder.UseLazyLoadingProxies();
|
optionsBuilder.UseLazyLoadingProxies();
|
||||||
@@ -214,6 +248,13 @@ namespace Elwig.Helpers {
|
|||||||
return c + 1;
|
return c + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<WineQualLevel> GetWineQualityLevel(double kmw) {
|
||||||
|
return await WineQualityLevels
|
||||||
|
.Where(q => !q.IsPredicate && (q.MinKmw == null || q.MinKmw <= kmw))
|
||||||
|
.OrderBy(q => q.MinKmw)
|
||||||
|
.LastAsync();
|
||||||
|
}
|
||||||
|
|
||||||
public void UpdateDeliveryPartModifiers(DeliveryPart part, IEnumerable<Modifier> oldModifiers, IEnumerable<Modifier> newModifiers) {
|
public void UpdateDeliveryPartModifiers(DeliveryPart part, IEnumerable<Modifier> oldModifiers, IEnumerable<Modifier> newModifiers) {
|
||||||
foreach (var m in Modifiers.Where(m => m.Year == part.Year)) {
|
foreach (var m in Modifiers.Where(m => m.Year == part.Year)) {
|
||||||
var mod = new DeliveryPartModifier {
|
var mod = new DeliveryPartModifier {
|
||||||
|
|||||||
@@ -9,17 +9,17 @@ 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 = 36;
|
public static readonly int RequiredSchemaVersion = 32;
|
||||||
|
|
||||||
private static int VersionOffset = 0;
|
private static int VersionOffset = 0;
|
||||||
|
|
||||||
public static async Task<Version> CheckDb() {
|
public static async Task<Version> CheckDb() {
|
||||||
using var cnx = AppDbContext.Connect();
|
using var cnx = AppDbContext.Connect();
|
||||||
|
|
||||||
var applId = (long?)await cnx.ExecuteScalar("PRAGMA application_id") ?? 0;
|
var applId = (long?)await AppDbContext.ExecuteScalar(cnx, "PRAGMA application_id") ?? 0;
|
||||||
if (applId != 0x454C5747) throw new Exception($"Invalid application_id in database (0x{applId:X08})");
|
if (applId != 0x454C5747) throw new Exception($"Invalid application_id in database (0x{applId:X08})");
|
||||||
|
|
||||||
var schemaVers = (long?)await cnx.ExecuteScalar("PRAGMA schema_version") ?? 0;
|
var schemaVers = (long?)await AppDbContext.ExecuteScalar(cnx, "PRAGMA schema_version") ?? 0;
|
||||||
VersionOffset = (int)(schemaVers % 100);
|
VersionOffset = (int)(schemaVers % 100);
|
||||||
if (VersionOffset != 0) {
|
if (VersionOffset != 0) {
|
||||||
// schema was modified manually/externally
|
// schema was modified manually/externally
|
||||||
@@ -27,12 +27,12 @@ namespace Elwig.Helpers {
|
|||||||
}
|
}
|
||||||
await UpdateDbSchema(cnx, (int)(schemaVers / 100), RequiredSchemaVersion);
|
await UpdateDbSchema(cnx, (int)(schemaVers / 100), RequiredSchemaVersion);
|
||||||
|
|
||||||
var userVers = (long?)await cnx.ExecuteScalar("PRAGMA user_version") ?? 0;
|
var userVers = (long?)await AppDbContext.ExecuteScalar(cnx, "PRAGMA user_version") ?? 0;
|
||||||
var v = new Version((int)(userVers >> 24), (int)((userVers >> 16) & 0xFF), (int)((userVers >> 8) & 0xFF), (int)(userVers & 0xFF));
|
var v = new Version((int)(userVers >> 24), (int)((userVers >> 16) & 0xFF), (int)((userVers >> 8) & 0xFF), (int)(userVers & 0xFF));
|
||||||
|
|
||||||
if (App.Version > v) {
|
if (App.Version > v) {
|
||||||
long vers = (App.Version.Major << 24) | (App.Version.Minor << 16) | (App.Version.Build << 8) | App.Version.Revision;
|
long vers = (App.Version.Major << 24) | (App.Version.Minor << 16) | (App.Version.Build << 8) | App.Version.Revision;
|
||||||
await cnx.ExecuteBatch($"PRAGMA user_version = {vers}");
|
await AppDbContext.ExecuteBatch(cnx, $"PRAGMA user_version = {vers}");
|
||||||
}
|
}
|
||||||
|
|
||||||
return v;
|
return v;
|
||||||
@@ -67,20 +67,20 @@ namespace Elwig.Helpers {
|
|||||||
if (toExecute.Count == 0)
|
if (toExecute.Count == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
await cnx.ExecuteBatch("""
|
await AppDbContext.ExecuteBatch(cnx, """
|
||||||
PRAGMA locking_mode = EXCLUSIVE;
|
PRAGMA locking_mode = EXCLUSIVE;
|
||||||
BEGIN EXCLUSIVE;
|
BEGIN EXCLUSIVE;
|
||||||
""");
|
""");
|
||||||
foreach (var script in toExecute) {
|
foreach (var script in toExecute) {
|
||||||
await cnx.ExecuteEmbeddedScript(asm, script);
|
await AppDbContext.ExecuteEmbeddedScript(cnx, asm, script);
|
||||||
}
|
}
|
||||||
var violations = await cnx.ForeignKeyCheck();
|
var violations = await AppDbContext.ForeignKeyCheck(cnx);
|
||||||
if (violations.Length > 0) {
|
if (violations.Length > 0) {
|
||||||
throw new Exception($"Foreign key violations ({violations.Length}):\n" + string.Join("\n", violations
|
throw new Exception($"Foreign key violations ({violations.Length}):\n" + string.Join("\n", violations
|
||||||
.Select(v => $"{v.Table} - {v.RowId} - {v.Parent} - {v.FkId}")));
|
.Select(v => $"{v.Table} - {v.RowId} - {v.Parent} - {v.FkId}")));
|
||||||
}
|
}
|
||||||
|
|
||||||
await cnx.ExecuteBatch($"""
|
await AppDbContext.ExecuteBatch(cnx, $"""
|
||||||
COMMIT;
|
COMMIT;
|
||||||
VACUUM;
|
VACUUM;
|
||||||
PRAGMA schema_version = {toVersion * 100 + VersionOffset};
|
PRAGMA schema_version = {toVersion * 100 + VersionOffset};
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ namespace Elwig.Helpers.Billing {
|
|||||||
|
|
||||||
public async Task FinishSeason() {
|
public async Task FinishSeason() {
|
||||||
using var cnx = await AppDbContext.ConnectAsync();
|
using var cnx = await AppDbContext.ConnectAsync();
|
||||||
await cnx.ExecuteBatch($"""
|
await AppDbContext.ExecuteBatch(cnx, $"""
|
||||||
UPDATE season
|
UPDATE season
|
||||||
SET (start_date, end_date) = (SELECT MIN(date), MAX(date) FROM delivery WHERE year = {Year})
|
SET (start_date, end_date) = (SELECT MIN(date), MAX(date) FROM delivery WHERE year = {Year})
|
||||||
WHERE year = {Year};
|
WHERE year = {Year};
|
||||||
@@ -37,7 +37,7 @@ namespace Elwig.Helpers.Billing {
|
|||||||
public async Task AutoAdjustBusinessShares(DateOnly date, int allowanceKg = 0, double allowanceBs = 0, int allowanceKgPerBs = 0, double allowanceRel = 0, int addMinBs = 1) {
|
public async Task AutoAdjustBusinessShares(DateOnly date, int allowanceKg = 0, double allowanceBs = 0, int allowanceKgPerBs = 0, double allowanceRel = 0, int addMinBs = 1) {
|
||||||
if (addMinBs < 1) addMinBs = 1;
|
if (addMinBs < 1) addMinBs = 1;
|
||||||
using var cnx = await AppDbContext.ConnectAsync();
|
using var cnx = await AppDbContext.ConnectAsync();
|
||||||
await cnx.ExecuteBatch($"""
|
await AppDbContext.ExecuteBatch(cnx, $"""
|
||||||
UPDATE member
|
UPDATE member
|
||||||
SET business_shares = member.business_shares - h.business_shares
|
SET business_shares = member.business_shares - h.business_shares
|
||||||
FROM member_history h
|
FROM member_history h
|
||||||
@@ -66,7 +66,7 @@ namespace Elwig.Helpers.Billing {
|
|||||||
|
|
||||||
public async Task UnAdjustBusinessShares() {
|
public async Task UnAdjustBusinessShares() {
|
||||||
using var cnx = await AppDbContext.ConnectAsync();
|
using var cnx = await AppDbContext.ConnectAsync();
|
||||||
await cnx.ExecuteBatch($"""
|
await AppDbContext.ExecuteBatch(cnx, $"""
|
||||||
UPDATE member
|
UPDATE member
|
||||||
SET business_shares = member.business_shares - h.business_shares
|
SET business_shares = member.business_shares - h.business_shares
|
||||||
FROM member_history h
|
FROM member_history h
|
||||||
@@ -157,9 +157,9 @@ namespace Elwig.Helpers.Billing {
|
|||||||
lastMgNr = mgnr;
|
lastMgNr = mgnr;
|
||||||
}
|
}
|
||||||
|
|
||||||
await cnx.ExecuteBatch($"UPDATE delivery_part_bucket SET value = 0 WHERE year = {Year}");
|
await AppDbContext.ExecuteBatch(cnx, $"UPDATE delivery_part_bucket SET value = 0 WHERE year = {Year}");
|
||||||
if (inserts.Count > 0) {
|
if (inserts.Count > 0) {
|
||||||
await cnx.ExecuteBatch($"""
|
await AppDbContext.ExecuteBatch(cnx, $"""
|
||||||
INSERT INTO delivery_part_bucket (year, did, dpnr, bktnr, discr, value)
|
INSERT INTO delivery_part_bucket (year, did, dpnr, bktnr, discr, value)
|
||||||
VALUES {string.Join(",\n ", inserts.Select(i => $"({Year}, {i.Item1}, {i.Item2}, {i.Item3}, '{i.Item4}', {i.Item5})"))}
|
VALUES {string.Join(",\n ", inserts.Select(i => $"({Year}, {i.Item1}, {i.Item2}, {i.Item3}, '{i.Item4}', {i.Item5})"))}
|
||||||
ON CONFLICT DO UPDATE
|
ON CONFLICT DO UPDATE
|
||||||
@@ -237,7 +237,7 @@ namespace Elwig.Helpers.Billing {
|
|||||||
if (needed == 0) break;
|
if (needed == 0) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
await cnx.ExecuteBatch($"""
|
await AppDbContext.ExecuteBatch(cnx, $"""
|
||||||
INSERT INTO delivery_part_bucket (year, did, dpnr, bktnr, discr, value)
|
INSERT INTO delivery_part_bucket (year, did, dpnr, bktnr, discr, value)
|
||||||
VALUES {string.Join(",\n ", posChanges.Select(i => $"({Year}, {i.Item1}, {i.Item2}, {i.Item3}, '', {i.Item4})"))}
|
VALUES {string.Join(",\n ", posChanges.Select(i => $"({Year}, {i.Item1}, {i.Item2}, {i.Item3}, '', {i.Item4})"))}
|
||||||
ON CONFLICT DO UPDATE
|
ON CONFLICT DO UPDATE
|
||||||
|
|||||||
@@ -20,19 +20,13 @@ namespace Elwig.Helpers.Billing {
|
|||||||
Data = PaymentBillingData.FromJson(PaymentVariant.Data, Utils.GetVaributes(ctx, Year, onlyDelivered: false));
|
Data = PaymentBillingData.FromJson(PaymentVariant.Data, Utils.GetVaributes(ctx, Year, onlyDelivered: false));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Calculate(bool strictPrices = true, bool? honorGebunden = null, bool? allowAttrsIntoLower = null, bool? avoidUnderDeliveries = null) {
|
public async Task Calculate(bool? honorGebunden = null, bool? allowAttrsIntoLower = null, bool? avoidUnderDeliveries = null) {
|
||||||
using var cnx = await AppDbContext.ConnectAsync();
|
using var cnx = await AppDbContext.ConnectAsync();
|
||||||
using var tx = await cnx.BeginTransactionAsync();
|
using var tx = await cnx.BeginTransactionAsync();
|
||||||
await CalculateBuckets(honorGebunden, allowAttrsIntoLower, avoidUnderDeliveries, cnx);
|
await CalculateBuckets(honorGebunden, allowAttrsIntoLower, avoidUnderDeliveries, cnx);
|
||||||
await DeleteInDb(cnx);
|
await DeleteInDb(cnx);
|
||||||
await SetCalcTime(cnx);
|
await SetCalcTime(cnx);
|
||||||
KeyNotFoundException? exception = null;
|
await CalculatePrices(cnx);
|
||||||
try {
|
|
||||||
await CalculatePrices(cnx, strictPrices);
|
|
||||||
} catch (KeyNotFoundException e) {
|
|
||||||
if (strictPrices) throw;
|
|
||||||
exception = e;
|
|
||||||
}
|
|
||||||
if (Data.ConsiderDelieryModifiers) {
|
if (Data.ConsiderDelieryModifiers) {
|
||||||
await CalculateDeliveryModifiers(cnx);
|
await CalculateDeliveryModifiers(cnx);
|
||||||
}
|
}
|
||||||
@@ -40,28 +34,26 @@ namespace Elwig.Helpers.Billing {
|
|||||||
await CalculateMemberModifiers(cnx);
|
await CalculateMemberModifiers(cnx);
|
||||||
}
|
}
|
||||||
await tx.CommitAsync();
|
await tx.CommitAsync();
|
||||||
if (exception != null)
|
|
||||||
throw exception;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Commit() {
|
public async Task Commit() {
|
||||||
await Revert();
|
await Revert();
|
||||||
using var cnx = await AppDbContext.ConnectAsync();
|
using var cnx = await AppDbContext.ConnectAsync();
|
||||||
await cnx.ExecuteBatch($"""
|
await AppDbContext.ExecuteBatch(cnx, $"""
|
||||||
INSERT INTO credit (year, tgnr, mgnr, avnr, net_amount, prev_net_amount, vat, modifiers, prev_modifiers)
|
INSERT INTO credit (year, tgnr, mgnr, avnr, net_amount, prev_net_amount, vat, modifiers, prev_modifiers)
|
||||||
SELECT s.year,
|
SELECT s.year,
|
||||||
COALESCE(t.tgnr, 0) + ROW_NUMBER() OVER(ORDER BY m.mgnr) AS tgnr,
|
COALESCE(t.tgnr, 0) + ROW_NUMBER() OVER(ORDER BY m.mgnr) AS tgnr,
|
||||||
m.mgnr,
|
m.mgnr,
|
||||||
v.avnr,
|
v.avnr,
|
||||||
ROUND(p.amount / POW(10, s.precision - 2)) AS net_amount,
|
ROUND(p.amount / POW(10, s.precision - 2)) AS net_amount,
|
||||||
IIF(lc.amount < 0, 0, ROUND(lp.amount / POW(10, s.precision - 2))) AS prev_net_amount,
|
IIF(lc.amount >= 0, ROUND(lp.amount / POW(10, s.precision - 2)), 0) AS prev_net_amount,
|
||||||
IIF(m.buchführend, s.vat_normal, s.vat_flatrate) AS vat,
|
IIF(m.buchführend, s.vat_normal, s.vat_flatrate) AS vat,
|
||||||
ROUND(IIF({Data.ConsiderTotalPenalty}, COALESCE(b.total_penalty, 0), 0) / POW(10, s.precision - 2)) +
|
ROUND(IIF({Data.ConsiderTotalPenalty}, COALESCE(b.total_penalty, 0), 0) / POW(10, s.precision - 2)) +
|
||||||
ROUND(IIF({Data.ConsiderContractPenalties}, COALESCE(u.total_penalty, 0), 0) / POW(10, 4 - 2)) +
|
ROUND(IIF({Data.ConsiderContractPenalties}, COALESCE(u.total_penalty, 0), 0) / POW(10, 4 - 2)) +
|
||||||
ROUND(IIF({Data.ConsiderAutoBusinessShares}, -COALESCE(a.total_amount, 0), 0) / POW(10, s.precision - 2)) +
|
ROUND(IIF({Data.ConsiderAutoBusinessShares}, -COALESCE(a.total_amount, 0), 0) / POW(10, s.precision - 2)) +
|
||||||
IIF({Data.ConsiderCustomModifiers}, COALESCE(x.amount, 0), 0)
|
IIF({Data.ConsiderCustomModifiers}, COALESCE(x.amount, 0), 0)
|
||||||
AS modifiers,
|
AS modifiers,
|
||||||
IIF(lc.amount < 0, 0, lc.modifiers) AS prev_modifiers
|
IIF(lc.amount >= 0, lc.modifiers, 0) AS prev_modifiers
|
||||||
FROM season s
|
FROM season s
|
||||||
JOIN payment_variant v ON v.year = s.year
|
JOIN payment_variant v ON v.year = s.year
|
||||||
LEFT JOIN payment_variant l ON l.year = s.year
|
LEFT JOIN payment_variant l ON l.year = s.year
|
||||||
@@ -82,27 +74,27 @@ namespace Elwig.Helpers.Billing {
|
|||||||
LEFT JOIN payment_custom x ON (x.year, x.mgnr) = (s.year, m.mgnr)
|
LEFT JOIN payment_custom x ON (x.year, x.mgnr) = (s.year, m.mgnr)
|
||||||
WHERE s.year = {Year} AND v.avnr = {AvNr};
|
WHERE s.year = {Year} AND v.avnr = {AvNr};
|
||||||
""");
|
""");
|
||||||
await cnx.ExecuteBatch($"""
|
await AppDbContext.ExecuteBatch(cnx, $"""
|
||||||
UPDATE payment_variant SET test_variant = FALSE WHERE (year, avnr) = ({Year}, {AvNr});
|
UPDATE payment_variant SET test_variant = FALSE WHERE (year, avnr) = ({Year}, {AvNr});
|
||||||
""");
|
""");
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Revert() {
|
public async Task Revert() {
|
||||||
using var cnx = await AppDbContext.ConnectAsync();
|
using var cnx = await AppDbContext.ConnectAsync();
|
||||||
await cnx.ExecuteBatch($"""
|
await AppDbContext.ExecuteBatch(cnx, $"""
|
||||||
DELETE FROM credit WHERE (year, avnr) = ({Year}, {AvNr});
|
DELETE FROM credit WHERE (year, avnr) = ({Year}, {AvNr});
|
||||||
UPDATE payment_variant SET test_variant = TRUE WHERE (year, avnr) = ({Year}, {AvNr});
|
UPDATE payment_variant SET test_variant = TRUE WHERE (year, avnr) = ({Year}, {AvNr});
|
||||||
""");
|
""");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async Task SetCalcTime(SqliteConnection cnx) {
|
protected async Task SetCalcTime(SqliteConnection cnx) {
|
||||||
await cnx.ExecuteBatch($"""
|
await AppDbContext.ExecuteBatch(cnx, $"""
|
||||||
UPDATE payment_variant SET calc_time = UNIXEPOCH() WHERE (year, avnr) = ({Year}, {AvNr})
|
UPDATE payment_variant SET calc_time = UNIXEPOCH() WHERE (year, avnr) = ({Year}, {AvNr})
|
||||||
""");
|
""");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async Task DeleteInDb(SqliteConnection cnx) {
|
protected async Task DeleteInDb(SqliteConnection cnx) {
|
||||||
await cnx.ExecuteBatch($"""
|
await AppDbContext.ExecuteBatch(cnx, $"""
|
||||||
DELETE FROM payment_delivery_part_bucket WHERE (year, avnr) = ({Year}, {AvNr});
|
DELETE FROM payment_delivery_part_bucket WHERE (year, avnr) = ({Year}, {AvNr});
|
||||||
DELETE FROM payment_delivery_part WHERE (year, avnr) = ({Year}, {AvNr});
|
DELETE FROM payment_delivery_part WHERE (year, avnr) = ({Year}, {AvNr});
|
||||||
DELETE FROM payment_member WHERE (year, avnr) = ({Year}, {AvNr});
|
DELETE FROM payment_member WHERE (year, avnr) = ({Year}, {AvNr});
|
||||||
@@ -116,7 +108,7 @@ namespace Elwig.Helpers.Billing {
|
|||||||
var multiplier = 0.50;
|
var multiplier = 0.50;
|
||||||
var includePredecessor = true;
|
var includePredecessor = true;
|
||||||
var modName = "Treue%";
|
var modName = "Treue%";
|
||||||
await cnx.ExecuteBatch($"""
|
await AppDbContext.ExecuteBatch(cnx, $"""
|
||||||
INSERT INTO payment_member (year, avnr, mgnr, net_amount, mod_abs, mod_rel)
|
INSERT INTO payment_member (year, avnr, mgnr, net_amount, mod_abs, mod_rel)
|
||||||
SELECT c.year, {AvNr}, s.mgnr, 0,
|
SELECT c.year, {AvNr}, s.mgnr, 0,
|
||||||
ROUND(s.sum * COALESCE(m.abs, 0)),
|
ROUND(s.sum * COALESCE(m.abs, 0)),
|
||||||
@@ -138,7 +130,7 @@ namespace Elwig.Helpers.Billing {
|
|||||||
mod_rel = mod_rel + excluded.mod_rel
|
mod_rel = mod_rel + excluded.mod_rel
|
||||||
""");
|
""");
|
||||||
}
|
}
|
||||||
await cnx.ExecuteBatch($"""
|
await AppDbContext.ExecuteBatch(cnx, $"""
|
||||||
INSERT INTO payment_member (year, avnr, mgnr, net_amount, mod_abs, mod_rel)
|
INSERT INTO payment_member (year, avnr, mgnr, net_amount, mod_abs, mod_rel)
|
||||||
SELECT x.year, {AvNr}, x.mgnr, 0, COALESCE(x.mod_abs * POW(10, s.precision - 2), 0), COALESCE(x.mod_rel, 0)
|
SELECT x.year, {AvNr}, x.mgnr, 0, COALESCE(x.mod_abs * POW(10, s.precision - 2), 0), COALESCE(x.mod_rel, 0)
|
||||||
FROM payment_custom x
|
FROM payment_custom x
|
||||||
@@ -150,8 +142,7 @@ namespace Elwig.Helpers.Billing {
|
|||||||
""");
|
""");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async Task CalculatePrices(SqliteConnection cnx, bool strict = true) {
|
protected async Task CalculatePrices(SqliteConnection cnx) {
|
||||||
var invalid = new HashSet<string>();
|
|
||||||
var parts = new List<(int Year, int DId, int DPNr, int BktNr, string SortId, string? AttrId, string? CultId, string Discr, int Value, double Oe, double Kmw, string QualId, bool AttrAreaCom)>();
|
var parts = new List<(int Year, int DId, int DPNr, int BktNr, string SortId, string? AttrId, string? CultId, string Discr, int Value, double Oe, double Kmw, string QualId, bool AttrAreaCom)>();
|
||||||
using (var cmd = cnx.CreateCommand()) {
|
using (var cmd = cnx.CreateCommand()) {
|
||||||
cmd.CommandText = $"""
|
cmd.CommandText = $"""
|
||||||
@@ -181,31 +172,21 @@ namespace Elwig.Helpers.Billing {
|
|||||||
var payAttrId = (part.Discr is "" or "_") ? null : part.Discr;
|
var payAttrId = (part.Discr is "" or "_") ? null : part.Discr;
|
||||||
var attrId = part.AttrAreaCom ? payAttrId : part.AttrId;
|
var attrId = part.AttrAreaCom ? payAttrId : part.AttrId;
|
||||||
var geb = !ungeb && (payAttrId == attrId || !part.AttrAreaCom);
|
var geb = !ungeb && (payAttrId == attrId || !part.AttrAreaCom);
|
||||||
decimal price = 0;
|
var price = Data.CalculatePrice(part.SortId, attrId, part.CultId, part.QualId, geb, part.Oe, part.Kmw);
|
||||||
try {
|
|
||||||
price = Data.CalculatePrice(part.SortId, attrId, part.CultId, part.QualId, geb, part.Oe, part.Kmw);
|
|
||||||
} catch (KeyNotFoundException e) {
|
|
||||||
invalid.Add(e.Message.Split('\'')[1]);
|
|
||||||
}
|
|
||||||
var priceL = PaymentVariant.Season.DecToDb(price);
|
var priceL = PaymentVariant.Season.DecToDb(price);
|
||||||
inserts.Add((part.Year, part.DId, part.DPNr, part.BktNr, priceL, priceL * part.Value));
|
inserts.Add((part.Year, part.DId, part.DPNr, part.BktNr, priceL, priceL * part.Value));
|
||||||
}
|
}
|
||||||
|
|
||||||
var msg = invalid.Count == 0 ? null : "Für folgende Sorten wurde noch keine Preiskurve festgelegt: " + string.Join(", ", invalid);
|
await AppDbContext.ExecuteBatch(cnx, $"""
|
||||||
if (msg != null && strict)
|
|
||||||
throw new KeyNotFoundException(msg);
|
|
||||||
await cnx.ExecuteBatch($"""
|
|
||||||
INSERT INTO payment_delivery_part_bucket (year, did, dpnr, bktnr, avnr, price, amount)
|
INSERT INTO payment_delivery_part_bucket (year, did, dpnr, bktnr, avnr, price, amount)
|
||||||
VALUES {string.Join(",\n ", inserts.Select(i => $"({i.Year}, {i.DId}, {i.DPNr}, {i.BktNr}, {AvNr}, {i.Price}, {i.Amount})"))};
|
VALUES {string.Join(",\n ", inserts.Select(i => $"({i.Year}, {i.DId}, {i.DPNr}, {i.BktNr}, {AvNr}, {i.Price}, {i.Amount})"))};
|
||||||
""");
|
""");
|
||||||
if (msg != null)
|
|
||||||
throw new KeyNotFoundException(msg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async Task CalculateDeliveryModifiers(SqliteConnection cnx) {
|
protected async Task CalculateDeliveryModifiers(SqliteConnection cnx) {
|
||||||
var netMod = Data.NetWeightModifier.ToString().Replace(',', '.');
|
var netMod = Data.NetWeightModifier.ToString().Replace(',', '.');
|
||||||
var grossMod = Data.GrossWeightModifier.ToString().Replace(',', '.');
|
var grossMod = Data.GrossWeightModifier.ToString().Replace(',', '.');
|
||||||
await cnx.ExecuteBatch($"""
|
await AppDbContext.ExecuteBatch(cnx, $"""
|
||||||
INSERT INTO payment_delivery_part (year, did, dpnr, avnr, net_amount, mod_abs, mod_rel)
|
INSERT INTO payment_delivery_part (year, did, dpnr, avnr, net_amount, mod_abs, mod_rel)
|
||||||
SELECT d.year, d.did, d.dpnr, {AvNr}, 0, 0, IIF(d.net_weight, {netMod}, {grossMod})
|
SELECT d.year, d.did, d.dpnr, {AvNr}, 0, 0, IIF(d.net_weight, {netMod}, {grossMod})
|
||||||
FROM delivery_part d
|
FROM delivery_part d
|
||||||
|
|||||||
@@ -19,6 +19,14 @@ namespace Elwig.Helpers {
|
|||||||
public bool IsSitzendorf => IsWinzerkeller && App.ZwstId == "S";
|
public bool IsSitzendorf => IsWinzerkeller && App.ZwstId == "S";
|
||||||
public bool IsGrInzersdorf => IsWeinland;
|
public bool IsGrInzersdorf => IsWeinland;
|
||||||
|
|
||||||
|
public bool HasNetWeighing(string? zwstId) => IsMatzen || (IsWinzerkeller && zwstId == "W");
|
||||||
|
public bool HasNetWeighing(Branch? b) => HasNetWeighing(b?.ZwstId);
|
||||||
|
public bool HasNetWeighing() => HasNetWeighing(App.ZwstId);
|
||||||
|
|
||||||
|
public bool HasBoxWeighing(string? zwstId) => IsWinzerkeller && (zwstId != "W");
|
||||||
|
public bool HasBoxWeighing(Branch? b) => HasBoxWeighing(b?.ZwstId);
|
||||||
|
public bool HasBoxWeighing() => HasBoxWeighing(App.ZwstId);
|
||||||
|
|
||||||
public string NameToken;
|
public string NameToken;
|
||||||
public string NameShort;
|
public string NameShort;
|
||||||
public string Name;
|
public string Name;
|
||||||
@@ -206,15 +214,15 @@ namespace Elwig.Helpers {
|
|||||||
case 1: orderingMemberList = "NAME"; break;
|
case 1: orderingMemberList = "NAME"; break;
|
||||||
case 2: orderingMemberList = "KG"; break;
|
case 2: orderingMemberList = "KG"; break;
|
||||||
}
|
}
|
||||||
string mailSendPostal = "WISH";
|
string mailSendPostal = "MGNR";
|
||||||
switch (MailSendPostal) {
|
switch (MailOrdering) {
|
||||||
case 0: mailSendPostal = "NONE"; break;
|
case 0: mailSendPostal = "NONE"; break;
|
||||||
case 1: mailSendPostal = "NO_EMAIL"; break;
|
case 1: mailSendPostal = "NO_EMAIL"; break;
|
||||||
case 2: mailSendPostal = "WISH"; break;
|
case 2: mailSendPostal = "WISH"; break;
|
||||||
case 3: mailSendPostal = "ALL"; break;
|
case 3: mailSendPostal = "ALL"; break;
|
||||||
}
|
}
|
||||||
string mailSendEmail = "WISH";
|
string mailSendEmail = "MGNR";
|
||||||
switch (MailSendEmail) {
|
switch (MailOrdering) {
|
||||||
case 0: mailSendEmail = "NONE"; break;
|
case 0: mailSendEmail = "NONE"; break;
|
||||||
case 1: mailSendEmail = "WISH"; break;
|
case 1: mailSendEmail = "WISH"; break;
|
||||||
case 2: mailSendEmail = "ALL"; break;
|
case 2: mailSendEmail = "ALL"; break;
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -6,8 +5,6 @@ using Microsoft.Extensions.Configuration;
|
|||||||
|
|
||||||
namespace Elwig.Helpers {
|
namespace Elwig.Helpers {
|
||||||
|
|
||||||
public enum WeighingMode { Gross, Net, Box }
|
|
||||||
|
|
||||||
public record struct ScaleConfig {
|
public record struct ScaleConfig {
|
||||||
public string Id;
|
public string Id;
|
||||||
public string? Type;
|
public string? Type;
|
||||||
@@ -44,7 +41,6 @@ namespace Elwig.Helpers {
|
|||||||
public string DatabaseFile = App.DataPath + "database.sqlite3";
|
public string DatabaseFile = App.DataPath + "database.sqlite3";
|
||||||
public string? DatabaseLog = null;
|
public string? DatabaseLog = null;
|
||||||
public string? Branch = null;
|
public string? Branch = null;
|
||||||
public WeighingMode? WeighingMode;
|
|
||||||
public string? UpdateUrl = null;
|
public string? UpdateUrl = null;
|
||||||
public bool UpdateAuto = false;
|
public bool UpdateAuto = false;
|
||||||
public string? SyncUrl = null;
|
public string? SyncUrl = null;
|
||||||
@@ -78,8 +74,6 @@ namespace Elwig.Helpers {
|
|||||||
DatabaseLog = log != null ? Path.Combine(Path.GetDirectoryName(FileName) ?? App.DataPath, log) : null;
|
DatabaseLog = log != null ? Path.Combine(Path.GetDirectoryName(FileName) ?? App.DataPath, log) : null;
|
||||||
Branch = config["general:branch"];
|
Branch = config["general:branch"];
|
||||||
Debug = TrueValues.Contains(config["general:debug"]?.ToLower());
|
Debug = TrueValues.Contains(config["general:debug"]?.ToLower());
|
||||||
var weighing = config["general:weighing"];
|
|
||||||
WeighingMode = weighing != null && Enum.TryParse<WeighingMode>(weighing, true, out var w) ? w : null;
|
|
||||||
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"];
|
||||||
|
|||||||
@@ -15,9 +15,7 @@ namespace Elwig.Helpers.Export {
|
|||||||
protected readonly char Separator;
|
protected readonly char Separator;
|
||||||
protected string? Header;
|
protected string? Header;
|
||||||
|
|
||||||
public Csv(string filename, char separator = ';') :
|
public Csv(string filename, char separator = ';') : this(filename, separator, Utils.UTF8) { }
|
||||||
this(filename, separator, Utils.UTF8) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public Csv(string filename, char separator, Encoding encoding) {
|
public Csv(string filename, char separator, Encoding encoding) {
|
||||||
_writer = new StreamWriter(filename, false, encoding);
|
_writer = new StreamWriter(filename, false, encoding);
|
||||||
@@ -60,22 +58,4 @@ namespace Elwig.Helpers.Export {
|
|||||||
|
|
||||||
public abstract string FormatRow(T row);
|
public abstract string FormatRow(T row);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CsvSimple : Csv<IEnumerable<object?>> {
|
|
||||||
|
|
||||||
public CsvSimple(string filename, char separator, Encoding encoding) :
|
|
||||||
base(filename, separator, encoding) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public CsvSimple(string filename, char separator = ';') :
|
|
||||||
base(filename, separator) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string FormatRow(IEnumerable<object?> row) {
|
|
||||||
return string.Join(Separator, row.Select(i => {
|
|
||||||
var str = $"{i}";
|
|
||||||
return str.Contains(Separator) || str.Contains('\n') ? $"\"{str.Replace("\"", "\"\"")}\"" : str;
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,243 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.IO.Compression;
|
|
||||||
using System.Text.Json.Nodes;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Elwig.Helpers.Export {
|
|
||||||
public static class Database {
|
|
||||||
|
|
||||||
private static async Task<(long? ApplicationId, string? UserVersion, long? SchemaVersion, long FileSize)> GetMeta() {
|
|
||||||
long size = new FileInfo(App.Config.DatabaseFile).Length;
|
|
||||||
using var cnx = await AppDbContext.ConnectAsync();
|
|
||||||
var applId = (long?)await cnx.ExecuteScalar("PRAGMA application_id");
|
|
||||||
var userVers = (long?)await cnx.ExecuteScalar("PRAGMA user_version");
|
|
||||||
var schemaVers = (long?)await cnx.ExecuteScalar("PRAGMA schema_version");
|
|
||||||
return (applId, userVers != null ? $"{userVers >> 24}.{(userVers >> 16) & 0xFF}.{(userVers >> 8) & 0xFF}.{userVers & 0xFF}" : null, schemaVers, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task ExportSqlite(string filename, bool zipFile) {
|
|
||||||
if (zipFile) {
|
|
||||||
File.Delete(filename);
|
|
||||||
using var zip = ZipFile.Open(filename, ZipArchiveMode.Create);
|
|
||||||
|
|
||||||
var version = zip.CreateEntry("version", CompressionLevel.NoCompression);
|
|
||||||
using (var writer = new StreamWriter(version.Open(), Utils.UTF8)) {
|
|
||||||
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, filename, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task ExportSql(string filename, bool zipFile) {
|
|
||||||
if (zipFile) {
|
|
||||||
File.Delete(filename);
|
|
||||||
using var zip = ZipFile.Open(filename, ZipArchiveMode.Create);
|
|
||||||
|
|
||||||
var version = zip.CreateEntry("version", CompressionLevel.NoCompression);
|
|
||||||
using (var writer = new StreamWriter(version.Open(), Utils.UTF8)) {
|
|
||||||
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 sql = zip.CreateEntry("database.sql", CompressionLevel.SmallestSize);
|
|
||||||
using (var writer = new StreamWriter(sql.Open(), Utils.UTF8)) {
|
|
||||||
await ExportSql(writer);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
using var stream = File.OpenWrite(filename);
|
|
||||||
using var writer = new StreamWriter(stream, Utils.UTF8);
|
|
||||||
await ExportSql(writer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task ExportSql(StreamWriter writer) {
|
|
||||||
using var cnx = await AppDbContext.ConnectAsync();
|
|
||||||
|
|
||||||
var tables = new List<(string Name, string Sql)>();
|
|
||||||
using (var cmd = cnx.CreateCommand()) {
|
|
||||||
cmd.CommandText = "SELECT name, sql FROM sqlite_schema WHERE type = 'table'";
|
|
||||||
using var reader = await cmd.ExecuteReaderAsync();
|
|
||||||
while (await reader.ReadAsync()) {
|
|
||||||
tables.Add((reader.GetString(0), reader.GetString(1)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var applId = (long?)await cnx.ExecuteScalar("PRAGMA application_id") ?? 0;
|
|
||||||
var userVers = (long?)await cnx.ExecuteScalar("PRAGMA user_version") ?? 0;
|
|
||||||
var schemaVers = (long?)await cnx.ExecuteScalar("PRAGMA schema_version") ?? 0;
|
|
||||||
|
|
||||||
await writer.WriteLineAsync($"-- Elwig database dump, {DateTime.Now:yyyy-MM-dd, HH:mm:ss}");
|
|
||||||
await writer.WriteLineAsync($"-- {Environment.MachineName}, Zwst. {App.BranchName}, {App.Client.Name}");
|
|
||||||
await writer.WriteLineAsync("BEGIN TRANSACTION;");
|
|
||||||
await writer.WriteLineAsync("PRAGMA foreign_keys=OFF;");
|
|
||||||
await writer.WriteLineAsync($"PRAGMA application_id=0x{applId:X8};");
|
|
||||||
await writer.WriteLineAsync($"PRAGMA user_version=0x{userVers:X8};");
|
|
||||||
|
|
||||||
foreach (var t in tables) {
|
|
||||||
await writer.WriteAsync(t.Sql);
|
|
||||||
await writer.WriteLineAsync(";");
|
|
||||||
|
|
||||||
var columnNames = new List<string>();
|
|
||||||
using (var cmd = cnx.CreateCommand()) {
|
|
||||||
cmd.CommandText = $"PRAGMA table_info({t.Name})";
|
|
||||||
using var reader = await cmd.ExecuteReaderAsync();
|
|
||||||
while (await reader.ReadAsync()) {
|
|
||||||
columnNames.Add(reader.GetString(1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
using (var cmd = cnx.CreateCommand()) {
|
|
||||||
cmd.CommandText = $"SELECT {string.Join(',', columnNames)} FROM {t.Name}";
|
|
||||||
using var reader = await cmd.ExecuteReaderAsync();
|
|
||||||
var columns = await reader.GetColumnSchemaAsync();
|
|
||||||
var values = new object[reader.FieldCount];
|
|
||||||
while (await reader.ReadAsync()) {
|
|
||||||
await writer.WriteAsync($"INSERT INTO {t.Name} VALUES (");
|
|
||||||
|
|
||||||
reader.GetValues(values);
|
|
||||||
for (int i = 0; i < columns.Count; i++) {
|
|
||||||
var c = columns[i];
|
|
||||||
var v = values[i];
|
|
||||||
if (i > 0) await writer.WriteAsync(",");
|
|
||||||
if (v == null || v is DBNull) {
|
|
||||||
await writer.WriteAsync("NULL");
|
|
||||||
} else if (c.DataTypeName == "TEXT") {
|
|
||||||
await writer.WriteAsync($"'{v.ToString()?.Replace("'", "''")}'");
|
|
||||||
} else {
|
|
||||||
await writer.WriteAsync(v.ToString()?.Replace(',', '.'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await writer.WriteLineAsync(");");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
using (var cmd = cnx.CreateCommand()) {
|
|
||||||
cmd.CommandText = "SELECT sql FROM sqlite_schema WHERE type != 'table' AND sql IS NOT NULL";
|
|
||||||
using var reader = await cmd.ExecuteReaderAsync();
|
|
||||||
while (await reader.ReadAsync()) {
|
|
||||||
await writer.WriteAsync(reader.GetString(0));
|
|
||||||
await writer.WriteLineAsync(";");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await writer.WriteLineAsync($"PRAGMA schema_version={schemaVers};");
|
|
||||||
await writer.WriteLineAsync("PRAGMA foreign_keys=ON;");
|
|
||||||
await writer.WriteLineAsync("COMMIT;");
|
|
||||||
await writer.WriteLineAsync("VACUUM;");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task Import(string filename) {
|
|
||||||
if (filename.EndsWith(".sql")) {
|
|
||||||
await ImportSql(filename, false);
|
|
||||||
} else if (filename.EndsWith(".sql.zip")) {
|
|
||||||
await ImportSql(filename, true);
|
|
||||||
} else if (filename.EndsWith(".sqlite3")) {
|
|
||||||
await ImportSqlite(filename, false);
|
|
||||||
} else if (filename.EndsWith(".sqlite3.zip")) {
|
|
||||||
await ImportSqlite(filename, true);
|
|
||||||
} else {
|
|
||||||
throw new ArgumentException($"Unknown file extension for importing: '{filename}'");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task ImportSql(string filename, bool zipFile = false) {
|
|
||||||
if (zipFile) {
|
|
||||||
using var zip = ZipFile.Open(filename, ZipArchiveMode.Read);
|
|
||||||
await zip.CheckIntegrity();
|
|
||||||
foreach (var entry in zip.Entries) {
|
|
||||||
if (entry.Name.EndsWith(".sql")) {
|
|
||||||
using var stream = entry.Open();
|
|
||||||
using var reader = new StreamReader(stream, Utils.UTF8);
|
|
||||||
await ImportSql(reader);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new FileFormatException("ZIP archive has to contain at least one .sql file");
|
|
||||||
} else {
|
|
||||||
using var stream = File.Open(filename, FileMode.Open);
|
|
||||||
using var reader = new StreamReader(stream, Utils.UTF8);
|
|
||||||
await ImportSql(reader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task ImportSqlite(string filename, bool zipFile = false) {
|
|
||||||
if (zipFile) {
|
|
||||||
var newName = Path.ChangeExtension(App.Config.DatabaseFile, ".new.sqlite3");
|
|
||||||
try {
|
|
||||||
using var zip = ZipFile.Open(filename, ZipArchiveMode.Read);
|
|
||||||
await zip.CheckIntegrity();
|
|
||||||
foreach (var entry in zip.Entries) {
|
|
||||||
if (entry.Name.EndsWith(".sqlite3")) {
|
|
||||||
entry.ExtractToFile(newName);
|
|
||||||
await ImportSqlite(newName);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new FileFormatException("ZIP archive has to contain at least one .sqlite3 file");
|
|
||||||
} finally {
|
|
||||||
if (File.Exists(newName)) File.Delete(newName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var oldName = Path.ChangeExtension(App.Config.DatabaseFile, ".old.sqlite3");
|
|
||||||
File.Move(App.Config.DatabaseFile, oldName, true);
|
|
||||||
File.Move(filename, App.Config.DatabaseFile, false);
|
|
||||||
|
|
||||||
using var cnx = await AppDbContext.ConnectAsync();
|
|
||||||
await cnx.ExecuteBatch("VACUUM");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task ImportSql(StreamReader reader) {
|
|
||||||
var newName = Path.ChangeExtension(App.Config.DatabaseFile, ".new.sqlite3");
|
|
||||||
File.Delete(newName);
|
|
||||||
try {
|
|
||||||
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 ImportSqlite(newName);
|
|
||||||
} finally {
|
|
||||||
if (File.Exists(newName)) File.Delete(newName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,6 +6,7 @@ using System.Globalization;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text.Json;
|
||||||
using System.Text.Json.Nodes;
|
using System.Text.Json.Nodes;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
@@ -17,6 +18,8 @@ namespace Elwig.Helpers.Export {
|
|||||||
|
|
||||||
public static readonly string ImportedTxt = Path.Combine(App.DataPath, "imported.txt");
|
public static readonly string ImportedTxt = Path.Combine(App.DataPath, "imported.txt");
|
||||||
|
|
||||||
|
private static readonly JsonSerializerOptions JsonOpts = new() { Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping };
|
||||||
|
|
||||||
public static async Task<string[]> GetImportedFiles() {
|
public static async Task<string[]> GetImportedFiles() {
|
||||||
try {
|
try {
|
||||||
return await File.ReadAllLinesAsync(ImportedTxt, Utils.UTF8);
|
return await File.ReadAllLinesAsync(ImportedTxt, Utils.UTF8);
|
||||||
@@ -74,14 +77,6 @@ namespace Elwig.Helpers.Export {
|
|||||||
int? DeliveryNum, string? DeliveryFilters)>();
|
int? DeliveryNum, string? DeliveryFilters)>();
|
||||||
|
|
||||||
foreach (var filename in filenames) {
|
foreach (var filename in filenames) {
|
||||||
try {
|
|
||||||
data.Add(new([], [], [], [], [], [], [], new([], [], [], [], new() {
|
|
||||||
["member"] = [],
|
|
||||||
["area_commitment"] = [],
|
|
||||||
["delivery"] = [],
|
|
||||||
})));
|
|
||||||
var r = data[^1];
|
|
||||||
|
|
||||||
// TODO read encrypted files
|
// TODO read encrypted files
|
||||||
using var zip = ZipFile.Open(filename, ZipArchiveMode.Read);
|
using var zip = ZipFile.Open(filename, ZipArchiveMode.Read);
|
||||||
await zip.CheckIntegrity();
|
await zip.CheckIntegrity();
|
||||||
@@ -89,7 +84,7 @@ namespace Elwig.Helpers.Export {
|
|||||||
var version = zip.GetEntry("version");
|
var version = zip.GetEntry("version");
|
||||||
using (var reader = new StreamReader(version!.Open(), Utils.UTF8)) {
|
using (var reader = new StreamReader(version!.Open(), Utils.UTF8)) {
|
||||||
if (await reader.ReadToEndAsync() != "elwig:1")
|
if (await reader.ReadToEndAsync() != "elwig:1")
|
||||||
throw new FileFormatException($"Ungültige Elwig-Export-Datei ({filename})");
|
throw new FileFormatException($"Ungültige Export-Datei ({filename})");
|
||||||
}
|
}
|
||||||
|
|
||||||
var metaJson = zip.GetEntry("meta.json");
|
var metaJson = zip.GetEntry("meta.json");
|
||||||
@@ -106,6 +101,13 @@ namespace Elwig.Helpers.Export {
|
|||||||
areaComCount, areaComFilters != null ? string.Join(" / ", areaComFilters) : null,
|
areaComCount, areaComFilters != null ? string.Join(" / ", areaComFilters) : null,
|
||||||
deliveryCount, deliveryFilters != null ? string.Join(" / ", deliveryFilters) : null));
|
deliveryCount, deliveryFilters != null ? string.Join(" / ", deliveryFilters) : null));
|
||||||
|
|
||||||
|
data.Add(new([], [], [], [], [], [], [], new([], [], [], [], new() {
|
||||||
|
["member"] = [],
|
||||||
|
["area_commitment"] = [],
|
||||||
|
["delivery"] = [],
|
||||||
|
})));
|
||||||
|
var r = data[^1];
|
||||||
|
|
||||||
var wbKgsJson = zip.GetEntry("wb_kgs.json");
|
var wbKgsJson = zip.GetEntry("wb_kgs.json");
|
||||||
if (wbKgsJson != null) {
|
if (wbKgsJson != null) {
|
||||||
using var reader = new StreamReader(wbKgsJson.Open(), Utils.UTF8);
|
using var reader = new StreamReader(wbKgsJson.Open(), Utils.UTF8);
|
||||||
@@ -168,25 +170,6 @@ namespace Elwig.Helpers.Export {
|
|||||||
r.Timestamps["delivery"].Add((d.Year, d.DId, timestamps.Value.CreatedAt, timestamps.Value.ModifiedAt));
|
r.Timestamps["delivery"].Add((d.Year, d.DId, timestamps.Value.CreatedAt, timestamps.Value.ModifiedAt));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception exc) when (
|
|
||||||
exc is InvalidDataException ||
|
|
||||||
exc is FileFormatException ||
|
|
||||||
exc is FileNotFoundException ||
|
|
||||||
exc is IOException) {
|
|
||||||
data.RemoveAt(data.Count - 1);
|
|
||||||
var str = $"Die Elwig-Export-Datei '{Path.GetFileName(filename)}' konnte nicht verarbeitet werden und wird übersprungen.\n\n" + exc.Message;
|
|
||||||
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
|
|
||||||
MessageBox.Show(str, "Fehler beim Importieren", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
await AddImportedFiles(Path.GetFileName(filename));
|
|
||||||
} catch (Exception exc) {
|
|
||||||
data.RemoveAt(data.Count - 1);
|
|
||||||
var str = $"Die Elwig-Export-Datei '{Path.GetFileName(filename)}' konnte nicht verarbeitet werden. Soll sie in Zukunft übersprungen werden?\n\n" + exc.Message;
|
|
||||||
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
|
|
||||||
var r = MessageBox.Show(str, "Fehler beim Importieren", MessageBoxButton.YesNo, MessageBoxImage.Error, MessageBoxResult.No);
|
|
||||||
if (r == MessageBoxResult.Yes) {
|
|
||||||
await AddImportedFiles(Path.GetFileName(filename));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var importedMembers = new List<(string FileName, string ZwstId, string Device, int New, int Overwritten, int NotImported, string Filters)>();
|
var importedMembers = new List<(string FileName, string ZwstId, string Device, int New, int Overwritten, int NotImported, string Filters)>();
|
||||||
@@ -345,7 +328,7 @@ namespace Elwig.Helpers.Export {
|
|||||||
$"mtime = {((DateTimeOffset)m.ModifiedAt.ToUniversalTime()).ToUnixTimeSeconds()} " +
|
$"mtime = {((DateTimeOffset)m.ModifiedAt.ToUniversalTime()).ToUnixTimeSeconds()} " +
|
||||||
$"WHERE ({primaryKeys[e.Key]}) = ({m.Id1}, {m.Id2});"));
|
$"WHERE ({primaryKeys[e.Key]}) = ({m.Id1}, {m.Id2});"));
|
||||||
using var cnx = AppDbContext.Connect();
|
using var cnx = AppDbContext.Connect();
|
||||||
await cnx.ExecuteBatch($"""
|
await AppDbContext.ExecuteBatch(cnx, $"""
|
||||||
BEGIN;
|
BEGIN;
|
||||||
UPDATE client_parameter SET value = '0' WHERE param = 'ENABLE_TIME_TRIGGERS';
|
UPDATE client_parameter SET value = '0' WHERE param = 'ENABLE_TIME_TRIGGERS';
|
||||||
{string.Join("\n", updateStmts)}
|
{string.Join("\n", updateStmts)}
|
||||||
@@ -422,6 +405,29 @@ namespace Elwig.Helpers.Export {
|
|||||||
}.Export(filename);
|
}.Export(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async Task ImportDatabase(string filename) {
|
||||||
|
var oldName = Path.ChangeExtension(App.Config.DatabaseFile, ".old.sqlite3");
|
||||||
|
var newName = Path.ChangeExtension(App.Config.DatabaseFile, ".new.sqlite3");
|
||||||
|
try {
|
||||||
|
using (var zip = ZipFile.Open(filename, ZipArchiveMode.Read)) {
|
||||||
|
await zip.CheckIntegrity();
|
||||||
|
var db = zip.GetEntry("database.sqlite3")!;
|
||||||
|
db.ExtractToFile(newName, true);
|
||||||
|
}
|
||||||
|
File.Move(App.Config.DatabaseFile, oldName, true);
|
||||||
|
File.Move(newName, App.Config.DatabaseFile, false);
|
||||||
|
} finally {
|
||||||
|
if (File.Exists(newName))
|
||||||
|
File.Delete(newName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ExportDatabase(string filename) {
|
||||||
|
File.Delete(filename);
|
||||||
|
using var zip = ZipFile.Open(filename, ZipArchiveMode.Create);
|
||||||
|
var db = zip.CreateEntryFromFile(App.Config.DatabaseFile, "database.sqlite3", CompressionLevel.SmallestSize);
|
||||||
|
}
|
||||||
|
|
||||||
public class ElwigExport {
|
public class ElwigExport {
|
||||||
public (IEnumerable<WbKg> WbKgs, IEnumerable<string> Filters)? WbKgs { get; set; }
|
public (IEnumerable<WbKg> WbKgs, IEnumerable<string> Filters)? WbKgs { get; set; }
|
||||||
public (IEnumerable<Member> Members, IEnumerable<string> Filters)? Members { get; set; }
|
public (IEnumerable<Member> Members, IEnumerable<string> Filters)? Members { get; set; }
|
||||||
@@ -466,7 +472,7 @@ namespace Elwig.Helpers.Export {
|
|||||||
["parts"] = Deliveries.Value.Deliveries.Sum(d => d.Parts.Count),
|
["parts"] = Deliveries.Value.Deliveries.Sum(d => d.Parts.Count),
|
||||||
["filters"] = new JsonArray(Deliveries.Value.Filters.Select(f => (JsonNode)f).ToArray()),
|
["filters"] = new JsonArray(Deliveries.Value.Filters.Select(f => (JsonNode)f).ToArray()),
|
||||||
};
|
};
|
||||||
await writer.WriteAsync(obj.ToJsonString(Utils.JsonOpts));
|
await writer.WriteAsync(obj.ToJsonString(JsonOpts));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO encrypt files
|
// TODO encrypt files
|
||||||
@@ -474,28 +480,28 @@ namespace Elwig.Helpers.Export {
|
|||||||
var json = zip.CreateEntry("wb_kgs.json", CompressionLevel.SmallestSize);
|
var json = zip.CreateEntry("wb_kgs.json", CompressionLevel.SmallestSize);
|
||||||
using var writer = new StreamWriter(json.Open(), Utils.UTF8);
|
using var writer = new StreamWriter(json.Open(), Utils.UTF8);
|
||||||
foreach (var k in WbKgs.Value.WbKgs) {
|
foreach (var k in WbKgs.Value.WbKgs) {
|
||||||
await writer.WriteLineAsync(k.ToJson().ToJsonString(Utils.JsonOpts));
|
await writer.WriteLineAsync(k.ToJson().ToJsonString(JsonOpts));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (Members != null) {
|
if (Members != null) {
|
||||||
var json = zip.CreateEntry("members.json", CompressionLevel.SmallestSize);
|
var json = zip.CreateEntry("members.json", CompressionLevel.SmallestSize);
|
||||||
using var writer = new StreamWriter(json.Open(), Utils.UTF8);
|
using var writer = new StreamWriter(json.Open(), Utils.UTF8);
|
||||||
foreach (var m in Members.Value.Members) {
|
foreach (var m in Members.Value.Members) {
|
||||||
await writer.WriteLineAsync(m.ToJson().ToJsonString(Utils.JsonOpts));
|
await writer.WriteLineAsync(m.ToJson().ToJsonString(JsonOpts));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (AreaComs != null) {
|
if (AreaComs != null) {
|
||||||
var json = zip.CreateEntry("area_commitments.json", CompressionLevel.SmallestSize);
|
var json = zip.CreateEntry("area_commitments.json", CompressionLevel.SmallestSize);
|
||||||
using var writer = new StreamWriter(json.Open(), Utils.UTF8);
|
using var writer = new StreamWriter(json.Open(), Utils.UTF8);
|
||||||
foreach (var c in AreaComs.Value.AreaComs) {
|
foreach (var c in AreaComs.Value.AreaComs) {
|
||||||
await writer.WriteLineAsync(c.ToJson().ToJsonString(Utils.JsonOpts));
|
await writer.WriteLineAsync(c.ToJson().ToJsonString(JsonOpts));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (Deliveries != null) {
|
if (Deliveries != null) {
|
||||||
var json = zip.CreateEntry("deliveries.json", CompressionLevel.SmallestSize);
|
var json = zip.CreateEntry("deliveries.json", CompressionLevel.SmallestSize);
|
||||||
using var writer = new StreamWriter(json.Open(), Utils.UTF8);
|
using var writer = new StreamWriter(json.Open(), Utils.UTF8);
|
||||||
foreach (var d in Deliveries.Value.Deliveries) {
|
foreach (var d in Deliveries.Value.Deliveries) {
|
||||||
await writer.WriteLineAsync(d.ToJson().ToJsonString(Utils.JsonOpts));
|
await writer.WriteLineAsync(d.ToJson().ToJsonString(JsonOpts));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -744,8 +750,8 @@ namespace Elwig.Helpers.Export {
|
|||||||
};
|
};
|
||||||
if (p.IsSplCheck) obj["spl_check"] = p.IsSplCheck;
|
if (p.IsSplCheck) obj["spl_check"] = p.IsSplCheck;
|
||||||
if (p.IsHandPicked != null) obj["hand_picked"] = p.IsHandPicked;
|
if (p.IsHandPicked != null) obj["hand_picked"] = p.IsHandPicked;
|
||||||
|
if (p.IsLesewagen != null) obj["lesewagen"] = p.IsLesewagen;
|
||||||
if (p.IsGebunden != null) obj["gebunden"] = p.IsGebunden;
|
if (p.IsGebunden != null) obj["gebunden"] = p.IsGebunden;
|
||||||
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.ScaleId != null) obj["scale_id"] = p.ScaleId;
|
||||||
@@ -818,12 +824,12 @@ namespace Elwig.Helpers.Export {
|
|||||||
Comment = p["comment"]?.AsValue().GetValue<string>(),
|
Comment = p["comment"]?.AsValue().GetValue<string>(),
|
||||||
IsSplCheck = p["spl_check"]?.AsValue().GetValue<bool>() ?? false,
|
IsSplCheck = p["spl_check"]?.AsValue().GetValue<bool>() ?? false,
|
||||||
IsHandPicked = p["hand_picked"]?.AsValue().GetValue<bool>(),
|
IsHandPicked = p["hand_picked"]?.AsValue().GetValue<bool>(),
|
||||||
|
IsLesewagen = p["lesewagen"]?.AsValue().GetValue<bool>(),
|
||||||
IsGebunden = p["gebunden"]?.AsValue().GetValue<bool>(),
|
IsGebunden = p["gebunden"]?.AsValue().GetValue<bool>(),
|
||||||
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>(),
|
ScaleId = p["scale_id"]?.AsValue().GetValue<string>(),
|
||||||
WeighingData = p["weighing_data"]?.AsObject().ToJsonString(Utils.JsonOpts),
|
WeighingData = p["weighing_data"]?.AsObject().ToJsonString(JsonOpts),
|
||||||
WeighingReason = p["weighing_reason"]?.AsValue().GetValue<string>(),
|
WeighingReason = p["weighing_reason"]?.AsValue().GetValue<string>(),
|
||||||
};
|
};
|
||||||
}).ToList(), json["parts"]!.AsArray().SelectMany(p => p!["modids"]!.AsArray().Select(m => new DeliveryPartModifier {
|
}).ToList(), json["parts"]!.AsArray().SelectMany(p => p!["modids"]!.AsArray().Select(m => new DeliveryPartModifier {
|
||||||
|
|||||||
@@ -1,69 +0,0 @@
|
|||||||
using Elwig.Models.Entities;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Elwig.Helpers.Export {
|
|
||||||
public class VCard : IExporter<Member> {
|
|
||||||
|
|
||||||
public static string FileExtension => "vcf";
|
|
||||||
|
|
||||||
private readonly StreamWriter _writer;
|
|
||||||
|
|
||||||
public VCard(string filename) : this(filename, Utils.UTF8) { }
|
|
||||||
|
|
||||||
public VCard(string filename, Encoding encoding) {
|
|
||||||
_writer = new StreamWriter(filename, false, encoding);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose() {
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
_writer.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ValueTask DisposeAsync() {
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
return _writer.DisposeAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task ExportAsync(IEnumerable<Member> data, IProgress<double>? progress = null) {
|
|
||||||
progress?.Report(0.0);
|
|
||||||
int count = data.Count() + 1, i = 0;
|
|
||||||
|
|
||||||
foreach (var row in data) {
|
|
||||||
var billingAddr = row.BillingAddress != null ? $"ADR;TYPE=work;LANGUAGE=de;LABEL=\"{Escape(row.BillingAddress.FullName)}\\n{Escape(row.BillingAddress.Address)}\\n{row.BillingAddress.PostalDest.AtPlz?.Plz} {Escape(row.BillingAddress.PostalDest.AtPlz?.Ort.Name)}\\nÖsterreich\":;;{Escape(row.BillingAddress.Address)};{Escape(row.BillingAddress.PostalDest.AtPlz?.Ort.Name)};;{row.BillingAddress.PostalDest.AtPlz?.Plz};Österreich\r\n" : null;
|
|
||||||
var tel = string.Join("", row.TelephoneNumbers
|
|
||||||
.Where(n => n.Type != "fax")
|
|
||||||
.Select(n => $"TEL;TYPE={(n.Type == "mobile" ? "cell" : "voice")}:{Escape(n.Number)}\r\n"));
|
|
||||||
var email = string.Join("", row.EmailAddresses.Select(a => $"EMAIL:{Escape(a.Address)}\r\n"));
|
|
||||||
await _writer.WriteLineAsync($"""
|
|
||||||
BEGIN:VCARD
|
|
||||||
VERSION:4.0
|
|
||||||
UID:mg{row.MgNr}@{App.Client.NameToken.ToLower()}.elwig.at
|
|
||||||
NOTE:MgNr. {row.MgNr}
|
|
||||||
FN:{Escape(row.AdministrativeName)}
|
|
||||||
N:{Escape(row.Name)};{Escape(row.GivenName)};{Escape(row.MiddleName)};{Escape(row.Prefix)};{Escape(row.Suffix)}
|
|
||||||
KIND:{(row.IsJuridicalPerson ? "org" : "individual")}
|
|
||||||
ADR{(billingAddr == null ? "" : ";TYPE=home")};LANGUAGE=de;LABEL="{Escape(row.Address)}\n{row.PostalDest.AtPlz?.Plz} {Escape(row.PostalDest.AtPlz?.Ort.Name)}\nÖsterreich":;;{Escape(row.Address)};{Escape(row.PostalDest.AtPlz?.Ort.Name)};;{row.PostalDest.AtPlz?.Plz};Österreich
|
|
||||||
{billingAddr}{tel}{email}REV:{row.ModifiedAt.ToUniversalTime():yyyyMMdd\THHmmss\Z}
|
|
||||||
END:VCARD
|
|
||||||
""");
|
|
||||||
progress?.Report(100.0 * ++i / count);
|
|
||||||
}
|
|
||||||
|
|
||||||
await _writer.FlushAsync();
|
|
||||||
progress?.Report(100.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Export(IEnumerable<Member> data, IProgress<double>? progress = null) {
|
|
||||||
ExportAsync(data, progress).GetAwaiter().GetResult();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string? Escape(string? text) {
|
|
||||||
return text?.Replace("\\", "\\\\").Replace(",", "\\,").Replace(";", "\\;").Replace("\n", "\\n").Replace("\r", "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
namespace Elwig.Helpers {
|
namespace Elwig.Helpers {
|
||||||
public enum ExportMode {
|
public enum ExportMode {
|
||||||
Show, SaveList, SavePdf, Print, Email, Vcf, Export, Upload
|
Show, SaveList, SavePdf, Print, Email, Export, Upload
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,14 @@
|
|||||||
using Microsoft.Data.Sqlite;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.IO.Hashing;
|
using System.IO.Hashing;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Reflection;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Elwig.Helpers {
|
namespace Elwig.Helpers {
|
||||||
public static partial class Extensions {
|
static partial class Extensions {
|
||||||
|
|
||||||
[LibraryImport("msvcrt.dll")]
|
[LibraryImport("msvcrt.dll")]
|
||||||
[UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])]
|
[UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])]
|
||||||
@@ -111,39 +108,5 @@ namespace Elwig.Helpers {
|
|||||||
throw new InvalidDataException($"CRC-32 mismatch in '{entry.FullName}'");
|
throw new InvalidDataException($"CRC-32 mismatch in '{entry.FullName}'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task ExecuteBatch(this SqliteConnection cnx, string sql) {
|
|
||||||
using var cmd = cnx.CreateCommand();
|
|
||||||
cmd.CommandText = sql;
|
|
||||||
using var reader = await cmd.ExecuteReaderAsync();
|
|
||||||
while (await reader.NextResultAsync()) ;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task ExecuteEmbeddedScript(this SqliteConnection cnx, Assembly asm, string name) {
|
|
||||||
using var stream = asm.GetManifestResourceStream(name) ?? throw new FileNotFoundException("Unable to load embedded resource");
|
|
||||||
using var reader = new StreamReader(stream);
|
|
||||||
await ExecuteBatch(cnx, await reader.ReadToEndAsync());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task<object?> ExecuteScalar(this SqliteConnection cnx, string sql) {
|
|
||||||
using var cmd = cnx.CreateCommand();
|
|
||||||
cmd.CommandText = sql;
|
|
||||||
return await cmd.ExecuteScalarAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task<(string Table, long RowId, string Parent, long FkId)[]> ForeignKeyCheck(this SqliteConnection cnx) {
|
|
||||||
using var cmd = cnx.CreateCommand();
|
|
||||||
cmd.CommandText = "PRAGMA foreign_key_check";
|
|
||||||
using var reader = await cmd.ExecuteReaderAsync();
|
|
||||||
var list = new List<(string, long, string, long)>();
|
|
||||||
while (await reader.ReadAsync()) {
|
|
||||||
var table = reader.GetString(0);
|
|
||||||
var rowid = reader.GetInt64(1);
|
|
||||||
var parent = reader.GetString(2);
|
|
||||||
var fkid = reader.GetInt64(3);
|
|
||||||
list.Add((table, rowid, parent, fkid));
|
|
||||||
}
|
|
||||||
return [.. list];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +1,20 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
using Elwig.Windows;
|
using Elwig.Windows;
|
||||||
using PdfiumViewer;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Drawing.Printing;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Reflection;
|
using PdfiumViewer;
|
||||||
using System.Text.RegularExpressions;
|
using System.Drawing.Printing;
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows;
|
|
||||||
|
|
||||||
namespace Elwig.Helpers.Printing {
|
namespace Elwig.Helpers.Printing {
|
||||||
public static class Pdf {
|
public static class Pdf {
|
||||||
|
|
||||||
private static readonly string WinziPrint = (Assembly.GetEntryAssembly()?.Location.Contains(@"\bin\") ?? false) ?
|
private static readonly string WinziPrint = new string[] { App.InstallPath }
|
||||||
Path.Combine(Assembly.GetEntryAssembly()!.Location.Split(@"\bin\")[0], "../Installer/Files/WinziPrint.exe") :
|
|
||||||
new string[] { App.InstallPath }
|
|
||||||
.Union(Environment.GetEnvironmentVariable("PATH")?.Split(';') ?? [])
|
.Union(Environment.GetEnvironmentVariable("PATH")?.Split(';') ?? [])
|
||||||
.Select(x => Path.Combine(x, "WinziPrint.exe"))
|
.Select(x => Path.Combine(x, "WinziPrint.exe"))
|
||||||
.Where(File.Exists)
|
.Where(File.Exists)
|
||||||
@@ -50,45 +46,24 @@ namespace Elwig.Helpers.Printing {
|
|||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<(int Pages, IEnumerable<int> PerDoc)> Convert(string htmlPath, string pdfPath, bool doublePaged = false, CancellationToken? cancelToken = null, IProgress<double>? progress = null) {
|
public static async Task<(int Pages, IEnumerable<int> PerDoc)> Convert(string htmlPath, string pdfPath, bool doublePaged = false, IProgress<double>? progress = null) {
|
||||||
return await Convert([htmlPath], pdfPath, doublePaged, cancelToken, progress);
|
return await Convert([htmlPath], pdfPath, doublePaged, progress);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<(int Pages, IEnumerable<int> PerDoc)> Convert(IEnumerable<string> htmlPath, string pdfPath, bool doublePaged = false, CancellationToken? cancelToken = null, IProgress<double>? progress = null) {
|
public static async Task<(int Pages, IEnumerable<int> PerDoc)> Convert(IEnumerable<string> htmlPath, string pdfPath, bool doublePaged = false, IProgress<double>? progress = null) {
|
||||||
if (WinziPrintProc == null) throw new InvalidOperationException("The WinziPrint process has not been initialized yet");
|
if (WinziPrintProc == null) throw new InvalidOperationException("The WinziPrint process has not been initialized yet");
|
||||||
progress?.Report(0.0);
|
progress?.Report(0.0);
|
||||||
using var client = new TcpClient("127.0.0.1", 30983);
|
using var client = new TcpClient("127.0.0.1", 30983);
|
||||||
using var stream = client.GetStream();
|
using var stream = client.GetStream();
|
||||||
string cnxId;
|
|
||||||
using var reader = new StreamReader(stream);
|
|
||||||
var first = await reader.ReadLineAsync() ?? throw new IOException("Invalid response from WinziPrint");
|
|
||||||
if (first.StartsWith("id:")) {
|
|
||||||
cnxId = first[3..].Trim();
|
|
||||||
} else {
|
|
||||||
throw new IOException("Invalid response from WinziPrint");
|
|
||||||
}
|
|
||||||
await stream.WriteAsync(Utils.UTF8.GetBytes(
|
await stream.WriteAsync(Utils.UTF8.GetBytes(
|
||||||
"-e utf-8;-p;" + (doublePaged ? "-2;" : "") +
|
"-e utf-8;-p;" + (doublePaged ? "-2;" : "") +
|
||||||
$"{string.Join(';', htmlPath)};{pdfPath}" +
|
$"{string.Join(';', htmlPath)};{pdfPath}" +
|
||||||
"\r\n"));
|
"\r\n"));
|
||||||
bool cancelled = false;
|
using var reader = new StreamReader(stream);
|
||||||
while (true) {
|
while (true) {
|
||||||
if (!cancelled && (cancelToken?.IsCancellationRequested ?? false)) {
|
|
||||||
try {
|
|
||||||
using var cancelClient = new TcpClient("127.0.0.1", 30983);
|
|
||||||
using var cancelStream = cancelClient.GetStream();
|
|
||||||
using var cancelReader = new StreamReader(cancelStream);
|
|
||||||
await cancelReader.ReadLineAsync();
|
|
||||||
await cancelStream.WriteAsync(Utils.UTF8.GetBytes($"cancel;{cnxId}\r\n"));
|
|
||||||
} catch { }
|
|
||||||
cancelled = true;
|
|
||||||
}
|
|
||||||
var line = await reader.ReadLineAsync() ?? throw new IOException("Invalid response from WinziPrint");
|
var line = await reader.ReadLineAsync() ?? throw new IOException("Invalid response from WinziPrint");
|
||||||
if (line.StartsWith("error:")) {
|
if (line.StartsWith("error:")) {
|
||||||
var msg = line[6..].Trim();
|
throw new IOException($"WinziPrint: {line[6..].Trim()}");
|
||||||
if (msg == "aborted")
|
|
||||||
throw new OperationCanceledException("Dokumentenerzeugung abgebrochen!");
|
|
||||||
throw new IOException($"WinziPrint: {msg}");
|
|
||||||
} else if (line.StartsWith("progress:")) {
|
} else if (line.StartsWith("progress:")) {
|
||||||
var parts = line[9..].Trim().Split('/').Select(int.Parse).ToArray();
|
var parts = line[9..].Trim().Split('/').Select(int.Parse).ToArray();
|
||||||
progress?.Report(100.0 * parts[0] / parts[1]);
|
progress?.Report(100.0 * parts[0] / parts[1]);
|
||||||
|
|||||||
@@ -1,60 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.IO.Ports;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Management;
|
|
||||||
|
|
||||||
namespace Elwig.Helpers {
|
|
||||||
public sealed class SerialPortWatcher : IDisposable {
|
|
||||||
|
|
||||||
private readonly ManagementEventWatcher _deviceArrivalWatcher;
|
|
||||||
private readonly ManagementEventWatcher _deviceRemovalWatcher;
|
|
||||||
|
|
||||||
private string[] _knownPorts;
|
|
||||||
|
|
||||||
public event EventHandler<string>? SerialPortConnected;
|
|
||||||
public event EventHandler<string>? SerialPortDisconnected;
|
|
||||||
|
|
||||||
public SerialPortWatcher() {
|
|
||||||
_knownPorts = SerialPort.GetPortNames();
|
|
||||||
_deviceArrivalWatcher = new ManagementEventWatcher("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 2");
|
|
||||||
_deviceArrivalWatcher.EventArrived += OnDeviceArrived;
|
|
||||||
_deviceRemovalWatcher = new ManagementEventWatcher("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 3");
|
|
||||||
_deviceRemovalWatcher.EventArrived += OnDeviceRemoved;
|
|
||||||
_deviceArrivalWatcher.Start();
|
|
||||||
_deviceRemovalWatcher.Start();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnDeviceArrived(object sender, EventArrivedEventArgs evt) {
|
|
||||||
App.MainDispatcher.Invoke(() => {
|
|
||||||
// "synchronized"
|
|
||||||
string[] currentPorts = SerialPort.GetPortNames();
|
|
||||||
var newPorts = currentPorts.Except(_knownPorts).ToArray();
|
|
||||||
foreach (var port in newPorts)
|
|
||||||
SerialPortConnected?.Invoke(this, port);
|
|
||||||
_knownPorts = currentPorts;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnDeviceRemoved(object sender, EventArrivedEventArgs evt) {
|
|
||||||
App.MainDispatcher.Invoke(() => {
|
|
||||||
// "synchronized"
|
|
||||||
string[] currentPorts = SerialPort.GetPortNames();
|
|
||||||
var removedPorts = _knownPorts.Except(currentPorts).ToArray();
|
|
||||||
foreach (var port in removedPorts)
|
|
||||||
SerialPortDisconnected?.Invoke(this, port);
|
|
||||||
_knownPorts = currentPorts;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose() {
|
|
||||||
try {
|
|
||||||
_deviceArrivalWatcher?.Stop();
|
|
||||||
_deviceRemovalWatcher?.Stop();
|
|
||||||
} finally {
|
|
||||||
_deviceArrivalWatcher?.Dispose();
|
|
||||||
_deviceRemovalWatcher?.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,43 +1,41 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.IO.Ports;
|
||||||
|
using System.Net.Sockets;
|
||||||
using Elwig.Dialogs;
|
using Elwig.Dialogs;
|
||||||
using Elwig.Documents;
|
using System.Text;
|
||||||
using Elwig.Helpers.Billing;
|
using System.Numerics;
|
||||||
using Elwig.Models;
|
|
||||||
using Elwig.Models.Entities;
|
using Elwig.Models.Entities;
|
||||||
using LinqKit;
|
using Elwig.Helpers.Billing;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Text.Json.Nodes;
|
||||||
|
using System.IO;
|
||||||
using MailKit.Net.Smtp;
|
using MailKit.Net.Smtp;
|
||||||
using MailKit.Security;
|
using MailKit.Security;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Win32;
|
|
||||||
using MimeKit;
|
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.IO;
|
|
||||||
using System.IO.Ports;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Linq.Expressions;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Net.Sockets;
|
|
||||||
using System.Numerics;
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.InteropServices;
|
using System.Collections;
|
||||||
using System.Text;
|
using Elwig.Documents;
|
||||||
using System.Text.Json;
|
using MimeKit;
|
||||||
using System.Text.Json.Nodes;
|
using System.Windows.Input;
|
||||||
using System.Text.RegularExpressions;
|
using LinqKit;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using Elwig.Models;
|
||||||
|
using Microsoft.Win32;
|
||||||
|
using System.Globalization;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Markup;
|
using System.Windows.Markup;
|
||||||
|
|
||||||
namespace Elwig.Helpers {
|
namespace Elwig.Helpers {
|
||||||
public static partial class Utils {
|
public static partial class Utils {
|
||||||
|
|
||||||
public static readonly Encoding UTF8 = new UTF8Encoding(false, true);
|
public static readonly Encoding UTF8 = new UTF8Encoding(false, true);
|
||||||
public static readonly Encoding UTF8BOM = new UTF8Encoding(true, true);
|
|
||||||
public static readonly JsonSerializerOptions JsonOpts = new() { Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping };
|
|
||||||
|
|
||||||
public static int CurrentYear => DateTime.Now.Year;
|
public static int CurrentYear => DateTime.Now.Year;
|
||||||
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);
|
||||||
@@ -432,8 +430,6 @@ namespace Elwig.Helpers {
|
|||||||
var client = new HttpClient() {
|
var client = new HttpClient() {
|
||||||
Timeout = TimeSpan.FromSeconds(5),
|
Timeout = TimeSpan.FromSeconds(5),
|
||||||
};
|
};
|
||||||
client.DefaultRequestHeaders.UserAgent.Clear();
|
|
||||||
client.DefaultRequestHeaders.UserAgent.ParseAdd($"Elwig/{App.Version} ({App.Client.NameToken}, {App.BranchName}, {Environment.MachineName}, {Environment.OSVersion})");
|
|
||||||
client.DefaultRequestHeaders.Accept.Clear();
|
client.DefaultRequestHeaders.Accept.Clear();
|
||||||
if (accept != null)
|
if (accept != null)
|
||||||
client.DefaultRequestHeaders.Accept.Add(new(accept));
|
client.DefaultRequestHeaders.Accept.Add(new(accept));
|
||||||
@@ -502,8 +498,10 @@ namespace Elwig.Helpers {
|
|||||||
public static async Task<bool> SendEmail(Member member, string subject, string text, IEnumerable<Document> docs) {
|
public static async Task<bool> SendEmail(Member member, string subject, string text, IEnumerable<Document> docs) {
|
||||||
if (App.Config.Smtp == null)
|
if (App.Config.Smtp == null)
|
||||||
return false;
|
return false;
|
||||||
return await Task.Run(async () => {
|
|
||||||
await AddSentMailBody(subject, text, 1);
|
Mouse.OverrideCursor = Cursors.Wait;
|
||||||
|
|
||||||
|
var success = await Task.Run(async () => {
|
||||||
SmtpClient? client = null;
|
SmtpClient? client = null;
|
||||||
try {
|
try {
|
||||||
client = await GetSmtpClient();
|
client = await GetSmtpClient();
|
||||||
@@ -521,11 +519,6 @@ namespace Elwig.Helpers {
|
|||||||
}
|
}
|
||||||
msg.Body = body;
|
msg.Body = body;
|
||||||
await client!.SendAsync(msg);
|
await client!.SendAsync(msg);
|
||||||
await AddSentMails([(
|
|
||||||
"email", member.MgNr, member.AdministrativeName,
|
|
||||||
member.EmailAddresses.OrderBy(a => a.Nr).Select(a => a.Address).ToArray(),
|
|
||||||
subject, docs.Select(d => d.Title).ToArray()
|
|
||||||
)]);
|
|
||||||
} catch (Exception exc) {
|
} catch (Exception exc) {
|
||||||
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
return false;
|
return false;
|
||||||
@@ -536,33 +529,22 @@ namespace Elwig.Helpers {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Mouse.OverrideCursor = null;
|
||||||
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task ExportDocument(Document doc, ExportMode mode, string? filename = null, (Member Member, string Subject, string Text)? emailData = null) {
|
public static async Task ExportDocument(Document doc, ExportMode mode, string? filename = null, (Member, string, string)? emailData = null) {
|
||||||
if (mode == ExportMode.Print && !App.Config.Debug) {
|
if (mode == ExportMode.Print && !App.Config.Debug) {
|
||||||
if (doc.IsPreview) {
|
|
||||||
MessageBox.Show("Dieses Dokument ist als vorläufig markiert und kann daher nicht ausgedruckt werden!",
|
|
||||||
"Vorläufiges Dokument", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await doc.Generate();
|
await doc.Generate();
|
||||||
await doc.Print();
|
await doc.Print();
|
||||||
} else if (mode == ExportMode.Email && emailData is (Member, string, string) e) {
|
} else if (mode == ExportMode.Email && emailData is (Member, string, string) e) {
|
||||||
if (doc.IsPreview) {
|
|
||||||
MessageBox.Show("Dieses Dokument ist als vorläufig markiert und kann daher nicht verschickt werden!",
|
|
||||||
"Vorläufiges Dokument", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await doc.Generate();
|
await doc.Generate();
|
||||||
var success = await SendEmail(e.Member, e.Subject, e.Text, [doc]);
|
var success = await SendEmail(e.Item1, e.Item2, e.Item3, [doc]);
|
||||||
if (success)
|
if (success)
|
||||||
MessageBox.Show("Die E-Mail wurde erfolgreich verschickt!\n\nEs kann einige Minuten dauern, bis die E-Mail im Posteingang des Empfängers aufscheint.", "E-Mail verschickt",
|
MessageBox.Show("Die E-Mail wurde erfolgreich verschickt!", "E-Mail verschickt",
|
||||||
MessageBoxButton.OK, MessageBoxImage.Information);
|
MessageBoxButton.OK, MessageBoxImage.Information);
|
||||||
} else if (mode == ExportMode.SavePdf) {
|
} else if (mode == ExportMode.SavePdf) {
|
||||||
if (doc.IsPreview) {
|
|
||||||
MessageBox.Show("Dieses Dokument ist als vorläufig markiert und sollte daher nicht langfristig gespeichert werden!",
|
|
||||||
"Vorläufiges Dokument", MessageBoxButton.OK, MessageBoxImage.Warning);
|
|
||||||
}
|
|
||||||
var d = new SaveFileDialog() {
|
var d = new SaveFileDialog() {
|
||||||
FileName = $"{NormalizeFileName(filename ?? doc.Title)}.pdf",
|
FileName = $"{NormalizeFileName(filename ?? doc.Title)}.pdf",
|
||||||
DefaultExt = "pdf",
|
DefaultExt = "pdf",
|
||||||
@@ -585,7 +567,9 @@ namespace Elwig.Helpers {
|
|||||||
Log = "Application",
|
Log = "Application",
|
||||||
Source = ".NET Runtime",
|
Source = ".NET Runtime",
|
||||||
};
|
};
|
||||||
return [.. log.Entries.OfType<EventLogEntry>().Where(e => e.InstanceId == 1026).Where(e => e.Message.StartsWith("Application: Elwig.exe"))];
|
return log.Entries.Cast<EventLogEntry>()
|
||||||
|
.Where(e => e.Message.StartsWith("Application: Elwig.exe"))
|
||||||
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int GetEntityIdetifierForPk(params object?[] primaryKey) {
|
public static int GetEntityIdetifierForPk(params object?[] primaryKey) {
|
||||||
@@ -675,9 +659,9 @@ namespace Elwig.Helpers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<string?> FindSentMailBody(DateTime target) {
|
public static async Task<string?> FindSentMailBody(DateTime target) {
|
||||||
var dt = $"{target:yyyy-MM-dd_HH-mm-ss}";
|
var dt = $"{target:yyyy-MM-dd_HH-mm-ss}_";
|
||||||
var filename = Directory.GetFiles(App.MailsPath, "????-??-??_??-??-??_*.txt")
|
var filename = Directory.GetFiles(App.MailsPath, "????-??-??_??-??-??_*.txt")
|
||||||
.Where(n => Path.GetFileName(n)[..19].CompareTo(dt) <= 0)
|
.Where(n => Path.GetFileName(n).CompareTo(dt) <= 0)
|
||||||
.Order()
|
.Order()
|
||||||
.LastOrDefault();
|
.LastOrDefault();
|
||||||
if (filename == null)
|
if (filename == null)
|
||||||
|
|||||||
@@ -15,17 +15,15 @@ namespace Elwig.Helpers.Weighing {
|
|||||||
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 event IEventScale.EventHandler<WeighingEventArgs>? WeighingEvent;
|
public event IEventScale.EventHandler<WeighingEventArgs> WeighingEvent;
|
||||||
|
|
||||||
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? empty = null, string? filling = null, int? limit = null, string? log = null) :
|
||||||
base(cnx, null, null, null, log, true, !required) {
|
base(cnx, empty, filling, limit, log) {
|
||||||
ScaleId = id;
|
ScaleId = id;
|
||||||
Model = model;
|
Model = model;
|
||||||
Connection = cnx;
|
|
||||||
IsReady = true;
|
IsReady = true;
|
||||||
HasFillingClearance = false;
|
HasFillingClearance = false;
|
||||||
Stream.WriteTimeout = -1;
|
Stream.WriteTimeout = -1;
|
||||||
@@ -52,49 +50,19 @@ namespace Elwig.Helpers.Weighing {
|
|||||||
var data = await Receive();
|
var data = await Receive();
|
||||||
if (data != null)
|
if (data != null)
|
||||||
RaiseWeighingEvent(new WeighingEventArgs(data.Value));
|
RaiseWeighingEvent(new WeighingEventArgs(data.Value));
|
||||||
} catch (ThreadInterruptedException) {
|
|
||||||
// ignore
|
|
||||||
} catch (IOException) {
|
|
||||||
await Task.Delay(500);
|
|
||||||
await Reconnect();
|
|
||||||
} catch (TimeoutException) {
|
|
||||||
await Task.Delay(500);
|
|
||||||
await Reconnect();
|
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
MessageBox.Show($"Beim Wiegen ist ein Fehler Aufgetreten:\n\n{ex.Message} ({ex.GetType().Name})", "Waagenfehler",
|
MessageBox.Show($"Beim Wiegen ist ein Fehler Aufgetreten:\n\n{ex.Message}", "Waagenfehler",
|
||||||
MessageBoxButton.OK, MessageBoxImage.Error);
|
MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async Task Reconnect() {
|
|
||||||
try { Reader.Close(); } catch { }
|
|
||||||
try { Stream.Close(); } catch { }
|
|
||||||
try { Serial?.Close(); } catch { }
|
|
||||||
while (IsRunning) {
|
|
||||||
try {
|
|
||||||
if (Connection.StartsWith("serial:")) {
|
|
||||||
Serial = Utils.OpenSerialConnection(Connection);
|
|
||||||
Stream = Serial.BaseStream;
|
|
||||||
} else if (Connection.StartsWith("tcp:")) {
|
|
||||||
Tcp = Utils.OpenTcpConnection(Connection);
|
|
||||||
Stream = Tcp.GetStream();
|
|
||||||
}
|
|
||||||
Reader = new(Stream, Encoding.ASCII, false, 512);
|
|
||||||
break;
|
|
||||||
} catch {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
await Task.Delay(1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async Task<WeighingResult?> Receive() {
|
protected async Task<WeighingResult?> Receive() {
|
||||||
var line = "";
|
var line = "";
|
||||||
while (line.Length < 33) {
|
while (line.Length < 33) {
|
||||||
var ch = Reader.Read();
|
var ch = Reader.Read();
|
||||||
if (ch == -1) {
|
if (ch == -1) {
|
||||||
throw new IOException("Connection closed");
|
return null;
|
||||||
} else if (line.Length > 0 || ch == ' ') {
|
} else if (line.Length > 0 || ch == ' ') {
|
||||||
line += char.ToString((char)ch);
|
line += char.ToString((char)ch);
|
||||||
}
|
}
|
||||||
@@ -103,7 +71,7 @@ namespace Elwig.Helpers.Weighing {
|
|||||||
if (line == null || line == "") {
|
if (line == null || line == "") {
|
||||||
return null;
|
return null;
|
||||||
} else if (line.Length != 33 || line[0] != ' ' || line[9] != ' ' || line[15] != ' ' || line[20] != ' ' || line[32] != ' ') {
|
} else if (line.Length != 33 || line[0] != ' ' || line[9] != ' ' || line[15] != ' ' || line[20] != ' ' || line[32] != ' ') {
|
||||||
throw new FormatException($"Invalid event from scale: '{line}'");
|
throw new IOException($"Invalid event from scale: '{line}'");
|
||||||
}
|
}
|
||||||
|
|
||||||
var date = line[ 1.. 9];
|
var date = line[ 1.. 9];
|
||||||
@@ -113,7 +81,7 @@ namespace Elwig.Helpers.Weighing {
|
|||||||
var unit = line[30..32];
|
var unit = line[30..32];
|
||||||
|
|
||||||
if (unit != "kg") {
|
if (unit != "kg") {
|
||||||
throw new WeighingException($"Unsupported unit in weighing event: '{unit}'");
|
throw new IOException($"Unsupported unit in weighing event: '{unit}'");
|
||||||
}
|
}
|
||||||
|
|
||||||
identNr = identNr.Length > 0 && identNr != "0" ? identNr : null;
|
identNr = identNr.Length > 0 && identNr != "0" ? identNr : null;
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ namespace Elwig.Helpers.Weighing {
|
|||||||
var line = await Reader.ReadUntilAsync('\x03');
|
var line = await Reader.ReadUntilAsync('\x03');
|
||||||
if (LogPath != null) await File.AppendAllTextAsync(LogPath, $"{line}\r\n");
|
if (LogPath != null) await File.AppendAllTextAsync(LogPath, $"{line}\r\n");
|
||||||
if (line == null || line.Length < 4 || !line.StartsWith('\x02')) {
|
if (line == null || line.Length < 4 || !line.StartsWith('\x02')) {
|
||||||
throw new FormatException("Invalid response from scale");
|
throw new IOException("Invalid response from scale");
|
||||||
}
|
}
|
||||||
|
|
||||||
var status = line[1..3];
|
var status = line[1..3];
|
||||||
@@ -45,9 +45,9 @@ namespace Elwig.Helpers.Weighing {
|
|||||||
switch (status[1]) {
|
switch (status[1]) {
|
||||||
case 'M': msg = "Waage in Bewegung"; break;
|
case 'M': msg = "Waage in Bewegung"; break;
|
||||||
}
|
}
|
||||||
throw new WeighingException($"Waagenfehler {status}: {msg}");
|
throw new IOException($"Waagenfehler {status}: {msg}");
|
||||||
} else if (status[0] != ' ') {
|
} else if (status[0] != ' ') {
|
||||||
throw new WeighingException($"Invalid response from scale (error code {status})");
|
throw new IOException($"Invalid response from scale (error code {status})");
|
||||||
}
|
}
|
||||||
|
|
||||||
return line[1..^1];
|
return line[1..^1];
|
||||||
@@ -57,7 +57,7 @@ namespace Elwig.Helpers.Weighing {
|
|||||||
await SendCommand(incIdentNr ? '\x05' : '?');
|
await SendCommand(incIdentNr ? '\x05' : '?');
|
||||||
string record = await ReceiveResponse();
|
string record = await ReceiveResponse();
|
||||||
if (record.Length != 45)
|
if (record.Length != 45)
|
||||||
throw new FormatException("Invalid response from scale: Received record has invalid size");
|
throw new IOException("Invalid response from scale: Received record has invalid size");
|
||||||
var line = record[2..];
|
var line = record[2..];
|
||||||
|
|
||||||
var brutto = line[ 0.. 7].Trim();
|
var brutto = line[ 0.. 7].Trim();
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using System.IO.Ports;
|
using System.IO.Ports;
|
||||||
|
using System.IO;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
|
using System;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Windows;
|
|
||||||
|
|
||||||
namespace Elwig.Helpers.Weighing {
|
namespace Elwig.Helpers.Weighing {
|
||||||
public abstract class Scale : IDisposable {
|
public abstract class Scale : IDisposable {
|
||||||
@@ -28,7 +27,7 @@ namespace Elwig.Helpers.Weighing {
|
|||||||
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 == "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.Empty, config.Filling, limit, config.Log);
|
||||||
} else if (config.Type == "Gassner") {
|
} else if (config.Type == "Gassner") {
|
||||||
return new GassnerScale(config.Id, config.Model!, config.Connection!, config.Empty, config.Filling, limit, config.Log);
|
return new GassnerScale(config.Id, config.Model!, config.Connection!, config.Empty, config.Filling, limit, config.Log);
|
||||||
} else {
|
} else {
|
||||||
@@ -36,17 +35,10 @@ namespace Elwig.Helpers.Weighing {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Scale(string cnx, string? empty, string? filling, int? limit, string? log, bool softFail = false, bool failSilent = false) {
|
protected Scale(string cnx, string? empty, string? filling, int? limit, string? log) {
|
||||||
if (cnx.StartsWith("serial:")) {
|
if (cnx.StartsWith("serial:")) {
|
||||||
try {
|
|
||||||
Serial = Utils.OpenSerialConnection(cnx);
|
Serial = Utils.OpenSerialConnection(cnx);
|
||||||
} catch (Exception e) {
|
Stream = Serial.BaseStream;
|
||||||
if (!softFail) throw;
|
|
||||||
if (!failSilent)
|
|
||||||
MessageBox.Show($"Verbindung zu Waage konnte nicht hergestellt werden:\n\n{e.Message}", "Waagenfehler",
|
|
||||||
MessageBoxButton.OK, MessageBoxImage.Warning);
|
|
||||||
}
|
|
||||||
Stream = Serial?.BaseStream ?? Stream.Null;
|
|
||||||
} else if (cnx.StartsWith("tcp:")) {
|
} else if (cnx.StartsWith("tcp:")) {
|
||||||
Tcp = Utils.OpenTcpConnection(cnx);
|
Tcp = Utils.OpenTcpConnection(cnx);
|
||||||
Stream = Tcp.GetStream();
|
Stream = Tcp.GetStream();
|
||||||
|
|||||||
@@ -34,14 +34,14 @@ namespace Elwig.Helpers.Weighing {
|
|||||||
var line = await Reader.ReadUntilAsync("\r\n");
|
var line = await Reader.ReadUntilAsync("\r\n");
|
||||||
if (LogPath != null) await File.AppendAllTextAsync(LogPath, line);
|
if (LogPath != null) await File.AppendAllTextAsync(LogPath, line);
|
||||||
if (line == null || line.Length < 4 || !line.StartsWith('<') || !line.EndsWith(">\r\n")) {
|
if (line == null || line.Length < 4 || !line.StartsWith('<') || !line.EndsWith(">\r\n")) {
|
||||||
throw new FormatException("Invalid response from scale");
|
throw new IOException("Invalid response from scale");
|
||||||
}
|
}
|
||||||
|
|
||||||
var error = line[1..3];
|
var error = line[1..3];
|
||||||
string msg = $"Unbekannter Fehler (Fehler code {error})";
|
string msg = $"Unbekannter Fehler (Fehler code {error})";
|
||||||
if (error[0] == '0') {
|
if (error[0] == '0') {
|
||||||
if (error[1] != '0') {
|
if (error[1] != '0') {
|
||||||
throw new WeighingException($"Invalid response from scale (error code {error})");
|
throw new IOException($"Invalid response from scale (error code {error})");
|
||||||
}
|
}
|
||||||
} else if (error[0] == '1') {
|
} else if (error[0] == '1') {
|
||||||
switch (error[1]) {
|
switch (error[1]) {
|
||||||
@@ -52,21 +52,21 @@ namespace Elwig.Helpers.Weighing {
|
|||||||
case '6': msg = "Drucker nicht bereit"; break;
|
case '6': msg = "Drucker nicht bereit"; break;
|
||||||
case '7': msg = "Druckmuster enthält ungültiges Kommando"; break;
|
case '7': msg = "Druckmuster enthält ungültiges Kommando"; break;
|
||||||
}
|
}
|
||||||
throw new WeighingException($"Waagenfehler {error}: {msg}");
|
throw new IOException($"Waagenfehler {error}: {msg}");
|
||||||
} else if (error[0] == '2') {
|
} else if (error[0] == '2') {
|
||||||
switch (error[1]) {
|
switch (error[1]) {
|
||||||
case '0': msg = "Brutto negativ"; break;
|
case '0': msg = "Brutto negativ"; break;
|
||||||
}
|
}
|
||||||
throw new WeighingException($"Fehler {error}: {msg}");
|
throw new IOException($"Fehler {error}: {msg}");
|
||||||
} else if (error[0] == '3') {
|
} else if (error[0] == '3') {
|
||||||
switch (error[1]) {
|
switch (error[1]) {
|
||||||
case '1': msg = "Übertragunsfehler"; break;
|
case '1': msg = "Übertragunsfehler"; break;
|
||||||
case '2': msg = "Ungültiger Befehl"; break;
|
case '2': msg = "Ungültiger Befehl"; break;
|
||||||
case '3': msg = "Ungültiger Parameter"; break;
|
case '3': msg = "Ungültiger Parameter"; break;
|
||||||
}
|
}
|
||||||
throw new WeighingException($"Kommunikationsfehler {error}: {msg}");
|
throw new IOException($"Kommunikationsfehler {error}: {msg}");
|
||||||
} else {
|
} else {
|
||||||
throw new WeighingException($"Invalid response from scale (error code {error})");
|
throw new IOException($"Invalid response from scale (error code {error})");
|
||||||
}
|
}
|
||||||
|
|
||||||
return line[1..^3];
|
return line[1..^3];
|
||||||
@@ -76,7 +76,7 @@ namespace Elwig.Helpers.Weighing {
|
|||||||
await SendCommand(incIdentNr ? $"RN{InternalScaleNr}" : $"RM{InternalScaleNr}");
|
await SendCommand(incIdentNr ? $"RN{InternalScaleNr}" : $"RM{InternalScaleNr}");
|
||||||
string record = await ReceiveResponse();
|
string record = await ReceiveResponse();
|
||||||
if (record.Length != 62)
|
if (record.Length != 62)
|
||||||
throw new FormatException("Invalid response from scale: Received record has invalid size");
|
throw new IOException("Invalid response from scale: Received record has invalid size");
|
||||||
var line = record[2..];
|
var line = record[2..];
|
||||||
|
|
||||||
var status = line[ 0.. 2];
|
var status = line[ 0.. 2];
|
||||||
@@ -94,9 +94,9 @@ namespace Elwig.Helpers.Weighing {
|
|||||||
var crc16 = line[52..60].Trim();
|
var crc16 = line[52..60].Trim();
|
||||||
|
|
||||||
if (Utils.CalcCrc16Modbus(record[..54]) != ushort.Parse(crc16)) {
|
if (Utils.CalcCrc16Modbus(record[..54]) != ushort.Parse(crc16)) {
|
||||||
throw new WeighingException($"Invalid response from scale: Invalid CRC16 checksum ({crc16} != {Utils.CalcCrc16Modbus(record[..54])})");
|
throw new IOException($"Invalid response from scale: Invalid CRC16 checksum ({crc16} != {Utils.CalcCrc16Modbus(record[..54])})");
|
||||||
} else if (unit != "kg") {
|
} else if (unit != "kg") {
|
||||||
throw new WeighingException($"Unsupported unit in weighing response: '{unit}'");
|
throw new IOException($"Unsupported unit in weighing response: '{unit}'");
|
||||||
}
|
}
|
||||||
|
|
||||||
identNr = identNr.Length > 0 && identNr != "0" ? identNr : null;
|
identNr = identNr.Length > 0 && identNr != "0" ? identNr : null;
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace Elwig.Helpers.Weighing {
|
|
||||||
public class WeighingException(string? message = null) : Exception(message) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
using Elwig.Models.Entities;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Elwig.Models.Dtos {
|
|
||||||
public class MemberDeliveryData : DataTable<MemberDeliveryRow> {
|
|
||||||
|
|
||||||
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),
|
|
||||||
("Weight", "Geliefert", "kg", 22),
|
|
||||||
];
|
|
||||||
|
|
||||||
public MemberDeliveryData(IEnumerable<MemberDeliveryRow> rows, List<string> filterNames) :
|
|
||||||
base("Liefermengen Gesamt", "Liefermengen pro Mitglied", string.Join(" / ", filterNames), rows, FieldNames) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task<MemberDeliveryData> FromQuery(IQueryable<DeliveryPart> query, List<string> filterNames) {
|
|
||||||
return new((await query
|
|
||||||
.GroupBy(p => new {
|
|
||||||
p.Delivery.MgNr,
|
|
||||||
p.Delivery.Member.Name,
|
|
||||||
p.Delivery.Member.GivenName,
|
|
||||||
p.Delivery.Member.Address,
|
|
||||||
p.Delivery.Member.PostalDest.AtPlz!.Plz,
|
|
||||||
Ort = p.Delivery.Member.PostalDest.AtPlz!.Ort.Name,
|
|
||||||
})
|
|
||||||
.Select(g => new {
|
|
||||||
g.Key,
|
|
||||||
Weight = g.Sum(p => p.Weight),
|
|
||||||
}).ToListAsync())
|
|
||||||
.Select(g => new MemberDeliveryRow {
|
|
||||||
MgNr = g.Key.MgNr,
|
|
||||||
Name1 = g.Key.Name,
|
|
||||||
Name2 = g.Key.GivenName,
|
|
||||||
Address = g.Key.Address,
|
|
||||||
Plz = g.Key.Plz,
|
|
||||||
Locality = g.Key.Ort,
|
|
||||||
Weight = g.Weight,
|
|
||||||
}), filterNames);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class MemberDeliveryRow {
|
|
||||||
public required int MgNr;
|
|
||||||
public required string Name1;
|
|
||||||
public required string? Name2;
|
|
||||||
public required string Address;
|
|
||||||
public required int Plz;
|
|
||||||
public required string Locality;
|
|
||||||
public required int Weight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
using Elwig.Models.Entities;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Elwig.Models.Dtos {
|
namespace Elwig.Models.Dtos {
|
||||||
public class MemberDeliveryPerVarietyData : DataTable<MemberDeliveryPerVarietyRow> {
|
public class MemberDeliveryPerVarietyData : DataTable<MemberDeliveryPerVariantRow> {
|
||||||
|
|
||||||
private static readonly (string, string, string?, int?)[] FieldNames = [
|
private static readonly (string, string, string?, int)[] FieldNames = [
|
||||||
("MgNr", "MgNr.", null, 12),
|
("MgNr", "MgNr.", null, 12),
|
||||||
("Name1", "Name", null, 40),
|
("Name1", "Name", null, 40),
|
||||||
("Name2", "Vorname", null, 40),
|
("Name2", "Vorname", null, 40),
|
||||||
@@ -16,63 +16,104 @@ namespace Elwig.Models.Dtos {
|
|||||||
("Locality", "Ort", null, 60),
|
("Locality", "Ort", null, 60),
|
||||||
("SortIds", "Sorte", null, 12),
|
("SortIds", "Sorte", null, 12),
|
||||||
("AttrIds", "Attribut", null, 16),
|
("AttrIds", "Attribut", null, 16),
|
||||||
("CultIds", "Bewirt.", null, 16),
|
|
||||||
("Weights", "Geliefert", "kg", 22),
|
("Weights", "Geliefert", "kg", 22),
|
||||||
|
("Areas", "Fläche", "m²", 22),
|
||||||
|
("Yields", "Ertrag", "kg/ha", 22),
|
||||||
];
|
];
|
||||||
|
|
||||||
public MemberDeliveryPerVarietyData(IEnumerable<MemberDeliveryPerVarietyRow> rows, List<string> filterNames) :
|
public MemberDeliveryPerVarietyData(IEnumerable<MemberDeliveryPerVariantRow> rows, int year) :
|
||||||
base("Liefermengen pro Sorte", "Liefermengen pro Mitglied, Sorte, Attribut und Bewirtschaftungsart", string.Join(" / ", filterNames), rows, FieldNames) {
|
base($"Liefermengen", $"Liefermengen pro Mitglied, Sorte und Attribut {year}", rows, FieldNames) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<MemberDeliveryPerVarietyData> FromQuery(IQueryable<DeliveryPart> query, List<string> filterNames) {
|
public static async Task<MemberDeliveryPerVarietyData> ForSeason(DbSet<MemberDeliveryPerVariantRowSingle> table, int year) {
|
||||||
return new((await query
|
return new MemberDeliveryPerVarietyData(
|
||||||
.GroupBy(p => new {
|
(await FromDbSet(table, year)).GroupBy(
|
||||||
p.Delivery.MgNr,
|
r => r.MgNr,
|
||||||
p.Delivery.Member.Name,
|
(k, g) => new MemberDeliveryPerVariantRow(g)
|
||||||
p.Delivery.Member.GivenName,
|
), year);
|
||||||
p.Delivery.Member.Address,
|
}
|
||||||
p.Delivery.Member.PostalDest.AtPlz!.Plz,
|
|
||||||
Ort = p.Delivery.Member.PostalDest.AtPlz!.Ort.Name,
|
private static async Task<IEnumerable<MemberDeliveryPerVariantRowSingle>> FromDbSet(DbSet<MemberDeliveryPerVariantRowSingle> table, int year) {
|
||||||
p.SortId,
|
return await table.FromSql($"""
|
||||||
p.AttrId,
|
SELECT m.mgnr, m.name AS name_1,
|
||||||
p.CultId,
|
COALESCE(m.prefix || ' ', '') || m.given_name ||
|
||||||
})
|
COALESCE(' ' || m.middle_names, '') || COALESCE(' ' || m.suffix, '') AS name_2,
|
||||||
.Select(g => new {
|
p.plz, o.name AS ort, m.address,
|
||||||
g.Key,
|
v.bucket, v.weight, v.area
|
||||||
Weight = g.Sum(p => p.Weight),
|
FROM (
|
||||||
})
|
SELECT c.year AS year,
|
||||||
.ToListAsync()).GroupBy(g => new {
|
c.mgnr AS mgnr,
|
||||||
g.Key.MgNr,
|
c.bucket AS bucket,
|
||||||
g.Key.Name,
|
COALESCE(d.weight, 0) AS weight,
|
||||||
g.Key.GivenName,
|
COALESCE(c.area, 0) AS area
|
||||||
g.Key.Address,
|
FROM v_area_commitment_bucket_strict c
|
||||||
g.Key.Plz,
|
LEFT JOIN v_delivery_bucket_strict d ON (d.year, d.mgnr, d.bucket) = (c.year, c.mgnr, c.bucket)
|
||||||
g.Key.Ort,
|
WHERE c.year = {year}
|
||||||
}).Select(g => new MemberDeliveryPerVarietyRow {
|
UNION
|
||||||
MgNr = g.Key.MgNr,
|
SELECT d.year,
|
||||||
Name1 = g.Key.Name,
|
d.mgnr,
|
||||||
Name2 = g.Key.GivenName,
|
d.bucket,
|
||||||
Address = g.Key.Address,
|
COALESCE(d.weight, 0),
|
||||||
Plz = g.Key.Plz,
|
COALESCE(c.area, 0)
|
||||||
Locality = g.Key.Ort,
|
FROM v_delivery_bucket_strict d
|
||||||
SortIds = [.. g.Select(d => d.Key.SortId)],
|
LEFT JOIN v_area_commitment_bucket_strict c ON (c.year, c.mgnr, c.bucket) = (d.year, d.mgnr, d.bucket)
|
||||||
AttrIds = [.. g.Select(d => d.Key.AttrId)],
|
WHERE d.year = {year}
|
||||||
CultIds = [.. g.Select(d => d.Key.CultId)],
|
) v
|
||||||
Weights = [.. g.Select(d => d.Weight)],
|
LEFT JOIN member m ON m.mgnr = v.mgnr
|
||||||
}), filterNames);
|
LEFT JOIN AT_plz_dest p ON p.id = m.postal_dest
|
||||||
|
LEFT JOIN AT_ort o ON o.okz = p.okz
|
||||||
|
ORDER BY m.mgnr, v.bucket
|
||||||
|
""").ToListAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class MemberDeliveryPerVarietyRow {
|
public class MemberDeliveryPerVariantRow {
|
||||||
public required int MgNr;
|
public int MgNr;
|
||||||
public required string Name1;
|
public string Name1;
|
||||||
public required string? Name2;
|
public string? Name2;
|
||||||
public required string Address;
|
public string Address;
|
||||||
public required int Plz;
|
public int Plz;
|
||||||
public required string Locality;
|
public string Locality;
|
||||||
public required string[] SortIds;
|
public string[] SortIds;
|
||||||
public required string?[] AttrIds;
|
public string[] AttrIds;
|
||||||
public required string?[] CultIds;
|
public int[] Areas;
|
||||||
public required int[] Weights;
|
public int[] Weights;
|
||||||
|
public int?[] Yields => Weights.Zip(Areas).Select(i => i.Second > 0 ? (int?)i.First * 10_000 / i.Second : null).ToArray();
|
||||||
|
|
||||||
|
public MemberDeliveryPerVariantRow(IEnumerable<MemberDeliveryPerVariantRowSingle> 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();
|
||||||
|
Weights = rows.Select(r => r.Weight).ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Keyless]
|
||||||
|
public class MemberDeliveryPerVariantRowSingle {
|
||||||
|
[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("weight")]
|
||||||
|
public int Weight { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,119 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Elwig.Models.Dtos {
|
|
||||||
public class MemberDeliveryYieldsPerVarietyData : DataTable<MemberDeliveryYieldsPerVarietyRow> {
|
|
||||||
|
|
||||||
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),
|
|
||||||
("Weights", "Geliefert", "kg", 22),
|
|
||||||
("Areas", "Fläche", "m²", 22),
|
|
||||||
("Yields", "Ertrag", "kg/ha", 22),
|
|
||||||
];
|
|
||||||
|
|
||||||
public MemberDeliveryYieldsPerVarietyData(IEnumerable<MemberDeliveryYieldsPerVarietyRow> rows, int year) :
|
|
||||||
base($"Liefermengen", $"Liefermengen pro Mitglied, Sorte und Attribut {year}", rows, FieldNames) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task<MemberDeliveryYieldsPerVarietyData> ForSeason(DbSet<MemberDeliveryPerVarietyRowSingle> table, int year) {
|
|
||||||
return new MemberDeliveryYieldsPerVarietyData(
|
|
||||||
(await FromDbSet(table, year)).GroupBy(
|
|
||||||
r => r.MgNr,
|
|
||||||
(k, g) => new MemberDeliveryYieldsPerVarietyRow(g)
|
|
||||||
), year);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async Task<IEnumerable<MemberDeliveryPerVarietyRowSingle>> FromDbSet(DbSet<MemberDeliveryPerVarietyRowSingle> 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,
|
|
||||||
v.bucket, v.weight, v.area
|
|
||||||
FROM (
|
|
||||||
SELECT c.year AS year,
|
|
||||||
c.mgnr AS mgnr,
|
|
||||||
c.bucket AS bucket,
|
|
||||||
COALESCE(d.weight, 0) AS weight,
|
|
||||||
COALESCE(c.area, 0) AS area
|
|
||||||
FROM v_area_commitment_bucket_strict c
|
|
||||||
LEFT JOIN v_delivery_bucket_strict d ON (d.year, d.mgnr, d.bucket) = (c.year, c.mgnr, c.bucket)
|
|
||||||
WHERE c.year = {year}
|
|
||||||
UNION
|
|
||||||
SELECT d.year,
|
|
||||||
d.mgnr,
|
|
||||||
d.bucket,
|
|
||||||
COALESCE(d.weight, 0),
|
|
||||||
COALESCE(c.area, 0)
|
|
||||||
FROM v_delivery_bucket_strict d
|
|
||||||
LEFT JOIN v_area_commitment_bucket_strict c ON (c.year, c.mgnr, c.bucket) = (d.year, d.mgnr, d.bucket)
|
|
||||||
WHERE d.year = {year}
|
|
||||||
) v
|
|
||||||
LEFT JOIN member m ON m.mgnr = v.mgnr
|
|
||||||
LEFT JOIN AT_plz_dest p ON p.id = m.postal_dest
|
|
||||||
LEFT JOIN AT_ort o ON o.okz = p.okz
|
|
||||||
ORDER BY m.mgnr, v.bucket
|
|
||||||
""").ToListAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class MemberDeliveryYieldsPerVarietyRow {
|
|
||||||
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[] Weights;
|
|
||||||
public int?[] Yields => Weights.Zip(Areas).Select(i => i.Second > 0 ? (int?)i.First * 10_000 / i.Second : null).ToArray();
|
|
||||||
|
|
||||||
public MemberDeliveryYieldsPerVarietyRow(IEnumerable<MemberDeliveryPerVarietyRowSingle> 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();
|
|
||||||
Weights = rows.Select(r => r.Weight).ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Keyless]
|
|
||||||
public class MemberDeliveryPerVarietyRowSingle {
|
|
||||||
[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("weight")]
|
|
||||||
public int Weight { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
using Elwig.Helpers;
|
using Elwig.Helpers;
|
||||||
using Elwig.Helpers.Billing;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -63,11 +62,6 @@ namespace Elwig.Models.Entities {
|
|||||||
[Column("comment")]
|
[Column("comment")]
|
||||||
public string? Comment { get; set; }
|
public string? Comment { get; set; }
|
||||||
|
|
||||||
[NotMapped]
|
|
||||||
public string[] Comments => [.. Parts.Select(p => p.Comment).Prepend(Comment).Where(c => c != null).Cast<string>()];
|
|
||||||
[NotMapped]
|
|
||||||
public string CommentsString => string.Join(" / ", Comments);
|
|
||||||
|
|
||||||
[Column("ctime"), DatabaseGenerated(DatabaseGeneratedOption.Computed)]
|
[Column("ctime"), DatabaseGenerated(DatabaseGeneratedOption.Computed)]
|
||||||
public long CTime { get; set; }
|
public long CTime { get; set; }
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
@@ -114,16 +108,16 @@ namespace Elwig.Models.Entities {
|
|||||||
public int Weight => Parts.Select(p => p.Weight).Sum();
|
public int Weight => Parts.Select(p => p.Weight).Sum();
|
||||||
public int FilteredWeight => FilteredParts.Select(p => p.Weight).Sum();
|
public int FilteredWeight => FilteredParts.Select(p => p.Weight).Sum();
|
||||||
|
|
||||||
public IEnumerable<RawVaribute> Vaributes => Parts
|
public IEnumerable<string> SortIds => Parts
|
||||||
.GroupBy(p => (p.SortId, p.AttrId, p.CultId))
|
.GroupBy(p => p.SortId)
|
||||||
.OrderByDescending(g => g.Select(p => p.Weight).Sum())
|
.OrderByDescending(g => g.Select(p => p.Weight).Sum())
|
||||||
.Select(g => new RawVaribute(g.Key.SortId, g.Key.AttrId, g.Key.CultId));
|
.Select(g => g.Key);
|
||||||
public IEnumerable<RawVaribute> FilteredVaributes => FilteredParts
|
public IEnumerable<string> FilteredSortIds => FilteredParts
|
||||||
.GroupBy(p => (p.SortId, p.AttrId, p.CultId))
|
.GroupBy(p => p.SortId)
|
||||||
.OrderByDescending(g => g.Select(p => p.Weight).Sum())
|
.OrderByDescending(g => g.Select(p => p.Weight).Sum())
|
||||||
.Select(g => new RawVaribute(g.Key.SortId, g.Key.AttrId, g.Key.CultId));
|
.Select(g => g.Key);
|
||||||
public string VaributeString => string.Join(", ", Vaributes);
|
public string SortIdString => string.Join(", ", SortIds);
|
||||||
public string FilteredVaributeString => string.Join(", ", FilteredVaributes);
|
public string FilteredSortIdString => string.Join(", ", FilteredSortIds);
|
||||||
|
|
||||||
public Brush? Color => Parts.Select(p => p.Variety.Color).Distinct().SingleOrDefault();
|
public Brush? Color => Parts.Select(p => p.Variety.Color).Distinct().SingleOrDefault();
|
||||||
public Brush? FilteredColor => FilteredParts.Select(p => p.Variety.Color).Distinct().SingleOrDefault();
|
public Brush? FilteredColor => FilteredParts.Select(p => p.Variety.Color).Distinct().SingleOrDefault();
|
||||||
|
|||||||
@@ -9,11 +9,6 @@ using System.Text.Json.Nodes;
|
|||||||
namespace Elwig.Models.Entities {
|
namespace Elwig.Models.Entities {
|
||||||
[Table("delivery_part"), PrimaryKey("Year", "DId", "DPNr")]
|
[Table("delivery_part"), PrimaryKey("Year", "DId", "DPNr")]
|
||||||
public class DeliveryPart : IDelivery {
|
public class DeliveryPart : IDelivery {
|
||||||
|
|
||||||
public const string Dumper = "dumper";
|
|
||||||
public const string Pumped = "pumped";
|
|
||||||
public const string Box = "box";
|
|
||||||
|
|
||||||
[Column("year")]
|
[Column("year")]
|
||||||
public int Year { get; set; }
|
public int Year { get; set; }
|
||||||
|
|
||||||
@@ -91,27 +86,12 @@ namespace Elwig.Models.Entities {
|
|||||||
[Column("hand_picked")]
|
[Column("hand_picked")]
|
||||||
public bool? IsHandPicked { get; set; }
|
public bool? IsHandPicked { get; set; }
|
||||||
|
|
||||||
|
[Column("lesewagen")]
|
||||||
|
public bool? IsLesewagen { get; set; }
|
||||||
|
|
||||||
[Column("gebunden")]
|
[Column("gebunden")]
|
||||||
public bool? IsGebunden { get; set; }
|
public bool? IsGebunden { get; set; }
|
||||||
|
|
||||||
[Column("unloading")]
|
|
||||||
public string? Unloading { get; set; }
|
|
||||||
[NotMapped]
|
|
||||||
public bool IsDumper {
|
|
||||||
get => Unloading == Dumper;
|
|
||||||
set => Unloading = value ? Dumper : Unloading;
|
|
||||||
}
|
|
||||||
[NotMapped]
|
|
||||||
public bool IsPumped {
|
|
||||||
get => Unloading == Pumped;
|
|
||||||
set => Unloading = value ? Pumped : Unloading;
|
|
||||||
}
|
|
||||||
[NotMapped]
|
|
||||||
public bool IsBox {
|
|
||||||
get => Unloading == Box;
|
|
||||||
set => Unloading = value ? Box : Unloading;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Column("temperature")]
|
[Column("temperature")]
|
||||||
public double? Temperature { get; set; }
|
public double? Temperature { get; set; }
|
||||||
|
|
||||||
|
|||||||
@@ -42,9 +42,7 @@ namespace Elwig.Models.Entities {
|
|||||||
[Column("max_weight")]
|
[Column("max_weight")]
|
||||||
public int? MaxWeight { get; set; }
|
public int? MaxWeight { get; set; }
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public int AnnouncedWeight => AnnouncedWeightOverride ?? Announcements.Sum(a => a.Weight);
|
public int AnnouncedWeight => Announcements.Sum(a => a.Weight);
|
||||||
[NotMapped]
|
|
||||||
public int? AnnouncedWeightOverride { get; set; }
|
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public double? Percent => (double)AnnouncedWeight / MaxWeight * 100;
|
public double? Percent => (double)AnnouncedWeight / MaxWeight * 100;
|
||||||
|
|
||||||
|
|||||||
@@ -16,9 +16,6 @@ namespace Elwig.Models.Entities {
|
|||||||
[Column("active")]
|
[Column("active")]
|
||||||
public bool IsActive { get; set; }
|
public bool IsActive { get; set; }
|
||||||
|
|
||||||
[Column("redacted")]
|
|
||||||
public bool IsRedacted { get; set; }
|
|
||||||
|
|
||||||
[Column("ordering")]
|
[Column("ordering")]
|
||||||
public int Ordering { get; set; }
|
public int Ordering { get; set; }
|
||||||
|
|
||||||
@@ -49,8 +46,6 @@ namespace Elwig.Models.Entities {
|
|||||||
(Rel != null) ? $"{Utils.GetSign(Rel.Value)}{(Math.Abs(Rel.Value) < 0.1m ? "\u2007" : "")}{Math.Abs(Rel.Value):0.00##\u00a0%}" :
|
(Rel != null) ? $"{Utils.GetSign(Rel.Value)}{(Math.Abs(Rel.Value) < 0.1m ? "\u2007" : "")}{Math.Abs(Rel.Value):0.00##\u00a0%}" :
|
||||||
"";
|
"";
|
||||||
|
|
||||||
public string? PublicValueStr => IsRedacted ? null : ValueStr;
|
|
||||||
|
|
||||||
public override string ToString() {
|
public override string ToString() {
|
||||||
return Name;
|
return Name;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,24 +11,16 @@ namespace Elwig.Models.Entities {
|
|||||||
[Column("type")]
|
[Column("type")]
|
||||||
public string Type { get; private set; } = null!;
|
public string Type { get; private set; } = null!;
|
||||||
|
|
||||||
[Column("max_qualid")]
|
|
||||||
public string MaxQualId { get; private set; } = null!;
|
|
||||||
|
|
||||||
[ForeignKey("MaxQualId")]
|
|
||||||
public virtual WineQualLevel MaxQualityLevel { get; private set; } = null!;
|
|
||||||
|
|
||||||
[Column("name")]
|
[Column("name")]
|
||||||
public string Name { get; private set; } = null!;
|
public string Name { get; private set; } = null!;
|
||||||
|
|
||||||
[Column("comment")]
|
[Column("comment")]
|
||||||
public string? Comment { get; private set; }
|
public string? Comment { get; private set; }
|
||||||
|
|
||||||
public string SortIdFormat => IsQuw ? SortId : $"({SortId})";
|
|
||||||
public string CommentFormat => (Comment != null) ? $" ({Comment})" : "";
|
public string CommentFormat => (Comment != null) ? $" ({Comment})" : "";
|
||||||
|
|
||||||
public bool IsRed => Type == "R";
|
public bool IsRed => Type == "R";
|
||||||
public bool IsWhite => Type == "W";
|
public bool IsWhite => Type == "W";
|
||||||
public bool IsQuw => MaxQualId == "QUW";
|
|
||||||
public Brush? Color => IsWhite ? Brushes.DarkGreen : IsRed ? Brushes.DarkRed : null;
|
public Brush? Color => IsWhite ? Brushes.DarkGreen : IsRed ? Brushes.DarkRed : null;
|
||||||
|
|
||||||
public WineVar() { }
|
public WineVar() { }
|
||||||
@@ -36,7 +28,6 @@ namespace Elwig.Models.Entities {
|
|||||||
public WineVar(string sortId, string name) {
|
public WineVar(string sortId, string name) {
|
||||||
SortId = sortId;
|
SortId = sortId;
|
||||||
Name = name;
|
Name = name;
|
||||||
MaxQualId = "QUW";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString() {
|
public override string ToString() {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
|
|||||||
<PublishDir>bin\Publish</PublishDir>
|
<PublishDir>bin\Publish</PublishDir>
|
||||||
<PublishProtocol>FileSystem</PublishProtocol>
|
<PublishProtocol>FileSystem</PublishProtocol>
|
||||||
<_TargetId>Folder</_TargetId>
|
<_TargetId>Folder</_TargetId>
|
||||||
<TargetFramework>net10.0-windows</TargetFramework>
|
<TargetFramework>net8.0-windows</TargetFramework>
|
||||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||||
<SelfContained>true</SelfContained>
|
<SelfContained>true</SelfContained>
|
||||||
<PublishSingleFile>false</PublishSingleFile>
|
<PublishSingleFile>false</PublishSingleFile>
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
-- schema version 32 to 33
|
|
||||||
|
|
||||||
ALTER TABLE wine_variety ADD COLUMN max_qualid TEXT NOT NULL DEFAULT 'QUW';
|
|
||||||
UPDATE wine_quality_level SET qualid = 'ALW' WHERE qualid = 'AUL';
|
|
||||||
UPDATE wine_variety SET comment = 'Muscato' WHERE sortid = 'MO';
|
|
||||||
|
|
||||||
INSERT INTO wine_variety (sortid, type, max_qualid, name, comment) VALUES
|
|
||||||
('DR', 'W', 'QUW', 'Donauriesling', NULL),
|
|
||||||
('DV', 'W', 'QUW', 'Donauveltliner', NULL),
|
|
||||||
('BN', 'W', 'RSW', 'Bronner', NULL),
|
|
||||||
('CB', 'W', 'RSW', 'Cabernet Blanc', NULL),
|
|
||||||
('CJ', 'R', 'RSW', 'Cabernet Jura', NULL),
|
|
||||||
('JO', 'W', 'RSW', 'Johanniter', NULL),
|
|
||||||
('OR', 'W', 'RSW', 'Orangetraube', NULL),
|
|
||||||
('PI', 'R', 'RSW', 'Pinot Nova', NULL),
|
|
||||||
('RE', 'R', 'RSW', 'Regent', NULL),
|
|
||||||
('SI', 'W', 'RSW', 'Solaris', NULL);
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
-- schema version 33 to 34
|
|
||||||
|
|
||||||
ALTER TABLE modifier ADD COLUMN redacted INTEGER NOT NULL CHECK (redacted IN (TRUE, FALSE)) DEFAULT FALSE;
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
-- schema version 34 to 35
|
|
||||||
|
|
||||||
ALTER TABLE delivery_part ADD COLUMN unloading TEXT DEFAULT NULL;
|
|
||||||
UPDATE delivery_part SET unloading = 'pumped' WHERE lesewagen;
|
|
||||||
UPDATE delivery_part SET unloading = 'box' WHERE (SELECT zwstid IN ('H','S') FROM delivery d WHERE (d.year, d.did) = (delivery_part.year, delivery_part.did));
|
|
||||||
ALTER TABLE delivery_part DROP COLUMN lesewagen;
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
-- schema version 35 to 36
|
|
||||||
|
|
||||||
CREATE VIEW v_member AS
|
|
||||||
SELECT m.mgnr, m.name,
|
|
||||||
(COALESCE(m.prefix || ' ', '') || m.given_name || COALESCE(' ' || m.middle_names, '') || COALESCE(' ' || m.suffix, '')) AS other_names,
|
|
||||||
m.address, p.plz, o.name AS locality,
|
|
||||||
a.name AS billing_name, a.address AS billing_address, p2.plz AS billing_plz, o2.name AS billing_locality,
|
|
||||||
k.name AS default_kg,
|
|
||||||
GROUP_CONCAT(e.address, ', ') AS email_addresses
|
|
||||||
FROM member m
|
|
||||||
LEFT JOIN AT_plz_dest p ON p.id = m.postal_dest
|
|
||||||
LEFT JOIN AT_ort o ON o.okz = p.okz
|
|
||||||
LEFT JOIN member_billing_address a ON a.mgnr = m.mgnr
|
|
||||||
LEFT JOIN AT_plz_dest p2 ON p2.id = a.postal_dest
|
|
||||||
LEFT JOIN AT_ort o2 ON o2.okz = p2.okz
|
|
||||||
LEFT JOIN AT_kg k ON k.kgnr = m.default_kgnr
|
|
||||||
LEFT JOIN member_email_address e ON e.mgnr = m.mgnr
|
|
||||||
GROUP BY m.mgnr
|
|
||||||
ORDER BY m.mgnr;
|
|
||||||
@@ -15,8 +15,10 @@ using LinqKit;
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using System.IO;
|
||||||
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
|
using System.Net.Http;
|
||||||
|
|
||||||
namespace Elwig.Services {
|
namespace Elwig.Services {
|
||||||
public static class DeliveryService {
|
public static class DeliveryService {
|
||||||
@@ -78,9 +80,9 @@ namespace Elwig.Services {
|
|||||||
vm.PartComment = p.Comment ?? "";
|
vm.PartComment = p.Comment ?? "";
|
||||||
vm.TemperatureString = (p.Temperature != null) ? $"{p.Temperature:N1}" : "";
|
vm.TemperatureString = (p.Temperature != null) ? $"{p.Temperature:N1}" : "";
|
||||||
vm.AcidString = (p.Acid != null) ? $"{p.Acid:N1}" : "";
|
vm.AcidString = (p.Acid != null) ? $"{p.Acid:N1}" : "";
|
||||||
|
vm.IsLesewagen = p.IsLesewagen ?? false;
|
||||||
vm.IsHandPicked = p.IsHandPicked;
|
vm.IsHandPicked = p.IsHandPicked;
|
||||||
vm.IsGebunden = p.IsGebunden;
|
vm.IsGebunden = p.IsGebunden;
|
||||||
vm.Unloading = p.Unloading;
|
|
||||||
|
|
||||||
vm.ScaleId = p.ScaleId;
|
vm.ScaleId = p.ScaleId;
|
||||||
vm.WeighingData = p.WeighingData;
|
vm.WeighingData = p.WeighingData;
|
||||||
@@ -186,54 +188,14 @@ namespace Elwig.Services {
|
|||||||
prd = prd.And(p => p.IsNetWeight == true);
|
prd = prd.And(p => p.IsNetWeight == true);
|
||||||
filter.RemoveAt(i--);
|
filter.RemoveAt(i--);
|
||||||
filterNames.Add("gerebelt gewogen");
|
filterNames.Add("gerebelt gewogen");
|
||||||
} else if (e.Length >= 5 && e.Length <= 11 && "planenwagen".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
|
|
||||||
prd = prd.And(p => p.Unloading == DeliveryPart.Dumper);
|
|
||||||
filter.RemoveAt(i--);
|
|
||||||
filterNames.Add("Planenw./Kipper");
|
|
||||||
} else if (e.Length >= 6 && e.Length <= 12 && "!planenwagen".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
|
|
||||||
prd = prd.And(p => p.Unloading != DeliveryPart.Dumper);
|
|
||||||
filter.RemoveAt(i--);
|
|
||||||
filterNames.Add("kein Planenw./Kipper");
|
|
||||||
} else if (e.Length >= 4 && e.Length <= 6 && "kipper".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
|
|
||||||
prd = prd.And(p => p.Unloading == DeliveryPart.Dumper);
|
|
||||||
filter.RemoveAt(i--);
|
|
||||||
filterNames.Add("Planenw./Kipper");
|
|
||||||
} else if (e.Length >= 5 && e.Length <= 7 && "!kipper".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
|
|
||||||
prd = prd.And(p => p.Unloading != DeliveryPart.Dumper);
|
|
||||||
filter.RemoveAt(i--);
|
|
||||||
filterNames.Add("kein Planenw./Kipper");
|
|
||||||
} else if (e.Length >= 5 && e.Length <= 9 && "lesewagen".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
|
} else if (e.Length >= 5 && e.Length <= 9 && "lesewagen".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
|
||||||
prd = prd.And(p => p.Unloading == DeliveryPart.Pumped);
|
prd = prd.And(p => p.IsLesewagen == true);
|
||||||
filter.RemoveAt(i--);
|
filter.RemoveAt(i--);
|
||||||
filterNames.Add("Lesewagen");
|
filterNames.Add("Lesewagen");
|
||||||
} else if (e.Length >= 6 && e.Length <= 10 && "!lesewagen".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
|
} else if (e.Length >= 6 && e.Length <= 10 && "!lesewagen".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
|
||||||
prd = prd.And(p => p.Unloading != DeliveryPart.Pumped);
|
prd = prd.And(p => p.IsLesewagen == false);
|
||||||
filter.RemoveAt(i--);
|
filter.RemoveAt(i--);
|
||||||
filterNames.Add("kein Lesewagen");
|
filterNames.Add("kein Lesewagen");
|
||||||
} else if (e.Length >= 5 && e.Length <= 6 && "kisten".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
|
|
||||||
prd = prd.And(p => p.Unloading == DeliveryPart.Box);
|
|
||||||
filter.RemoveAt(i--);
|
|
||||||
filterNames.Add("Kisten");
|
|
||||||
} else if (e.Length >= 6 && e.Length <= 7 && "!kisten".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
|
|
||||||
prd = prd.And(p => p.Unloading != DeliveryPart.Box);
|
|
||||||
filter.RemoveAt(i--);
|
|
||||||
filterNames.Add("keine Kisten");
|
|
||||||
} else if ("upload".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
|
|
||||||
prd = prd.And(p => (p.Delivery.XTime == null || p.Delivery.MTime > p.Delivery.XTime) && (p.Delivery.ITime == null || p.Delivery.MTime > p.Delivery.ITime));
|
|
||||||
filter.RemoveAt(i--);
|
|
||||||
filterNames.Add("geändert seit letztem Export");
|
|
||||||
} else if ("!upload".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
|
|
||||||
prd = prd.And(p => !((p.Delivery.XTime == null || p.Delivery.MTime > p.Delivery.XTime) && (p.Delivery.ITime == null || p.Delivery.MTime > p.Delivery.ITime)));
|
|
||||||
filter.RemoveAt(i--);
|
|
||||||
filterNames.Add("unverändert seit letztem Export");
|
|
||||||
} else if (">import".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
|
|
||||||
prd = prd.And(p => p.ITime != null && p.Delivery.MTime > p.Delivery.ITime);
|
|
||||||
filter.RemoveAt(i--);
|
|
||||||
filterNames.Add("geändert seit letztem Import");
|
|
||||||
} else if ("<import".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
|
|
||||||
prd = prd.And(p => p.Delivery.MTime <= p.Delivery.ITime);
|
|
||||||
filter.RemoveAt(i--);
|
|
||||||
filterNames.Add("unverändert seit letztem Import");
|
|
||||||
} else if (e.Length == 2 && var.ContainsKey(e.ToUpper())) {
|
} else if (e.Length == 2 && var.ContainsKey(e.ToUpper())) {
|
||||||
filterVar.Add(e.ToUpper());
|
filterVar.Add(e.ToUpper());
|
||||||
filter.RemoveAt(i--);
|
filter.RemoveAt(i--);
|
||||||
@@ -521,8 +483,8 @@ namespace Elwig.Services {
|
|||||||
|
|
||||||
IsNetWeight = vm.IsNetWeight,
|
IsNetWeight = vm.IsNetWeight,
|
||||||
IsHandPicked = vm.IsHandPicked,
|
IsHandPicked = vm.IsHandPicked,
|
||||||
|
IsLesewagen = vm.IsLesewagen,
|
||||||
IsGebunden = vm.IsGebunden,
|
IsGebunden = vm.IsGebunden,
|
||||||
Unloading = vm.Unloading,
|
|
||||||
Temperature = vm.Temperature,
|
Temperature = vm.Temperature,
|
||||||
Acid = vm.Acid,
|
Acid = vm.Acid,
|
||||||
Comment = string.IsNullOrEmpty(vm.PartComment) ? null : vm.PartComment,
|
Comment = string.IsNullOrEmpty(vm.PartComment) ? null : vm.PartComment,
|
||||||
@@ -609,13 +571,6 @@ namespace Elwig.Services {
|
|||||||
s.DPNr = dpnr++;
|
s.DPNr = dpnr++;
|
||||||
s.Weight = w;
|
s.Weight = w;
|
||||||
ctx.Add(s);
|
ctx.Add(s);
|
||||||
|
|
||||||
ctx.AddRange(p.PartModifiers.Select(m => new DeliveryPartModifier() {
|
|
||||||
Year = s.Year,
|
|
||||||
DId = s.DId,
|
|
||||||
DPNr = s.DPNr,
|
|
||||||
ModId = m.ModId,
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -653,13 +608,6 @@ namespace Elwig.Services {
|
|||||||
s.DPNr = dpnr++;
|
s.DPNr = dpnr++;
|
||||||
s.Weight = w;
|
s.Weight = w;
|
||||||
ctx.Add(s);
|
ctx.Add(s);
|
||||||
|
|
||||||
ctx.AddRange(p.PartModifiers.Select(m => new DeliveryPartModifier() {
|
|
||||||
Year = s.Year,
|
|
||||||
DId = s.DId,
|
|
||||||
DPNr = s.DPNr,
|
|
||||||
ModId = m.ModId,
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -694,13 +642,6 @@ namespace Elwig.Services {
|
|||||||
n.QualId = "WEI";
|
n.QualId = "WEI";
|
||||||
n.HkId = "OEST";
|
n.HkId = "OEST";
|
||||||
ctx.Add(n);
|
ctx.Add(n);
|
||||||
|
|
||||||
ctx.AddRange(p.PartModifiers.Select(m => new DeliveryPartModifier() {
|
|
||||||
Year = n.Year,
|
|
||||||
DId = n.DId,
|
|
||||||
DPNr = n.DPNr,
|
|
||||||
ModId = m.ModId,
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await ctx.SaveChangesAsync();
|
await ctx.SaveChangesAsync();
|
||||||
@@ -780,11 +721,9 @@ namespace Elwig.Services {
|
|||||||
FileName = subject == ExportSubject.Selected ? $"Lieferung_{vm.SelectedDelivery?.LsNr}.elwig.zip" : $"Lieferungen_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{App.ZwstId}.elwig.zip",
|
FileName = subject == ExportSubject.Selected ? $"Lieferung_{vm.SelectedDelivery?.LsNr}.elwig.zip" : $"Lieferungen_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{App.ZwstId}.elwig.zip",
|
||||||
DefaultExt = "elwig.zip",
|
DefaultExt = "elwig.zip",
|
||||||
Filter = "Elwig-Export-Datei (*.elwig.zip)|*.elwig.zip",
|
Filter = "Elwig-Export-Datei (*.elwig.zip)|*.elwig.zip",
|
||||||
Title = $"{DeliveryJournal.Name} speichern unter - Elwig",
|
Title = $"{DeliveryJournal.Name} speichern unter - Elwig"
|
||||||
AddExtension = false,
|
|
||||||
};
|
};
|
||||||
if (d.ShowDialog() == true) {
|
if (d.ShowDialog() == true) {
|
||||||
if (!d.FileName.EndsWith(".elwig.zip")) d.FileName += ".elwig.zip";
|
|
||||||
Mouse.OverrideCursor = Cursors.Wait;
|
Mouse.OverrideCursor = Cursors.Wait;
|
||||||
await Task.Run(async () => {
|
await Task.Run(async () => {
|
||||||
try {
|
try {
|
||||||
@@ -792,7 +731,6 @@ namespace Elwig.Services {
|
|||||||
.Select(p => p.Delivery)
|
.Select(p => p.Delivery)
|
||||||
.Distinct()
|
.Distinct()
|
||||||
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers)
|
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers)
|
||||||
.Include(d => d.Parts).ThenInclude(p => p.Rd)
|
|
||||||
.Include(d => d.Parts).ThenInclude(p => p.Kg!.Gl)
|
.Include(d => d.Parts).ThenInclude(p => p.Kg!.Gl)
|
||||||
.AsSplitQuery()
|
.AsSplitQuery()
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
@@ -813,7 +751,39 @@ namespace Elwig.Services {
|
|||||||
} else if (mode == ExportMode.Upload && App.Config.SyncUrl != null) {
|
} else if (mode == ExportMode.Upload && App.Config.SyncUrl != null) {
|
||||||
Mouse.OverrideCursor = Cursors.Wait;
|
Mouse.OverrideCursor = Cursors.Wait;
|
||||||
await Task.Run(async () => {
|
await Task.Run(async () => {
|
||||||
await SyncService.Upload(App.Config.SyncUrl, App.Config.SyncUrl, App.Config.SyncPassword, query, filterNames);
|
try {
|
||||||
|
var filename = $"{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{App.ZwstId}.elwig.zip";
|
||||||
|
var path = Path.Combine(App.TempPath, filename);
|
||||||
|
var list = await query
|
||||||
|
.Select(p => p.Delivery)
|
||||||
|
.Distinct()
|
||||||
|
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers)
|
||||||
|
.Include(d => d.Parts).ThenInclude(p => p.Kg!.Gl)
|
||||||
|
.AsSplitQuery()
|
||||||
|
.ToListAsync();
|
||||||
|
var wbKgs = list
|
||||||
|
.SelectMany(d => d.Parts)
|
||||||
|
.Where(p => p.Kg != null)
|
||||||
|
.Select(p => p.Kg!)
|
||||||
|
.DistinctBy(k => k.KgNr)
|
||||||
|
.OrderBy(k => k.KgNr)
|
||||||
|
.ToList();
|
||||||
|
if (list.Count == 0) {
|
||||||
|
MessageBox.Show("Es wurden keine Lieferungen zum Hochladen ausgewählt!", "Lieferungen hochladen",
|
||||||
|
MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
|
} else {
|
||||||
|
await ElwigData.Export(path, list, wbKgs, filterNames);
|
||||||
|
await Utils.UploadExportData(path, App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
|
||||||
|
MessageBox.Show($"Hochladen von {list.Count:N0} Lieferungen erfolgreich!", "Lieferungen hochgeladen",
|
||||||
|
MessageBoxButton.OK, MessageBoxImage.Information);
|
||||||
|
}
|
||||||
|
} catch (HttpRequestException exc) {
|
||||||
|
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Lieferungen hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
|
} catch (TaskCanceledException exc) {
|
||||||
|
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
|
} catch (Exception exc) {
|
||||||
|
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
Mouse.OverrideCursor = null;
|
Mouse.OverrideCursor = null;
|
||||||
} else {
|
} else {
|
||||||
@@ -964,52 +934,6 @@ namespace Elwig.Services {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task GenerateDeliveryDataList(this DeliveryAdminViewModel vm, ExportSubject subject, ExportMode mode) {
|
|
||||||
using var ctx = new AppDbContext();
|
|
||||||
IQueryable<DeliveryPart> query;
|
|
||||||
List<string> filterNames = [];
|
|
||||||
if (subject == ExportSubject.FromFilters) {
|
|
||||||
var (f, _, q, _, _) = await vm.GetFilters(ctx);
|
|
||||||
query = q;
|
|
||||||
filterNames.AddRange(f);
|
|
||||||
} else if (subject == ExportSubject.FromSeason) {
|
|
||||||
var year = vm.FilterSeason ?? Utils.CurrentLastSeason;
|
|
||||||
query = ctx.DeliveryParts
|
|
||||||
.Where(p => p.Year == year);
|
|
||||||
filterNames.Add($"{year}");
|
|
||||||
} else {
|
|
||||||
throw new ArgumentException("Invalid value for ExportSubject");
|
|
||||||
}
|
|
||||||
|
|
||||||
query = query
|
|
||||||
.OrderBy(p => p.Delivery.MgNr)
|
|
||||||
.ThenBy(p => p.SortId)
|
|
||||||
.ThenBy(p => p.AttrId)
|
|
||||||
.ThenBy(p => p.CultId);
|
|
||||||
|
|
||||||
var d = new SaveFileDialog() {
|
|
||||||
FileName = $"Liefermengen.ods",
|
|
||||||
DefaultExt = "ods",
|
|
||||||
Filter = "OpenDocument Format Spreadsheet (*.ods)|*.ods",
|
|
||||||
Title = $"Liefermengen speichern unter - Elwig"
|
|
||||||
};
|
|
||||||
if (d.ShowDialog() == true) {
|
|
||||||
Mouse.OverrideCursor = Cursors.Wait;
|
|
||||||
await Task.Run(async () => {
|
|
||||||
try {
|
|
||||||
using var ods = new OdsFile(d.FileName);
|
|
||||||
var tblTotal = await MemberDeliveryData.FromQuery(query, filterNames);
|
|
||||||
var tbl = await MemberDeliveryPerVarietyData.FromQuery(query, filterNames);
|
|
||||||
await ods.AddTable(tblTotal);
|
|
||||||
await ods.AddTable(tbl);
|
|
||||||
} catch (Exception exc) {
|
|
||||||
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Mouse.OverrideCursor = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void AddToolTipCell(Grid grid, string text, int row, int col, int colSpan = 1, bool bold = false, bool alignRight = false, bool alignCenter = false) {
|
private static void AddToolTipCell(Grid grid, string text, int row, int col, int colSpan = 1, bool bold = false, bool alignRight = false, bool alignCenter = false) {
|
||||||
var tb = new TextBlock() {
|
var tb = new TextBlock() {
|
||||||
Text = text,
|
Text = text,
|
||||||
|
|||||||
@@ -9,7 +9,9 @@ using Microsoft.EntityFrameworkCore;
|
|||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
@@ -313,22 +315,6 @@ namespace Elwig.Services {
|
|||||||
memberQuery = memberQuery.Where(m => !m.ContactViaPost);
|
memberQuery = memberQuery.Where(m => !m.ContactViaPost);
|
||||||
filter.RemoveAt(i--);
|
filter.RemoveAt(i--);
|
||||||
filterNames.Add("nicht Kontaktart Post");
|
filterNames.Add("nicht Kontaktart Post");
|
||||||
} else if ("upload".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
|
|
||||||
memberQuery = memberQuery.Where(p => (p.XTime == null || p.MTime > p.XTime) && (p.ITime == null || p.MTime > p.ITime));
|
|
||||||
filter.RemoveAt(i--);
|
|
||||||
filterNames.Add("geändert seit letztem Export");
|
|
||||||
} else if ("!upload".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
|
|
||||||
memberQuery = memberQuery.Where(p => !((p.XTime == null || p.MTime > p.XTime) && (p.ITime == null || p.MTime > p.ITime)));
|
|
||||||
filter.RemoveAt(i--);
|
|
||||||
filterNames.Add("unverändert seit letztem Export");
|
|
||||||
} else if (">import".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
|
|
||||||
memberQuery = memberQuery.Where(p => p.MTime > p.ITime);
|
|
||||||
filter.RemoveAt(i--);
|
|
||||||
filterNames.Add("geändert seit letztem Import");
|
|
||||||
} else if ("<import".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
|
|
||||||
memberQuery = memberQuery.Where(p => p.MTime <= p.ITime);
|
|
||||||
filter.RemoveAt(i--);
|
|
||||||
filterNames.Add("unverändert seit letztem Import");
|
|
||||||
} else if (e.All(char.IsAsciiDigit) && mgnr.ContainsKey(e)) {
|
} else if (e.All(char.IsAsciiDigit) && mgnr.ContainsKey(e)) {
|
||||||
filterMgNr.Add(int.Parse(e));
|
filterMgNr.Add(int.Parse(e));
|
||||||
filter.RemoveAt(i--);
|
filter.RemoveAt(i--);
|
||||||
@@ -507,42 +493,14 @@ namespace Elwig.Services {
|
|||||||
});
|
});
|
||||||
Mouse.OverrideCursor = null;
|
Mouse.OverrideCursor = null;
|
||||||
}
|
}
|
||||||
} else if (mode == ExportMode.Vcf) {
|
|
||||||
var d = new SaveFileDialog() {
|
|
||||||
FileName = "Mitglieder.vcf",
|
|
||||||
DefaultExt = "vcf",
|
|
||||||
Filter = "vCard-Datei (*.vcf)|*.vcf",
|
|
||||||
Title = "Kontakte speichern unter - Elwig"
|
|
||||||
};
|
|
||||||
if (d.ShowDialog() == true) {
|
|
||||||
Mouse.OverrideCursor = Cursors.Wait;
|
|
||||||
await Task.Run(async () => {
|
|
||||||
try {
|
|
||||||
var members = await query
|
|
||||||
.OrderBy(m => m.MgNr)
|
|
||||||
.Include(m => m.BillingAddress)
|
|
||||||
.Include(m => m.TelephoneNumbers)
|
|
||||||
.Include(m => m.EmailAddresses)
|
|
||||||
.AsSplitQuery()
|
|
||||||
.ToListAsync();
|
|
||||||
using var exporter = new VCard(d.FileName);
|
|
||||||
await exporter.ExportAsync(members);
|
|
||||||
} catch (Exception exc) {
|
|
||||||
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Mouse.OverrideCursor = null;
|
|
||||||
}
|
|
||||||
} else if (mode == ExportMode.Export) {
|
} else if (mode == ExportMode.Export) {
|
||||||
var d = new SaveFileDialog() {
|
var d = new SaveFileDialog() {
|
||||||
FileName = subject == ExportSubject.Selected ? $"Mitglied_{vm.SelectedMember?.MgNr}.elwig.zip" : $"Mitglieder_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{App.ZwstId}.elwig.zip",
|
FileName = subject == ExportSubject.Selected ? $"Mitglied_{vm.SelectedMember?.MgNr}.elwig.zip" : $"Mitglieder_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{App.ZwstId}.elwig.zip",
|
||||||
DefaultExt = "elwig.zip",
|
DefaultExt = ".elwig.zip",
|
||||||
Filter = "Elwig-Export-Datei (*.elwig.zip)|*.elwig.zip",
|
Filter = "Elwig-Export-Datei (*.elwig.zip)|*.elwig.zip",
|
||||||
Title = $"{MemberList.Name} speichern unter - Elwig",
|
Title = $"{MemberList.Name} speichern unter - Elwig"
|
||||||
AddExtension = false,
|
|
||||||
};
|
};
|
||||||
if (d.ShowDialog() == true) {
|
if (d.ShowDialog() == true) {
|
||||||
if (!d.FileName.EndsWith(".elwig.zip")) d.FileName += ".elwig.zip";
|
|
||||||
Mouse.OverrideCursor = Cursors.Wait;
|
Mouse.OverrideCursor = Cursors.Wait;
|
||||||
await Task.Run(async () => {
|
await Task.Run(async () => {
|
||||||
try {
|
try {
|
||||||
@@ -576,7 +534,46 @@ namespace Elwig.Services {
|
|||||||
} else if (mode == ExportMode.Upload && App.Config.SyncUrl != null) {
|
} else if (mode == ExportMode.Upload && App.Config.SyncUrl != null) {
|
||||||
Mouse.OverrideCursor = Cursors.Wait;
|
Mouse.OverrideCursor = Cursors.Wait;
|
||||||
await Task.Run(async () => {
|
await Task.Run(async () => {
|
||||||
await SyncService.Upload(App.Config.SyncUrl, App.Config.SyncUrl, App.Config.SyncPassword, query, filterNames);
|
try {
|
||||||
|
var filename = $"{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{App.ZwstId}.elwig.zip";
|
||||||
|
var path = Path.Combine(App.TempPath, filename);
|
||||||
|
var members = await query
|
||||||
|
.OrderBy(m => m.MgNr)
|
||||||
|
.Include(m => m.BillingAddress)
|
||||||
|
.Include(m => m.TelephoneNumbers)
|
||||||
|
.Include(m => m.EmailAddresses)
|
||||||
|
.Include(m => m.DefaultWbKg!.Gl)
|
||||||
|
.AsSplitQuery()
|
||||||
|
.ToListAsync();
|
||||||
|
var areaComs = await query
|
||||||
|
.SelectMany(m => m.AreaCommitments)
|
||||||
|
.OrderBy(c => c.MgNr).ThenBy(c => c.FbNr)
|
||||||
|
.Include(c => c.Rd)
|
||||||
|
.Include(c => c.Kg.Gl)
|
||||||
|
.ToListAsync();
|
||||||
|
var wbKgs = members
|
||||||
|
.Where(m => m.DefaultWbKg != null)
|
||||||
|
.Select(m => m.DefaultWbKg!)
|
||||||
|
.Union(areaComs.Select(c => c.Kg))
|
||||||
|
.Distinct()
|
||||||
|
.OrderBy(k => k.KgNr)
|
||||||
|
.ToList();
|
||||||
|
if (members.Count == 0) {
|
||||||
|
MessageBox.Show("Es wurden keine Mitglieder zum Hochladen ausgewählt!", "Mitglieder hochladen",
|
||||||
|
MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
|
} else {
|
||||||
|
await ElwigData.Export(path, members, areaComs, wbKgs, filterNames);
|
||||||
|
await Utils.UploadExportData(path, App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
|
||||||
|
MessageBox.Show($"Hochladen von {members.Count:N0} Mitgliedern erfolgreich!", "Mitglieder hochgeladen",
|
||||||
|
MessageBoxButton.OK, MessageBoxImage.Information);
|
||||||
|
}
|
||||||
|
} catch (HttpRequestException exc) {
|
||||||
|
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Mitglieder hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
|
} catch (TaskCanceledException exc) {
|
||||||
|
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Mitglieder hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
|
} catch (Exception exc) {
|
||||||
|
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
Mouse.OverrideCursor = null;
|
Mouse.OverrideCursor = null;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,277 +0,0 @@
|
|||||||
using Elwig.Helpers;
|
|
||||||
using Elwig.Helpers.Export;
|
|
||||||
using Elwig.Models.Entities;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Linq.Expressions;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows;
|
|
||||||
|
|
||||||
namespace Elwig.Services {
|
|
||||||
public static class SyncService {
|
|
||||||
|
|
||||||
public static readonly Expression<Func<Member, bool>> ChangedMembers = (m) => ((m.XTime == null && m.MTime > 1751328000) || m.MTime > m.XTime) && (m.ITime == null || m.MTime > m.ITime);
|
|
||||||
public static readonly Expression<Func<Delivery, bool>> ChangedDeliveries = (d) => ((d.XTime == null && d.MTime > 1751328000) || d.MTime > d.XTime) && (d.ITime == null || d.MTime > d.ITime);
|
|
||||||
|
|
||||||
public static async Task Upload(string url, string username, string password, IQueryable<Member> query, IEnumerable<string> filterNames) {
|
|
||||||
try {
|
|
||||||
var filename = $"{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{App.ZwstId}.elwig.zip";
|
|
||||||
var path = Path.Combine(App.TempPath, filename);
|
|
||||||
var members = await query
|
|
||||||
.OrderBy(m => m.MgNr)
|
|
||||||
.Include(m => m.BillingAddress)
|
|
||||||
.Include(m => m.TelephoneNumbers)
|
|
||||||
.Include(m => m.EmailAddresses)
|
|
||||||
.Include(m => m.DefaultWbKg!.Gl)
|
|
||||||
.AsSplitQuery()
|
|
||||||
.ToListAsync();
|
|
||||||
var areaComs = await query
|
|
||||||
.SelectMany(m => m.AreaCommitments)
|
|
||||||
.OrderBy(c => c.MgNr).ThenBy(c => c.FbNr)
|
|
||||||
.Include(c => c.Rd)
|
|
||||||
.Include(c => c.Kg.Gl)
|
|
||||||
.ToListAsync();
|
|
||||||
var wbKgs = members
|
|
||||||
.Where(m => m.DefaultWbKg != null)
|
|
||||||
.Select(m => m.DefaultWbKg!)
|
|
||||||
.Union(areaComs.Select(c => c.Kg))
|
|
||||||
.Distinct()
|
|
||||||
.OrderBy(k => k.KgNr)
|
|
||||||
.ToList();
|
|
||||||
if (members.Count == 0) {
|
|
||||||
MessageBox.Show("Es wurden keine Mitglieder zum Hochladen ausgewählt!", "Mitglieder hochladen",
|
|
||||||
MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
} else {
|
|
||||||
var exportedAt = DateTime.Now;
|
|
||||||
await ElwigData.Export(path, members, areaComs, wbKgs, filterNames);
|
|
||||||
await Utils.UploadExportData(path, url, username, password);
|
|
||||||
await UpdateExportedAt(members, [], exportedAt);
|
|
||||||
MessageBox.Show($"Hochladen von {members.Count:N0} Mitgliedern erfolgreich!", "Mitglieder hochgeladen",
|
|
||||||
MessageBoxButton.OK, MessageBoxImage.Information);
|
|
||||||
}
|
|
||||||
} catch (HttpRequestException exc) {
|
|
||||||
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Mitglieder hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
} catch (TaskCanceledException exc) {
|
|
||||||
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Mitglieder hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
} catch (Exception exc) {
|
|
||||||
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task Upload(string url, string username, string password, IQueryable<DeliveryPart> query, IEnumerable<string> filterNames) {
|
|
||||||
try {
|
|
||||||
var filename = $"{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{App.ZwstId}.elwig.zip";
|
|
||||||
var path = Path.Combine(App.TempPath, filename);
|
|
||||||
var list = await query
|
|
||||||
.Select(p => p.Delivery)
|
|
||||||
.Distinct()
|
|
||||||
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers).ThenInclude(m => m.Modifier)
|
|
||||||
.Include(d => d.Parts).ThenInclude(p => p.Rd)
|
|
||||||
.Include(d => d.Parts).ThenInclude(p => p.Kg!.Gl)
|
|
||||||
.AsSplitQuery()
|
|
||||||
.ToListAsync();
|
|
||||||
var wbKgs = list
|
|
||||||
.SelectMany(d => d.Parts)
|
|
||||||
.Where(p => p.Kg != null)
|
|
||||||
.Select(p => p.Kg!)
|
|
||||||
.DistinctBy(k => k.KgNr)
|
|
||||||
.OrderBy(k => k.KgNr)
|
|
||||||
.ToList();
|
|
||||||
if (list.Count == 0) {
|
|
||||||
MessageBox.Show("Es wurden keine Lieferungen zum Hochladen ausgewählt!", "Lieferungen hochladen",
|
|
||||||
MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
} else {
|
|
||||||
var exportedAt = DateTime.Now;
|
|
||||||
await ElwigData.Export(path, list, wbKgs, filterNames);
|
|
||||||
await Utils.UploadExportData(path, url, username, password);
|
|
||||||
await UpdateExportedAt([], list, exportedAt);
|
|
||||||
MessageBox.Show($"Hochladen von {list.Count:N0} Lieferungen erfolgreich!", "Lieferungen hochgeladen",
|
|
||||||
MessageBoxButton.OK, MessageBoxImage.Information);
|
|
||||||
}
|
|
||||||
} catch (HttpRequestException exc) {
|
|
||||||
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Lieferungen hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
} catch (TaskCanceledException exc) {
|
|
||||||
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
} catch (Exception exc) {
|
|
||||||
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task UploadModified(string url, string username, string password) {
|
|
||||||
try {
|
|
||||||
var path = Path.Combine(App.TempPath, $"{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{App.ZwstId}.elwig.zip");
|
|
||||||
List<Member> members;
|
|
||||||
List<AreaCom> areaComs;
|
|
||||||
List<Delivery> deliveries;
|
|
||||||
using (var ctx = new AppDbContext()) {
|
|
||||||
members = await ctx.Members
|
|
||||||
.Where(ChangedMembers)
|
|
||||||
.Include(m => m.BillingAddress)
|
|
||||||
.Include(m => m.TelephoneNumbers)
|
|
||||||
.Include(m => m.EmailAddresses)
|
|
||||||
.Include(m => m.DefaultWbKg!.Gl)
|
|
||||||
.OrderBy(m => m.MgNr)
|
|
||||||
.AsSplitQuery()
|
|
||||||
.ToListAsync();
|
|
||||||
areaComs = await ctx.Members
|
|
||||||
.Where(ChangedMembers)
|
|
||||||
.SelectMany(m => m.AreaCommitments)
|
|
||||||
.Include(c => c.Rd)
|
|
||||||
.Include(c => c.Kg.Gl)
|
|
||||||
.OrderBy(c => c.MgNr).ThenBy(c => c.FbNr)
|
|
||||||
.ToListAsync();
|
|
||||||
deliveries = await ctx.Deliveries
|
|
||||||
.Where(ChangedDeliveries)
|
|
||||||
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers).ThenInclude(m => m.Modifier)
|
|
||||||
.Include(d => d.Parts).ThenInclude(p => p.Rd)
|
|
||||||
.Include(d => d.Parts).ThenInclude(p => p.Kg).ThenInclude(k => k!.Gl)
|
|
||||||
.OrderBy(d => d.DateString).ThenBy(d => d.TimeString).ThenBy(d => d.LsNr)
|
|
||||||
.AsSplitQuery()
|
|
||||||
.ToListAsync();
|
|
||||||
}
|
|
||||||
var wbKgs = members
|
|
||||||
.Where(m => m.DefaultWbKg != null)
|
|
||||||
.Select(m => m.DefaultWbKg!)
|
|
||||||
.Union(areaComs.Select(c => c.Kg))
|
|
||||||
.Union(deliveries.SelectMany(d => d.Parts)
|
|
||||||
.Where(p => p.Kg != null)
|
|
||||||
.Select(p => p.Kg!))
|
|
||||||
.DistinctBy(k => k.KgNr)
|
|
||||||
.OrderBy(k => k.KgNr)
|
|
||||||
.ToList();
|
|
||||||
if (members.Count == 0 && deliveries.Count == 0) {
|
|
||||||
MessageBox.Show("Es gibt keine geänderten Mitglieder oder Lieferungen, die hochgeladen werden könnten!", "Mitglieder und Lieferungen hochladen",
|
|
||||||
MessageBoxButton.OK, MessageBoxImage.Information);
|
|
||||||
} else {
|
|
||||||
var exportedAt = DateTime.Now;
|
|
||||||
await (new ElwigData.ElwigExport {
|
|
||||||
Members = (members, ["geändert seit letztem Export"]),
|
|
||||||
AreaComs = (areaComs, ["von exportierten Mitgliedern"]),
|
|
||||||
Deliveries = (deliveries, ["geändert seit letzem Export"]),
|
|
||||||
WbKgs = (wbKgs, ["von exportierten Mitgliedern, Flächenbindungen und Lieferungen"]),
|
|
||||||
}).Export(path);
|
|
||||||
await Utils.UploadExportData(path, url, username, password);
|
|
||||||
await UpdateExportedAt(members, deliveries, exportedAt);
|
|
||||||
MessageBox.Show($"Hochladen von {members.Count:N0} Mitgliedern und {deliveries.Count:N0} Lieferungen erfolgreich!", "Mitglieder und Lieferungen hochladen",
|
|
||||||
MessageBoxButton.OK, MessageBoxImage.Information);
|
|
||||||
}
|
|
||||||
} catch (HttpRequestException exc) {
|
|
||||||
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Mitglieder und Lieferungen hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
} catch (TaskCanceledException exc) {
|
|
||||||
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Mitglieder und Lieferungen hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
} catch (Exception exc) {
|
|
||||||
MessageBox.Show(exc.Message, "Mitglieder und Lieferungen hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task UploadBranchDeliveries(string url, string username, string password, int? year = null) {
|
|
||||||
try {
|
|
||||||
year ??= Utils.CurrentLastSeason;
|
|
||||||
var path = Path.Combine(App.TempPath, $"{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{App.ZwstId}.elwig.zip");
|
|
||||||
using var ctx = new AppDbContext();
|
|
||||||
var deliveries = await ctx.Deliveries
|
|
||||||
.Where(d => d.Year == year && d.ZwstId == App.ZwstId)
|
|
||||||
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers).ThenInclude(m => m.Modifier)
|
|
||||||
.Include(d => d.Parts).ThenInclude(p => p.Rd)
|
|
||||||
.Include(d => d.Parts).ThenInclude(p => p.Kg).ThenInclude(k => k!.Gl)
|
|
||||||
.OrderBy(d => d.DateString).ThenBy(d => d.TimeString).ThenBy(d => d.LsNr)
|
|
||||||
.AsSplitQuery()
|
|
||||||
.ToListAsync();
|
|
||||||
var wbKgs = deliveries
|
|
||||||
.SelectMany(d => d.Parts)
|
|
||||||
.Where(p => p.Kg != null)
|
|
||||||
.Select(p => p.Kg!)
|
|
||||||
.DistinctBy(k => k.KgNr)
|
|
||||||
.ToList();
|
|
||||||
if (deliveries.Count == 0) {
|
|
||||||
MessageBox.Show("Es gibt keine Lieferungen, die hochgeladen werden können!", "Lieferungen hochladen",
|
|
||||||
MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
} else {
|
|
||||||
var exportedAt = DateTime.Now;
|
|
||||||
await ElwigData.Export(path, deliveries, wbKgs, [$"{year}", $"Zweigstelle {App.BranchName}"]);
|
|
||||||
await Utils.UploadExportData(path, url, username, password);
|
|
||||||
await UpdateExportedAt([], deliveries, exportedAt);
|
|
||||||
MessageBox.Show($"Hochladen von {deliveries.Count:N0} Lieferungen erfolgreich!", "Lieferungen hochladen",
|
|
||||||
MessageBoxButton.OK, MessageBoxImage.Information);
|
|
||||||
}
|
|
||||||
} catch (HttpRequestException exc) {
|
|
||||||
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Lieferungen hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
} catch (TaskCanceledException exc) {
|
|
||||||
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Lieferungen hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
} catch (Exception exc) {
|
|
||||||
MessageBox.Show(exc.Message, "Lieferungen hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task<List<(string Name, string Url)>> GetFilesToImport(string url, string username, string password) {
|
|
||||||
var data = await Utils.GetExportMetaData(url, username, password);
|
|
||||||
var files = data
|
|
||||||
.Select(f => new {
|
|
||||||
Name = f!["name"]!.AsValue().GetValue<string>(),
|
|
||||||
Timestamp = f!["timestamp"] != null && DateTime.TryParseExact(f!["timestamp"]!.AsValue().GetValue<string>(), "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None, out var dt) ? dt : (DateTime?)null,
|
|
||||||
ZwstId = f!["meta"]?["zwstid"]?.AsValue().GetValue<string>() ?? f!["zwstid"]?.AsValue().GetValue<string>(),
|
|
||||||
Device = f!["meta"]?["device"]?.AsValue().GetValue<string>(),
|
|
||||||
Url = f!["url"]!.AsValue().GetValue<string>(),
|
|
||||||
Size = f!["size"]!.AsValue().GetValue<long>(),
|
|
||||||
})
|
|
||||||
.Where(f => f.Timestamp >= new DateTime(Utils.CurrentLastSeason, 7, 1))
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
var imported = await ElwigData.GetImportedFiles();
|
|
||||||
return [.. files
|
|
||||||
.Where(f => f.Device != Environment.MachineName && !imported.Contains(f.Name))
|
|
||||||
.Select(f => (f.Name, f.Url))
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task Download(string url, string username, string password) {
|
|
||||||
try {
|
|
||||||
var import = await GetFilesToImport(url, username, password);
|
|
||||||
var paths = new List<string>();
|
|
||||||
using (var client = Utils.GetHttpClient(username, password)) {
|
|
||||||
foreach (var f in import) {
|
|
||||||
var filename = Path.Combine(App.TempPath, f.Name);
|
|
||||||
using var stream = new FileStream(filename, FileMode.Create);
|
|
||||||
await client.DownloadAsync(f.Url, stream);
|
|
||||||
paths.Add(filename);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await ElwigData.Import(paths, ElwigData.ImportMode.FromBranches);
|
|
||||||
} catch (HttpRequestException exc) {
|
|
||||||
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Daten herunterladen", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
} catch (TaskCanceledException exc) {
|
|
||||||
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Daten herunterladen", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
} catch (Exception exc) {
|
|
||||||
MessageBox.Show(exc.Message, "Daten herunterladen", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async Task UpdateExportedAt(IEnumerable<Member> member, IEnumerable<Delivery> deliveries, DateTime dateTime) {
|
|
||||||
var timestamp = ((DateTimeOffset)dateTime.ToUniversalTime()).ToUnixTimeSeconds();
|
|
||||||
var mgnrs = string.Join(",", member.Select(m => $"{m.MgNr}").Append("0"));
|
|
||||||
var dids = string.Join(",", deliveries.Select(d => $"({d.Year},{d.DId})").Append("(0,0)"));
|
|
||||||
using (var cnx = await AppDbContext.ConnectAsync()) {
|
|
||||||
await cnx.ExecuteBatch($"""
|
|
||||||
BEGIN;
|
|
||||||
UPDATE client_parameter SET value = '0' WHERE param = 'ENABLE_TIME_TRIGGERS';
|
|
||||||
UPDATE member SET xtime = {timestamp} WHERE mgnr IN ({mgnrs});
|
|
||||||
UPDATE area_commitment SET xtime = {timestamp} WHERE mgnr IN ({mgnrs});
|
|
||||||
UPDATE delivery SET xtime = {timestamp} WHERE (year, did) IN ({dids});
|
|
||||||
UPDATE delivery_part SET xtime = {timestamp} WHERE (year, did) IN ({dids});
|
|
||||||
UPDATE client_parameter SET value = '1' WHERE param = 'ENABLE_TIME_TRIGGERS';
|
|
||||||
COMMIT;
|
|
||||||
""");
|
|
||||||
}
|
|
||||||
App.HintContextChange();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task<bool> ChangesAvailable(AppDbContext ctx, string url, string username, string password) {
|
|
||||||
return await ctx.Members.AnyAsync(ChangedMembers) || await ctx.Deliveries.AnyAsync(ChangedDeliveries) || (Utils.HasInternetConnectivity() && (await GetFilesToImport(url, username, password)).Count > 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -169,28 +169,10 @@ namespace Elwig.ViewModels {
|
|||||||
set => AcidString = $"{value:0.0}";
|
set => AcidString = $"{value:0.0}";
|
||||||
}
|
}
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
|
private bool _isLesewagen;
|
||||||
|
[ObservableProperty]
|
||||||
private bool? _isHandPicked;
|
private bool? _isHandPicked;
|
||||||
|
|
||||||
public string? Unloading {
|
|
||||||
get => IsUnloadingDumper ? DeliveryPart.Dumper : IsUnloadingPumped ? DeliveryPart.Pumped : IsUnloadingBox ? DeliveryPart.Box : null;
|
|
||||||
set {
|
|
||||||
switch (value) {
|
|
||||||
case DeliveryPart.Dumper: IsUnloadingDumper = true; break;
|
|
||||||
case DeliveryPart.Pumped: IsUnloadingPumped = true; break;
|
|
||||||
case DeliveryPart.Box: IsUnloadingBox = true; break;
|
|
||||||
default: IsUnloadingOther = true; break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
[ObservableProperty]
|
|
||||||
private bool _isUnloadingDumper;
|
|
||||||
[ObservableProperty]
|
|
||||||
private bool _isUnloadingPumped;
|
|
||||||
[ObservableProperty]
|
|
||||||
private bool _isUnloadingBox;
|
|
||||||
[ObservableProperty]
|
|
||||||
private bool _isUnloadingOther;
|
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private string _statusMembers = "-";
|
private string _statusMembers = "-";
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
<Window x:Class="Elwig.Windows.AboutWindow"
|
|
||||||
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.Windows"
|
|
||||||
Title="Über - Elwig" Height="340" Width="460" ResizeMode="NoResize">
|
|
||||||
<Grid>
|
|
||||||
<TextBlock Margin="20,10" FontSize="12">
|
|
||||||
<Bold>Produkt:</Bold> Elwig<LineBreak/>
|
|
||||||
<Bold>Beschreibung:</Bold> Elektronische Winzergenossenschaftsverwaltung<LineBreak/>
|
|
||||||
<Bold>Typ:</Bold> Warenwirtschaftssystem (ERP-System)<LineBreak/>
|
|
||||||
<Bold>Version:</Bold> <Run x:Name="Version">0.0.0.0</Run> (<Hyperlink NavigateUri="https://elwig.at/changelog" RequestNavigate="Hyperlink_RequestNavigate">Änderungsprotokoll</Hyperlink>)<LineBreak/>
|
|
||||||
<Bold>Lizenz:</Bold> <Hyperlink NavigateUri="https://www.gnu.org/licenses/gpl-3.0.html" RequestNavigate="Hyperlink_RequestNavigate">GNU General Public License 3.0 (GPLv3)</Hyperlink><LineBreak/>
|
|
||||||
<Bold>Website:</Bold> <Hyperlink NavigateUri="https://elwig.at/" RequestNavigate="Hyperlink_RequestNavigate">https://elwig.at/</Hyperlink><LineBreak/>
|
|
||||||
<Bold>Entwickler:</Bold> Lorenz Stechauner, Thomas Hilscher<LineBreak/>
|
|
||||||
<Bold>Kontakt:</Bold> <Hyperlink NavigateUri="mailto:lorenz.stechauner@necronda.net" RequestNavigate="Hyperlink_RequestNavigate">lorenz.stechauner@necronda.net</Hyperlink>, <Hyperlink NavigateUri="mailto:thomas.hilscher@gmail.com" RequestNavigate="Hyperlink_RequestNavigate">thomas.hilscher@gmail.com</Hyperlink><LineBreak/>
|
|
||||||
<Bold>Quellcode:</Bold> <Hyperlink NavigateUri="https://git.necronda.net/winzer/elwig" RequestNavigate="Hyperlink_RequestNavigate">https://git.necronda.net/winzer/elwig</Hyperlink><LineBreak/>
|
|
||||||
<Bold>Entwicklungszeitraum:</Bold> 2022–2025<LineBreak/>
|
|
||||||
<LineBreak/>
|
|
||||||
<Bold>Verwendete Technologien:</Bold><LineBreak/>
|
|
||||||
Programmiersprache: C#<LineBreak/>
|
|
||||||
Framework: Windows Presentation Framework (WPF)<LineBreak/>
|
|
||||||
Datenbank: <Hyperlink NavigateUri="https://sqlite.org/" RequestNavigate="Hyperlink_RequestNavigate">SQLite</Hyperlink><LineBreak/>
|
|
||||||
PDF-Erstellung: <Hyperlink NavigateUri="https://weasyprint.org/" RequestNavigate="Hyperlink_RequestNavigate">WeasyPrint</Hyperlink>, <Hyperlink NavigateUri="https://github.com/toddams/RazorLight" RequestNavigate="Hyperlink_RequestNavigate">RazorLight</Hyperlink>, <Hyperlink NavigateUri="https://github.com/pvginkel/PdfiumViewer" RequestNavigate="Hyperlink_RequestNavigate">PdfiumViewer</Hyperlink><LineBreak/>
|
|
||||||
Paketierung: <Hyperlink NavigateUri="https://www.firegiant.com/wixtoolset/" RequestNavigate="Hyperlink_RequestNavigate">WiX Toolset</Hyperlink>
|
|
||||||
</TextBlock>
|
|
||||||
|
|
||||||
<Image Source="\Resources\Images\Elwig.png" RenderOptions.BitmapScalingMode="HighQuality" Height="64"
|
|
||||||
HorizontalAlignment="Right" Margin="10" VerticalAlignment="Top"/>
|
|
||||||
</Grid>
|
|
||||||
</Window>
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
using System.Diagnostics;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Navigation;
|
|
||||||
|
|
||||||
namespace Elwig.Windows {
|
|
||||||
public partial class AboutWindow : Window {
|
|
||||||
|
|
||||||
public AboutWindow() {
|
|
||||||
InitializeComponent();
|
|
||||||
Version.Text = App.Version.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e) {
|
|
||||||
Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri) { UseShellExecute = true });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -13,8 +13,8 @@ using System.Windows.Input;
|
|||||||
namespace Elwig.Windows {
|
namespace Elwig.Windows {
|
||||||
public abstract class AdministrationWindow : ContextWindow {
|
public abstract class AdministrationWindow : ContextWindow {
|
||||||
|
|
||||||
protected Control[] ExemptInputs { get; set; }
|
protected Control[] ExemptInputs { private get; set; }
|
||||||
protected Control[] RequiredInputs { get; set; }
|
protected Control[] RequiredInputs { private get; set; }
|
||||||
|
|
||||||
private bool _isEditing;
|
private bool _isEditing;
|
||||||
private bool _isCreating;
|
private bool _isCreating;
|
||||||
@@ -166,10 +166,8 @@ namespace Elwig.Windows {
|
|||||||
Valid[input] = false;
|
Valid[input] = false;
|
||||||
} else if (input is ComboBox cb && cb.SelectedItem == null && cb.ItemsSource != null && cb.ItemsSource.Cast<object>().Any()) {
|
} else if (input is ComboBox cb && cb.SelectedItem == null && cb.ItemsSource != null && cb.ItemsSource.Cast<object>().Any()) {
|
||||||
ControlUtils.SetInputInvalid(input);
|
ControlUtils.SetInputInvalid(input);
|
||||||
Valid[input] = false;
|
|
||||||
} else if (input is ListBox lb && lb.SelectedItem == null && lb.ItemsSource != null && lb.ItemsSource.Cast<object>().Any()) {
|
} else if (input is ListBox lb && lb.SelectedItem == null && lb.ItemsSource != null && lb.ItemsSource.Cast<object>().Any()) {
|
||||||
ControlUtils.SetInputInvalid(input);
|
ControlUtils.SetInputInvalid(input);
|
||||||
Valid[input] = false;
|
|
||||||
} else if (input is CheckBox ckb && ((ckb.IsThreeState && ckb.IsChecked == null) || (!ckb.IsThreeState && ckb.IsChecked != true))) {
|
} else if (input is CheckBox ckb && ((ckb.IsThreeState && ckb.IsChecked == null) || (!ckb.IsThreeState && ckb.IsChecked != true))) {
|
||||||
ControlUtils.SetInputInvalid(input);
|
ControlUtils.SetInputInvalid(input);
|
||||||
Valid[input] = false;
|
Valid[input] = false;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
xmlns:local="clr-namespace:Elwig.Windows"
|
xmlns:local="clr-namespace:Elwig.Windows"
|
||||||
xmlns:ctrl="clr-namespace:Elwig.Controls"
|
xmlns:ctrl="clr-namespace:Elwig.Controls"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
Title="Stammdaten - Elwig" Height="520" MinHeight="400" Width="860" MinWidth="810"
|
Title="Stammdaten - Elwig" Height="500" MinHeight="400" Width="850" MinWidth="810"
|
||||||
Loaded="Window_Loaded">
|
Loaded="Window_Loaded">
|
||||||
<Window.Resources>
|
<Window.Resources>
|
||||||
<Style TargetType="Label">
|
<Style TargetType="Label">
|
||||||
@@ -532,10 +532,6 @@
|
|||||||
<CheckBox x:Name="SeasonModifierActiveInput" Content="In Übernahme-Fenster anzeigen"
|
<CheckBox x:Name="SeasonModifierActiveInput" Content="In Übernahme-Fenster anzeigen"
|
||||||
Grid.Column="1" Grid.ColumnSpan="2" Margin="10,134,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"
|
Grid.Column="1" Grid.ColumnSpan="2" Margin="10,134,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"
|
||||||
Checked="SeasonModifier_Changed" Unchecked="SeasonModifier_Changed"/>
|
Checked="SeasonModifier_Changed" Unchecked="SeasonModifier_Changed"/>
|
||||||
|
|
||||||
<CheckBox x:Name="SeasonModifierRedactedInput" Content="Wert auf Lieferschein verbergen"
|
|
||||||
Grid.Column="1" Grid.ColumnSpan="2" Margin="10,154,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"
|
|
||||||
Checked="SeasonModifier_Changed" Unchecked="SeasonModifier_Changed"/>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</GroupBox>
|
</GroupBox>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||
@@ -135,14 +135,12 @@ namespace Elwig.Windows {
|
|||||||
SeasonModifierRelInput.Text = "";
|
SeasonModifierRelInput.Text = "";
|
||||||
SeasonModifierAbsInput.Text = "";
|
SeasonModifierAbsInput.Text = "";
|
||||||
SeasonModifierActiveInput.IsChecked = false;
|
SeasonModifierActiveInput.IsChecked = false;
|
||||||
SeasonModifierRedactedInput.IsChecked = false;
|
|
||||||
} else {
|
} else {
|
||||||
SeasonModifierIdInput.Text = mod.ModId;
|
SeasonModifierIdInput.Text = mod.ModId;
|
||||||
SeasonModifierNameInput.Text = mod.Name;
|
SeasonModifierNameInput.Text = mod.Name;
|
||||||
SeasonModifierRelInput.Text = (mod.Rel * 100)?.ToString() ?? "";
|
SeasonModifierRelInput.Text = (mod.Rel * 100)?.ToString() ?? "";
|
||||||
SeasonModifierAbsInput.Text = mod.Abs?.ToString() ?? "";
|
SeasonModifierAbsInput.Text = mod.Abs?.ToString() ?? "";
|
||||||
SeasonModifierActiveInput.IsChecked = mod.IsActive;
|
SeasonModifierActiveInput.IsChecked = mod.IsActive;
|
||||||
SeasonModifierRedactedInput.IsChecked = mod.IsRedacted;
|
|
||||||
}
|
}
|
||||||
_modUpdate = false;
|
_modUpdate = false;
|
||||||
}
|
}
|
||||||
@@ -159,7 +157,6 @@ namespace Elwig.Windows {
|
|||||||
mod.Rel = decimal.TryParse(SeasonModifierRelInput.Text, out var vRel) ? vRel / 100 : null;
|
mod.Rel = decimal.TryParse(SeasonModifierRelInput.Text, out var vRel) ? vRel / 100 : null;
|
||||||
mod.AbsValue = decimal.TryParse(SeasonModifierAbsInput.Text, out var vAbs) ? Utils.DecToDb(vAbs, s.Precision) : null;
|
mod.AbsValue = decimal.TryParse(SeasonModifierAbsInput.Text, out var vAbs) ? Utils.DecToDb(vAbs, s.Precision) : null;
|
||||||
mod.IsActive = SeasonModifierActiveInput.IsChecked ?? false;
|
mod.IsActive = SeasonModifierActiveInput.IsChecked ?? false;
|
||||||
mod.IsRedacted = SeasonModifierRedactedInput.IsChecked ?? false;
|
|
||||||
|
|
||||||
CollectionViewSource.GetDefaultView(_modList).Refresh();
|
CollectionViewSource.GetDefaultView(_modList).Refresh();
|
||||||
UpdateButtons();
|
UpdateButtons();
|
||||||
|
|||||||
@@ -664,10 +664,8 @@ namespace Elwig.Windows {
|
|||||||
try {
|
try {
|
||||||
await Task.Run(async () => {
|
await Task.Run(async () => {
|
||||||
var b = new BillingVariant(PaymentVar.Year, PaymentVar.AvNr);
|
var b = new BillingVariant(PaymentVar.Year, PaymentVar.AvNr);
|
||||||
await b.Calculate(false);
|
await b.Calculate();
|
||||||
});
|
});
|
||||||
} catch (KeyNotFoundException exc) {
|
|
||||||
MessageBox.Show(exc.Message, "Noch nicht alle Preise festgelegt", MessageBoxButton.OK, MessageBoxImage.Information);
|
|
||||||
} catch (Exception exc) {
|
} catch (Exception exc) {
|
||||||
MessageBox.Show(exc.Message, "Berechnungsfehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
MessageBox.Show(exc.Message, "Berechnungsfehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -129,10 +129,6 @@
|
|||||||
<MenuItem x:Name="Menu_DeliveryDepreciationList_PrintSeason" Header="...von Saison drucken"
|
<MenuItem x:Name="Menu_DeliveryDepreciationList_PrintSeason" Header="...von Saison drucken"
|
||||||
Click="Menu_DeliveryDepreciationList_PrintSeason_Click"/>
|
Click="Menu_DeliveryDepreciationList_PrintSeason_Click"/>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="Liefermengen" x:Name="Menu_DeliveryDataList">
|
|
||||||
<MenuItem x:Name="Menu_DeliveryDataList_SaveFilters" Header="...aus Filtern speichern... (Excel)"
|
|
||||||
Click="Menu_DeliveryDataList_SaveFilters_Click"/>
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem Header="Statistik" x:Name="Menu_Statistics">
|
<MenuItem Header="Statistik" x:Name="Menu_Statistics">
|
||||||
<MenuItem Header="Qualitätsstatistik..." x:Name="Menu_Statistics_WineQuality">
|
<MenuItem Header="Qualitätsstatistik..." x:Name="Menu_Statistics_WineQuality">
|
||||||
<MenuItem x:Name="Menu_Statistics_WineQuality_ShowFilters" Header="...aus Filtern anzeigen (PDF)"
|
<MenuItem x:Name="Menu_Statistics_WineQuality_ShowFilters" Header="...aus Filtern anzeigen (PDF)"
|
||||||
@@ -226,7 +222,6 @@
|
|||||||
<Bold>Uhrzeit</Bold>: z.B. 06:00-08:00, 18:00-, ...<LineBreak/>
|
<Bold>Uhrzeit</Bold>: z.B. 06:00-08:00, 18:00-, ...<LineBreak/>
|
||||||
<Bold>Handwiegung</Bold>: handw[iegung], !Handw[iegung] (alle ohne Handwiegung)<LineBreak/>
|
<Bold>Handwiegung</Bold>: handw[iegung], !Handw[iegung] (alle ohne Handwiegung)<LineBreak/>
|
||||||
<Bold>Handlese</Bold>: Handl[ese], !handl[ese] (alle ohne Handlese)<LineBreak/>
|
<Bold>Handlese</Bold>: Handl[ese], !handl[ese] (alle ohne Handlese)<LineBreak/>
|
||||||
<Bold>Anlieferung</Bold>: Plane[nwagen]/Kipp[er], !plane[nwagen]/!kipp[er], Lesew[agen], !lesew[agen], kiste[n], !kiste[n]<LineBreak/>
|
|
||||||
<Bold>Gebunden</Bold>: geb[unden], ungeb[unden], !geb[unden], !ungeb[unden]<LineBreak/>
|
<Bold>Gebunden</Bold>: geb[unden], ungeb[unden], !geb[unden], !ungeb[unden]<LineBreak/>
|
||||||
<Bold>Gerebelt</Bold>: gerebelt, !Gerebelt (nicht gerebelt gewogen)<LineBreak/>
|
<Bold>Gerebelt</Bold>: gerebelt, !Gerebelt (nicht gerebelt gewogen)<LineBreak/>
|
||||||
<Bold>Freitext</Bold>: z.B. Lieferscheinnummern, Anmerkung, "quw" (sucht nach dem Text "quw")
|
<Bold>Freitext</Bold>: z.B. Lieferscheinnummern, Anmerkung, "quw" (sucht nach dem Text "quw")
|
||||||
@@ -270,18 +265,13 @@
|
|||||||
</Style>
|
</Style>
|
||||||
</DataGridTextColumn.CellStyle>
|
</DataGridTextColumn.CellStyle>
|
||||||
</DataGridTextColumn>
|
</DataGridTextColumn>
|
||||||
<DataGridTextColumn Header="Sorte" Binding="{Binding FilteredVaributeString}" Width="60">
|
<DataGridTextColumn Header="Sorte" Binding="{Binding FilteredSortIdString}" Width="50">
|
||||||
<DataGridTextColumn.CellStyle>
|
<DataGridTextColumn.CellStyle>
|
||||||
<Style>
|
<Style>
|
||||||
<Setter Property="TextBlock.Foreground" Value="{Binding FilteredColor}"/>
|
<Setter Property="TextBlock.Foreground" Value="{Binding FilteredColor}"/>
|
||||||
<Setter Property="TextBlock.TextAlignment" Value="Center"/>
|
<Setter Property="TextBlock.TextAlignment" Value="Center"/>
|
||||||
</Style>
|
</Style>
|
||||||
</DataGridTextColumn.CellStyle>
|
</DataGridTextColumn.CellStyle>
|
||||||
<DataGridTextColumn.ElementStyle>
|
|
||||||
<Style TargetType="TextBlock">
|
|
||||||
<Setter Property="TextTrimming" Value="CharacterEllipsis"/>
|
|
||||||
</Style>
|
|
||||||
</DataGridTextColumn.ElementStyle>
|
|
||||||
</DataGridTextColumn>
|
</DataGridTextColumn>
|
||||||
<DataGridTextColumn Header="Menge" Binding="{Binding FilteredWeight, StringFormat='{}{0:N0} kg '}" Width="75">
|
<DataGridTextColumn Header="Menge" Binding="{Binding FilteredWeight, StringFormat='{}{0:N0} kg '}" Width="75">
|
||||||
<DataGridTextColumn.CellStyle>
|
<DataGridTextColumn.CellStyle>
|
||||||
@@ -300,7 +290,6 @@
|
|||||||
<DataGridTextColumn Header="LsNr." Binding="{Binding LsNr}" Width="120"/>
|
<DataGridTextColumn Header="LsNr." Binding="{Binding LsNr}" Width="120"/>
|
||||||
<DataGridTextColumn Header="Mitglied" Binding="{Binding Member.AdministrativeName}" Width="180"/>
|
<DataGridTextColumn Header="Mitglied" Binding="{Binding Member.AdministrativeName}" Width="180"/>
|
||||||
<DataGridTextColumn Header="Zu-/Abschläge" Binding="{Binding FilteredModifiersString}" Width="150"/>
|
<DataGridTextColumn Header="Zu-/Abschläge" Binding="{Binding FilteredModifiersString}" Width="150"/>
|
||||||
<DataGridTextColumn Header="Kommentar" Binding="{Binding CommentsString}" Width="150"/>
|
|
||||||
</DataGrid.Columns>
|
</DataGrid.Columns>
|
||||||
</DataGrid>
|
</DataGrid>
|
||||||
|
|
||||||
@@ -374,9 +363,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="*"/>
|
||||||
<RowDefinition Height="0.875*"/>
|
<RowDefinition Height="*"/>
|
||||||
<RowDefinition Height="0.25*"/>
|
|
||||||
<RowDefinition Height="*"/>
|
<RowDefinition Height="*"/>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
@@ -410,7 +398,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="2" Margin="5,5,5,5">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="100"/>
|
<ColumnDefinition Width="100"/>
|
||||||
@@ -569,7 +557,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="3" Margin="5,5,5,10">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="100"/>
|
<ColumnDefinition Width="100"/>
|
||||||
@@ -598,31 +586,18 @@
|
|||||||
TextChanged="TemperatureAcidInput_TextChanged" LostFocus="TemperatureAcidInput_LostFocus"
|
TextChanged="TemperatureAcidInput_TextChanged" LostFocus="TemperatureAcidInput_LostFocus"
|
||||||
Grid.Column="1" Margin="0,100,10,10" VerticalAlignment="Top"/>
|
Grid.Column="1" Margin="0,100,10,10" VerticalAlignment="Top"/>
|
||||||
|
|
||||||
|
<CheckBox x:Name="LesewagenInput" IsChecked="{Binding IsLesewagen, Mode=TwoWay}"
|
||||||
|
Content="Lesewagen" Margin="10,75,0,0" Grid.Column="2"
|
||||||
|
VerticalAlignment="Top" HorizontalAlignment="Left"
|
||||||
|
Checked="LesewagenInput_Changed" Unchecked="LesewagenInput_Changed"/>
|
||||||
<CheckBox x:Name="HandPickedInput" IsChecked="{Binding IsHandPicked, Mode=TwoWay}"
|
<CheckBox x:Name="HandPickedInput" IsChecked="{Binding IsHandPicked, Mode=TwoWay}"
|
||||||
Content="Handlese" Margin="10,135,10,0" Grid.Column="0" Grid.ColumnSpan="2" IsThreeState="True"
|
Content="Handlese" Margin="10,105,0,0" Grid.Column="2" IsThreeState="True"
|
||||||
VerticalAlignment="Top" HorizontalAlignment="Left"
|
VerticalAlignment="Top" HorizontalAlignment="Left"
|
||||||
Checked="HandPickedInput_Changed" Unchecked="HandPickedInput_Changed" Indeterminate="HandPickedInput_Changed"/>
|
Checked="HandPickedInput_Changed" Unchecked="HandPickedInput_Changed" Indeterminate="HandPickedInput_Changed"/>
|
||||||
|
|
||||||
<RadioButton x:Name="UnloadingDumperInput" GroupName="Unloading" IsChecked="{Binding IsUnloadingDumper, Mode=TwoWay}"
|
|
||||||
Content="Planenw./Kipper" Margin="10,75,0,0" Grid.Column="2"
|
|
||||||
VerticalAlignment="Top" HorizontalAlignment="Left"
|
|
||||||
Checked="UnloadingInput_Checked" Unchecked="UnloadingInput_Unchecked"/>
|
|
||||||
<RadioButton x:Name="UnloadingPumpedInput" GroupName="Unloading" IsChecked="{Binding IsUnloadingPumped, Mode=TwoWay}"
|
|
||||||
Content="Lesewagen" Margin="10,95,0,0" Grid.Column="2"
|
|
||||||
VerticalAlignment="Top" HorizontalAlignment="Left"
|
|
||||||
Checked="UnloadingInput_Checked" Unchecked="UnloadingInput_Unchecked"/>
|
|
||||||
<RadioButton x:Name="UnloadingBoxInput" GroupName="Unloading" IsChecked="{Binding IsUnloadingBox, Mode=TwoWay}"
|
|
||||||
Content="Kiste(n)" Margin="10,115,0,0" Grid.Column="2"
|
|
||||||
VerticalAlignment="Top" HorizontalAlignment="Left"
|
|
||||||
Checked="UnloadingInput_Checked" Unchecked="UnloadingInput_Unchecked"/>
|
|
||||||
<RadioButton x:Name="UnloadingOtherInput" GroupName="Unloading" IsChecked="{Binding IsUnloadingOther, Mode=TwoWay}"
|
|
||||||
Content="Andere/Unbek." Margin="10,135,0,0" Grid.Column="2"
|
|
||||||
VerticalAlignment="Top" HorizontalAlignment="Left"
|
|
||||||
Checked="UnloadingInput_Checked" Unchecked="UnloadingInput_Unchecked"/>
|
|
||||||
</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="3" Margin="5,5,5,10">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="100"/>
|
<ColumnDefinition Width="100"/>
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ using Elwig.ViewModels;
|
|||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
@@ -35,8 +34,6 @@ namespace Elwig.Windows {
|
|||||||
|
|
||||||
private readonly Button[] WeighingButtons;
|
private readonly Button[] WeighingButtons;
|
||||||
|
|
||||||
private List<WineQualLevel> WineQualityLevels = [];
|
|
||||||
|
|
||||||
public DeliveryAdminWindow(bool receipt = false) {
|
public DeliveryAdminWindow(bool receipt = false) {
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
CommandBindings.Add(new CommandBinding(CtrlF, FocusSearchInput));
|
CommandBindings.Add(new CommandBinding(CtrlF, FocusSearchInput));
|
||||||
@@ -92,10 +89,6 @@ namespace Elwig.Windows {
|
|||||||
foreach (var s in App.EventScales) {
|
foreach (var s in App.EventScales) {
|
||||||
s.WeighingEvent += Scale_Weighing;
|
s.WeighingEvent += Scale_Weighing;
|
||||||
}
|
}
|
||||||
if (App.Client.IsMatzen) {
|
|
||||||
RequiredInputs = [.. RequiredInputs, ModifiersInput];
|
|
||||||
}
|
|
||||||
ModifiersInput.ItemTemplate = (DataTemplate)ModifiersInput.FindResource("PublicModifierTemplate");
|
|
||||||
} else {
|
} else {
|
||||||
WeighingManualButton.Visibility = Visibility.Hidden;
|
WeighingManualButton.Visibility = Visibility.Hidden;
|
||||||
WeighingAButton.Visibility = Visibility.Hidden;
|
WeighingAButton.Visibility = Visibility.Hidden;
|
||||||
@@ -135,7 +128,7 @@ namespace Elwig.Windows {
|
|||||||
NewDeliveryButton_Click(null, null);
|
NewDeliveryButton_Click(null, null);
|
||||||
using var ctx = new AppDbContext();
|
using var ctx = new AppDbContext();
|
||||||
if (ctx.Seasons.Find(Utils.CurrentYear) == null) {
|
if (ctx.Seasons.Find(Utils.CurrentYear) == null) {
|
||||||
MessageBox.Show("Die Saison für das aktuelle Jahr wurde noch nicht erstellt. Neue Lieferungen können nicht abgespeichert werden.\n\n(Stammdaten -> Saisons -> Neu anlegen...)",
|
MessageBox.Show("Die Saison für das aktuelle Jahr wurde noch nicht erstellt. Neue Lieferungen können nicht abgespeichert werden.",
|
||||||
"Saison noch nicht erstellt", MessageBoxButton.OK, MessageBoxImage.Warning);
|
"Saison noch nicht erstellt", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -260,7 +253,7 @@ namespace Elwig.Windows {
|
|||||||
await App.Client.UpdateValues();
|
await App.Client.UpdateValues();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void Menu_Statistic_Locality_SaveFilters_Click(object sender, RoutedEventArgs evt) =>
|
private async void Menu_Statistic_Locality_SaveFilters_Click(object sender, RoutedEventArgs evt)=>
|
||||||
await ViewModel.GenerateLocalityStatistics(DeliveryService.ExportSubject.FromFilters);
|
await ViewModel.GenerateLocalityStatistics(DeliveryService.ExportSubject.FromFilters);
|
||||||
|
|
||||||
private async void Menu_DeliveryDepreciationList_SaveFilters_Click(object sender, RoutedEventArgs evt) =>
|
private async void Menu_DeliveryDepreciationList_SaveFilters_Click(object sender, RoutedEventArgs evt) =>
|
||||||
@@ -280,15 +273,11 @@ namespace Elwig.Windows {
|
|||||||
private async void Menu_DeliveryDepreciationList_PrintSeason_Click(object sender, RoutedEventArgs evt) =>
|
private async void Menu_DeliveryDepreciationList_PrintSeason_Click(object sender, RoutedEventArgs evt) =>
|
||||||
await ViewModel.GenerateDeliveryDepreciationList(DeliveryService.ExportSubject.FromSeason, ExportMode.Print);
|
await ViewModel.GenerateDeliveryDepreciationList(DeliveryService.ExportSubject.FromSeason, ExportMode.Print);
|
||||||
|
|
||||||
private async void Menu_DeliveryDataList_SaveFilters_Click(object sender, RoutedEventArgs evt) =>
|
|
||||||
await ViewModel.GenerateDeliveryDataList(DeliveryService.ExportSubject.FromFilters, ExportMode.SaveList);
|
|
||||||
|
|
||||||
private void Menu_Settings_EnableFreeEditing_Checked(object sender, RoutedEventArgs evt) {
|
private void Menu_Settings_EnableFreeEditing_Checked(object sender, RoutedEventArgs evt) {
|
||||||
if (IsEditing || IsCreating) {
|
if (IsEditing || IsCreating) {
|
||||||
DateInput.IsReadOnly = false;
|
DateInput.IsReadOnly = false;
|
||||||
TimeInput.IsReadOnly = false;
|
TimeInput.IsReadOnly = false;
|
||||||
BranchInput.IsEnabled = true;
|
BranchInput.IsEnabled = true;
|
||||||
GerebeltGewogenInput.IsEnabled = true;
|
|
||||||
if (IsCreating) ViewModel.Time = "";
|
if (IsCreating) ViewModel.Time = "";
|
||||||
OnSecondPassed(null, null);
|
OnSecondPassed(null, null);
|
||||||
}
|
}
|
||||||
@@ -298,7 +287,6 @@ namespace Elwig.Windows {
|
|||||||
DateInput.IsReadOnly = true;
|
DateInput.IsReadOnly = true;
|
||||||
TimeInput.IsReadOnly = true;
|
TimeInput.IsReadOnly = true;
|
||||||
BranchInput.IsEnabled = false;
|
BranchInput.IsEnabled = false;
|
||||||
GerebeltGewogenInput.IsEnabled = App.Config.WeighingMode != WeighingMode.Net;
|
|
||||||
OnSecondPassed(null, null);
|
OnSecondPassed(null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -313,7 +301,7 @@ namespace Elwig.Windows {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void InitialDefaultInputs() {
|
private void InitialDefaultInputs() {
|
||||||
if (App.Config.WeighingMode == WeighingMode.Net) {
|
if (App.Client.HasNetWeighing(ViewModel.Branch)) {
|
||||||
GerebeltGewogenInput.IsEnabled = false;
|
GerebeltGewogenInput.IsEnabled = false;
|
||||||
SetDefaultValue(GerebeltGewogenInput, true);
|
SetDefaultValue(GerebeltGewogenInput, true);
|
||||||
} else {
|
} else {
|
||||||
@@ -322,20 +310,15 @@ namespace Elwig.Windows {
|
|||||||
UnsetDefaultValue(GerebeltGewogenInput);
|
UnsetDefaultValue(GerebeltGewogenInput);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (App.Config.WeighingMode == WeighingMode.Box) {
|
if (App.Client.HasBoxWeighing(ViewModel.Branch)) {
|
||||||
SetDefaultValue(UnloadingDumperInput, false);
|
LesewagenInput.IsEnabled = false;
|
||||||
SetDefaultValue(UnloadingPumpedInput, false);
|
SetDefaultValue(LesewagenInput, false);
|
||||||
SetDefaultValue(UnloadingBoxInput, true);
|
|
||||||
SetDefaultValue(UnloadingOtherInput, false);
|
|
||||||
UnloadingBoxInput.IsChecked = true;
|
|
||||||
} else {
|
} else {
|
||||||
UnsetDefaultValue(UnloadingDumperInput);
|
LesewagenInput.IsEnabled = true;
|
||||||
UnsetDefaultValue(UnloadingPumpedInput);
|
UnsetDefaultValue(LesewagenInput);
|
||||||
UnsetDefaultValue(UnloadingBoxInput);
|
|
||||||
UnsetDefaultValue(UnloadingOtherInput);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (App.Config.WeighingMode != WeighingMode.Net) {
|
if (!App.Client.HasNetWeighing(ViewModel.Branch)) {
|
||||||
HandPickedInput.IsThreeState = false;
|
HandPickedInput.IsThreeState = false;
|
||||||
UnsetDefaultValue(HandPickedInput);
|
UnsetDefaultValue(HandPickedInput);
|
||||||
} else {
|
} else {
|
||||||
@@ -361,13 +344,13 @@ namespace Elwig.Windows {
|
|||||||
ClearOriginalValues();
|
ClearOriginalValues();
|
||||||
ClearDefaultValues();
|
ClearDefaultValues();
|
||||||
|
|
||||||
ViewModel.IsNetWeight = App.Config.WeighingMode == WeighingMode.Net;
|
ViewModel.IsNetWeight = App.Client.HasNetWeighing(ViewModel.Branch);
|
||||||
ViewModel.IsHandPicked = App.Config.WeighingMode != WeighingMode.Net ? true : null;
|
ViewModel.IsLesewagen = false;
|
||||||
ViewModel.Unloading = null;
|
ViewModel.IsHandPicked = !App.Client.HasNetWeighing(ViewModel.Branch) ? true : null;
|
||||||
ViewModel.IsGebunden = null;
|
ViewModel.IsGebunden = null;
|
||||||
InitialDefaultInputs();
|
InitialDefaultInputs();
|
||||||
|
|
||||||
//WineQualityLevelInput.IsEnabled = false; // disable wine quality level input in Übernahme
|
WineQualityLevelInput.IsEnabled = false;
|
||||||
ValidateRequiredInputs();
|
ValidateRequiredInputs();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -495,8 +478,7 @@ namespace Elwig.Windows {
|
|||||||
var cultList = await ctx.WineCultivations.OrderBy(a => a.Name).Cast<object>().ToListAsync();
|
var cultList = await ctx.WineCultivations.OrderBy(a => a.Name).Cast<object>().ToListAsync();
|
||||||
cultList.Insert(0, new NullItem(""));
|
cultList.Insert(0, new NullItem(""));
|
||||||
ControlUtils.RenewItemsSource(CultivationInput, cultList, null, ControlUtils.RenewSourceDefault.First);
|
ControlUtils.RenewItemsSource(CultivationInput, cultList, null, ControlUtils.RenewSourceDefault.First);
|
||||||
WineQualityLevels = await ctx.WineQualityLevels.ToListAsync();
|
ControlUtils.RenewItemsSource(WineQualityLevelInput, await ctx.WineQualityLevels.ToListAsync());
|
||||||
ControlUtils.RenewItemsSource(WineQualityLevelInput, WineQualityLevels);
|
|
||||||
ControlUtils.RenewItemsSource(ModifiersInput, await ctx.Modifiers
|
ControlUtils.RenewItemsSource(ModifiersInput, await ctx.Modifiers
|
||||||
.Where(m => m.Year == y && (!IsCreating || m.IsActive))
|
.Where(m => m.Year == y && (!IsCreating || m.IsActive))
|
||||||
.OrderBy(m => m.Ordering)
|
.OrderBy(m => m.Ordering)
|
||||||
@@ -1157,7 +1139,6 @@ namespace Elwig.Windows {
|
|||||||
DateInput.IsReadOnly = !Menu_Settings_EnableFreeEditing.IsChecked;
|
DateInput.IsReadOnly = !Menu_Settings_EnableFreeEditing.IsChecked;
|
||||||
TimeInput.IsReadOnly = !Menu_Settings_EnableFreeEditing.IsChecked;
|
TimeInput.IsReadOnly = !Menu_Settings_EnableFreeEditing.IsChecked;
|
||||||
BranchInput.IsEnabled = Menu_Settings_EnableFreeEditing.IsChecked;
|
BranchInput.IsEnabled = Menu_Settings_EnableFreeEditing.IsChecked;
|
||||||
GerebeltGewogenInput.IsEnabled = App.Config.WeighingMode == WeighingMode.Net || Menu_Settings_EnableFreeEditing.IsChecked;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DisableWeighingButtons() {
|
private void DisableWeighingButtons() {
|
||||||
@@ -1177,19 +1158,6 @@ namespace Elwig.Windows {
|
|||||||
WeighingDButton.IsEnabled = n > 3 && App.CommandScales[3].IsReady;
|
WeighingDButton.IsEnabled = n > 3 && App.CommandScales[3].IsReady;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateScales() {
|
|
||||||
if (!ViewModel.IsReceipt) return;
|
|
||||||
foreach (var s in App.EventScales) {
|
|
||||||
s.WeighingEvent -= Scale_Weighing;
|
|
||||||
s.WeighingEvent += Scale_Weighing;
|
|
||||||
}
|
|
||||||
if (WeighingManualButton.IsEnabled) {
|
|
||||||
EnableWeighingButtons();
|
|
||||||
} else {
|
|
||||||
DisableWeighingButtons();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task UpdateLsNr() {
|
private async Task UpdateLsNr() {
|
||||||
if (string.IsNullOrEmpty(ViewModel.Date) || ViewModel.Branch == null) {
|
if (string.IsNullOrEmpty(ViewModel.Date) || ViewModel.Branch == null) {
|
||||||
ViewModel.LsNr = "";
|
ViewModel.LsNr = "";
|
||||||
@@ -1233,7 +1201,6 @@ namespace Elwig.Windows {
|
|||||||
AttributeInput.SelectedIndex = 0;
|
AttributeInput.SelectedIndex = 0;
|
||||||
CultivationInput.SelectedIndex = 0;
|
CultivationInput.SelectedIndex = 0;
|
||||||
}
|
}
|
||||||
UpdateWineQualityLevels();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SortIdInput_TextChanged(object sender, TextChangedEventArgs evt) {
|
private void SortIdInput_TextChanged(object sender, TextChangedEventArgs evt) {
|
||||||
@@ -1247,39 +1214,19 @@ namespace Elwig.Windows {
|
|||||||
private void WineVarietyInput_SelectionChanged(object sender, SelectionChangedEventArgs evt) {
|
private void WineVarietyInput_SelectionChanged(object sender, SelectionChangedEventArgs evt) {
|
||||||
if (WineVarietyInput.SelectedItem is WineVar s)
|
if (WineVarietyInput.SelectedItem is WineVar s)
|
||||||
ViewModel.SortId = s.SortId;
|
ViewModel.SortId = s.SortId;
|
||||||
UpdateWineQualityLevels();
|
|
||||||
if (!ViewModel.WineVar?.IsQuw ?? false) {
|
|
||||||
App.MainDispatcher.BeginInvoke(() => {
|
|
||||||
MessageBox.Show("Die eingegebene Sorte darf nicht als Qualitätswein\nübernommen werden!", "Kein Qualitätswein",
|
|
||||||
MessageBoxButton.OK, MessageBoxImage.Warning);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private WineQualLevel GetWineQualityLevel(double kmw, string? maxQualId = null) {
|
|
||||||
return WineQualityLevels
|
|
||||||
.Where(q => !q.IsPredicate && (q.MinKmw == null || q.MinKmw <= kmw))
|
|
||||||
.Where(q => maxQualId == null || q.QualId == "WEI" || q.QualId == maxQualId)
|
|
||||||
.OrderBy(q => q.MinKmw)
|
|
||||||
.Last();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateWineQualityLevels() {
|
private void UpdateWineQualityLevels() {
|
||||||
|
using var ctx = new AppDbContext();
|
||||||
if (!GetInputValid(GradationKmwInput)) {
|
if (!GetInputValid(GradationKmwInput)) {
|
||||||
UnsetDefaultValue(WineQualityLevelInput);
|
UnsetDefaultValue(WineQualityLevelInput);
|
||||||
ComboBox_SelectionChanged(WineQualityLevelInput, null);
|
ComboBox_SelectionChanged(WineQualityLevelInput, null);
|
||||||
WineQualityLevelInput.ItemsSource = WineQualityLevels;
|
WineQualityLevelInput.ItemsSource = ctx.WineQualityLevels.Where(q => q.QualId == "WEI").ToList();
|
||||||
WineQualityLevelInput.SelectedItem = null;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var kmw = (double)ViewModel.GradationKmw!;
|
var kmw = (double)ViewModel.GradationKmw!;
|
||||||
var max = ViewModel.WineVar?.MaxQualId;
|
WineQualityLevelInput.ItemsSource = ctx.WineQualityLevels.Where(q => q.MinKmw == null || q.MinKmw <= kmw).ToList();
|
||||||
var quw = ViewModel.WineVar?.IsQuw ?? true;
|
var qual = ctx.GetWineQualityLevel(kmw).GetAwaiter().GetResult();
|
||||||
WineQualityLevelInput.ItemsSource = WineQualityLevels
|
|
||||||
.Where(q => q.MinKmw == null || q.MinKmw <= kmw)
|
|
||||||
.Where(q => quw || q.QualId == "WEI" || q.QualId == max)
|
|
||||||
.ToList();
|
|
||||||
var qual = GetWineQualityLevel(kmw, !quw ? max : null);
|
|
||||||
SetDefaultValue(WineQualityLevelInput, qual);
|
SetDefaultValue(WineQualityLevelInput, qual);
|
||||||
if (WineQualityLevelInput.SelectedItem == null || (WineQualityLevelInput.SelectedItem is WineQualLevel selected && !selected.IsPredicate)) {
|
if (WineQualityLevelInput.SelectedItem == null || (WineQualityLevelInput.SelectedItem is WineQualLevel selected && !selected.IsPredicate)) {
|
||||||
ControlUtils.SelectItem(WineQualityLevelInput, qual);
|
ControlUtils.SelectItem(WineQualityLevelInput, qual);
|
||||||
@@ -1333,73 +1280,42 @@ namespace Elwig.Windows {
|
|||||||
|
|
||||||
private void ModifiersInput_SelectionChanged(object sender, SelectionChangedEventArgs evt) {
|
private void ModifiersInput_SelectionChanged(object sender, SelectionChangedEventArgs evt) {
|
||||||
if (!IsEditing && !IsCreating) return;
|
if (!IsEditing && !IsCreating) return;
|
||||||
var mod = ViewModel.Modifiers.ToList();
|
var mod = ModifiersInput.SelectedItems.Cast<Modifier>().ToList();
|
||||||
var source = ViewModel.ModifiersSource.ToList();
|
|
||||||
if (App.Client.IsMatzen) {
|
if (App.Client.IsMatzen) {
|
||||||
var kl = mod.Where(m => m.Name.StartsWith("Klasse "));
|
var kl = mod.Where(m => m.Name.StartsWith("Klasse "));
|
||||||
if (kl.Count() > 1) {
|
if (kl.Count() > 1) {
|
||||||
App.MainDispatcher.BeginInvoke(() => {
|
App.MainDispatcher.BeginInvoke(() => {
|
||||||
foreach (var r in kl.Take(kl.Count() - 1))
|
foreach (var r in kl.Take(kl.Count() - 1))
|
||||||
ViewModel.Modifiers.Remove(r);
|
ModifiersInput.SelectedItems.Remove(r);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (App.Client.IsWinzerkeller) {
|
} else if (App.Client.IsWinzerkeller) {
|
||||||
if (source.Any(m => m.Name.Contains("Lesewagen"))) {
|
|
||||||
if (mod.Any(m => m.Name.Contains("Lesewagen"))) {
|
if (mod.Any(m => m.Name.Contains("Lesewagen"))) {
|
||||||
ViewModel.IsUnloadingPumped = true;
|
ViewModel.IsLesewagen = true;
|
||||||
} else {
|
} else {
|
||||||
ViewModel.IsUnloadingPumped = false;
|
ViewModel.IsLesewagen = false;
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (App.Client.IsBaden) {
|
|
||||||
if (source.Any(m => m.Name.Contains("Kiste"))) {
|
|
||||||
if (mod.Any(m => m.Name.Contains("Kiste"))) {
|
|
||||||
ViewModel.IsUnloadingBox = true;
|
|
||||||
} else {
|
|
||||||
ViewModel.IsUnloadingBox = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UnloadingInput_Checked(object sender, RoutedEventArgs evt) {
|
private void LesewagenInput_Changed(object sender, RoutedEventArgs evt) {
|
||||||
if (!IsEditing && !IsCreating) return;
|
if (!IsEditing && !IsCreating) return;
|
||||||
var mod = ViewModel.Modifiers.ToList();
|
var mod = ModifiersInput.SelectedItems.Cast<Modifier>().ToList();
|
||||||
var source = ViewModel.ModifiersSource.ToList();
|
var source = ModifiersInput.ItemsSource.Cast<Modifier>().ToList();
|
||||||
|
var lw = LesewagenInput.IsChecked == true;
|
||||||
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("A")[0];
|
||||||
if (ViewModel.IsUnloadingPumped && (kl == 'A' || kl == '_')) {
|
if (lw) kl++; else kl--;
|
||||||
kl = 'B';
|
var newKl = source.FirstOrDefault(m => m.ModId == kl.ToString());
|
||||||
} else if (ViewModel.IsUnloadingDumper && kl == '_') {
|
if (newKl != null) ModifiersInput.SelectedItems.Add(newKl);
|
||||||
kl = 'A';
|
|
||||||
} else {
|
|
||||||
kl = '_';
|
|
||||||
}
|
|
||||||
var newKl = source.FirstOrDefault(m => m?.ModId == kl.ToString(), null);
|
|
||||||
if (newKl != null) ViewModel.Modifiers.Add(newKl);
|
|
||||||
} else if (App.Client.IsWinzerkeller) {
|
} else if (App.Client.IsWinzerkeller) {
|
||||||
if (source.Any(m => m.Name.Contains("Lesewagen"))) {
|
if (lw && !mod.Any(m => m.Name.Contains("Lesewagen"))) {
|
||||||
if (ViewModel.IsUnloadingPumped && !mod.Any(m => m.Name.Contains("Lesewagen"))) {
|
ModifiersInput.SelectedItems.Add(source.First(m => m.Name.Contains("Lesewagen")));
|
||||||
ViewModel.Modifiers.Add(source.First(m => m.Name.Contains("Lesewagen")));
|
} else if (!lw && mod.Any(m => m.Name.Contains("Lesewagen"))) {
|
||||||
} else if (!ViewModel.IsUnloadingPumped && mod.Any(m => m.Name.Contains("Lesewagen"))) {
|
ModifiersInput.SelectedItems.Remove(mod.First(m => m.Name.Contains("Lesewagen")));
|
||||||
ViewModel.Modifiers.Remove(mod.First(m => m.Name.Contains("Lesewagen")));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (App.Client.IsBaden) {
|
CheckBox_Changed(sender, evt);
|
||||||
if (source.Any(m => m.Name.Contains("Kiste"))) {
|
|
||||||
if (ViewModel.IsUnloadingBox && !mod.Any(m => m.Name.Contains("Kiste"))) {
|
|
||||||
ViewModel.Modifiers.Add(source.First(m => m.Name.Contains("Kiste")));
|
|
||||||
} else if (!ViewModel.IsUnloadingBox && mod.Any(m => m.Name.Contains("Kiste"))) {
|
|
||||||
ViewModel.Modifiers.Remove(mod.First(m => m.Name.Contains("Kiste")));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RadioButton_Changed(sender, evt);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UnloadingInput_Unchecked(object sender, RoutedEventArgs evt) {
|
|
||||||
if (!IsEditing && !IsCreating) return;
|
|
||||||
RadioButton_Changed(sender, evt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateWineOrigin() {
|
private void UpdateWineOrigin() {
|
||||||
@@ -1450,7 +1366,8 @@ namespace Elwig.Windows {
|
|||||||
AbgewertetInput.IsChecked = false;
|
AbgewertetInput.IsChecked = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var defQual = GetWineQualityLevel(ViewModel.GradationKmw!.Value, !(ViewModel.WineVar?.IsQuw ?? true) ? ViewModel.WineVar?.MaxQualId : null);
|
using var ctx = new AppDbContext();
|
||||||
|
var defQual = ctx.GetWineQualityLevel(double.Parse(GradationKmwInput.Text)).GetAwaiter().GetResult();
|
||||||
AbgewertetInput.IsChecked = !qual.IsPredicate && defQual != qual;
|
AbgewertetInput.IsChecked = !qual.IsPredicate && defQual != qual;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1472,17 +1389,17 @@ namespace Elwig.Windows {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void GerebeltGewogenInput_Changed(object sender, RoutedEventArgs evt) {
|
private void GerebeltGewogenInput_Changed(object sender, RoutedEventArgs evt) {
|
||||||
if ((IsEditing || IsCreating) && App.Config.WeighingMode != WeighingMode.Net) {
|
if ((IsEditing || IsCreating) && !App.Client.HasNetWeighing(ViewModel.Branch)) {
|
||||||
HandPickedInput.IsChecked = !GerebeltGewogenInput.IsChecked;
|
HandPickedInput.IsChecked = !GerebeltGewogenInput.IsChecked;
|
||||||
}
|
}
|
||||||
if (!ViewModel.IsReceipt || App.Config.WeighingMode == WeighingMode.Net) {
|
if (!ViewModel.IsReceipt || App.Client.HasNetWeighing(ViewModel.Branch)) {
|
||||||
GerebeltGewogenInput.IsChecked ??= false;
|
GerebeltGewogenInput.IsChecked ??= false;
|
||||||
}
|
}
|
||||||
CheckBox_Changed(sender, evt);
|
CheckBox_Changed(sender, evt);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandPickedInput_Changed(object sender, RoutedEventArgs evt) {
|
private void HandPickedInput_Changed(object sender, RoutedEventArgs evt) {
|
||||||
if ((IsEditing || IsCreating) && App.Config.WeighingMode != WeighingMode.Net) {
|
if ((IsEditing || IsCreating) && !App.Client.HasNetWeighing(ViewModel.Branch)) {
|
||||||
GerebeltGewogenInput.IsChecked = !HandPickedInput.IsChecked;
|
GerebeltGewogenInput.IsChecked = !HandPickedInput.IsChecked;
|
||||||
}
|
}
|
||||||
CheckBox_Changed(sender, evt);
|
CheckBox_Changed(sender, evt);
|
||||||
|
|||||||
@@ -83,19 +83,14 @@ namespace Elwig.Windows {
|
|||||||
|
|
||||||
private async Task RefreshDeliveryScheduleList() {
|
private async Task RefreshDeliveryScheduleList() {
|
||||||
using var ctx = new AppDbContext();
|
using var ctx = new AppDbContext();
|
||||||
var list = await ctx.DeliverySchedules
|
var deliverySchedules = await ctx.DeliverySchedules
|
||||||
.Where(s => s.Year == ViewModel.FilterSeason)
|
.Where(s => s.Year == ViewModel.FilterSeason)
|
||||||
.Include(s => s.Branch)
|
.Include(s => s.Branch)
|
||||||
|
.Include(s => s.Announcements)
|
||||||
.OrderBy(s => s.DateString)
|
.OrderBy(s => s.DateString)
|
||||||
.ThenBy(s => s.Branch.Name)
|
.ThenBy(s => s.Branch.Name)
|
||||||
.ThenBy(s => s.Description)
|
.ThenBy(s => s.Description)
|
||||||
.Select(s => new {
|
|
||||||
Schedule = s,
|
|
||||||
AnnouncedWeight = s.Announcements.Sum(a => a.Weight)
|
|
||||||
})
|
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
list.ForEach(v => v.Schedule.AnnouncedWeightOverride = v.AnnouncedWeight);
|
|
||||||
var deliverySchedules = list.Select(v => v.Schedule).ToList();
|
|
||||||
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(Utils.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);
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
using Elwig.Helpers;
|
using Elwig.Helpers;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Input;
|
|
||||||
|
|
||||||
namespace Elwig.Windows {
|
namespace Elwig.Windows {
|
||||||
public partial class LogWindow : Window {
|
public partial class LogWindow : Window {
|
||||||
@@ -13,10 +11,9 @@ namespace Elwig.Windows {
|
|||||||
WindowState = WindowState.Maximized;
|
WindowState = WindowState.Maximized;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void Window_Loaded(object sender, RoutedEventArgs evt) {
|
private void Window_Loaded(object sender, RoutedEventArgs evt) {
|
||||||
Mouse.OverrideCursor = Cursors.Wait;
|
var log = Utils.GetLogEntries();
|
||||||
await Task.Run(async () => {
|
EventList.ItemsSource = log
|
||||||
var list = Utils.GetLogEntries()
|
|
||||||
.Select(e => new {
|
.Select(e => new {
|
||||||
Event = e,
|
Event = e,
|
||||||
Lines = e.Message.Split('\n').ToArray(),
|
Lines = e.Message.Split('\n').ToArray(),
|
||||||
@@ -35,12 +32,7 @@ namespace Elwig.Windows {
|
|||||||
})
|
})
|
||||||
.OrderByDescending(e => e.Event.TimeGenerated)
|
.OrderByDescending(e => e.Event.TimeGenerated)
|
||||||
.ToList();
|
.ToList();
|
||||||
await App.MainDispatcher.BeginInvoke(() => {
|
|
||||||
EventList.ItemsSource = list;
|
|
||||||
EventList.SelectedIndex = 0;
|
EventList.SelectedIndex = 0;
|
||||||
});
|
|
||||||
});
|
|
||||||
Mouse.OverrideCursor = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EventList_SelectionChanged(object sender, RoutedEventArgs evt) {
|
private void EventList_SelectionChanged(object sender, RoutedEventArgs evt) {
|
||||||
|
|||||||
@@ -302,9 +302,6 @@
|
|||||||
<Button x:Name="GenerateButton" Content="Generieren"
|
<Button x:Name="GenerateButton" Content="Generieren"
|
||||||
Grid.Row="0" Grid.Column="0" FontSize="14"
|
Grid.Row="0" Grid.Column="0" FontSize="14"
|
||||||
Click="GenerateButton_Click"/>
|
Click="GenerateButton_Click"/>
|
||||||
<Button x:Name="AbortButton" Content="Abbrechen" Visibility="Hidden" IsEnabled="False"
|
|
||||||
Grid.Row="0" Grid.Column="0" FontSize="14"
|
|
||||||
Click="AbortButton_Click"/>
|
|
||||||
<ProgressBar x:Name="ProgressBar"
|
<ProgressBar x:Name="ProgressBar"
|
||||||
Grid.Row="2" Grid.Column="0" SnapsToDevicePixels="True"/>
|
Grid.Row="2" Grid.Column="0" SnapsToDevicePixels="True"/>
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ using System.Collections.ObjectModel;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
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;
|
||||||
@@ -62,8 +61,6 @@ namespace Elwig.Windows {
|
|||||||
protected Dictionary<Member, List<Document>>? PrintMemberDocuments;
|
protected Dictionary<Member, List<Document>>? PrintMemberDocuments;
|
||||||
protected Dictionary<Member, List<Document>>? EmailDocuments;
|
protected Dictionary<Member, List<Document>>? EmailDocuments;
|
||||||
|
|
||||||
private CancellationTokenSource? CancelGeneration;
|
|
||||||
|
|
||||||
public static readonly DependencyProperty PostalAllCountProperty = DependencyProperty.Register(nameof(PostalAllCount), typeof(int), typeof(MailWindow));
|
public static readonly DependencyProperty PostalAllCountProperty = DependencyProperty.Register(nameof(PostalAllCount), typeof(int), typeof(MailWindow));
|
||||||
public int PostalAllCount {
|
public int PostalAllCount {
|
||||||
get => (int)GetValue(PostalAllCountProperty);
|
get => (int)GetValue(PostalAllCountProperty);
|
||||||
@@ -597,32 +594,20 @@ namespace Elwig.Windows {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void Window_Closed(object sender, EventArgs evt) {
|
private void Window_Closed(object sender, EventArgs evt) {
|
||||||
CancelGeneration?.Dispose();
|
|
||||||
DisposeDocs();
|
DisposeDocs();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void AbortButton_Click(object sender, RoutedEventArgs evt) {
|
|
||||||
AbortButton.IsEnabled = false;
|
|
||||||
CancelGeneration?.Cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void GenerateButton_Click(object sender, RoutedEventArgs evt) {
|
private async void GenerateButton_Click(object sender, RoutedEventArgs evt) {
|
||||||
LockInputs();
|
LockInputs();
|
||||||
PreviewButton.IsEnabled = false;
|
PreviewButton.IsEnabled = false;
|
||||||
PrintButton.IsEnabled = false;
|
PrintButton.IsEnabled = false;
|
||||||
EmailButton.IsEnabled = false;
|
EmailButton.IsEnabled = false;
|
||||||
Mouse.OverrideCursor = Cursors.Wait;
|
Mouse.OverrideCursor = Cursors.Wait;
|
||||||
AbortButton.IsEnabled = true;
|
|
||||||
AbortButton.Visibility = Visibility.Visible;
|
|
||||||
GenerateButton.IsEnabled = false;
|
GenerateButton.IsEnabled = false;
|
||||||
GenerateButton.Visibility = Visibility.Hidden;
|
|
||||||
|
|
||||||
DisposeDocs();
|
DisposeDocs();
|
||||||
await UpdateClientParameters();
|
await UpdateClientParameters();
|
||||||
|
|
||||||
CancelGeneration?.Dispose();
|
|
||||||
CancelGeneration = new();
|
|
||||||
|
|
||||||
using var ctx = new AppDbContext();
|
using var ctx = new AppDbContext();
|
||||||
|
|
||||||
var doublePaged = DoublePagedInput.IsChecked == true;
|
var doublePaged = DoublePagedInput.IsChecked == true;
|
||||||
@@ -677,9 +662,6 @@ namespace Elwig.Windows {
|
|||||||
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
UnlockInputs();
|
UnlockInputs();
|
||||||
GenerateButton.IsEnabled = true;
|
GenerateButton.IsEnabled = true;
|
||||||
GenerateButton.Visibility = Visibility.Visible;
|
|
||||||
AbortButton.IsEnabled = false;
|
|
||||||
AbortButton.Visibility = Visibility.Hidden;
|
|
||||||
Mouse.OverrideCursor = null;
|
Mouse.OverrideCursor = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -697,9 +679,6 @@ namespace Elwig.Windows {
|
|||||||
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
UnlockInputs();
|
UnlockInputs();
|
||||||
GenerateButton.IsEnabled = true;
|
GenerateButton.IsEnabled = true;
|
||||||
GenerateButton.Visibility = Visibility.Visible;
|
|
||||||
AbortButton.IsEnabled = false;
|
|
||||||
AbortButton.Visibility = Visibility.Hidden;
|
|
||||||
Mouse.OverrideCursor = null;
|
Mouse.OverrideCursor = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -754,27 +733,12 @@ namespace Elwig.Windows {
|
|||||||
}).ToList()
|
}).ToList()
|
||||||
}).ToList();
|
}).ToList();
|
||||||
|
|
||||||
var hasPreviewDocs = memberDocs.Any(m => m.Docs.Any(d => d.Doc.IsPreview));
|
|
||||||
if (hasPreviewDocs) {
|
|
||||||
var res = MessageBox.Show("Einige der ausgewählten Dokumente sind nur als vorläufig zu betrachten und können daher nicht verschickt/ausgedruckt werden!\n\nDies könnte an einer noch nicht festgesetzen Auszahlungsvariante liegen.\n\nSoll mit dem Generieren fortgefahren werden?",
|
|
||||||
"Vorläufige Dokumente", MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
|
|
||||||
if (res != MessageBoxResult.OK) {
|
|
||||||
UnlockInputs();
|
|
||||||
GenerateButton.IsEnabled = true;
|
|
||||||
GenerateButton.Visibility = Visibility.Visible;
|
|
||||||
AbortButton.IsEnabled = false;
|
|
||||||
AbortButton.Visibility = Visibility.Hidden;
|
|
||||||
Mouse.OverrideCursor = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var printMode = PostalAllInput.IsChecked == true ? 3 :
|
var printMode = PostalAllInput.IsChecked == true ? 3 :
|
||||||
PostalWishInput.IsChecked == true ? 2 :
|
PostalWishInput.IsChecked == true ? 2 :
|
||||||
PostalNoEmailInput.IsChecked == true ? 1 : 0;
|
PostalNoEmailInput.IsChecked == true ? 1 : 0;
|
||||||
var emailMode = EmailAllInput.IsChecked == true ? 2 : EmailWishInput.IsChecked == true ? 1 : 0;
|
var emailMode = EmailAllInput.IsChecked == true ? 2 : EmailWishInput.IsChecked == true ? 1 : 0;
|
||||||
|
|
||||||
double printNum = printMode == 3 ? PostalAllCount : printMode == 2 ? PostalWishCount : printMode == 1 ? PostalNoEmailCount : 0;
|
double printNum = printMode == 3 ? PostalAllCount : printMode == 2 ? PostalWishCount : printMode == 2 ? PostalNoEmailCount : 0;
|
||||||
double emailNum = emailMode == 2 ? EmailAllCount : emailMode == 1 ? EmailWishCount : 0;
|
double emailNum = emailMode == 2 ? EmailAllCount : emailMode == 1 ? EmailWishCount : 0;
|
||||||
double totalNum = printNum + emailNum;
|
double totalNum = printNum + emailNum;
|
||||||
|
|
||||||
@@ -783,7 +747,7 @@ namespace Elwig.Windows {
|
|||||||
.ToDictionary(d => d.Member, m => {
|
.ToDictionary(d => d.Member, m => {
|
||||||
var docs = m.Docs.Select(d => d.Doc).ToList();
|
var docs = m.Docs.Select(d => d.Doc).ToList();
|
||||||
foreach (var doc in docs) {
|
foreach (var doc in docs) {
|
||||||
doc!.IsDoublePaged = false;
|
doc!.DoublePaged = false;
|
||||||
if (doc is BusinessDocument b) {
|
if (doc is BusinessDocument b) {
|
||||||
b.IncludeSender = false;
|
b.IncludeSender = false;
|
||||||
b.Location = location;
|
b.Location = location;
|
||||||
@@ -795,7 +759,7 @@ namespace Elwig.Windows {
|
|||||||
try {
|
try {
|
||||||
foreach (var item1 in email.Select((e, i) => new { Index = i, e.Key, e.Value })) {
|
foreach (var item1 in email.Select((e, i) => new { Index = i, e.Key, e.Value })) {
|
||||||
foreach (var item2 in item1.Value.Select((d, i) => new { Index = i, Doc = d })) {
|
foreach (var item2 in item1.Value.Select((d, i) => new { Index = i, Doc = d })) {
|
||||||
await item2.Doc.Generate(CancelGeneration.Token, new Progress<double>(v => {
|
await item2.Doc.Generate(new Progress<double>(v => {
|
||||||
ProgressBar.Value = v * (item2.Index + 1) / item1.Value.Count / totalNum + 100.0 * item1.Index / totalNum;
|
ProgressBar.Value = v * (item2.Index + 1) / item1.Value.Count / totalNum + 100.0 * item1.Index / totalNum;
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@@ -804,9 +768,6 @@ namespace Elwig.Windows {
|
|||||||
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
UnlockInputs();
|
UnlockInputs();
|
||||||
GenerateButton.IsEnabled = true;
|
GenerateButton.IsEnabled = true;
|
||||||
GenerateButton.Visibility = Visibility.Visible;
|
|
||||||
AbortButton.IsEnabled = false;
|
|
||||||
AbortButton.Visibility = Visibility.Hidden;
|
|
||||||
Mouse.OverrideCursor = null;
|
Mouse.OverrideCursor = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -827,7 +788,7 @@ namespace Elwig.Windows {
|
|||||||
docs.Insert(0, new Letterhead(m.Member));
|
docs.Insert(0, new Letterhead(m.Member));
|
||||||
}
|
}
|
||||||
docs.ForEach(doc => {
|
docs.ForEach(doc => {
|
||||||
doc.IsDoublePaged = doublePaged;
|
doc.DoublePaged = doublePaged;
|
||||||
if (doc is BusinessDocument b)
|
if (doc is BusinessDocument b)
|
||||||
b.Location = location;
|
b.Location = location;
|
||||||
});
|
});
|
||||||
@@ -840,8 +801,8 @@ namespace Elwig.Windows {
|
|||||||
if (printDocs.Count > 0) {
|
if (printDocs.Count > 0) {
|
||||||
try {
|
try {
|
||||||
var print = Document.Merge(printDocs);
|
var print = Document.Merge(printDocs);
|
||||||
print.IsDoublePaged = doublePaged;
|
print.DoublePaged = doublePaged;
|
||||||
await print.Generate(CancelGeneration.Token, new Progress<double>(v => {
|
await print.Generate(new Progress<double>(v => {
|
||||||
ProgressBar.Value = 100.0 * emailNum / totalNum + v * printNum / totalNum;
|
ProgressBar.Value = 100.0 * emailNum / totalNum + v * printNum / totalNum;
|
||||||
}));
|
}));
|
||||||
PrintDocument = print;
|
PrintDocument = print;
|
||||||
@@ -850,9 +811,6 @@ namespace Elwig.Windows {
|
|||||||
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
UnlockInputs();
|
UnlockInputs();
|
||||||
GenerateButton.IsEnabled = true;
|
GenerateButton.IsEnabled = true;
|
||||||
GenerateButton.Visibility = Visibility.Visible;
|
|
||||||
AbortButton.IsEnabled = false;
|
|
||||||
AbortButton.Visibility = Visibility.Hidden;
|
|
||||||
Mouse.OverrideCursor = null;
|
Mouse.OverrideCursor = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -864,13 +822,10 @@ namespace Elwig.Windows {
|
|||||||
|
|
||||||
UnlockInputs();
|
UnlockInputs();
|
||||||
GenerateButton.IsEnabled = true;
|
GenerateButton.IsEnabled = true;
|
||||||
GenerateButton.Visibility = Visibility.Visible;
|
|
||||||
AbortButton.IsEnabled = false;
|
|
||||||
AbortButton.Visibility = Visibility.Hidden;
|
|
||||||
Mouse.OverrideCursor = null;
|
Mouse.OverrideCursor = null;
|
||||||
PreviewButton.IsEnabled = true;
|
PreviewButton.IsEnabled = true;
|
||||||
PrintButton.IsEnabled = PrintDocument != null && !hasPreviewDocs;
|
PrintButton.IsEnabled = PrintDocument != null;
|
||||||
EmailButton.IsEnabled = EmailDocuments != null && !hasPreviewDocs && App.Config.Smtp != null;
|
EmailButton.IsEnabled = EmailDocuments != null && App.Config.Smtp != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void PreviewButton_Click(object sender, RoutedEventArgs evt) {
|
private async void PreviewButton_Click(object sender, RoutedEventArgs evt) {
|
||||||
@@ -974,13 +929,13 @@ namespace Elwig.Windows {
|
|||||||
await Utils.AddSentMails([(
|
await Utils.AddSentMails([(
|
||||||
"email", m.MgNr, m.AdministrativeName,
|
"email", m.MgNr, m.AdministrativeName,
|
||||||
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()
|
||||||
)]);
|
)]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
MessageBox.Show("Erfolgreich alle E-Mails verschickt!\n\nEs kann einige Minuten dauern, bis die E-Mails in den Posteingängen der Empfänger aufscheinen.", "Rundschreiben verschicken",
|
MessageBox.Show("Erfolgreich alle E-Mails verschickt!", "Rundschreiben verschicken", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||||
MessageBoxButton.OK, MessageBoxImage.Information);
|
|
||||||
} catch (Exception exc) {
|
} catch (Exception exc) {
|
||||||
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
} finally {
|
} finally {
|
||||||
@@ -999,7 +954,7 @@ namespace Elwig.Windows {
|
|||||||
AvaiableDocumentsList.SelectedIndex = 1;
|
AvaiableDocumentsList.SelectedIndex = 1;
|
||||||
if (AvaiableDocumentsList.SelectedItem is not string s || SelectedDocs.Any(d => d.Type == DocType.DeliveryConfirmation))
|
if (AvaiableDocumentsList.SelectedItem is not string s || SelectedDocs.Any(d => d.Type == DocType.DeliveryConfirmation))
|
||||||
return;
|
return;
|
||||||
SelectedDocs.Add(new(DocType.DeliveryConfirmation, s, Year));
|
SelectedDocs.Add(new(DocType.DeliveryConfirmation, s, (Year, DocumentNonDeliverersInput.IsChecked == true)));
|
||||||
SelectedDocumentsList.SelectedIndex = SelectedDocs.Count - 1;
|
SelectedDocumentsList.SelectedIndex = SelectedDocs.Count - 1;
|
||||||
RecipientsDeliveryMembersInput.IsChecked = true;
|
RecipientsDeliveryMembersInput.IsChecked = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,17 +31,6 @@
|
|||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<Separator/>
|
<Separator/>
|
||||||
<MenuItem Header="Datenbank sichern..." Click="Menu_Database_Backup_Click">
|
|
||||||
<MenuItem.Icon>
|
|
||||||
<TextBlock FontFamily="Segoe MDL2 Assets" FontSize="16" Text=""/>
|
|
||||||
</MenuItem.Icon>
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem Header="Datenbank wiederherstellen..." Click="Menu_Database_Restore_Click">
|
|
||||||
<MenuItem.Icon>
|
|
||||||
<TextBlock FontFamily="Segoe MDL2 Assets" FontSize="16" Text=""/>
|
|
||||||
</MenuItem.Icon>
|
|
||||||
</MenuItem>
|
|
||||||
<Separator/>
|
|
||||||
<MenuItem Header="Abfragen stellen" Click="Menu_Database_Query_Click">
|
<MenuItem Header="Abfragen stellen" Click="Menu_Database_Query_Click">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<TextBlock FontFamily="Segoe MDL2 Assets" FontSize="16" Text=""/>
|
<TextBlock FontFamily="Segoe MDL2 Assets" FontSize="16" Text=""/>
|
||||||
@@ -64,23 +53,6 @@
|
|||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="Synchronisieren" x:Name="Menu_Sync" IsEnabled="false">
|
|
||||||
<MenuItem x:Name="Menu_Sync_Download" Header="Mitgliederdaten und Lieferungen herunterladen" Click="Menu_Sync_Download_Click">
|
|
||||||
<MenuItem.Icon>
|
|
||||||
<TextBlock FontFamily="Segoe MDL2 Assets" FontSize="16" Text=""/>
|
|
||||||
</MenuItem.Icon>
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem x:Name="Menu_Sync_UploadBranchDeliveries" Header="Lieferungen dieser Saison/Zweigstelle hochladen" Click="Menu_Sync_UploadBranchDeliveries_Click">
|
|
||||||
<MenuItem.Icon>
|
|
||||||
<TextBlock FontFamily="Segoe MDL2 Assets" FontSize="16" Text=""/>
|
|
||||||
</MenuItem.Icon>
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem x:Name="Menu_Sync_UploadModified" Header="Geänderte Mitglieder und Lieferungen hochladen" Click="Menu_Sync_UploadModified_Click">
|
|
||||||
<MenuItem.Icon>
|
|
||||||
<TextBlock FontFamily="Segoe MDL2 Assets" FontSize="16" Text=""/>
|
|
||||||
</MenuItem.Icon>
|
|
||||||
</MenuItem>
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem Header="Waage">
|
<MenuItem Header="Waage">
|
||||||
<MenuItem Header="Datum und Uhrzeit setzen" Click="Menu_Scale_SetDateTime_Click">
|
<MenuItem Header="Datum und Uhrzeit setzen" Click="Menu_Scale_SetDateTime_Click">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
@@ -89,7 +61,7 @@
|
|||||||
</MenuItem>
|
</MenuItem>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem x:Name="HelpMenu" Header="Hilfe">
|
<MenuItem x:Name="HelpMenu" Header="Hilfe">
|
||||||
<MenuItem Header="Über" Click="Menu_Help_About_Click">
|
<MenuItem Header="Über">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<TextBlock FontFamily="Segoe MDL2 Assets" FontSize="16" Text=""/>
|
<TextBlock FontFamily="Segoe MDL2 Assets" FontSize="16" Text=""/>
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
@@ -191,18 +163,16 @@
|
|||||||
</Grid>
|
</Grid>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button x:Name="SyncButton" Click="SyncButton_Click"
|
<Button x:Name="DownloadButton" Click="DownloadButton_Click"
|
||||||
Margin="375,135,0,0" Padding="1.0,0.5,0,0" Height="30" Width="30"
|
Margin="310,135,0,0" Padding="0.375,0.5,0,0" Height="30" Width="30"
|
||||||
FontFamily="Segoe MDL2 Assets" FontSize="16"
|
Content="" FontFamily="Segoe MDL2 Assets" FontSize="16"
|
||||||
HorizontalContentAlignment="Center"
|
HorizontalContentAlignment="Center"
|
||||||
ToolTip="Geänderte Mitgliederdaten und Lieferungen synchronisieren">
|
ToolTip="Lieferungen und Mitgliederdaten anderer Zweigstellen herunterladen"/>
|
||||||
<Button.Content>
|
<Button x:Name="UploadButton" Click="UploadButton_Click"
|
||||||
<Grid TextElement.FontFamily="Segoe MDL2 Assets">
|
Margin="375,135,0,0" Padding="1.0,0.5,0,0" Height="30" Width="30"
|
||||||
<TextBlock x:Name="SyncButton_1" Text=""/>
|
Content="" FontFamily="Segoe MDL2 Assets" FontSize="16"
|
||||||
<TextBlock x:Name="SyncButton_2" Text="" Foreground="DarkOrange"/>
|
HorizontalContentAlignment="Center"
|
||||||
</Grid>
|
ToolTip="Lieferungen dieser Zweigstelle hochladen"/>
|
||||||
</Button.Content>
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<Expander x:Name="SeasonFinish" Header="Leseabschluss" SnapsToDevicePixels="True"
|
<Expander x:Name="SeasonFinish" Header="Leseabschluss" SnapsToDevicePixels="True"
|
||||||
Expanded="SeasonFinish_Expanded" Collapsed="SeasonFinish_Collapsed"
|
Expanded="SeasonFinish_Expanded" Collapsed="SeasonFinish_Collapsed"
|
||||||
|
|||||||
@@ -2,30 +2,26 @@ using Elwig.Helpers;
|
|||||||
using Elwig.Helpers.Billing;
|
using Elwig.Helpers.Billing;
|
||||||
using Elwig.Helpers.Export;
|
using Elwig.Helpers.Export;
|
||||||
using Elwig.Models.Dtos;
|
using Elwig.Models.Dtos;
|
||||||
using Elwig.Services;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Net.NetworkInformation;
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Threading;
|
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.Input;
|
using System.Windows.Input;
|
||||||
using System.Windows.Threading;
|
|
||||||
|
|
||||||
namespace Elwig.Windows {
|
namespace Elwig.Windows {
|
||||||
public partial class MainWindow : ContextWindow {
|
public partial class MainWindow : ContextWindow {
|
||||||
|
|
||||||
private readonly DispatcherTimer _syncTimer = new() { Interval = TimeSpan.FromHours(1) };
|
|
||||||
|
|
||||||
public MainWindow() {
|
public MainWindow() {
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
var v = Assembly.GetExecutingAssembly().GetName().Version;
|
var v = Assembly.GetExecutingAssembly().GetName().Version;
|
||||||
@@ -33,21 +29,14 @@ namespace Elwig.Windows {
|
|||||||
if (App.Client.Client == null) VersionField.Text += " (Unbekannt)";
|
if (App.Client.Client == null) VersionField.Text += " (Unbekannt)";
|
||||||
Menu_Help_Update.IsEnabled = App.Config.UpdateUrl != null;
|
Menu_Help_Update.IsEnabled = App.Config.UpdateUrl != null;
|
||||||
Menu_Help_Smtp.IsEnabled = App.Config.Smtp != null;
|
Menu_Help_Smtp.IsEnabled = App.Config.Smtp != null;
|
||||||
Menu_Sync.IsEnabled = App.Config.SyncUrl != null;
|
DownloadButton.Visibility = App.Config.SyncUrl != null ? Visibility.Visible : Visibility.Hidden;
|
||||||
SyncButton.Visibility = App.Config.SyncUrl != null ? Visibility.Visible : Visibility.Hidden;
|
UploadButton.Visibility = App.Config.SyncUrl != null ? Visibility.Visible : Visibility.Hidden;
|
||||||
Menu_Database_Upload.IsEnabled = App.Config.SyncUrl != null;
|
Menu_Database_Upload.IsEnabled = App.Config.SyncUrl != null;
|
||||||
Menu_Database_Download.IsEnabled = App.Config.SyncUrl != null;
|
Menu_Database_Download.IsEnabled = App.Config.SyncUrl != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Window_Loaded(object sender, RoutedEventArgs evt) {
|
private void Window_Loaded(object sender, RoutedEventArgs evt) {
|
||||||
SeasonInput.Value = Utils.CurrentLastSeason;
|
SeasonInput.Value = Utils.CurrentLastSeason;
|
||||||
|
|
||||||
if (Utils.HasInternetConnectivity()) {
|
|
||||||
CheckSync(200);
|
|
||||||
}
|
|
||||||
NetworkChange.NetworkAvailabilityChanged += OnNetworkAvailabilityChanged;
|
|
||||||
_syncTimer.Tick += new EventHandler(OnSyncTimer);
|
|
||||||
_syncTimer.Start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Window_Closing(object sender, CancelEventArgs evt) {
|
private void Window_Closing(object sender, CancelEventArgs evt) {
|
||||||
@@ -70,11 +59,6 @@ namespace Elwig.Windows {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Menu_Help_About_Click(object sender, RoutedEventArgs evt) {
|
|
||||||
var w = new AboutWindow();
|
|
||||||
w.Show();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void Menu_Help_Update_Click(object sender, RoutedEventArgs evt) {
|
private async void Menu_Help_Update_Click(object sender, RoutedEventArgs evt) {
|
||||||
await App.CheckForUpdates(true);
|
await App.CheckForUpdates(true);
|
||||||
}
|
}
|
||||||
@@ -162,87 +146,92 @@ namespace Elwig.Windows {
|
|||||||
Mouse.OverrideCursor = null;
|
Mouse.OverrideCursor = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void Menu_Database_Backup_Click(object sender, RoutedEventArgs evt) {
|
private async void DownloadButton_Click(object sender, RoutedEventArgs evt) {
|
||||||
|
if (App.Config.SyncUrl == null)
|
||||||
|
return;
|
||||||
|
Mouse.OverrideCursor = Cursors.Wait;
|
||||||
|
await Task.Run(async () => {
|
||||||
try {
|
try {
|
||||||
var d = new SaveFileDialog() {
|
var data = await Utils.GetExportMetaData(App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
|
||||||
Title = "Datenbank sichern - Elwig",
|
var files = data
|
||||||
FileName = $"database_{Utils.Today:yyyy-MM-dd}.sql.zip",
|
.Select(f => new {
|
||||||
DefaultExt = "sql.zip",
|
Name = f!["name"]!.AsValue().GetValue<string>(),
|
||||||
Filter = "Komprimierte SQL-Datei (*.sql.zip)|*.sql.zip",
|
Timestamp = f!["timestamp"] != null && DateTime.TryParseExact(f!["timestamp"]!.AsValue().GetValue<string>(), "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None, out var dt) ? dt : (DateTime?)null,
|
||||||
AddExtension = false,
|
ZwstId = f!["meta"]?["zwstid"]?.AsValue().GetValue<string>() ?? f!["zwstid"]?.AsValue().GetValue<string>(),
|
||||||
};
|
Device = f!["meta"]?["device"]?.AsValue().GetValue<string>(),
|
||||||
if (d.ShowDialog() == true) {
|
Url = f!["url"]!.AsValue().GetValue<string>(),
|
||||||
if (!d.FileName.EndsWith(".sql.zip")) d.FileName += ".sql.zip";
|
Size = f!["size"]!.AsValue().GetValue<long>(),
|
||||||
Mouse.OverrideCursor = Cursors.Wait;
|
})
|
||||||
await Task.Run(async () => {
|
.Where(f => f.Timestamp >= new DateTime(Utils.CurrentLastSeason, 7, 1))
|
||||||
await Database.ExportSql(d.FileName, true);
|
.ToList();
|
||||||
});
|
|
||||||
|
var imported = await ElwigData.GetImportedFiles();
|
||||||
|
var import = files
|
||||||
|
.Where(f => f.Device != Environment.MachineName && !imported.Contains(f.Name))
|
||||||
|
.ToList();
|
||||||
|
var paths = new List<string>();
|
||||||
|
using (var client = Utils.GetHttpClient(App.Config.SyncUsername, App.Config.SyncPassword)) {
|
||||||
|
foreach (var f in import) {
|
||||||
|
var filename = Path.Combine(App.TempPath, f.Name);
|
||||||
|
using var stream = new FileStream(filename, FileMode.Create);
|
||||||
|
await client.DownloadAsync(f.Url, stream);
|
||||||
|
paths.Add(filename);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
await ElwigData.Import(paths, ElwigData.ImportMode.FromBranches);
|
||||||
|
} catch (HttpRequestException exc) {
|
||||||
|
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Daten herunterladen", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
|
} catch (TaskCanceledException exc) {
|
||||||
|
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Daten herunterladen", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
} catch (Exception exc) {
|
} catch (Exception exc) {
|
||||||
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
MessageBox.Show(exc.Message, "Daten herunterladen", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
Mouse.OverrideCursor = null;
|
Mouse.OverrideCursor = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void Menu_Database_Restore_Click(object sender, RoutedEventArgs evt) {
|
private async void UploadButton_Click(object sender, RoutedEventArgs evt) {
|
||||||
|
if (App.Config.SyncUrl == null)
|
||||||
|
return;
|
||||||
|
Mouse.OverrideCursor = Cursors.Wait;
|
||||||
|
await Task.Run(async () => {
|
||||||
try {
|
try {
|
||||||
var d = new OpenFileDialog() {
|
var path = Path.Combine(App.TempPath, $"{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{App.ZwstId}.elwig.zip");
|
||||||
Title = "Datenbank wiederherstellen - Elwig",
|
using var ctx = new AppDbContext();
|
||||||
DefaultExt = "sql.zip",
|
var deliveries = await ctx.Deliveries
|
||||||
Filter = "SQLite-Datenbank (*.sqlite3, *.sqlite3.zip, *.sql, *.sql.zip)|*.sqlite3;*.sqlite3.zip;*.sql;*.sql.zip",
|
.Where(d => d.Year == Utils.CurrentLastSeason && d.ZwstId == App.ZwstId)
|
||||||
};
|
.Include(d => d.Parts)
|
||||||
if (d.ShowDialog() == true) {
|
.ThenInclude(p => p.PartModifiers)
|
||||||
var res = MessageBox.Show("Soll die Datenbank wirklich unwiederruflich durch die wiederhergestellte Version ersetzt werden?", "Datenbank wiederherstellen",
|
.Include(d => d.Parts)
|
||||||
MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
|
.ThenInclude(p => p.Kg)
|
||||||
if (res != MessageBoxResult.OK)
|
.ThenInclude(k => k!.Gl)
|
||||||
return;
|
.OrderBy(d => d.DateString)
|
||||||
|
.ThenBy(d => d.TimeString)
|
||||||
Mouse.OverrideCursor = Cursors.Wait;
|
.ThenBy(d => d.LsNr)
|
||||||
await App.ReplaceDatabase(d.FileName);
|
.AsSplitQuery()
|
||||||
|
.ToListAsync();
|
||||||
|
var wbKgs = deliveries
|
||||||
|
.SelectMany(d => d.Parts)
|
||||||
|
.Where(p => p.Kg != null)
|
||||||
|
.Select(p => p.Kg!)
|
||||||
|
.DistinctBy(k => k.KgNr)
|
||||||
|
.ToList();
|
||||||
|
if (deliveries.Count == 0) {
|
||||||
|
MessageBox.Show("Es gibt keine Lieferungen, die hochgeladen werden können!", "Lieferungen hochladen",
|
||||||
|
MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
|
} else {
|
||||||
|
await ElwigData.Export(path, deliveries, wbKgs, [$"{Utils.CurrentLastSeason}", $"Zweigstelle {App.BranchName}"]);
|
||||||
|
await Utils.UploadExportData(path, App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
|
||||||
|
MessageBox.Show($"Hochladen von {deliveries.Count:N0} Lieferungen erfolgreich!", "Lieferungen hochladen",
|
||||||
|
MessageBoxButton.OK, MessageBoxImage.Information);
|
||||||
}
|
}
|
||||||
|
} catch (HttpRequestException exc) {
|
||||||
|
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Lieferungen hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
|
} catch (TaskCanceledException exc) {
|
||||||
|
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Lieferungen hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
} catch (Exception exc) {
|
} catch (Exception exc) {
|
||||||
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
MessageBox.Show(exc.Message, "Lieferungen hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
}
|
}
|
||||||
Mouse.OverrideCursor = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void SyncButton_Click(object sender, RoutedEventArgs evt) {
|
|
||||||
if (App.Config.SyncUrl == null)
|
|
||||||
return;
|
|
||||||
Mouse.OverrideCursor = Cursors.Wait;
|
|
||||||
await Task.Run(async () => {
|
|
||||||
await SyncService.Download(App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
|
|
||||||
await SyncService.UploadModified(App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
|
|
||||||
});
|
|
||||||
Mouse.OverrideCursor = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void Menu_Sync_Download_Click(object sender, RoutedEventArgs evt) {
|
|
||||||
if (App.Config.SyncUrl == null)
|
|
||||||
return;
|
|
||||||
Mouse.OverrideCursor = Cursors.Wait;
|
|
||||||
await Task.Run(async () => {
|
|
||||||
await SyncService.Download(App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
|
|
||||||
});
|
|
||||||
Mouse.OverrideCursor = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void Menu_Sync_UploadBranchDeliveries_Click(object sender, RoutedEventArgs evt) {
|
|
||||||
if (App.Config.SyncUrl == null)
|
|
||||||
return;
|
|
||||||
Mouse.OverrideCursor = Cursors.Wait;
|
|
||||||
await Task.Run(async () => {
|
|
||||||
await SyncService.UploadBranchDeliveries(App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
|
|
||||||
});
|
|
||||||
Mouse.OverrideCursor = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void Menu_Sync_UploadModified_Click(object sender, RoutedEventArgs evt) {
|
|
||||||
if (App.Config.SyncUrl == null)
|
|
||||||
return;
|
|
||||||
Mouse.OverrideCursor = Cursors.Wait;
|
|
||||||
await Task.Run(async () => {
|
|
||||||
await SyncService.UploadModified(App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
|
|
||||||
});
|
});
|
||||||
Mouse.OverrideCursor = null;
|
Mouse.OverrideCursor = null;
|
||||||
}
|
}
|
||||||
@@ -254,23 +243,21 @@ namespace Elwig.Windows {
|
|||||||
await Task.Run(async () => {
|
await Task.Run(async () => {
|
||||||
try {
|
try {
|
||||||
var data = await Utils.GetExportMetaData(App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
|
var data = await Utils.GetExportMetaData(App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
|
||||||
var files = data
|
var file = data
|
||||||
.Select(f => new {
|
.Select(f => new {
|
||||||
Name = f!["name"]!.AsValue().GetValue<string>(),
|
Name = f!["name"]!.AsValue().GetValue<string>(),
|
||||||
Timestamp = f!["modified"] != null && DateTime.TryParseExact(f!["modified"]!.AsValue().GetValue<string>(), "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None, out var dt) ? dt : (DateTime?)null,
|
Timestamp = f!["modified"] != null && DateTime.TryParseExact(f!["modified"]!.AsValue().GetValue<string>(), "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None, out var dt) ? dt : (DateTime?)null,
|
||||||
Url = f!["url"]!.AsValue().GetValue<string>(),
|
Url = f!["url"]!.AsValue().GetValue<string>(),
|
||||||
Size = f!["size"]!.AsValue().GetValue<long>(),
|
Size = f!["size"]!.AsValue().GetValue<long>(),
|
||||||
})
|
})
|
||||||
.Where(f => f.Name.StartsWith("database.") && f.Name.EndsWith(".zip"))
|
.Where(f => f.Name == "database.sqlite3.zip")
|
||||||
.OrderBy(f => f.Size)
|
.FirstOrDefault();
|
||||||
.ToList();
|
|
||||||
|
|
||||||
if (files.Count == 0) {
|
if (file == null) {
|
||||||
MessageBox.Show("Die Datenbank wurde noch nicht vom Hauptgerät hochgeladen!", "Datenbank herunterladen",
|
MessageBox.Show("Die Datenbank wurde noch nicht vom Hauptgerät hochgeladen!", "Datenbank herunterladen",
|
||||||
MessageBoxButton.OK, MessageBoxImage.Error);
|
MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var file = files[0];
|
|
||||||
|
|
||||||
var res = MessageBox.Show($"Es wurde eine komprimierte Datenbank (ca. {file.Size / 1024 / 1024} MB) vom {file.Timestamp:dd.MM.yyyy, HH:mm} gefunden.\n\nWollen Sie wirklich die aktuelle Datenbank unwiederruflich\nlöschen und durch die gefundene ersetzen?\n\nDas kann zu Datenverlust führen!", "Datenbank herunterladen",
|
var res = MessageBox.Show($"Es wurde eine komprimierte Datenbank (ca. {file.Size / 1024 / 1024} MB) vom {file.Timestamp:dd.MM.yyyy, HH:mm} gefunden.\n\nWollen Sie wirklich die aktuelle Datenbank unwiederruflich\nlöschen und durch die gefundene ersetzen?\n\nDas kann zu Datenverlust führen!", "Datenbank herunterladen",
|
||||||
MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
|
MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
|
||||||
@@ -314,8 +301,8 @@ namespace Elwig.Windows {
|
|||||||
Mouse.OverrideCursor = Cursors.Wait;
|
Mouse.OverrideCursor = Cursors.Wait;
|
||||||
await Task.Run(async () => {
|
await Task.Run(async () => {
|
||||||
try {
|
try {
|
||||||
var path = Path.Combine(App.TempPath, "database.sql.zip");
|
var path = Path.Combine(App.TempPath, "database.sqlite3.zip");
|
||||||
await Database.ExportSql(path, true);
|
ElwigData.ExportDatabase(path);
|
||||||
await Utils.UploadExportData(path, App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
|
await Utils.UploadExportData(path, App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
|
||||||
MessageBox.Show($"Hochladen der gesamten Datenbank erfolgreich!", "Datenbank hochladen",
|
MessageBox.Show($"Hochladen der gesamten Datenbank erfolgreich!", "Datenbank hochladen",
|
||||||
MessageBoxButton.OK, MessageBoxImage.Information);
|
MessageBoxButton.OK, MessageBoxImage.Information);
|
||||||
@@ -356,42 +343,9 @@ namespace Elwig.Windows {
|
|||||||
App.FocusMailWindow();
|
App.FocusMailWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async override Task OnRenewContext(AppDbContext ctx) {
|
protected override Task OnRenewContext(AppDbContext ctx) {
|
||||||
SeasonInput_TextChanged(null, null);
|
SeasonInput_TextChanged(null, null);
|
||||||
CheckSync();
|
return Task.CompletedTask;
|
||||||
}
|
|
||||||
|
|
||||||
private void OnSyncTimer(object? sender, EventArgs? evt) {
|
|
||||||
if (Utils.HasInternetConnectivity()) {
|
|
||||||
CheckSync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnNetworkAvailabilityChanged(object? sender, NetworkAvailabilityEventArgs evt) {
|
|
||||||
if (!evt.IsAvailable) return;
|
|
||||||
if (Utils.HasInternetConnectivity()) {
|
|
||||||
CheckSync(1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void CheckSync(int delay = 0) {
|
|
||||||
if (App.Config.SyncUrl == null) return;
|
|
||||||
Utils.RunBackground("Daten Synchronisieren", async () => {
|
|
||||||
await Task.Delay(delay);
|
|
||||||
var ch = false;
|
|
||||||
using (var ctx = new AppDbContext()) {
|
|
||||||
ch = await SyncService.ChangesAvailable(ctx, App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
|
|
||||||
}
|
|
||||||
await App.MainDispatcher.BeginInvoke(() => {
|
|
||||||
if (ch) {
|
|
||||||
SyncButton_1.Text = "\uEA6A";
|
|
||||||
SyncButton_2.Text = "\uEA81";
|
|
||||||
} else {
|
|
||||||
SyncButton_1.Text = "\uE895";
|
|
||||||
SyncButton_2.Text = "";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SeasonFinish_Expanded(object sender, RoutedEventArgs evt) {
|
private void SeasonFinish_Expanded(object sender, RoutedEventArgs evt) {
|
||||||
@@ -574,7 +528,7 @@ namespace Elwig.Windows {
|
|||||||
App.HintContextChange();
|
App.HintContextChange();
|
||||||
|
|
||||||
using var ctx = new AppDbContext();
|
using var ctx = new AppDbContext();
|
||||||
var tbl = await MemberDeliveryYieldsPerVarietyData.ForSeason(ctx.MemberDeliveryPerVariantRows, year);
|
var tbl = await MemberDeliveryPerVarietyData.ForSeason(ctx.MemberDeliveryPerVariantRows, year);
|
||||||
using var ods = new OdsFile(d.FileName);
|
using var ods = new OdsFile(d.FileName);
|
||||||
await ods.AddTable(tbl);
|
await ods.AddTable(tbl);
|
||||||
} catch (Exception exc) {
|
} catch (Exception exc) {
|
||||||
|
|||||||
@@ -164,14 +164,6 @@
|
|||||||
<MenuItem x:Name="Menu_Export_UploadAll" Header="...von allen Mitgliedern hochladen"
|
<MenuItem x:Name="Menu_Export_UploadAll" Header="...von allen Mitgliedern hochladen"
|
||||||
Click="Menu_Export_UploadAll_Click"/>
|
Click="Menu_Export_UploadAll_Click"/>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="Kontakte">
|
|
||||||
<MenuItem x:Name="Menu_Contacts_Selected" Header="...von ausgewähltem Mitglied speichern..." IsEnabled="False"
|
|
||||||
Click="Menu_Contacts_Selected_Click"/>
|
|
||||||
<MenuItem x:Name="Menu_Contacts_Filters" Header="...aus Filtern speichern..."
|
|
||||||
Click="Menu_Contacts_Filters_Click"/>
|
|
||||||
<MenuItem x:Name="Menu_Contacts_All" Header="...von allen Mitgliedern speichern..."
|
|
||||||
Click="Menu_Contacts_All_Click"/>
|
|
||||||
</MenuItem>
|
|
||||||
</Menu>
|
</Menu>
|
||||||
|
|
||||||
<Grid Grid.Row="1" Margin="5,0,0,0">
|
<Grid Grid.Row="1" Margin="5,0,0,0">
|
||||||
|
|||||||
@@ -319,11 +319,9 @@ namespace Elwig.Windows {
|
|||||||
if (MemberList.SelectedItem is Member m) {
|
if (MemberList.SelectedItem is Member m) {
|
||||||
Menu_Export_ExportSelected.IsEnabled = !IsEditing && !IsCreating;
|
Menu_Export_ExportSelected.IsEnabled = !IsEditing && !IsCreating;
|
||||||
Menu_Export_UploadSelected.IsEnabled = !IsEditing && !IsCreating && App.Config.SyncUrl != null;
|
Menu_Export_UploadSelected.IsEnabled = !IsEditing && !IsCreating && App.Config.SyncUrl != null;
|
||||||
Menu_Contacts_Selected.IsEnabled = !IsEditing && !IsCreating;
|
|
||||||
} else {
|
} else {
|
||||||
Menu_Export_ExportSelected.IsEnabled = false;
|
Menu_Export_ExportSelected.IsEnabled = false;
|
||||||
Menu_Export_UploadSelected.IsEnabled = false;
|
Menu_Export_UploadSelected.IsEnabled = false;
|
||||||
Menu_Contacts_Selected.IsEnabled = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -651,13 +649,6 @@ namespace Elwig.Windows {
|
|||||||
await ViewModel.GenerateMemberList(MemberService.ExportSubject.Selected, ExportMode.Upload);
|
await ViewModel.GenerateMemberList(MemberService.ExportSubject.Selected, ExportMode.Upload);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void Menu_Contacts_All_Click(object sender, RoutedEventArgs evt) =>
|
|
||||||
await ViewModel.GenerateMemberList(MemberService.ExportSubject.All, ExportMode.Vcf);
|
|
||||||
private async void Menu_Contacts_Filters_Click(object sender, RoutedEventArgs evt) =>
|
|
||||||
await ViewModel.GenerateMemberList(MemberService.ExportSubject.FromFilters, ExportMode.Vcf);
|
|
||||||
private async void Menu_Contacts_Selected_Click(object sender, RoutedEventArgs evt) =>
|
|
||||||
await ViewModel.GenerateMemberList(MemberService.ExportSubject.Selected, ExportMode.Vcf);
|
|
||||||
|
|
||||||
private async void Menu_List_Order_Click(object sender, RoutedEventArgs evt) {
|
private async void Menu_List_Order_Click(object sender, RoutedEventArgs evt) {
|
||||||
Menu_List.IsSubmenuOpen = true;
|
Menu_List.IsSubmenuOpen = true;
|
||||||
if (sender == Menu_List_OrderMgNr) {
|
if (sender == Menu_List_OrderMgNr) {
|
||||||
|
|||||||
@@ -55,9 +55,6 @@ namespace Elwig.Windows {
|
|||||||
.OrderBy(v => v.AvNr)
|
.OrderBy(v => v.AvNr)
|
||||||
.Include(v => v.Season.Currency)
|
.Include(v => v.Season.Currency)
|
||||||
.ToListAsync());
|
.ToListAsync());
|
||||||
if (PaymentVariantList.SelectedItem == null && PaymentVariantList.Items.Count > 0) {
|
|
||||||
PaymentVariantList.SelectedIndex = PaymentVariantList.Items.Count - 1;
|
|
||||||
}
|
|
||||||
Update();
|
Update();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,11 +119,6 @@ namespace Elwig.Windows {
|
|||||||
private async void DeleteButton_Click(object sender, RoutedEventArgs evt) {
|
private async void DeleteButton_Click(object sender, RoutedEventArgs evt) {
|
||||||
if (PaymentVariantList.SelectedItem is not PaymentVar v || !v.TestVariant)
|
if (PaymentVariantList.SelectedItem is not PaymentVar v || !v.TestVariant)
|
||||||
return;
|
return;
|
||||||
var res = MessageBox.Show(
|
|
||||||
$"Soll die Auszahlungsvariante \"{v.Name}\" wirklich unwiderruflich gelöscht werden?",
|
|
||||||
"Auszahlungsvariante löschen", MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
|
|
||||||
if (res != MessageBoxResult.OK)
|
|
||||||
return;
|
|
||||||
Mouse.OverrideCursor = Cursors.Wait;
|
Mouse.OverrideCursor = Cursors.Wait;
|
||||||
try {
|
try {
|
||||||
await PaymentVariantService.DeletePaymentVariant(v.Year, v.AvNr);
|
await PaymentVariantService.DeletePaymentVariant(v.Year, v.AvNr);
|
||||||
|
|||||||
@@ -5,35 +5,27 @@
|
|||||||
Title="Datenbankabfragen - Elwig" Height="450" Width="800" MinWidth="400" MinHeight="300">
|
Title="Datenbankabfragen - Elwig" Height="450" Width="800" MinWidth="400" MinHeight="300">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="1*" MinHeight="100"/>
|
||||||
<RowDefinition Height="5"/>
|
<RowDefinition Height="5"/>
|
||||||
<RowDefinition Height="1*" MinHeight="50"/>
|
<RowDefinition Height="3*" MinHeight="100"/>
|
||||||
<RowDefinition Height="5"/>
|
|
||||||
<RowDefinition Height="1*" MinHeight="50"/>
|
|
||||||
<RowDefinition Height="5"/>
|
|
||||||
<RowDefinition Height="6*" MinHeight="100"/>
|
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<TextBox x:Name="QueryInput" Text="SELECT * FROM v_member" Grid.Row="1" Grid.RowSpan="3"
|
<TextBox x:Name="QueryInput" Text="SELECT * FROM v_delivery"
|
||||||
AcceptsReturn="True" VerticalScrollBarVisibility="Visible" TextWrapping="Wrap"
|
AcceptsReturn="True" VerticalScrollBarVisibility="Visible" TextWrapping="Wrap"
|
||||||
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10,5,120,5"
|
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10,10,120,5"
|
||||||
FontFamily="Cascadia Code Light" FontSize="13">
|
FontFamily="Cascadia Code Light" FontSize="13">
|
||||||
<TextBox.InputBindings>
|
<TextBox.InputBindings>
|
||||||
<KeyBinding Key="Return" Modifiers="Control" Command="{Binding EnterCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:QueryWindow}}}" />
|
<KeyBinding Key="Return" Modifiers="Control" Command="{Binding EnterCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:QueryWindow}}}" />
|
||||||
<KeyBinding Key="S" Modifiers="Control" Command="{Binding SaveCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:QueryWindow}}}" />
|
|
||||||
</TextBox.InputBindings>
|
</TextBox.InputBindings>
|
||||||
</TextBox>
|
</TextBox>
|
||||||
<Button x:Name="QueryButton" Content="Abfragen" Grid.Row="1"
|
<Button x:Name="QueryButton" Content="Abfragen"
|
||||||
HorizontalAlignment="Right" VerticalAlignment="Stretch" Margin="10,5,10,0"
|
HorizontalAlignment="Right" VerticalAlignment="Stretch" Margin="10,10,10,5"
|
||||||
Click="QueryButton_Click" Width="100"
|
Click="QueryButton_Click" Width="100"
|
||||||
FontSize="14"/>
|
FontSize="14"/>
|
||||||
<Button x:Name="SaveButton" Content="Speichern" Grid.Row="3"
|
|
||||||
HorizontalAlignment="Right" VerticalAlignment="Stretch" Margin="10,0,10,5"
|
|
||||||
Click="SaveButton_Click" Width="100"
|
|
||||||
FontSize="14"/>
|
|
||||||
|
|
||||||
<GridSplitter Grid.Row="4" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
|
<GridSplitter Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
|
||||||
|
|
||||||
<DataGrid x:Name="DataList" Grid.Row="5"
|
<DataGrid x:Name="DataList" Grid.Row="2"
|
||||||
AutoGenerateColumns="False" HeadersVisibility="Column" IsReadOnly="True" GridLinesVisibility="None" SelectionMode="Extended"
|
AutoGenerateColumns="False" HeadersVisibility="Column" IsReadOnly="True" GridLinesVisibility="None" SelectionMode="Extended"
|
||||||
CanUserDeleteRows="False" CanUserResizeRows="False" CanUserAddRows="False"
|
CanUserDeleteRows="False" CanUserResizeRows="False" CanUserAddRows="False"
|
||||||
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10,5,10,10"/>
|
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10,5,10,10"/>
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
using Elwig.Helpers;
|
using Elwig.Helpers;
|
||||||
using Elwig.Helpers.Export;
|
|
||||||
using Microsoft.Win32;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Data.Common;
|
using System.Data.Common;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
@@ -16,12 +13,7 @@ namespace Elwig.Windows {
|
|||||||
|
|
||||||
private ICommand? _enterCommand;
|
private ICommand? _enterCommand;
|
||||||
public ICommand EnterCommand => _enterCommand ??= new ActionCommand(async () => {
|
public ICommand EnterCommand => _enterCommand ??= new ActionCommand(async () => {
|
||||||
await DisplayQuery();
|
await ExecuteQuery();
|
||||||
});
|
|
||||||
|
|
||||||
private ICommand? _saveCommand;
|
|
||||||
public ICommand SaveCommand => _saveCommand ??= new ActionCommand(async () => {
|
|
||||||
await SaveQuery();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -30,45 +22,33 @@ namespace Elwig.Windows {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async void QueryButton_Click(object sender, RoutedEventArgs evt) {
|
private async void QueryButton_Click(object sender, RoutedEventArgs evt) {
|
||||||
await DisplayQuery();
|
await ExecuteQuery();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void SaveButton_Click(object sender, RoutedEventArgs evt) {
|
private async Task ExecuteQuery() {
|
||||||
await SaveQuery();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task DisplayQuery() {
|
|
||||||
try {
|
try {
|
||||||
Mouse.OverrideCursor = Cursors.Wait;
|
await ExecuteQuery(QueryInput.Text);
|
||||||
await DisplayQuery(QueryInput.Text);
|
|
||||||
Mouse.OverrideCursor = null;
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Mouse.OverrideCursor = null;
|
|
||||||
MessageBox.Show(e.Message, "Fehler beim Ausführen", MessageBoxButton.OK, MessageBoxImage.Error);
|
MessageBox.Show(e.Message, "Fehler beim Ausführen", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SaveQuery() {
|
private async Task ExecuteQuery(string sqlQuery) {
|
||||||
await SaveQuery(QueryInput.Text);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async Task<(IList<DbColumn>, IEnumerable<object[]>)> ExecuteQuery(string sqlQuery) {
|
|
||||||
var rows = new List<object[]>();
|
var rows = new List<object[]>();
|
||||||
using var cnx = await AppDbContext.ConnectAsync();
|
IList<DbColumn> header;
|
||||||
using var cmd = cnx.CreateCommand();
|
|
||||||
|
using (var cnx = await AppDbContext.ConnectAsync()) {
|
||||||
|
var cmd = cnx.CreateCommand();
|
||||||
cmd.CommandText = sqlQuery;
|
cmd.CommandText = sqlQuery;
|
||||||
using var reader = await cmd.ExecuteReaderAsync();
|
using var reader = await cmd.ExecuteReaderAsync();
|
||||||
var header = await reader.GetColumnSchemaAsync();
|
header = await reader.GetColumnSchemaAsync();
|
||||||
while (await reader.ReadAsync()) {
|
while (await reader.ReadAsync()) {
|
||||||
var values = new object[reader.FieldCount];
|
var values = new object[reader.FieldCount];
|
||||||
reader.GetValues(values);
|
reader.GetValues(values);
|
||||||
rows.Add(values);
|
rows.Add(values);
|
||||||
}
|
}
|
||||||
return (header, rows);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task DisplayQuery(string sqlQuery) {
|
|
||||||
var (header, rows) = await ExecuteQuery(sqlQuery);
|
|
||||||
var styleRight = new Style();
|
var styleRight = new Style();
|
||||||
styleRight.Setters.Add(new Setter(TextBlock.TextAlignmentProperty, TextAlignment.Right));
|
styleRight.Setters.Add(new Setter(TextBlock.TextAlignmentProperty, TextAlignment.Right));
|
||||||
|
|
||||||
@@ -83,27 +63,5 @@ namespace Elwig.Windows {
|
|||||||
}
|
}
|
||||||
DataList.ItemsSource = rows;
|
DataList.ItemsSource = rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task SaveQuery(string sqlQuery) {
|
|
||||||
var d = new SaveFileDialog() {
|
|
||||||
FileName = $"Abfrage.csv",
|
|
||||||
DefaultExt = "csv",
|
|
||||||
Filter = "CSV-Datei (*.csv)|*.csv",
|
|
||||||
Title = $"Datenbank Abfrage speichern unter - Elwig"
|
|
||||||
};
|
|
||||||
if (d.ShowDialog() == true) {
|
|
||||||
Mouse.OverrideCursor = Cursors.Wait;
|
|
||||||
await Task.Run(async () => {
|
|
||||||
try {
|
|
||||||
var (header, rows) = await ExecuteQuery(sqlQuery);
|
|
||||||
using var csv = new CsvSimple(d.FileName, ';', Utils.UTF8BOM);
|
|
||||||
await csv.ExportAsync(rows.Prepend([.. header.Select(h => h.ColumnName)]));
|
|
||||||
} catch (Exception exc) {
|
|
||||||
MessageBox.Show(exc.Message, "Fehler beim Ausführen", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Mouse.OverrideCursor = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
40
README.md
40
README.md
@@ -5,43 +5,3 @@ Elwig
|
|||||||
**El**ektronische **Wi**nzer**g**enossenschaftsverwaltung (Electronic Management for Vintners' Cooperatives).
|
**El**ektronische **Wi**nzer**g**enossenschaftsverwaltung (Electronic Management for Vintners' Cooperatives).
|
||||||
|
|
||||||
Further information may be found on [the website](https://elwig.at).
|
Further information may be found on [the website](https://elwig.at).
|
||||||
|
|
||||||
|
|
||||||
About
|
|
||||||
=====
|
|
||||||
|
|
||||||
**Product:** Elwig
|
|
||||||
**Description:** Electronic Management for Vintners' Cooperatives
|
|
||||||
**Type:** ERP system
|
|
||||||
**Version:** 1.0.3.0 ([Changelog](./CHANGELOG.md))
|
|
||||||
**License:** [GNU General Public License 3.0 (GPLv3)](./LICENSE)
|
|
||||||
**Website:** https://elwig.at/
|
|
||||||
**Source code:** https://git.necronda.net/winzer/elwig
|
|
||||||
**Developement period:** 2022–2025
|
|
||||||
|
|
||||||
**Technology Stack:**
|
|
||||||
Language: C#
|
|
||||||
Framework: Windows Presentation Framework (WPF)
|
|
||||||
Database: [SQLite](https://sqlite.org/)
|
|
||||||
PDF creation: [WeasyPrint](https://weasyprint.org/), [RazorLight](https://github.com/toddams/RazorLight), [PdfiumViewer](https://github.com/pvginkel/PdfiumViewer)
|
|
||||||
Packaging: [WiX Toolset](https://www.firegiant.com/wixtoolset/)
|
|
||||||
|
|
||||||
|
|
||||||
Über
|
|
||||||
====
|
|
||||||
|
|
||||||
**Produkt:** Elwig
|
|
||||||
**Beschreibung:** Elektronische Winzergenossenschaftsverwaltung
|
|
||||||
**Typ:** Warenwirtschaftssystem (ERP-System)
|
|
||||||
**Version:** 1.0.3.0 ([Änderungsprotokoll](./CHANGELOG.md))
|
|
||||||
**Lizenz:** [GNU General Public License 3.0 (GPLv3)](./LICENSE)
|
|
||||||
**Website:** https://elwig.at/
|
|
||||||
**Quellcode:** https://git.necronda.net/winzer/elwig
|
|
||||||
**Entwicklungszeitraum:** 2022–2025
|
|
||||||
|
|
||||||
**Verwendete Technologien:**
|
|
||||||
Programmiersprache: C#
|
|
||||||
Framework: Windows Presentation Framework (WPF)
|
|
||||||
Datenbank: [SQLite](https://sqlite.org/)
|
|
||||||
PDF-Erstellung: [WeasyPrint](https://weasyprint.org/), [RazorLight](https://github.com/toddams/RazorLight), [PdfiumViewer](https://github.com/pvginkel/PdfiumViewer)
|
|
||||||
Paketierung: [WiX Toolset](https://www.firegiant.com/wixtoolset/)
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
</Target>
|
</Target>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Installer\Installer.wixproj" />
|
<ProjectReference Include="..\Installer\Installer.wixproj" />
|
||||||
<PackageReference Include="WixToolset.Bal.wixext" Version="6.0.2" />
|
<PackageReference Include="WixToolset.Bal.wixext" Version="6.0.1" />
|
||||||
<PackageReference Include="WixToolset.Util.wixext" Version="6.0.2" />
|
<PackageReference Include="WixToolset.Util.wixext" Version="6.0.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
@@ -14,8 +14,8 @@ namespace Tests {
|
|||||||
public async Task Setup_1_Database() {
|
public async Task Setup_1_Database() {
|
||||||
AppDbContext.ConnectionStringOverride = $"Data Source=ElwigTestDB; Mode=Memory; Foreign Keys=True; Cache=Shared";
|
AppDbContext.ConnectionStringOverride = $"Data Source=ElwigTestDB; Mode=Memory; Foreign Keys=True; Cache=Shared";
|
||||||
Connection = await AppDbContext.ConnectAsync();
|
Connection = await AppDbContext.ConnectAsync();
|
||||||
await Connection.ExecuteEmbeddedScript(Assembly.GetExecutingAssembly(), "Tests.Resources.Sql.Create.sql");
|
await AppDbContext.ExecuteEmbeddedScript(Connection, Assembly.GetExecutingAssembly(), "Tests.Resources.Sql.Create.sql");
|
||||||
await Connection.ExecuteEmbeddedScript(Assembly.GetExecutingAssembly(), "Tests.Resources.Sql.Insert.sql");
|
await AppDbContext.ExecuteEmbeddedScript(Connection, Assembly.GetExecutingAssembly(), "Tests.Resources.Sql.Insert.sql");
|
||||||
}
|
}
|
||||||
|
|
||||||
[OneTimeSetUp]
|
[OneTimeSetUp]
|
||||||
|
|||||||
@@ -16,9 +16,9 @@ namespace Tests.E2ETests {
|
|||||||
public static async Task SetupDatabase() {
|
public static async Task SetupDatabase() {
|
||||||
if (File.Exists(Utils.TestDatabasePath)) File.Delete(Utils.TestDatabasePath);
|
if (File.Exists(Utils.TestDatabasePath)) File.Delete(Utils.TestDatabasePath);
|
||||||
using var cnx = await AppDbContext.ConnectAsync($"Data Source=\"{Utils.TestDatabasePath}\"; Mode=ReadWriteCreate; Foreign Keys=True; Cache=Default; Pooling=False");
|
using var cnx = await AppDbContext.ConnectAsync($"Data Source=\"{Utils.TestDatabasePath}\"; Mode=ReadWriteCreate; Foreign Keys=True; Cache=Default; Pooling=False");
|
||||||
await cnx.ExecuteEmbeddedScript(Assembly.GetExecutingAssembly(), "Tests.Resources.Sql.Create.sql");
|
await AppDbContext.ExecuteEmbeddedScript(cnx, Assembly.GetExecutingAssembly(), "Tests.Resources.Sql.Create.sql");
|
||||||
await cnx.ExecuteEmbeddedScript(Assembly.GetExecutingAssembly(), "Tests.Resources.Sql.Insert.sql");
|
await AppDbContext.ExecuteEmbeddedScript(cnx, Assembly.GetExecutingAssembly(), "Tests.Resources.Sql.Insert.sql");
|
||||||
await cnx.ExecuteEmbeddedScript(Assembly.GetExecutingAssembly(), "Tests.Resources.Sql.E2EInsert.sql");
|
await AppDbContext.ExecuteEmbeddedScript(cnx, Assembly.GetExecutingAssembly(), "Tests.Resources.Sql.E2EInsert.sql");
|
||||||
}
|
}
|
||||||
|
|
||||||
[OneTimeTearDown]
|
[OneTimeTearDown]
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ namespace Tests.E2ETests {
|
|||||||
|
|
||||||
public const int WINDOW_OPEN_SLEEP = 2000;
|
public const int WINDOW_OPEN_SLEEP = 2000;
|
||||||
|
|
||||||
public static readonly string ApplicationPath = Path.GetFullPath(@"..\..\..\..\Elwig\bin\Debug\net10.0-windows\Elwig.exe");
|
public static readonly string ApplicationPath = Path.GetFullPath(@"..\..\..\..\Elwig\bin\Debug\net8.0-windows\Elwig.exe");
|
||||||
public static readonly string ConfigPath = Path.GetFullPath(@"..\..\..\..\Tests\config.test.ini");
|
public static readonly string ConfigPath = Path.GetFullPath(@"..\..\..\..\Tests\config.test.ini");
|
||||||
public static readonly string TestDatabasePath = Path.GetFullPath(@"..\..\..\..\Tests\ElwigTestDB.sqlite3");
|
public static readonly string TestDatabasePath = Path.GetFullPath(@"..\..\..\..\Tests\ElwigTestDB.sqlite3");
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net10.0-windows</TargetFramework>
|
<TargetFramework>net8.0-windows</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
@@ -19,12 +19,12 @@
|
|||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
||||||
<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.4.0" />
|
<PackageReference Include="NUnit" Version="4.4.0" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="6.1.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="5.1.0" />
|
||||||
<PackageReference Include="NUnit.Analyzers" Version="4.11.2">
|
<PackageReference Include="NUnit.Analyzers" Version="4.10.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>
|
||||||
|
|||||||
@@ -12,13 +12,13 @@ namespace Tests.UnitTests.DocumentTests {
|
|||||||
[OneTimeSetUp]
|
[OneTimeSetUp]
|
||||||
public async Task SetupDatabase() {
|
public async Task SetupDatabase() {
|
||||||
Connection = await AppDbContext.ConnectAsync();
|
Connection = await AppDbContext.ConnectAsync();
|
||||||
await Connection.ExecuteEmbeddedScript(Assembly.GetExecutingAssembly(), "Tests.Resources.Sql.DocumentInsert.sql");
|
await AppDbContext.ExecuteEmbeddedScript(Connection, Assembly.GetExecutingAssembly(), "Tests.Resources.Sql.DocumentInsert.sql");
|
||||||
}
|
}
|
||||||
|
|
||||||
[OneTimeTearDown]
|
[OneTimeTearDown]
|
||||||
public async Task TeardownDatabase() {
|
public async Task TeardownDatabase() {
|
||||||
if (Connection == null) return;
|
if (Connection == null) return;
|
||||||
await Connection.ExecuteEmbeddedScript(Assembly.GetExecutingAssembly(), "Tests.Resources.Sql.DocumentDelete.sql");
|
await AppDbContext.ExecuteEmbeddedScript(Connection, Assembly.GetExecutingAssembly(), "Tests.Resources.Sql.DocumentDelete.sql");
|
||||||
await Connection.DisposeAsync();
|
await Connection.DisposeAsync();
|
||||||
Connection = null;
|
Connection = null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,13 +24,13 @@ namespace Tests.UnitTests.HelperTests {
|
|||||||
[OneTimeSetUp]
|
[OneTimeSetUp]
|
||||||
public async Task SetupDatabase() {
|
public async Task SetupDatabase() {
|
||||||
Connection = await AppDbContext.ConnectAsync();
|
Connection = await AppDbContext.ConnectAsync();
|
||||||
await Connection.ExecuteEmbeddedScript(Assembly.GetExecutingAssembly(), "Tests.Resources.Sql.BillingInsert.sql");
|
await AppDbContext.ExecuteEmbeddedScript(Connection, Assembly.GetExecutingAssembly(), "Tests.Resources.Sql.BillingInsert.sql");
|
||||||
}
|
}
|
||||||
|
|
||||||
[OneTimeTearDown]
|
[OneTimeTearDown]
|
||||||
public async Task TeardownDatabase() {
|
public async Task TeardownDatabase() {
|
||||||
if (Connection == null) return;
|
if (Connection == null) return;
|
||||||
await Connection.ExecuteEmbeddedScript(Assembly.GetExecutingAssembly(), "Tests.Resources.Sql.BillingDelete.sql");
|
await AppDbContext.ExecuteEmbeddedScript(Connection, Assembly.GetExecutingAssembly(), "Tests.Resources.Sql.BillingDelete.sql");
|
||||||
await Connection.DisposeAsync();
|
await Connection.DisposeAsync();
|
||||||
Connection = null;
|
Connection = null;
|
||||||
}
|
}
|
||||||
@@ -72,7 +72,7 @@ namespace Tests.UnitTests.HelperTests {
|
|||||||
[TearDown]
|
[TearDown]
|
||||||
public async Task CleanupDatabasePayment() {
|
public async Task CleanupDatabasePayment() {
|
||||||
if (Connection == null) return;
|
if (Connection == null) return;
|
||||||
await Connection.ExecuteBatch("""
|
await AppDbContext.ExecuteBatch(Connection, """
|
||||||
DELETE FROM credit;
|
DELETE FROM credit;
|
||||||
DELETE FROM payment_variant;
|
DELETE FROM payment_variant;
|
||||||
DELETE FROM delivery_part_bucket;
|
DELETE FROM delivery_part_bucket;
|
||||||
@@ -115,7 +115,7 @@ namespace Tests.UnitTests.HelperTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Task InsertPaymentVariant(int year, int avnr, string data) {
|
private Task InsertPaymentVariant(int year, int avnr, string data) {
|
||||||
return Connection!.ExecuteBatch($"""
|
return AppDbContext.ExecuteBatch(Connection!, $"""
|
||||||
INSERT INTO payment_variant (year, avnr, name, date, transfer_date, test_variant, calc_time, data)
|
INSERT INTO payment_variant (year, avnr, name, date, transfer_date, test_variant, calc_time, data)
|
||||||
VALUES ({year}, {avnr}, 'Test', '2021-01-15', NULL, TRUE, NULL, '{data}');
|
VALUES ({year}, {avnr}, 'Test', '2021-01-15', NULL, TRUE, NULL, '{data}');
|
||||||
""");
|
""");
|
||||||
@@ -188,7 +188,7 @@ namespace Tests.UnitTests.HelperTests {
|
|||||||
Assert.That(payment["GV"], Is.EqualTo(10_000));
|
Assert.That(payment["GV"], Is.EqualTo(10_000));
|
||||||
});
|
});
|
||||||
|
|
||||||
await b.Calculate(true, false, false, false);
|
await b.Calculate(false, false, false);
|
||||||
var prices = await GetMemberDeliveryPrices(year, mgnr);
|
var prices = await GetMemberDeliveryPrices(year, mgnr);
|
||||||
Assert.Multiple(() => {
|
Assert.Multiple(() => {
|
||||||
Assert.That(prices, Has.Count.EqualTo(7));
|
Assert.That(prices, Has.Count.EqualTo(7));
|
||||||
@@ -234,7 +234,7 @@ namespace Tests.UnitTests.HelperTests {
|
|||||||
Assert.That(payment["GV"], Is.EqualTo(8_000));
|
Assert.That(payment["GV"], Is.EqualTo(8_000));
|
||||||
});
|
});
|
||||||
|
|
||||||
await b.Calculate(true, true, false, false);
|
await b.Calculate(true, false, false);
|
||||||
var prices = await GetMemberDeliveryPrices(year, mgnr);
|
var prices = await GetMemberDeliveryPrices(year, mgnr);
|
||||||
Assert.Multiple(() => {
|
Assert.Multiple(() => {
|
||||||
Assert.That(prices, Has.Count.EqualTo(6));
|
Assert.That(prices, Has.Count.EqualTo(6));
|
||||||
|
|||||||
@@ -11,13 +11,13 @@ namespace Tests.UnitTests.ServiceTests {
|
|||||||
[OneTimeSetUp]
|
[OneTimeSetUp]
|
||||||
public async Task SetupDatabase() {
|
public async Task SetupDatabase() {
|
||||||
Connection = await AppDbContext.ConnectAsync();
|
Connection = await AppDbContext.ConnectAsync();
|
||||||
await Connection.ExecuteEmbeddedScript(Assembly.GetExecutingAssembly(), "Tests.Resources.Sql.ServiceInsert.sql");
|
await AppDbContext.ExecuteEmbeddedScript(Connection, Assembly.GetExecutingAssembly(), "Tests.Resources.Sql.ServiceInsert.sql");
|
||||||
}
|
}
|
||||||
|
|
||||||
[OneTimeTearDown]
|
[OneTimeTearDown]
|
||||||
public async Task TeardownDatabase() {
|
public async Task TeardownDatabase() {
|
||||||
if (Connection == null) return;
|
if (Connection == null) return;
|
||||||
await Connection.ExecuteEmbeddedScript(Assembly.GetExecutingAssembly(), "Tests.Resources.Sql.ServiceDelete.sql");
|
await AppDbContext.ExecuteEmbeddedScript(Connection, Assembly.GetExecutingAssembly(), "Tests.Resources.Sql.ServiceDelete.sql");
|
||||||
await Connection.DisposeAsync();
|
await Connection.DisposeAsync();
|
||||||
Connection = null;
|
Connection = null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ namespace Tests.UnitTests.WeighingTests {
|
|||||||
public void Test_03_Moving() {
|
public void Test_03_Moving() {
|
||||||
Mock.Weight = 1_000;
|
Mock.Weight = 1_000;
|
||||||
Mock.Error = "moving";
|
Mock.Error = "moving";
|
||||||
var ex = Assert.ThrowsAsync<WeighingException>(async () => await Scale!.Weigh());
|
IOException ex = Assert.ThrowsAsync<IOException>(async () => await Scale!.Weigh());
|
||||||
Assert.That(ex.Message, Contains.Substring("Waage in Bewegung"));
|
Assert.That(ex.Message, Contains.Substring("Waage in Bewegung"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@ namespace Tests.UnitTests.WeighingTests {
|
|||||||
public void Test_04_Overloaded() {
|
public void Test_04_Overloaded() {
|
||||||
Mock.Weight = 10_000;
|
Mock.Weight = 10_000;
|
||||||
Mock.Error = "overloaded";
|
Mock.Error = "overloaded";
|
||||||
var ex = Assert.ThrowsAsync<WeighingException>(async () => await Scale!.Weigh());
|
IOException ex = Assert.ThrowsAsync<IOException>(async () => await Scale!.Weigh());
|
||||||
Assert.That(ex.Message, Contains.Substring("Waage in Überlast"));
|
Assert.That(ex.Message, Contains.Substring("Waage in Überlast"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,14 +87,14 @@ namespace Tests.UnitTests.WeighingTests {
|
|||||||
public void Test_05_InvalidResponse() {
|
public void Test_05_InvalidResponse() {
|
||||||
Mock.Weight = 1_000;
|
Mock.Weight = 1_000;
|
||||||
Mock.Error = "invalid";
|
Mock.Error = "invalid";
|
||||||
Assert.ThrowsAsync<FormatException>(async () => await Scale!.Weigh());
|
Assert.ThrowsAsync<IOException>(async () => await Scale!.Weigh());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void Test_06_InvalidCrc() {
|
public void Test_06_InvalidCrc() {
|
||||||
Mock.Weight = 1_000;
|
Mock.Weight = 1_000;
|
||||||
Mock.Error = "crc";
|
Mock.Error = "crc";
|
||||||
var ex = Assert.ThrowsAsync<WeighingException>(async () => await Scale!.Weigh());
|
IOException ex = Assert.ThrowsAsync<IOException>(async () => await Scale!.Weigh());
|
||||||
Assert.That(ex.Message, Contains.Substring("Invalid CRC16 checksum"));
|
Assert.That(ex.Message, Contains.Substring("Invalid CRC16 checksum"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,7 +102,7 @@ namespace Tests.UnitTests.WeighingTests {
|
|||||||
public void Test_07_InvalidUnit() {
|
public void Test_07_InvalidUnit() {
|
||||||
Mock.Weight = 1_000;
|
Mock.Weight = 1_000;
|
||||||
Mock.Error = "unit";
|
Mock.Error = "unit";
|
||||||
var ex = Assert.ThrowsAsync<WeighingException>(async () => await Scale!.Weigh());
|
IOException ex = Assert.ThrowsAsync<IOException>(async () => await Scale!.Weigh());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ namespace Tests.UnitTests.WeighingTests {
|
|||||||
Mock.Weight = 1_000;
|
Mock.Weight = 1_000;
|
||||||
Mock.Tare = 41;
|
Mock.Tare = 41;
|
||||||
Mock.Error = "moving";
|
Mock.Error = "moving";
|
||||||
var ex = Assert.ThrowsAsync<WeighingException>(async () => await Scale!.Weigh());
|
IOException ex = Assert.ThrowsAsync<IOException>(async () => await Scale!.Weigh());
|
||||||
Assert.That(ex.Message, Contains.Substring("Waage in Bewegung"));
|
Assert.That(ex.Message, Contains.Substring("Waage in Bewegung"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,7 +109,7 @@ namespace Tests.UnitTests.WeighingTests {
|
|||||||
Mock.Weight = 1_000;
|
Mock.Weight = 1_000;
|
||||||
Mock.Tare = 41;
|
Mock.Tare = 41;
|
||||||
Mock.Error = "invalid";
|
Mock.Error = "invalid";
|
||||||
Assert.ThrowsAsync<FormatException>(async () => await Scale!.Weigh());
|
Assert.ThrowsAsync<IOException>(async () => await Scale!.Weigh());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ namespace Tests.UnitTests.WeighingTests {
|
|||||||
public void Test_03_Moving() {
|
public void Test_03_Moving() {
|
||||||
Mock.Weight = 1_000;
|
Mock.Weight = 1_000;
|
||||||
Mock.Error = "moving";
|
Mock.Error = "moving";
|
||||||
var ex = Assert.ThrowsAsync<WeighingException>(async () => await Scale!.Weigh());
|
IOException ex = Assert.ThrowsAsync<IOException>(async () => await Scale!.Weigh());
|
||||||
Assert.That(ex.Message, Contains.Substring("Waage in Bewegung"));
|
Assert.That(ex.Message, Contains.Substring("Waage in Bewegung"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@ namespace Tests.UnitTests.WeighingTests {
|
|||||||
public void Test_04_Overloaded() {
|
public void Test_04_Overloaded() {
|
||||||
Mock.Weight = 10_000;
|
Mock.Weight = 10_000;
|
||||||
Mock.Error = "overloaded";
|
Mock.Error = "overloaded";
|
||||||
var ex = Assert.ThrowsAsync<WeighingException>(async () => await Scale!.Weigh());
|
IOException ex = Assert.ThrowsAsync<IOException>(async () => await Scale!.Weigh());
|
||||||
Assert.That(ex.Message, Contains.Substring("Waage in Überlast"));
|
Assert.That(ex.Message, Contains.Substring("Waage in Überlast"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,14 +87,14 @@ namespace Tests.UnitTests.WeighingTests {
|
|||||||
public void Test_05_InvalidResponse() {
|
public void Test_05_InvalidResponse() {
|
||||||
Mock.Weight = 1_000;
|
Mock.Weight = 1_000;
|
||||||
Mock.Error = "invalid";
|
Mock.Error = "invalid";
|
||||||
Assert.ThrowsAsync<FormatException>(async () => await Scale!.Weigh());
|
Assert.ThrowsAsync<IOException>(async () => await Scale!.Weigh());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void Test_06_InvalidCrc() {
|
public void Test_06_InvalidCrc() {
|
||||||
Mock.Weight = 1_000;
|
Mock.Weight = 1_000;
|
||||||
Mock.Error = "crc";
|
Mock.Error = "crc";
|
||||||
var ex = Assert.ThrowsAsync<WeighingException>(async () => await Scale!.Weigh());
|
IOException ex = Assert.ThrowsAsync<IOException>(async () => await Scale!.Weigh());
|
||||||
Assert.That(ex.Message, Contains.Substring("Invalid CRC16 checksum"));
|
Assert.That(ex.Message, Contains.Substring("Invalid CRC16 checksum"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,7 +102,7 @@ namespace Tests.UnitTests.WeighingTests {
|
|||||||
public void Test_07_InvalidUnit() {
|
public void Test_07_InvalidUnit() {
|
||||||
Mock.Weight = 1_000;
|
Mock.Weight = 1_000;
|
||||||
Mock.Error = "unit";
|
Mock.Error = "unit";
|
||||||
var ex = Assert.ThrowsAsync<WeighingException>(async () => await Scale!.Weigh());
|
IOException ex = Assert.ThrowsAsync<IOException>(async () => await Scale!.Weigh());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ namespace Tests.UnitTests.WeighingTests {
|
|||||||
Mock.Weight = 1_000;
|
Mock.Weight = 1_000;
|
||||||
Mock.Tare = 41;
|
Mock.Tare = 41;
|
||||||
Mock.Error = "moving";
|
Mock.Error = "moving";
|
||||||
var ex = Assert.ThrowsAsync<WeighingException>(async () => await Scale!.Weigh());
|
IOException ex = Assert.ThrowsAsync<IOException>(async () => await Scale!.Weigh());
|
||||||
Assert.That(ex.Message, Contains.Substring("Waage in Bewegung"));
|
Assert.That(ex.Message, Contains.Substring("Waage in Bewegung"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,7 +109,7 @@ namespace Tests.UnitTests.WeighingTests {
|
|||||||
Mock.Weight = 1_000;
|
Mock.Weight = 1_000;
|
||||||
Mock.Tare = 41;
|
Mock.Tare = 41;
|
||||||
Mock.Error = "invalid";
|
Mock.Error = "invalid";
|
||||||
Assert.ThrowsAsync<FormatException>(async () => await Scale!.Weigh());
|
Assert.ThrowsAsync<IOException>(async () => await Scale!.Weigh());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ namespace Tests.UnitTests.WeighingTests {
|
|||||||
public void Test_03_Moving() {
|
public void Test_03_Moving() {
|
||||||
MockA.Weight = 1_000;
|
MockA.Weight = 1_000;
|
||||||
MockA.Error = "moving";
|
MockA.Error = "moving";
|
||||||
var ex = Assert.ThrowsAsync<WeighingException>(async () => await ScaleA!.Weigh());
|
IOException ex = Assert.ThrowsAsync<IOException>(async () => await ScaleA!.Weigh());
|
||||||
Assert.That(ex.Message, Contains.Substring("Waage in Bewegung"));
|
Assert.That(ex.Message, Contains.Substring("Waage in Bewegung"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,7 +99,7 @@ namespace Tests.UnitTests.WeighingTests {
|
|||||||
public void Test_04_Overloaded() {
|
public void Test_04_Overloaded() {
|
||||||
MockA.Weight = 10_000;
|
MockA.Weight = 10_000;
|
||||||
MockA.Error = "overloaded";
|
MockA.Error = "overloaded";
|
||||||
var ex = Assert.ThrowsAsync<WeighingException>(async () => await ScaleA!.Weigh());
|
IOException ex = Assert.ThrowsAsync<IOException>(async () => await ScaleA!.Weigh());
|
||||||
Assert.That(ex.Message, Contains.Substring("Waage in Überlast"));
|
Assert.That(ex.Message, Contains.Substring("Waage in Überlast"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,14 +107,14 @@ namespace Tests.UnitTests.WeighingTests {
|
|||||||
public void Test_05_InvalidResponse() {
|
public void Test_05_InvalidResponse() {
|
||||||
MockA.Weight = 1_000;
|
MockA.Weight = 1_000;
|
||||||
MockA.Error = "invalid";
|
MockA.Error = "invalid";
|
||||||
Assert.ThrowsAsync<FormatException>(async () => await ScaleA!.Weigh());
|
Assert.ThrowsAsync<IOException>(async () => await ScaleA!.Weigh());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void Test_06_InvalidCrc() {
|
public void Test_06_InvalidCrc() {
|
||||||
MockA.Weight = 1_000;
|
MockA.Weight = 1_000;
|
||||||
MockA.Error = "crc";
|
MockA.Error = "crc";
|
||||||
var ex = Assert.ThrowsAsync<WeighingException>(async () => await ScaleA!.Weigh());
|
IOException ex = Assert.ThrowsAsync<IOException>(async () => await ScaleA!.Weigh());
|
||||||
Assert.That(ex.Message, Contains.Substring("Invalid CRC16 checksum"));
|
Assert.That(ex.Message, Contains.Substring("Invalid CRC16 checksum"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,7 +122,7 @@ namespace Tests.UnitTests.WeighingTests {
|
|||||||
public void Test_07_InvalidUnit() {
|
public void Test_07_InvalidUnit() {
|
||||||
MockA.Weight = 1_000;
|
MockA.Weight = 1_000;
|
||||||
MockA.Error = "unit";
|
MockA.Error = "unit";
|
||||||
var ex = Assert.ThrowsAsync<WeighingException>(async () => await ScaleA!.Weigh());
|
IOException ex = Assert.ThrowsAsync<IOException>(async () => await ScaleA!.Weigh());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
curl --fail -s -L "https://elwig.at/files/create.sql?v=36" -u "elwig:ganzGeheim123!" -o "Resources\Sql\Create.sql"
|
curl --fail -s -L "https://elwig.at/files/create.sql?v=32" -u "elwig:ganzGeheim123!" -o "Resources\Sql\Create.sql"
|
||||||
|
|||||||
Reference in New Issue
Block a user