Compare commits

..
1 Commits
Author SHA1 Message Date
thomas.hilscher 70e1e7c73a Add automatic database backups
Test / Run tests (push) Successful in 2m46s
2026-08-24 20:52:50 +02:00
112 changed files with 1320 additions and 5990 deletions

No files matched your search

-80
View File
@@ -2,86 +2,6 @@
Changelog
=========
[v1.1.2.2][v1.1.2.2] (2026-09-14) {#v1.1.2.2}
---------------------------------------------
### Neue Funktionen {#v1.1.2.2-features}
* Bei einigen Fenstern werden in den Titeln nun die aktiven Filter der Suche angezeigt. (fea779bd95)
* Im Lieferungen-Fenster (`DeliveryAdminWindow`) ist es nun möglich die Tara nachträglich zu korrigieren. (8ba051198f, 6436762e8d)
### Behobene Fehler {#v1.1.2.2-bugfixes}
* Bei Lieferscheinen (`DeliveryNote`) hat bei Anmerkungen zu Teil-Lfrg. ein `:` gefehlt.
Außerdem wurden Seitenumbrüche so platziert, dass sie nicht mehr innerhalb einer Teil-Lfrg. liegen. (e66780ccd0, f4cc443521)
### Sonstiges {#v1.1.2.2-misc}
* Bei Datenbank-Fehler sind die Fehlermeldungen nun genauer bzw. auf deutsch übersetzt. (cc01f92005)
* Im Mitglieder-Fenster (`MemberAdminWindow`) wurden Überschriften und Tooltips leicht angepasst. (6441fa4f50)
* Abhängigkeiten aktualisiert. (4cc33b56c8, 6bed370eba)
[v1.1.2.2]: https://git.necronda.net/winzer/elwig/releases/tag/v1.1.2.2
[v1.1.2.1][v1.1.2.1] (2026-08-27) {#v1.1.2.1}
---------------------------------------------
### Behobene Fehler {#v1.1.2.1-bugfixes}
* Im Anmeldungen-Fenster (`DeliveryAncmtAdminWindow`) und im Leseplanung-Fenster (`DeliveryScheduleAdminWindow`) kam es seit [v1.1.1.2](#v1.1.1.2) (2026-08-25) zu einem Absturz. (f0745eae4e)
### Sonstiges {#v1.1.2.1-misc}
* Bei E-Mails wird ab jetzt auch Datum und Uhrzeit gesetzt. (848a6d1ce0)
[v1.1.2.1]: https://git.necronda.net/winzer/elwig/releases/tag/v1.1.2.1
[v1.1.2.0][v1.1.2.0] (2026-08-26) {#v1.1.2.0}
---------------------------------------------
### Neue Funktionen {#v1.1.2.0-features}
* Eine Automatische Backup-/Sicherungs-Funktion für die Datenbank wurde hinzugefügt. (ca5b719630, cadac4302d)
### Behobene Fehler {#v1.1.2.0-bugfixes}
* Wenn am heutigen Tag noch keine Lieferung übernommen wurde, wurden im Lieferungen-/Übernahme-Fenster (`DeliveryAdminWindow`) mit dem Filter "Nur heute" auch Lieferungen des vorhergehenden Tages angezeigt. (c1690bf104)
### Sonstiges {#v1.1.2.0-misc}
* Abhängigkeiten aktualisiert. (2360402124, 7add96dfd5)
[v1.1.2.0]: https://git.necronda.net/winzer/elwig/releases/tag/v1.1.2.0
[v1.1.1.2][v1.1.1.2] (2026-08-25) {#v1.1.1.2}
---------------------------------------------
### Behobene Fehler {#v1.1.1.2-bugfixes}
* Auf Lieferscheinen (`DeliveryNote`) waren die Mengenangaben nicht rechtsbündig. (ff71e9fb7f)
* Beim Importieren von Mitgliedern mit Stamm-KG ohne Großlage kam es zu einem Fehler, obwohl die Großlage automatisch hätte zugewiesen werden müssen. (edf3678154)
### Sonstiges {#v1.1.1.2-misc}
* In Matzen werden für Planenw./Kipper und Lesewagen die Klassen automatisch gesetzt. (3366cc25eb)
* Im Lieferungen-Fenster (`DeliveryAdminWindow`) wird für "Nur heute" nicht mehr nur das Datum, sondern die letzten zusammenhängenden Lieferungen verwendet. (46e596ae23)
* Für Pamhagen wird als standard Wiege-Methode "brutto" verwendet. (0c4611024f)
* Für Waagen kann das automatische setzen von Datum und Uhrzeit nun per Opt-out ausgeschalten werden (Konfigurationsdatei -> `[scale.X]` -> `synctime = false`). (f450dc35b1)
[v1.1.1.2]: https://git.necronda.net/winzer/elwig/releases/tag/v1.1.1.2
[v1.1.1.1][v1.1.1.1] (2026-08-24) {#v1.1.1.1}
---------------------------------------------
+2 -1
View File
@@ -2,7 +2,8 @@
x:Class="Elwig.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ctrl="clr-namespace:Elwig.Controls">
xmlns:ctrl="clr-namespace:Elwig.Controls"
Exit="Application_Exit">
<Application.Resources>
<ctrl:BoolToStringConverter x:Key="BoolToStarConverter" FalseValue="" TrueValue="*"/>
<ctrl:WidthToMarginConverter x:Key="WidthToMarginConverter"/>
+36 -56
View File
@@ -18,18 +18,18 @@ using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Threading;
namespace Elwig {
public partial class App : Application {
public static App CurrentApp;
protected static App CurrentApp;
public static int NumWindows => CurrentApp.Windows.Count;
public static bool ForceShutdown { get; set; } = false;
public static bool ForceShutdown { get; private set; } = false;
private readonly DispatcherTimer _autoUpdateTimer = new() { Interval = TimeSpan.FromHours(1) };
private readonly DispatcherTimer _autoBackupTimer = new() { Interval = TimeSpan.FromMinutes(10) };
private readonly DispatcherTimer _autoBackupTimer = new() { Interval = TimeSpan.FromHours(1) };
private DatabaseBackupService? _databaseBackupService;
public readonly SerialPortWatcher SerialPortWatcher = new();
public static readonly string DataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Elwig");
@@ -76,7 +76,7 @@ namespace Elwig {
Config = new(Path.GetFullPath(args[1]));
}
ContextTimer.Tick += (sender, evt) => {
ContextTimer.Tick += (object? sender, EventArgs evt) => {
var ch = CurrentLastWrite;
if (ch > LastChanged) {
LastChanged = ch;
@@ -94,33 +94,35 @@ namespace Elwig {
try {
await AppDbUpdater.CheckDb();
} catch (FileNotFoundException exc) {
InteractionService.ShowException("Datenbank nicht gefunden", "Die Datenbank konnte nicht gefunden werden", exc);
} catch (Exception exc) {
if (Config.UpdateUrl != null && Utils.HasInternetConnectivity()) {
await CheckForUpdates();
}
InteractionService.ShowException("Fehlerhafte Datenbank", "Schwerwiegender Fehler in der Datenbank, unbedingt den Programmierern melden!", exc);
if (InteractionService.AskQuestion("Backup wiederherstellen", "Soll die Datenbank aus einem Backup wiederhergestellt werden?\n\nAchtung: Das kann zu Datenverlust führen!", false))
await BackupService.RestoreDatabase();
ShutdownNow();
InteractionService.ShowException("Fehlerhafte Datenbank", "Fehlerhafte Datenbank", exc);
Shutdown();
return;
}
if (Config.DatabaseBackup) {
_databaseBackupService = new DatabaseBackupService(Config.DatabaseFile);
await _databaseBackupService.RunIfNeededAsync();
_autoBackupTimer.Tick += OnAutoBackupTimer;
_autoBackupTimer.Start();
}
LastChanged = CurrentLastWrite;
ContextTimer.Start();
Dictionary<string, (string, string, int?, string?, string?, string?, string?, string?)> branches = [];
using (var ctx = new AppDbContext()) {
branches = await ctx.FetchBranches()
.ToDictionaryAsync(b => b.Name.ToLower(), b => (b.ZwstId, b.Name, b.PostalDest?.AtPlz?.Plz, b.PostalDest?.AtPlz?.Ort.Name, b.Address, b.PhoneNr, b.FaxNr, b.MobileNr));
branches = ctx.FetchBranches()
.ToDictionaryAsync(b => b.Name.ToLower(), b => (b.ZwstId, b.Name, b.PostalDest?.AtPlz?.Plz, b.PostalDest?.AtPlz?.Ort.Name, b.Address, b.PhoneNr, b.FaxNr, b.MobileNr))
.GetAwaiter().GetResult();
try {
Client = new(ctx);
} catch (Exception exc) {
InteractionService.ShowException("Fehler", "Fehler beim Laden der Mandantendaten, unbedingt den Programmierern melden!", exc);
if (InteractionService.AskQuestion("Backup wiederherstellen", "Soll die Datenbank aus einem Backup wiederhergestellt werden?\n\nAchtung: Das kann zu Datenverlust führen!", false))
await BackupService.RestoreDatabase();
ShutdownNow();
InteractionService.ShowException("Fehler", "Fehler beim Laden der Mandantendaten", exc);
Shutdown();
return;
}
BranchNum = branches.Count;
@@ -131,23 +133,9 @@ namespace Elwig {
return Task.CompletedTask;
});
Utils.RunBackground("PDF Initialization", async () => Pdf.Init());
Utils.RunBackground("PDF Initialization", () => Pdf.Init());
Utils.RunBackground("JSON Schema Initialization", BillingData.Init);
if (Config.BackupAuto && !Config.Debug) {
Utils.RunBackground("Automatisches Backup", async () => {
Directory.CreateDirectory(Config.BackupPath);
await Task.Delay(500);
await BackupService.TryDatabaseBackup();
});
_autoBackupTimer.Tick += new EventHandler((sender, evt) => {
Utils.RunBackground("Automatisches Backup", async () => {
await BackupService.TryDatabaseBackup();
});
});
_autoBackupTimer.Start();
}
if (Config.UpdateAuto && Config.UpdateUrl != null) {
if (Utils.HasInternetConnectivity()) {
Utils.RunBackground("Auto Updater", async () => {
@@ -167,7 +155,7 @@ namespace Elwig {
foreach (var s in Config.Scales) {
try {
var scale = Scale.FromConfig(s);
if (s.SyncTime && scale is ICommandScale cmd) {
if (scale is ICommandScale cmd) {
try {
await cmd.SetDateAndTime(DateTime.Now);
} catch { }
@@ -184,7 +172,7 @@ namespace Elwig {
if (Config.Branch != null) {
if (!branches.ContainsKey(Config.Branch.ToLower())) {
InteractionService.ShowError("Ungültige Zweigstelle", "Ungültige Zweigstelle in Konfigurationsdatei!");
ShutdownNow();
Shutdown();
} else {
SetBranch(branches[Config.Branch.ToLower()]);
}
@@ -192,7 +180,7 @@ namespace Elwig {
SetBranch(branches.First().Value);
} else {
InteractionService.ShowError("Ungültige Zweigstelle", "Erkennen der lokalen Zweigstelle nicht möglich!");
ShutdownNow();
Shutdown();
}
if (Config.WeighingMode == null) {
@@ -200,7 +188,7 @@ namespace Elwig {
Config.WeighingMode = WeighingMode.Net;
} else if (Client.IsHaugsdorf || Client.IsSitzendorf) {
Config.WeighingMode = WeighingMode.Box;
} else if (Client.IsBaden || Client.IsGrInzersdorf || Client.IsPamhagen) {
} else if (Client.IsBaden || Client.IsGrInzersdorf) {
Config.WeighingMode = WeighingMode.Gross;
}
}
@@ -211,29 +199,19 @@ namespace Elwig {
window.Show();
}
public static void ShutdownNow() {
ForceShutdown = true;
Current.Shutdown();
}
public async void ShutdownGracefully() {
Mouse.OverrideCursor = Cursors.AppStarting;
if (Config.BackupAuto && !Config.Debug) {
try {
await BackupService.TryDatabaseBackup();
} catch (Exception exc) {
InteractionService.ShowException("Automatisches Backup", exc);
}
}
private async void Application_Exit(object sender, ExitEventArgs evt) {
_autoBackupTimer.Stop();
SerialPortWatcher.Dispose();
foreach (var s in EventScales) {
s.Dispose();
}
Pdf.Cleanup();
await Pdf.Cleanup();
}
Shutdown();
private async void OnAutoBackupTimer(object? sender, EventArgs evt) {
if (_databaseBackupService != null) {
await _databaseBackupService.RunIfNeededAsync();
}
}
public static void SetBranch(Branch b) {
@@ -344,7 +322,8 @@ namespace Elwig {
await MainDispatcher.BeginInvoke(() => {
var d = new UpdateDialog(latest.Value.Version, latest.Value.Url, latest.Value.Size);
if (d.ShowDialog() == true) {
ShutdownNow();
ForceShutdown = true;
Current.Shutdown();
}
});
} else if (showAlert) {
@@ -362,7 +341,8 @@ namespace Elwig {
await Database.Import(filename);
});
InteractionService.ShowInformation("Datenbank ersetzen", "Das Ersetzen war erfolgreich!\n\nBitte starten Sie Elwig neu!");
ShutdownNow();
ForceShutdown = true;
Current.Shutdown();
} catch (Exception exc) {
InteractionService.ShowException("Datenbank ersetzen", "Fehler beim Ersetzen", exc);
}
+4 -4
View File
@@ -1,11 +1,9 @@
<Window x:Class="Elwig.Dialogs.ManualWeighingDialog"
AutomationProperties.AutomationId="ManualWeighingDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Elwig.Dialogs"
xmlns:ctrl="clr-namespace:Elwig.Controls"
ResizeMode="NoResize" ShowInTaskbar="False" Topmost="True"
WindowStartupLocation="CenterOwner"
FocusManager.FocusedElement="{Binding ElementName=WeightInput}"
@@ -39,9 +37,11 @@
</Grid.ColumnDefinitions>
<Label Content="Gewicht:" Margin="10,20,10,10"/>
<ctrl:UnitTextBox x:Name="WeightInput" Grid.Column="1" Width="62" Height="25" Unit="kg"
Margin="0,20,10,10" HorizontalAlignment="Left" VerticalAlignment="Top" FontSize="14" Padding="2"
<Grid Grid.Column="1" Width="70" Height="25" Margin="0,20,10,10" HorizontalAlignment="Left" VerticalAlignment="Top">
<TextBox x:Name="WeightInput" TextAlignment="Right" Padding="2,2,17,2"
TextChanged="WeightInput_TextChanged"/>
<Label Content="kg" Margin="0,4,3,0" HorizontalAlignment="Right" FontSize="10" Padding="2,4,2,4"/>
</Grid>
<Label Content="Grund:" Margin="10,50,10,10"/>
<TextBox x:Name="ReasonInput" Grid.Column="1" Margin="0,50,10,10"
+2 -2
View File
@@ -6,8 +6,8 @@ using System.Windows.Controls;
namespace Elwig.Dialogs {
public partial class ManualWeighingDialog : Window {
public int Weight { get; private set; }
public string? Reason { get; private set; }
public int Weight = 0;
public string? Reason = null;
public ManualWeighingDialog(string? reason = null) {
InitializeComponent();
-55
View File
@@ -1,55 +0,0 @@
<Window x:Class="Elwig.Dialogs.TareCorrectionDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Elwig.Dialogs"
xmlns:ctrl="clr-namespace:Elwig.Controls"
ResizeMode="NoResize" ShowInTaskbar="False" Topmost="True"
WindowStartupLocation="CenterOwner"
FocusManager.FocusedElement="{Binding ElementName=TargetTareInput}"
Title="Tara korrigieren" Height="170" Width="300">
<Window.Resources>
<Style TargetType="Label">
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="VerticalAlignment" Value="Top"/>
<Setter Property="Padding" Value="2,4,2,4"/>
<Setter Property="Height" Value="25"/>
</Style>
<Style TargetType="TextBox">
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalAlignment" Value="Top"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="Padding" Value="2"/>
<Setter Property="Height" Value="25"/>
<Setter Property="TextWrapping" Value="NoWrap"/>
</Style>
<Style TargetType="Button">
<Setter Property="HorizontalAlignment" Value="Right"/>
<Setter Property="VerticalAlignment" Value="Bottom"/>
<Setter Property="Width" Value="100"/>
<Setter Property="Height" Value="25"/>
</Style>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="70"/>
<ColumnDefinition Width="3*"/>
</Grid.ColumnDefinitions>
<Label Content="Ist-Tara:" Margin="10,20,0,10" Grid.Column="1"/>
<ctrl:UnitTextBox x:Name="ActualTareInput" Grid.Column="2" Width="56" Height="25" Unit="kg" IsReadOnly="True"
Margin="0,20,10,10" HorizontalAlignment="Left" VerticalAlignment="Top" FontSize="14" Padding="2"
TextChanged="TareInput_TextChanged"/>
<Label Content="Soll-Tara:" Margin="10,50,0,10" Grid.Column="1"/>
<ctrl:UnitTextBox x:Name="TargetTareInput" Grid.Column="2" Width="56" Height="25" Unit="kg"
Margin="0,50,10,10" HorizontalAlignment="Left" VerticalAlignment="Top" FontSize="14" Padding="2"
TextChanged="TareInput_TextChanged"/>
<Button x:Name="ConfirmButton" Content="Bestätigen" Margin="10,10,115,10" Grid.ColumnSpan="3" IsEnabled="False" IsDefault="True"
Click="ConfirmButton_Click"/>
<Button x:Name="CancelButton" Content="Abbrechen" Margin="10,10,10,10" Grid.ColumnSpan="3" IsCancel="True"/>
</Grid>
</Window>
@@ -1,38 +0,0 @@
using Elwig.Helpers;
using System.Windows;
using System.Windows.Controls;
namespace Elwig.Dialogs {
public partial class TareCorrectionDialog : Window {
public int ActualTare { get; private set; }
public int TargetTare { get; private set; }
public TareCorrectionDialog(int? actualTare, int? targetTare = null) {
InitializeComponent();
ActualTare = actualTare ?? 0;
TargetTare = targetTare ?? actualTare ?? 0;
ActualTareInput.IsReadOnly = actualTare != null;
ActualTareInput.Text = ActualTare.ToString();
TargetTareInput.Text = TargetTare.ToString();
TargetTareInput.SelectAll();
}
private void ConfirmButton_Click(object sender, RoutedEventArgs evt) {
DialogResult = true;
ActualTare = int.Parse(ActualTareInput.Text);
TargetTare = int.Parse(TargetTareInput.Text);
Close();
}
private void UpdateButtons() {
ConfirmButton.IsEnabled = ActualTareInput.Text.Length > 0 && TargetTareInput.Text.Length > 0;
}
private void TareInput_TextChanged(object sender, TextChangedEventArgs evt) {
if (sender is not TextBox b) return;
Validator.CheckInteger(b, true, 4);
UpdateButtons();
}
}
}
+18 -37
View File
@@ -30,27 +30,23 @@ namespace Elwig.Documents {
get {
IAddress addr = (Member.BillingAddress != null && UseBillingAddress) ? Member.BillingAddress : Member;
var plz = addr.PostalDest.AtPlz;
return string.Join("\n", ((string?[])[addr is BillingAddr ? addr.FullName : null, Member.AdministrativeName, Member.ForTheAttentionOf, addr.Address, $"{plz?.Plz} {plz?.Ort.Name.Split(",")[0]}", addr.PostalDest.Country.Name]).Where(s => !string.IsNullOrWhiteSpace(s)));
return string.Join("\n", ((string?[])[Member.BillingAddress?.FullName, Member.AdministrativeName, Member.ForTheAttentionOf, addr.Address, $"{plz?.Plz} {plz?.Ort.Name.Split(",")[0]}", addr.PostalDest.Country.Name]).Where(s => !string.IsNullOrWhiteSpace(s)));
}
}
protected Cell NewAsideCell(Paragraph text, int colspan = 1, bool isName = false, bool right = false, bool center = false) {
var cell = NewCell(text, colspan: colspan).SetPaddingsMM(0.25f, center ? 0 : right ? 1 : 0.5f, 0.25f, isName ? 1 : 0);
if (colspan == 26) {
protected Cell NewAsideCell(Paragraph text, int colspan = 1, bool isName = false) {
var cell = NewCell(text, colspan: colspan).SetPaddingsMM(0.25f, 0.5f, 0.25f, isName ? 1 : 0);
if (colspan > 1) {
cell.SetTextAlignment(TextAlignment.CENTER).SetFont(BF)
.SetBackgroundColor(new DeviceRgb(0xe0, 0xe0, 0xe0))
.SetBorderTop(new SolidBorder(new DeviceRgb(0x80, 0x80, 0x80), BorderThickness))
.SetPaddingsMM(0.5f, 1, 0.5f, 1);
} else if (isName) {
cell.SetBorderLeft(new SolidBorder(new DeviceRgb(0x80, 0x80, 0x80), BorderThickness));
}
if (right) cell.SetTextAlignment(TextAlignment.RIGHT);
if (center) cell.SetTextAlignment(TextAlignment.CENTER);
return cell;
}
protected Cell NewAsideCell(string text, int colspan = 1, bool isName = false, bool right = false, bool center = false) {
return NewAsideCell(new KernedParagraph(text, 10), colspan, isName, right, center);
protected Cell NewAsideCell(string text, int colspan = 1, bool isName = false) {
return NewAsideCell(new KernedParagraph(text, 10), colspan, isName);
}
public BusinessDocument(string title, Member m, DateOnly? dateFrom, bool includeSender = false) :
@@ -64,27 +60,16 @@ namespace Elwig.Documents {
protected override void BeforeRenderBody(iText.Layout.Document doc, PdfDocument pdf) {
base.BeforeRenderBody(doc, pdf);
Aside = new Table(ColsMM(2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5))
.SetWidth(UnitValue.CreatePointValue(65 * PtInMM)).SetFixedLayout()
.SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE)
var uid = new KernedParagraph(Member.UstIdNr ?? "-", 10);
if (!Member.IsBuchführend) uid.Add(Normal(" ")).Add(Italic("(pauschaliert)"));
Aside = new Table(ColsMM(22.5, 42.5))
.SetFont(NF).SetFontSize(10)
.SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE)
.SetBorder(new SolidBorder(new DeviceRgb(0x80, 0x80, 0x80), BorderThickness))
.AddCell(NewAsideCell("Mitglied", 26));
if (Member.IsOrganic) {
Aside
.AddCell(NewAsideCell("Mitgl.-Nr.:", 8, isName: true)).AddCell(NewAsideCell($"{Member.MgNr}", 4, right: true))
.AddCell(NewAsideCell("Bio-KSt.:", 6, isName: true)).AddCell(NewAsideCell(Member.OrganicAuthorityCode ?? "-", 8, right: true, center: Member.OrganicAuthorityCode == null))
.AddCell(NewAsideCell("Betr.-Nr.:", 6, isName: true)).AddCell(NewAsideCell(Member.LfbisNr ?? "-", 6, right: true, center: Member.LfbisNr == null))
.AddCell(NewAsideCell("OOC-ID:", 6, isName: true)).AddCell(NewAsideCell(Member.OrganicOperatorId ?? "-", 8, right: true, center: Member.OrganicOperatorId == null))
.AddCell(NewAsideCell("UID:", 6, isName: true)).AddCell(NewAsideCell(Member.UstIdNr ?? "-", 10, right: true, center: Member.UstIdNr == null))
.AddCell(NewAsideCell(new KernedParagraph("", 10).Add(Italic(Member.IsAccounting ? "(buchführend)" : "(pauschaliert)")), 10, center: true));
} else {
Aside
.AddCell(NewAsideCell("Mitglieds-Nr.:", 12, isName: true)).AddCell(NewAsideCell($"{Member.MgNr}", 4, right: true)).AddCell(NewAsideCell("", 10))
.AddCell(NewAsideCell("Betriebs-Nr.:", 10, isName: true)).AddCell(NewAsideCell(Member.LfbisNr ?? "-", 6, right: true, center: Member.LfbisNr == null)).AddCell(NewAsideCell("", 10))
.AddCell(NewAsideCell("UID:", 6, isName: true)).AddCell(NewAsideCell(Member.UstIdNr ?? "-", 10, right: true, center: Member.UstIdNr == null))
.AddCell(NewAsideCell(new KernedParagraph("", 10).Add(Italic(Member.IsAccounting ? "(buchführend)" : "(pauschaliert)")), 10, center: true));
}
.AddCell(NewAsideCell("Mitglied", 2))
.AddCell(NewAsideCell("Mitglieds-Nr.:", isName: true)).AddCell(NewAsideCell($"{Member.MgNr}"))
.AddCell(NewAsideCell("Betriebs-Nr.:", isName: true)).AddCell(NewAsideCell(Member.LfbisNr ?? ""))
.AddCell(NewAsideCell("UID:", isName: true)).AddCell(NewAsideCell(uid));
}
protected void RenderAddress(Canvas canvas, Rectangle pageSize) {
@@ -137,15 +122,11 @@ namespace Elwig.Documents {
return new KernedParagraph(10)
.AddAll(Utils.GenerateFooter("\n", " \u00b7 ")
.Item(c.NameFull).NextLine()
.Item(c.Address).Item($"{c.Plz} {c.Ort}").Item("Österreich").NextGroup()
.Item("Tel.", c.PhoneNr).Item("Fax", c.FaxNr).NextGroup()
.Item(c.EmailAddress != null ? link1 : null).NextLine()
.Item(c.Website != null ? link2 : null).NextGroup()
.Item("Betriebs-Nr.", c.LfbisNr).NextGroup()
.Item("Bio-KSt.", c.OrganicAuthorityCode).NextGroup()
.Item("OOC-ID", c.OrganicOperatorId).NextLine()
.Item(c.Address).Item($"{c.Plz} {c.Ort}").Item("Österreich").Item("Tel.", c.PhoneNr).Item("Fax", c.FaxNr).NextLine()
.Item(c.EmailAddress != null ? link1 : null)
.Item(c.Website != null ? link2 : null)
.Item("Betriebs-Nr.", c.LfbisNr).Item("Bio-KSt.", c.OrganicAuthority).NextLine()
.Item("UID", c.UstIdNr).Item("BIC", c.Bic).Item("IBAN", c.Iban)
.RebalanceLines()
.ToLeafElements());
}
+4 -4
View File
@@ -125,10 +125,10 @@ namespace Elwig.Documents {
protected override void BeforeRenderBody(iText.Layout.Document doc, PdfDocument pdf) {
base.BeforeRenderBody(doc, pdf);
Aside?.AddCell(NewAsideCell("Gutschrift", 26))
.AddCell(NewAsideCell("Tr.-Gutschr.-Nr.:", 12, isName: true)).AddCell(NewAsideCell(Payment?.Credit != null ? $"{Payment.Credit.Year}/{Payment.Credit.TgNr:000}" : "-", 14))
.AddCell(NewAsideCell("Datum:", 12, isName: true)).AddCell(NewAsideCell($"{Payment?.Variant.Date:dd.MM.yyyy}", 14))
.AddCell(NewAsideCell("Überwiesen am:", 12, isName: true)).AddCell(NewAsideCell($"{Payment?.Variant.TransferDate:dd.MM.yyyy}", 14));
Aside?.AddCell(NewAsideCell("Gutschrift", 2))
.AddCell(NewAsideCell("TG-Nr.:", isName: true)).AddCell(NewAsideCell(Payment?.Credit != null ? $"{Payment.Credit.Year}/{Payment.Credit.TgNr:000}" : "-"))
.AddCell(NewAsideCell("Datum:", isName: true)).AddCell(NewAsideCell($"{Payment?.Variant.Date:dd.MM.yyyy}"))
.AddCell(NewAsideCell("Überw. am:", isName: true)).AddCell(NewAsideCell($"{Payment?.Variant.TransferDate:dd.MM.yyyy}"));
}
protected override void RenderBody(iText.Layout.Document doc, PdfDocument pdf) {
+5 -5
View File
@@ -30,7 +30,7 @@ namespace Elwig.Documents {
_year = year;
ShowDateAndLocation = true;
UseBillingAddress = true;
DocumentId = $"Anlfrg.-Bstng. {_year}/{m.MgNr}";
DocumentId = $"Anl.-Best. {_year}/{m.MgNr}";
Data = data;
}
@@ -55,10 +55,10 @@ namespace Elwig.Documents {
base.BeforeRenderBody(doc, pdf);
var firstDay = Data.Rows.MinBy(r => r.Date)?.Date;
var lastDay = Data.Rows.MaxBy(r => r.Date)?.Date;
Aside?.AddCell(NewAsideCell("Saison", 26))
.AddCell(NewAsideCell("Lieferungen:", 12, isName: true)).AddCell(NewAsideCell($"{Data.Rows.DistinctBy(r => r.LsNr).Count():N0} (Teil-Lfrg.: {Data.RowNum:N0})", 14))
.AddCell(NewAsideCell("Zeitraum:", 8, isName: true)).AddCell(NewAsideCell(firstDay == null || lastDay == null ? "-" : firstDay == lastDay ? $"{firstDay:dd.MM.} (1 Tag)" : $"{firstDay:dd.MM.}\u2013{lastDay:dd.MM.} ({lastDay?.DayNumber - firstDay?.DayNumber + 1:N0} Tage)", 18, center: true))
.AddCell(NewAsideCell("Menge:", 12, isName: true)).AddCell(NewAsideCell($"{MemberStats.Sum(s => s.Weight):N0} kg", 14));
Aside?.AddCell(NewAsideCell("Saison", 2))
.AddCell(NewAsideCell("Lieferungen:", isName: true)).AddCell(NewAsideCell($"{Data.Rows.DistinctBy(r => r.LsNr).Count():N0} (Teil-Lfrg.: {Data.RowNum:N0})"))
.AddCell(NewAsideCell("Zeitraum:", isName: true)).AddCell(NewAsideCell(firstDay == null || lastDay == null ? "-" : firstDay == lastDay ? $"{firstDay:dd.MM.} (1 Tag)" : $"{firstDay:dd.MM.}\u2013{lastDay:dd.MM.} ({lastDay?.DayNumber - firstDay?.DayNumber + 1:N0} Tage)"))
.AddCell(NewAsideCell("Menge:", isName: true)).AddCell(NewAsideCell($"{MemberStats.Sum(s => s.Weight):N0} kg"));
}
protected override void RenderBody(iText.Layout.Document doc, PdfDocument pdf) {
+16 -28
View File
@@ -72,10 +72,10 @@ namespace Elwig.Documents {
protected override void BeforeRenderBody(iText.Layout.Document doc, PdfDocument pdf) {
base.BeforeRenderBody(doc, pdf);
Aside?.AddCell(NewAsideCell("Lieferung", 26))
.AddCell(NewAsideCell("Lieferschein-Nr.:", 12, isName: true)).AddCell(NewAsideCell(Delivery.LsNr, 14))
.AddCell(NewAsideCell("Datum/Zeit:", 12, isName: true)).AddCell(NewAsideCell($"{Delivery.Date:dd.MM.yyyy} / {Delivery.Time:HH:mm}", 14))
.AddCell(NewAsideCell("Zweigstelle:", 12, isName: true)).AddCell(NewAsideCell(Delivery.Branch.Name, 14));
Aside?.AddCell(NewAsideCell("Lieferung", 2))
.AddCell(NewAsideCell("LS-Nr.:", isName: true)).AddCell(NewAsideCell(Delivery.LsNr))
.AddCell(NewAsideCell("Datum/Zeit:", isName: true)).AddCell(NewAsideCell($"{Delivery.Date:dd.MM.yyyy} / {Delivery.Time:HH:mm}"))
.AddCell(NewAsideCell("Zweigstelle:", isName: true)).AddCell(NewAsideCell(Delivery.Branch.Name));
}
protected override void RenderBody(iText.Layout.Document doc, PdfDocument pdf) {
@@ -121,7 +121,7 @@ namespace Elwig.Documents {
}
protected Table NewDeliveryTable() {
var tbl = new Table(ColsMM(10, 21, 25, 20, 20, 30, 12.5, 12.5, 14), true)
var tbl = new Table(ColsMM(10, 21, 25, 19.5, 19.5, 30, 12.5, 12.5, 15), true)
.SetWidth(UnitValue.CreatePercentValue(100)).SetFixedLayout()
.SetBorder(Border.NO_BORDER).SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE);
@@ -130,16 +130,15 @@ namespace Elwig.Documents {
.AddHeaderCell(NewTh("Attribut", colspan: 2, rowspan: 2, left: true))
.AddHeaderCell(NewTh("Qualitätsstufe", rowspan: 2, left: true))
.AddHeaderCell(NewTh("Gradation", colspan: 2))
.AddHeaderCell(NewTh("Menge").SetPaddingRight(0))
.AddHeaderCell(NewTh("Menge"))
.AddHeaderCell(NewTh("[°Oe]", 8))
.AddHeaderCell(NewTh("[°KMW]", 8))
.AddHeaderCell(NewTh("[kg]", 8).SetPaddingRight(0));
.AddHeaderCell(NewTh("[kg]", 8));
foreach (var part in Delivery.Parts.OrderBy(p => p.DPNr)) {
var sub = new Table(ColsMM(10, 21, 25, 20, 20, 30, 12.5, 12.5, 14), true)
var sub = new Table(ColsMM(10, 21, 25, 19.5, 19.5, 30, 12.5, 12.5, 15), true)
.SetWidth(UnitValue.CreatePercentValue(100)).SetFixedLayout()
.SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE)
.SetKeepTogether(true);
.SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE);
int rowspan = 1 + (part.Cultivation != null ? 1 : 0) + 1 + part.Modifiers.Count() + 1 + (part.Comment != null ? 1 : 0) + (part.Temperature != null || part.Acid != null ? 1 : 0);
sub.AddCell(NewDeliveryMainTd($"{part.DPNr:N0}", center: true))
@@ -148,14 +147,11 @@ namespace Elwig.Documents {
.AddCell(NewDeliveryMainTd(part.Quality.Name))
.AddCell(NewDeliveryMainTd($"{part.Oe:N0}", center: true))
.AddCell(NewDeliveryMainTd($"{part.Kmw:N1}", center: true))
.AddCell(NewDeliveryMainTd($"{part.Weight:N0}", right: true).SetPaddingRight(0));
.AddCell(NewDeliveryMainTd($"{part.Weight:N0}", center: true));
if (part.Cultivation != null) {
var cult = new KernedParagraph(8);
cult.Add(Italic("Bewirtschaftung:")).Add(Normal(" " + part.Cultivation.Name + (part.Cultivation.Description != null ? $" ({part.Cultivation.Description})" : "")));
if (part.Cultivation.IsOrganic) {
cult.Add(" \u2013 ").Add(Italic("Kontrollstelle:")).Add(Normal($" {Member.OrganicAuthorityCode ?? "?"}"));
}
sub.AddCell(NewTd())
.AddCell(NewTd(cult, colspan: 5))
.AddCell(NewTd(colspan: 3));
@@ -200,17 +196,9 @@ namespace Elwig.Documents {
.Add(Italic("Brutto:"))
.Add(Normal($" {info.Gross:N0} kg \u2013 "))
.Add(Italic("Tara:"))
.Add(Normal($" {info.Tare:N0} kg "));
if (info.TareCorrection != null && info.TareCorrection != 0)
weighing.Add(Bold($"(Korr.: {Utils.GetSign(info.TareCorrection.Value)}{Math.Abs(info.TareCorrection.Value)} kg)")).Add(" ");
weighing
.Add(Normal("\u2013 "))
.Add(Normal($" {info.Tare:N0} kg \u2013 "))
.Add(Italic("Netto:"))
.Add(Normal($" {info.Net:N0} kg "));
if (info.TareCorrection != null && info.TareCorrection != 0)
weighing.Add(Normal($"({Utils.GetSign(-info.TareCorrection.Value)}{Math.Abs(info.TareCorrection.Value)} kg) "));
weighing
.Add(Normal("\u2013 "))
.Add(Normal($" {info.Net:N0} kg \u2013 "))
.Add(Italic(part.IsNetWeight ? "gerebelt gewogen" : "nicht gerebelt gewogen"));
} else {
weighing.Add(" ")
@@ -222,7 +210,7 @@ namespace Elwig.Documents {
.AddCell(NewCell(colspan: 3));
if (part.Comment != null) {
sub.AddCell(NewCell())
.AddCell(NewCell(new KernedParagraph(8).Add(Italic("Anmerkung:")).Add(Normal(" " + part.Comment)), colspan: 5))
.AddCell(NewCell(new KernedParagraph(8).Add(Italic("Anmerkung")).Add(Normal(" " + part.Comment)), colspan: 5))
.AddCell(NewCell(colspan: 3));
}
if (part.Temperature != null || part.Acid != null) {
@@ -232,7 +220,7 @@ namespace Elwig.Documents {
if (part.Temperature != null && part.Acid != null)
p.Add(Normal(", "));
if (part.Acid != null)
p.Add(Italic("Säure:")).Add(Normal($" {part.Acid:N1} g/l"));
p.Add(Italic("Säure")).Add(Normal($" {part.Acid:N1} g/l"));
sub.AddCell(NewCell())
.AddCell(NewCell(p, colspan: 5))
.AddCell(NewCell(colspan: 3));
@@ -241,10 +229,10 @@ namespace Elwig.Documents {
}
if (Delivery.Parts.Count > 1) {
tbl.AddCell(NewTd("Gesamt:", 12, bold: true, borderTop: true, colspan: 6).SetPaddingsMM(1, 1, 1, 0))
tbl.AddCell(NewTd("Gesamt:", 12, bold: true, borderTop: true, colspan: 6).SetPaddingsMM(1, 1, 1, 1))
.AddCell(NewTd($"{Delivery.Oe:N0}", 12, bold: true, center: true, borderTop: true).SetPaddingsMM(1, 1, 1, 1))
.AddCell(NewTd($"{Delivery.Kmw:N1}", 12, bold: true, center: true, borderTop: true).SetPaddingsMM(1, 1, 1, 1))
.AddCell(NewTd($"{Delivery.Weight:N0}", 12, bold: true, right: true, borderTop: true).SetPaddingsMM(1, 0, 1, 1));
.AddCell(NewTd($"{Delivery.Weight:N0}", 12, bold: true, right: true, borderTop: true).SetPaddingsMM(1, 1, 1, 1));
}
return tbl;
+2 -2
View File
@@ -57,7 +57,7 @@ namespace Elwig.Documents {
public Document(string title) {
Title = title;
Author = App.Client.NameFull;
Date = DateOnly.FromDateTime(DateTime.Today);
Date = DateOnly.FromDateTime(Utils.Today);
}
~Document() {
@@ -252,7 +252,7 @@ namespace Elwig.Documents {
public async Task Print(int copies = 1) {
if (PdfPath == null) throw new InvalidOperationException("Pdf file has not been generated yet");
Pdf.Print(PdfPath, copies, IsDoublePaged);
await Pdf.Print(PdfPath, copies, IsDoublePaged);
}
public void Show() {
+5 -6
View File
@@ -158,21 +158,20 @@ namespace Elwig.Documents {
.AddCell(NewDataTh("Betriebs-Nr.:")).AddCell(NewTd(Member.LfbisNr))
.AddCell(NewDataTh("UID:", colspan: 2)).AddCell(NewTd(Member.UstIdNr, colspan: 2))
.AddCell(NewDataTh("Stammgemeinde:")).AddCell(NewTd(Member.DefaultKg?.Name))
.AddCell(NewDataTh("Buchführend:", colspan: 2)).AddCell(NewTd(new KernedParagraph(Member.IsAccounting ? "Ja " : "Nein ", 10)
.Add(Normal($"({(Member.IsAccounting ? season.VatNormal : season.VatFlatrate) * 100:N0}% USt.)", 8)), colspan: 2))
.AddCell(NewDataTh("Buchführend:", colspan: 2)).AddCell(NewTd(new KernedParagraph(Member.IsBuchführend ? "Ja " : "Nein ", 10)
.Add(Normal($"({(Member.IsBuchführend ? season.VatNormal : season.VatFlatrate) * 100:N0}% USt.)", 8)), colspan: 2))
.AddCell(NewDataTh("(Katastralgemeinde mit dem größten Anteil an Weinbauflächen)", 8, colspan: 2))
.AddCell(NewDataTh("Bio:", colspan: 2)).AddCell(NewTd(new KernedParagraph(Member.IsOrganic ? "Ja" : "Nein", 10)
.Add(Normal(Member.OrganicAuthorityCode != null || Member.OrganicOperatorId != null ? $" ({Member.OrganicAuthorityCode}{(Member.OrganicAuthorityCode != null && Member.OrganicOperatorId != null ? ", " : "")}{Member.OrganicOperatorId})" : "", 8)), colspan: 2))
.AddCell(NewDataTh("Bio:", colspan: 2)).AddCell(NewTd(Member.IsOrganic ? "Ja" : "Nein", colspan: 2))
.AddCell(NewDataHdr("Genossenschaft", colspan: 6))
.AddCell(NewDataTh("Status:")).AddCell(NewTd(new KernedParagraph(Member.IsActive ? "Aktiv " : "Nicht aktiv ", 10)
.Add(Normal("(" + (Member.ExitDate != null ? $"{Member.EntryDate:dd.MM.yyyy}\u2013{Member.ExitDate:dd.MM.yyyy}" : $"seit {Member.EntryDate:dd.MM.yyyy}") + ")", 8))))
.AddCell(NewDataTh("Geschäftsanteile:", colspan: 2)).AddCell(NewTd(shares, colspan: 2))
.AddCell(NewDataTh("Stamm-Zweigstelle:")).AddCell(NewTd(Member.Branch?.Name))
.AddCell(NewDataTh("Vollablieferer:", colspan: 2)).AddCell(NewTd(Member.IsFullDelivery ? "Ja" : "Nein", colspan: 2))
.AddCell(NewDataTh("Volllieferant:", colspan: 2)).AddCell(NewTd(Member.IsVollLieferant ? "Ja" : "Nein", colspan: 2))
.AddCell(NewDataTh("Zusendungen per\u2026")).AddCell(NewTd(new KernedParagraph(10)
.Add(Italic("Post:")).Add(Normal(Member.ContactViaPost ? " Ja \u2013 " : " Nein \u2013 "))
.Add(Italic("E-Mail:")).Add(Normal(Member.ContactViaEmail ? " Ja" : " Nein"))))
.AddCell(NewDataTh("Funktionär:", colspan: 2)).AddCell(NewTd(Member.IsOfficer ? "Ja" : "Nein", colspan: 2));
.AddCell(NewDataTh("Funktionär:", colspan: 2)).AddCell(NewTd(Member.IsFunktionär ? "Ja" : "Nein", colspan: 2));
return tbl;
}
+22 -22
View File
@@ -108,16 +108,16 @@ namespace Elwig.Documents {
var totalSum = _credits.Sum(p => p.Amount);
var weiRows = data.Rows.Where(r => r.QualityLevel == "Wein");
var minWei = weiRows.Min(r => r.UnCtrd.MinPrice);
var maxWei = weiRows.Max(r => r.UnCtrd.MaxPrice);
var minWei = weiRows.Min(r => r.Ungeb.MinPrice);
var maxWei = weiRows.Max(r => r.Ungeb.MaxPrice);
var quwRows = data.Rows.Where(r => r.QualityLevel != "Wein");
var minPrice = quwRows.Min(r => r.UnCtrd.MinPrice);
var maxPrice = quwRows.Max(r => r.UnCtrd.MaxPrice);
var ctrdRows = data.Rows
.Where(r => r.Ctrd.MaxPrice != null && r.UnCtrd.MinPrice != null)
.Select(r => r.Ctrd.MaxPrice - r.UnCtrd.MinPrice);
var minCtrd = ctrdRows.Min();
var maxCtrd = ctrdRows.Max();
var minPrice = quwRows.Min(r => r.Ungeb.MinPrice);
var maxPrice = quwRows.Max(r => r.Ungeb.MaxPrice);
var gebRows = data.Rows
.Where(r => r.Geb.MaxPrice != null && r.Ungeb.MinPrice != null)
.Select(r => r.Geb.MaxPrice - r.Ungeb.MinPrice);
var minGeb = gebRows.Min();
var maxGeb = gebRows.Max();
tbl.AddCell(NewSectionHdr("Allgemein", colspan: 5))
.AddCell(NewSectionHdr("Berücksichtigt", colspan: 3, borderLeft: true))
@@ -197,7 +197,7 @@ namespace Elwig.Documents {
.AddCell(NewTd(CurrencySymbol))
.AddCell(NewTd($"{Math.Abs(vat):N2}", right: true))
.AddCell(NewSectionTh("Gebunden-Zuschlag:", borderLeft: true))
.AddCell(NewTd(minCtrd == null && maxCtrd == null ? "-" : minCtrd != maxCtrd ? $"{minCtrd:N4}\u2013{maxCtrd:N4} {CurrencySymbol}/kg" : minCtrd == 0 ? "-" : $"{minCtrd:N4} {CurrencySymbol}/kg", colspan: 2, center: true))
.AddCell(NewTd(minGeb == null && maxGeb == null ? "-" : minGeb != maxGeb ? $"{minGeb:N4}\u2013{maxGeb:N4} {CurrencySymbol}/kg" : minGeb == 0 ? "-" : $"{minGeb:N4} {CurrencySymbol}/kg", colspan: 2, center: true))
.AddCell(NewSectionTh("Bruttosumme:", colspan: 2))
.AddCell(NewTd(borderTop: true))
@@ -211,21 +211,21 @@ namespace Elwig.Documents {
.AddCell(NewTd(CurrencySymbol))
.AddCell(NewTd($"{Math.Abs(totalMods):N2}", right: true))
.AddCell(NewSectionTh("Menge (ungebunden):", borderLeft: true, borderTop: true))
.AddCell(NewTd($"{data.Rows.Sum(r => r.UnCtrd.Weight):N0} kg", colspan: 2, right: true, borderTop: true))
.AddCell(NewTd($"{data.Rows.Sum(r => r.Ungeb.Weight):N0} kg", colspan: 2, right: true, borderTop: true))
.AddCell(NewSectionTh("Bereits berücksichtigte Abzüge:", colspan: 2))
.AddCell(NewTd(Utils.GetSign(considered)))
.AddCell(NewTd(CurrencySymbol))
.AddCell(NewTd($"{Math.Abs(considered):N2}", right: true))
.AddCell(NewSectionTh("Menge (gebunden):", borderLeft: true))
.AddCell(NewTd($"{data.Rows.Sum(r => r.Ctrd.Weight + r.LowCtrd.Weight):N0} kg", colspan: 2, right: true))
.AddCell(NewTd($"{data.Rows.Sum(r => r.Geb.Weight + r.LowGeb.Weight):N0} kg", colspan: 2, right: true))
.AddCell(NewSectionTh("Auszahlungsbetrag:", colspan: 2))
.AddCell(NewTd(borderTop: true))
.AddCell(NewTd(CurrencySymbol, borderTop: true))
.AddCell(NewTd($"{totalSum:N2}", right: true, borderTop: true))
.AddCell(NewSectionTh("Gesamtmenge:", borderLeft: true))
.AddCell(NewTd($"{data.Rows.Sum(r => r.UnCtrd.Weight + r.LowCtrd.Weight + r.Ctrd.Weight):N0} kg", colspan: 2, right: true, borderTop: true));
.AddCell(NewTd($"{data.Rows.Sum(r => r.Ungeb.Weight + r.LowGeb.Weight + r.Geb.Weight):N0} kg", colspan: 2, right: true, borderTop: true));
return tbl;
}
@@ -290,22 +290,22 @@ namespace Elwig.Documents {
.ToList();
var border = lastHdr != null;
tbl.AddCell(NewTd(hdr, colspan: 2, bold: true, italic: true, borderTop: border))
.AddCell(NewTd($"{rows.Sum(r => r.UnCtrd.Weight):N0}", right: true, bold: true, borderTop: border))
.AddCell(NewTd($"{rows.Sum(r => r.Ungeb.Weight):N0}", right: true, bold: true, borderTop: border))
.AddCell(NewTd(borderTop: border))
.AddCell(NewTd($"{rows.Sum(r => r.LowCtrd.Weight):N0}", right: true, bold: true, borderTop: border))
.AddCell(NewTd($"{rows.Sum(r => r.LowGeb.Weight):N0}", right: true, bold: true, borderTop: border))
.AddCell(NewTd(borderTop: border))
.AddCell(NewTd($"{rows.Sum(r => r.Ctrd.Weight):N0}", right: true, bold: true, borderTop: border))
.AddCell(NewTd($"{rows.Sum(r => r.Geb.Weight):N0}", right: true, bold: true, borderTop: border))
.AddCell(NewTd(borderTop: border))
.AddCell(NewTd($"{rows.Sum(r => r.Amount):N2}", right: true, bold: true, borderTop: border));
}
tbl.AddCell(NewTd(row.QualityLevel))
.AddCell(NewTd($"{row.Oe:N0}", center: true))
.AddCell(NewTd(row.UnCtrd.Weight != 0 ? $"{row.UnCtrd.Weight:N0}" : "-", right: true))
.AddCell(NewTd(row.UnCtrd.MaxPrice != null ? $"{row.UnCtrd.MaxPrice:N4}" : "-", right: true))
.AddCell(NewTd(row.LowCtrd.Weight != 0 ? $"{row.LowCtrd.Weight:N0}" : "-", right: true))
.AddCell(NewTd(row.LowCtrd.MaxPrice != null ? $"{row.LowCtrd.MaxPrice:N4}" : "-", right: true))
.AddCell(NewTd(row.Ctrd.Weight != 0 ? $"{row.Ctrd.Weight:N0}" : "-", right: true))
.AddCell(NewTd(row.Ctrd.MaxPrice != null ? $"{row.Ctrd.MaxPrice:N4}" : "-", right: true))
.AddCell(NewTd(row.Ungeb.Weight != 0 ? $"{row.Ungeb.Weight:N0}" : "-", right: true))
.AddCell(NewTd(row.Ungeb.MaxPrice != null ? $"{row.Ungeb.MaxPrice:N4}" : "-", right: true))
.AddCell(NewTd(row.LowGeb.Weight != 0 ? $"{row.LowGeb.Weight:N0}" : "-", right: true))
.AddCell(NewTd(row.LowGeb.MaxPrice != null ? $"{row.LowGeb.MaxPrice:N4}" : "-", right: true))
.AddCell(NewTd(row.Geb.Weight != 0 ? $"{row.Geb.Weight:N0}" : "-", right: true))
.AddCell(NewTd(row.Geb.MaxPrice != null ? $"{row.Geb.MaxPrice:N4}" : "-", right: true))
.AddCell(NewTd($"{row.Amount:N2}", right: true));
lastHdr = hdr;
}
+9 -9
View File
@@ -9,7 +9,7 @@
<UseWindowsForms>true</UseWindowsForms>
<PreserveCompilationContext>true</PreserveCompilationContext>
<ApplicationIcon>Resources\Images\Elwig.ico</ApplicationIcon>
<Version>1.1.2.2</Version>
<Version>1.1.1.1</Version>
<SatelliteResourceLanguages>de-AT</SatelliteResourceLanguages>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<ApplicationManifest>App.manifest</ApplicationManifest>
@@ -23,21 +23,21 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="bblanchon.PDFium.Win32" Version="156.0.8076" />
<PackageReference Include="bblanchon.PDFium.Win32" Version="153.0.8009" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.2" />
<PackageReference Include="itext" Version="9.7.0" />
<PackageReference Include="itext.bouncy-castle-adapter" Version="9.7.0" />
<PackageReference Include="LinqKit" Version="1.3.11" />
<PackageReference Include="MailKit" Version="4.18.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.12" />
<PackageReference Include="Microsoft.Extensions.Configuration.Ini" Version="10.0.12" />
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.4258.31" />
<PackageReference Include="MailKit" Version="4.17.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.11" />
<PackageReference Include="Microsoft.Extensions.Configuration.Ini" Version="10.0.11" />
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.4129.50" />
<PackageReference Include="NJsonSchema" Version="11.6.1" />
<PackageReference Include="ScottPlot.WPF" Version="5.1.59" />
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="3.0.5" />
<PackageReference Include="System.IO.Hashing" Version="10.0.12" />
<PackageReference Include="System.IO.Ports" Version="10.0.12" />
<PackageReference Include="System.Management" Version="10.0.12" />
<PackageReference Include="System.IO.Hashing" Version="10.0.11" />
<PackageReference Include="System.IO.Ports" Version="10.0.11" />
<PackageReference Include="System.Management" Version="10.0.11" />
</ItemGroup>
</Project>
+2 -13
View File
@@ -170,25 +170,16 @@ namespace Elwig.Helpers {
SavedChanges += OnSavedChanges;
}
private static void CreateFunctions(SqliteConnection cnx) {
cnx.CreateFunction<string, string?, bool?>("REGEXP", (pattern, value) => {
return value == null ? null : Regex.IsMatch(value, pattern);
}, true);
cnx.CreateFunction<string?, string?, string?>("NORMALIZE_ADDRESS", (address, locality) => {
return string.IsNullOrWhiteSpace(address) ? null : Normalizer.NormalizeAddress(address, locality);
}, true);
}
public static SqliteConnection Connect(string? connectionString = null) {
var cnx = new SqliteConnection(connectionString ?? ConnectionString);
CreateFunctions(cnx);
cnx.CreateFunction<string, string?, bool?>("REGEXP", (pattern, value) => value == null ? null : Regex.Match(value, pattern).Success, true);
cnx.Open();
return cnx;
}
public static async Task<SqliteConnection> ConnectAsync(string? connectionString = null) {
var cnx = new SqliteConnection(connectionString ?? ConnectionString);
CreateFunctions(cnx);
cnx.CreateFunction<string, string?, bool?>("REGEXP", (pattern, value) => value == null ? null : Regex.Match(value, pattern).Success, true);
await cnx.OpenAsync();
return cnx;
}
@@ -243,8 +234,6 @@ namespace Elwig.Helpers {
modelBuilder.Entity<DeliveryAncmt>().Navigation(a => a.Schedule).AutoInclude();
modelBuilder.Entity<DeliveryAncmt>().Navigation(a => a.Variety).AutoInclude();
modelBuilder.Entity<DeliverySchedule>().Navigation(s => s.Branch).AutoInclude();
modelBuilder.Entity<DeliverySchedule>().Navigation(s => s.Attribute).AutoInclude();
modelBuilder.Entity<DeliverySchedule>().Navigation(s => s.Cultivation).AutoInclude();
modelBuilder.Entity<MemberHistory>().Navigation(s => s.FromMember).AutoInclude();
modelBuilder.Entity<MemberHistory>().Navigation(s => s.ToMember).AutoInclude();
modelBuilder.Entity<MemberHistory>().Navigation(s => s.Currency).AutoInclude();
+11 -76
View File
@@ -1,33 +1,23 @@
using Elwig.Services;
using Microsoft.Data.Sqlite;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows.Input;
namespace Elwig.Helpers {
public static class AppDbUpdater {
// Don't forget to update value in Tests/fetch-resources.bat!
public static readonly int RequiredSchemaVersion = 42;
public static readonly int RequiredSchemaVersion = 41;
private static int VersionOffset = 0;
public static async Task<Version> CheckDb() {
if (!File.Exists(App.Config.DatabaseFile))
throw new FileNotFoundException($"Die Datei \"{App.Config.DatabaseFile}\" exisitiert nicht");
long? applId, schemaVers;
using (var cnx = await AppDbContext.ConnectAsync()) {
await cnx.QuickCheck();
applId = (long?)await cnx.ExecuteScalar("PRAGMA application_id") ?? 0;
if (applId != 0x454C5747)
throw new FileFormatException($"Invalid application_id in database (0x{applId:X08})");
if (applId != 0x454C5747) throw new Exception($"Invalid application_id in database (0x{applId:X08})");
schemaVers = (long?)await cnx.ExecuteScalar("PRAGMA schema_version") ?? 0;
VersionOffset = (int)(schemaVers % 100);
@@ -71,11 +61,11 @@ namespace Elwig.Helpers {
})
.OrderBy(s => s.Item1).ThenBy(s => s.Item2)];
List<(int ToVersion, string File)> toExecute = [];
List<string> toExecute = [];
var vers = fromVersion;
while (vers < toVersion) {
var (_, to, name) = scripts.Last(s => s.From == vers);
toExecute.Add((to, name));
toExecute.Add(name);
vers = to;
}
if (toExecute.Count == 0)
@@ -86,19 +76,16 @@ namespace Elwig.Helpers {
try {
using var cnx = await AppDbContext.ConnectAsync();
await cnx.ExecuteBatch("PRAGMA locking_mode = EXCLUSIVE");
await cnx.IntegrityCheck();
await cnx.ForeignKeyCheck();
foreach (var (to, script) in toExecute) {
foreach (var script in toExecute) {
await cnx.ExecuteEmbeddedScript(asm, script);
if (to == 42) {
await UpdateDbSchema_41_To_42(cnx);
}
}
await cnx.IntegrityCheck();
await cnx.ForeignKeyCheck();
var violations = await cnx.ForeignKeyCheck();
if (violations.Length > 0) {
throw new Exception($"Foreign key violations ({violations.Length}):\n" + string.Join("\n", violations
.Take(50)
.Select(v => $"{v.Table} - {v.RowId} - {v.Parent} - {v.FkId}")));
}
await cnx.ExecuteBatch("VACUUM");
await cnx.ExecuteBatch($"PRAGMA schema_version = {toVersion * 100 + VersionOffset}");
@@ -109,57 +96,5 @@ namespace Elwig.Helpers {
File.Delete(backup);
}
}
private static async Task UpdateDbSchema_41_To_42(SqliteConnection cnx) {
List<(int MgNr, string LfbisNr, string Name, string Address, int Plz)> members = [];
using (var cmd = cnx.CreateCommand()) {
cmd.CommandText = """
SELECT m.mgnr, m.lfbis_nr,
COALESCE(a.name, (COALESCE(m.prefix || ' ', '') || COALESCE(m.given_name || ' ', '') || m.name || COALESCE(' ' || m.middle_names, '') || COALESCE(' ' || m.suffix, ''))),
COALESCE(a.address, m.address),
COALESCE(aplz.plz, mplz.plz)
FROM member m
JOIN postal_dest mp ON (mp.country, mp.id) = (m.country, m.postal_dest)
JOIN AT_plz_dest ma ON (ma.country, ma.id) = (mp.country, mp.id)
JOIN AT_plz mplz ON mplz.plz = ma.plz
LEFT JOIN member_billing_address a ON a.mgnr = m.mgnr
LEFT JOIN postal_dest ap ON (ap.country, ap.id) = (a.country, a.postal_dest)
LEFT JOIN AT_plz_dest aa ON (aa.country, aa.id) = (ap.country, mp.id)
LEFT JOIN AT_plz aplz ON aplz.plz = aa.plz
WHERE organic
""";
using var reader = await cmd.ExecuteReaderAsync();
var header = await reader.GetColumnSchemaAsync();
while (await reader.ReadAsync()) {
members.Add((reader.GetInt32(0), reader.GetString(1), reader.GetString(2), reader.GetString(3), reader.GetInt32(4)));
}
}
if (members.Count > 0)
InteractionService.ShowInformation("Datenbank-Update", "Es wird versucht, die Bio-Kontrollstellen-Informationen der Mitglieder automatisch abzurufen. Dies könnte einen kurzen Moment dauern.");
try {
Mouse.OverrideCursor = Cursors.Wait;
foreach (var m in members) {
string? oocId = null;
string? authCode = null;
var certs = await OrganicService.FetchTracesCertificates(lfbisNr: m.LfbisNr, address: (m.Name, m.Address, m.Plz.ToString()));
if (certs.Length > 0) {
oocId = certs[0].OperatorId;
authCode = certs[0].AuthorityCode;
}
if (oocId != null || authCode != null) {
oocId = oocId == null ? "NULL" : $"'{oocId}'";
authCode = authCode == null ? "NULL" : $"'{authCode}'";
await cnx.ExecuteBatch($"UPDATE member SET ooc_id = {oocId}, org_auth_code = {authCode} WHERE mgnr = {m.MgNr}");
}
}
} finally {
Mouse.OverrideCursor = null;
}
}
}
}
+6 -6
View File
@@ -77,13 +77,13 @@ namespace Elwig.Helpers.Billing {
}
public async Task CalculateBuckets(
bool? honorContractedField = null,
bool? honorGebundenField = null,
bool? allowAttributesIntoLower = null,
bool? avoidUnderDeliveries = null,
SqliteConnection? cnx = null
) {
using var ctx = new AppDbContext();
var honorContracted = honorContractedField ?? Season.Billing_HonorContracted;
var honorGebunden = honorGebundenField ?? Season.Billing_HonorGebunden;
var allowAttrsIntoLower = allowAttributesIntoLower ?? Season.Billing_AllowAttrsIntoLower;
var avoidUnderDlvrs = avoidUnderDeliveries ?? Season.Billing_AvoidUnderDeliveries;
var attrVals = ctx.WineAttributes.ToDictionary(a => a.AttrId, a => (a.IsStrict, a.FillLower));
@@ -96,10 +96,10 @@ namespace Elwig.Helpers.Billing {
var deliveries = new List<(int, int, int, string, int, double, string, string?, string[], bool?)>();
using (var cmd = cnx.CreateCommand()) {
cmd.CommandText = $"""
SELECT mgnr, did, dpnr, sortid, weight, kmw, qualid, attrid, modifiers, contracted
SELECT mgnr, did, dpnr, sortid, weight, kmw, qualid, attrid, modifiers, gebunden
FROM v_delivery
WHERE year = {Year}
ORDER BY mgnr, sortid, abgewertet ASC, {(honorContracted ? "contracted IS NOT NULL DESC, contracted DESC," : "")}
ORDER BY mgnr, sortid, abgewertet ASC, {(honorGebunden ? "gebunden IS NOT NULL DESC, gebunden DESC," : "")}
attribute_prio DESC, COALESCE(attrid, '~'), kmw DESC, lsnr, dpnr
""";
using var reader = await cmd.ExecuteReaderAsync();
@@ -117,12 +117,12 @@ namespace Elwig.Helpers.Billing {
int lastMgNr = 0;
Dictionary<string, AreaComBucket>? rightsAndObligations = null;
Dictionary<string, int> used = [];
foreach (var (mgnr, did, dpnr, sortid, weight, kmw, qualid, attrid, modifiers, contracted) in deliveries) {
foreach (var (mgnr, did, dpnr, sortid, weight, kmw, qualid, attrid, modifiers, gebunden) in deliveries) {
if (lastMgNr != mgnr) {
rightsAndObligations = await ctx.GetMemberAreaCommitmentBuckets(Year, mgnr);
used = [];
}
if ((honorContracted && contracted == false) ||
if ((honorGebunden && gebunden == false) ||
rightsAndObligations == null || rightsAndObligations.Count == 0 ||
qualid == "WEI" || qualid == "RSW" || qualid == "LDW")
{
+10 -12
View File
@@ -14,7 +14,7 @@ namespace Elwig.Helpers.Billing {
public enum CalculationMode { Elwig, WgMaster }
public enum CurveMode { Oe, Kmw }
public record struct Curve(CurveMode Mode, Dictionary<double, decimal> Normal, Dictionary<double, decimal>? Contracted);
public record struct Curve(CurveMode Mode, Dictionary<double, decimal> Normal, Dictionary<double, decimal>? Gebunden);
public static JsonSchema? Schema { get; private set; }
@@ -179,10 +179,10 @@ namespace Elwig.Helpers.Billing {
} else {
throw new InvalidOperationException();
}
var ctrd = obj["contracted"] ?? obj["geb"];
if (ctrd is JsonObject) {
c2 = GetCurveData(ctrd.AsObject(), cMode);
} else if (ctrd?.AsValue().TryGetValue(out decimal v) == true) {
var geb = obj["geb"];
if (geb is JsonObject) {
c2 = GetCurveData(geb.AsObject(), cMode);
} else if (geb?.AsValue().TryGetValue(out decimal v) == true) {
var splitVal = GetCurveValueAt(c1, quw);
c2 = c1.ToDictionary(e => e.Key, e => e.Value + (e.Key >= quw ? v : 0));
c2[quw] = splitVal + v;
@@ -274,7 +274,7 @@ namespace Elwig.Helpers.Billing {
protected static JsonNode GraphEntryToJson(GraphEntry entry) {
try {
if (entry.ContractedFlatBonus == null) {
if (entry.GebundenFlatBonus == null) {
return JsonValue.Create((decimal)entry.DataGraph.DataY.Distinct().Single());
}
} catch { }
@@ -286,12 +286,10 @@ namespace Elwig.Helpers.Billing {
curve["data"] = GraphToJson(entry.DataGraph, entry.Mode.ToString().ToLower());
if (entry.ContractedFlatBonus != null) {
curve["contracted"] = (decimal)entry.ContractedFlatBonus;
curve.Remove("geb");
} else if (entry.ContractedGraph != null) {
curve["contracted"] = GraphToJson(entry.ContractedGraph, entry.Mode.ToString().ToLower());
curve.Remove("geb");
if (entry.GebundenFlatBonus != null) {
curve["geb"] = (decimal)entry.GebundenFlatBonus;
} else if (entry.GebundenGraph != null) {
curve["geb"] = GraphToJson(entry.GebundenGraph, entry.Mode.ToString().ToLower());
}
return curve;
+6 -6
View File
@@ -37,11 +37,11 @@ namespace Elwig.Helpers.Billing {
return new BillingVariant(year, avnr, season, attributes, modifiers, areaComTypes, paymentVar, data);
}
public async Task Calculate(bool strictPrices = true, bool? honorContracted = null, bool? allowAttrsIntoLower = null, bool? avoidUnderDeliveries = null) {
public async Task Calculate(bool strictPrices = true, bool? honorGebunden = null, bool? allowAttrsIntoLower = null, bool? avoidUnderDeliveries = null) {
if (PaymentVariant == null || Data == null) throw new Exception("Call Load before Calculate");
using var cnx = await AppDbContext.ConnectAsync();
using var tx = await cnx.BeginTransactionAsync();
await CalculateBuckets(honorContracted, allowAttrsIntoLower, avoidUnderDeliveries, cnx);
await CalculateBuckets(honorGebunden, allowAttrsIntoLower, avoidUnderDeliveries, cnx);
await DeleteInDb(cnx);
await SetCalcTime(cnx);
KeyNotFoundException? exception = null;
@@ -73,7 +73,7 @@ namespace Elwig.Helpers.Billing {
v.avnr,
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(m.accounting, 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.ConsiderContractPenalties}, COALESCE(u.total_penalty, 0), 0) / POW(10, 4 - 2)) +
ROUND(IIF({Data.ConsiderAutoBusinessShares}, -COALESCE(a.total_amount, 0), 0)) +
@@ -195,13 +195,13 @@ namespace Elwig.Helpers.Billing {
foreach (var part in parts) {
if (part.Value == 0)
continue;
var unctrd = part.Discr == "_";
var ungeb = part.Discr == "_";
var payAttrId = (part.Discr is "" or "_") ? null : part.Discr;
var attrId = part.AttrAreaCom ? payAttrId : part.AttrId;
var ctrd = !unctrd && (payAttrId == attrId || !part.AttrAreaCom);
var geb = !ungeb && (payAttrId == attrId || !part.AttrAreaCom);
decimal price = 0;
try {
price = Data.CalculatePrice(part.SortId, attrId, part.CultId, part.QualId, ctrd, part.Oe, part.Kmw);
price = Data.CalculatePrice(part.SortId, attrId, part.CultId, part.QualId, geb, part.Oe, part.Kmw);
} catch (KeyNotFoundException e) {
invalid.Add(e.Message.Split('\'')[1]);
}
+17 -17
View File
@@ -7,7 +7,7 @@ namespace Elwig.Helpers.Billing {
public class GraphEntry {
public const int MinX = 50;
public const int MinXCtrd = 73;
public const int MinXGeb = 73;
public const int MaxX = 120;
public int Id { get; set; }
@@ -15,11 +15,11 @@ namespace Elwig.Helpers.Billing {
public bool Abgewertet { get; set; }
public Graph DataGraph { get; set; }
public Graph? ContractedGraph { get; set; }
public double? ContractedFlatBonus {
public Graph? GebundenGraph { get; set; }
public double? GebundenFlatBonus {
get {
try {
var val = ContractedGraph?.DataX.Zip(ContractedGraph.DataY)
var val = GebundenGraph?.DataX.Zip(GebundenGraph.DataY)
.Select(e => Math.Round(e.Second - DataGraph.GetPriceAtOe(e.First), Precision))
.Distinct()
.Single();
@@ -30,10 +30,10 @@ namespace Elwig.Helpers.Billing {
}
set {
if (value is not double v) return;
var values = Enumerable.Range(MinXCtrd, MaxX - MinXCtrd + 1)
var values = Enumerable.Range(MinXGeb, MaxX - MinXGeb + 1)
.Select(i => Math.Round(DataGraph.GetPriceAtOe(i) + v, Precision))
.ToArray();
ContractedGraph = new Graph(values, Precision, MinXCtrd, MaxX);
GebundenGraph = new Graph(values, Precision, MinXGeb, MaxX);
}
}
@@ -52,39 +52,39 @@ namespace Elwig.Helpers.Billing {
Vaributes = [];
}
public GraphEntry(int id, int precision, BillingData.CurveMode mode, Dictionary<double, decimal> data, Dictionary<double, decimal>? contracted) :
public GraphEntry(int id, int precision, BillingData.CurveMode mode, Dictionary<double, decimal> data, Dictionary<double, decimal>? gebunden) :
this(id, precision, mode) {
DataGraph = new Graph(data, precision, MinX, MaxX);
if (contracted != null) ContractedGraph = new Graph(contracted, precision, MinXCtrd, MaxX);
if (gebunden != null) GebundenGraph = new Graph(gebunden, precision, MinXGeb, MaxX);
}
public GraphEntry(int id, int precision, BillingData.Curve curve, List<Varibute> vaributes) :
this(id, precision, curve.Mode) {
DataGraph = new Graph(curve.Normal, precision, MinX, MaxX);
if (curve.Contracted != null)
ContractedGraph = new Graph(curve.Contracted, precision, MinXCtrd, MaxX);
if (curve.Gebunden != null)
GebundenGraph = new Graph(curve.Gebunden, precision, MinXGeb, MaxX);
Vaributes = vaributes;
}
private GraphEntry(int id, int precision, BillingData.CurveMode mode, Graph dataGraph, Graph? contractedGraph, List<Varibute> vaributes) {
private GraphEntry(int id, int precision, BillingData.CurveMode mode, Graph dataGraph, Graph? gebundenGraph, List<Varibute> vaributes) {
Id = id;
Precision = precision;
Mode = mode;
DataGraph = dataGraph;
ContractedGraph = contractedGraph;
GebundenGraph = gebundenGraph;
Vaributes = vaributes;
}
public void AddContractedGraph() {
ContractedGraph ??= new Graph(Precision, MinXCtrd, MaxX);
public void AddGebundenGraph() {
GebundenGraph ??= new Graph(Precision, MinXGeb, MaxX);
}
public void RemoveContractedGraph() {
ContractedGraph = null;
public void RemoveGebundenGraph() {
GebundenGraph = null;
}
public GraphEntry Copy(int id) {
return new GraphEntry(id, Precision, Mode, (Graph)DataGraph.Clone(), (Graph?)ContractedGraph?.Clone(), []);
return new GraphEntry(id, Precision, Mode, (Graph)DataGraph.Clone(), (Graph?)GebundenGraph?.Clone(), []);
}
}
}
+2 -2
View File
@@ -45,9 +45,9 @@ namespace Elwig.Helpers.Billing {
return dict;
}
public decimal CalculatePrice(string sortid, string? attrid, string? cultid, string qualid, bool contracted, double oe, double kmw) {
public decimal CalculatePrice(string sortid, string? attrid, string? cultid, string qualid, bool gebunden, double oe, double kmw) {
var curve = GetQualityCurve(qualid, sortid, attrid, cultid) ?? GetCurve(sortid, attrid, cultid);
return GetCurveValueAt((contracted ? curve.Contracted : null) ?? curve.Normal, curve.Mode == CurveMode.Oe ? oe : kmw);
return GetCurveValueAt((gebunden ? curve.Gebunden : null) ?? curve.Normal, curve.Mode == CurveMode.Oe ? oe : kmw);
}
private Curve LookupCurve(JsonValue val) {
+3 -6
View File
@@ -49,8 +49,7 @@ namespace Elwig.Helpers {
public string? Bic;
public string? UstIdNr;
public string? LfbisNr;
public string? OrganicOperatorId;
public string? OrganicAuthorityCode;
public string? OrganicAuthority;
public string? PhoneNr;
public string? FaxNr;
@@ -115,8 +114,7 @@ namespace Elwig.Helpers {
UstIdNr = parameters.GetValueOrDefault("CLIENT_USTIDNR");
Bic = parameters.GetValueOrDefault("CLIENT_BIC");
Iban = parameters.GetValueOrDefault("CLIENT_IBAN");
OrganicOperatorId = parameters.GetValueOrDefault("CLIENT_ORGANIC_OPERATORID");
OrganicAuthorityCode = parameters.GetValueOrDefault("CLIENT_ORGANIC_AUTHORITYCODE");
OrganicAuthority = parameters.GetValueOrDefault("CLIENT_ORGANIC_AUTHORITY");
EnableMemberHistory = (parameters.GetValueOrDefault("ENABLE_MEMBERHISTORY")?.ToUpper()) switch {
"1" or "TRUE" or "YES" or "JA" => true,
@@ -275,8 +273,7 @@ namespace Elwig.Helpers {
("CLIENT_USTIDNR", UstIdNr),
("CLIENT_BIC", Bic),
("CLIENT_IBAN", Iban),
("CLIENT_ORGANIC_OPERATORID", OrganicOperatorId),
("CLIENT_ORGANIC_AUTHORITYCODE", OrganicAuthorityCode),
("CLIENT_ORGANIC_AUTHORITY", OrganicAuthority),
("ENABLE_MEMBERHISTORY", EnableMemberHistory ? "YES" : "NO"),
("MODE_BUSINESSSHARES", businessShares),
("MODE_DELIVERYNOTE_STATS", deliveryNoteStats),
+5 -24
View File
@@ -17,11 +17,10 @@ namespace Elwig.Helpers {
public string? Filling;
public string? Limit;
public bool Required;
public bool SyncTime;
public string? Log;
public string? _Log;
public ScaleConfig(string id, string? type, string? model, string? cnx, string? empty, string? filling, string? limit, bool? required, bool? syncTime, string? log) {
public ScaleConfig(string id, string? type, string? model, string? cnx, string? empty, string? filling, string? limit, bool? required, string? log) {
Id = id;
Type = type;
Model = model;
@@ -30,7 +29,6 @@ namespace Elwig.Helpers {
Filling = filling;
Limit = limit;
Required = required ?? true;
SyncTime = syncTime ?? true;
_Log = log;
Log = log != null ? Path.Combine(App.DataPath, log) : null;
}
@@ -39,26 +37,17 @@ namespace Elwig.Helpers {
public class Config {
private static readonly string[] TrueValues = ["1", "true", "yes", "on"];
private static readonly string[] FalseValues = ["0", "false", "no", "off"];
private readonly string FileName;
public bool Debug;
public string DatabaseFile = Path.Combine(App.DataPath, "database.sqlite3");
public string DatabaseFile = App.DataPath + "database.sqlite3";
public bool DatabaseBackup = true;
public string? DatabaseLog = null;
public string? Branch = null;
public WeighingMode? WeighingMode;
public bool BackupAuto = true;
public string BackupPath = Path.Combine(App.DataPath, "backups");
public int BackupRetainHours = 36;
public int BackupRetainDays = 8;
public int BackupRetainWeeks = 6;
public int BackupRetainMonths = 18;
public string? UpdateUrl = null;
public bool UpdateAuto = false;
public string? SyncUrl = null;
public string SyncUsername = "";
public string SyncPassword = "";
@@ -88,23 +77,16 @@ namespace Elwig.Helpers {
var config = new ConfigurationBuilder().AddIniFile(FileName).Build();
DatabaseFile = Path.Combine(Path.GetDirectoryName(FileName) ?? App.DataPath, config["database:file"] ?? "database.sqlite3");
var backup = config["database:backup"];
DatabaseBackup = backup == null || TrueValues.Contains(backup.ToLower());
var log = config["database:log"];
DatabaseLog = log != null ? Path.Combine(Path.GetDirectoryName(FileName) ?? App.DataPath, log) : null;
Branch = config["general:branch"];
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;
BackupAuto = !FalseValues.Contains(config["backup:auto"]?.ToLower());
BackupPath = Path.Combine(Path.GetDirectoryName(DatabaseFile) ?? App.DataPath, config["backup:path"] ?? "backups");
BackupRetainHours = int.TryParse(config["backup:retain_hours"], out var hours) ? hours : 36;
BackupRetainDays = int.TryParse(config["backup:retain_days"], out var days) ? days : 8;
BackupRetainWeeks = int.TryParse(config["backup:retain_weeks"], out var weeks) ? weeks : 6;
BackupRetainMonths = int.TryParse(config["backup:retain_months"], out var months) ? months : 18;
UpdateUrl = config["update:url"];
UpdateAuto = TrueValues.Contains(config["update:auto"]?.ToLower());
SyncUrl = config["sync:url"];
SyncUsername = config["sync:username"] ?? "";
SyncPassword = config["sync:password"] ?? "";
@@ -126,7 +108,6 @@ namespace Elwig.Helpers {
s, config[$"scale.{s}:type"], config[$"scale.{s}:model"], config[$"scale.{s}:connection"],
config[$"scale.{s}:empty"], config[$"scale.{s}:filling"], config[$"scale.{s}:limit"],
config[$"scale.{s}:required"] != null ? TrueValues.Contains(config[$"scale.{s}:required"]?.ToLower()) : null,
config[$"scale.{s}:synctime"] != null ? !FalseValues.Contains(config[$"scale.{s}:synctime"]?.ToLower()) : null,
config[$"scale.{s}:log"]
));
}
+201
View File
@@ -0,0 +1,201 @@
using Microsoft.Data.Sqlite;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Elwig.Helpers {
internal sealed class DatabaseBackupService {
private const int DailyBackupCount = 7;
private const int WeeklyBackupCount = 5;
private readonly string DatabaseFile;
private readonly string BackupDirectory;
private readonly string DatabaseName;
private readonly string BackupPrefix;
private readonly string LockFile;
private readonly Func<DateTime> Now;
private readonly SemaphoreSlim Gate = new(1, 1);
internal DatabaseBackupService(string databaseFile, Func<DateTime>? now = null) {
DatabaseFile = Path.GetFullPath(databaseFile);
BackupDirectory = Path.Combine(Path.GetDirectoryName(DatabaseFile)!, "backup");
DatabaseName = Path.GetFileNameWithoutExtension(DatabaseFile);
BackupPrefix = $"{DatabaseName}_";
LockFile = Path.Combine(BackupDirectory, $".{DatabaseName}.backup.lock");
Now = now ?? (() => DateTime.Now);
}
internal async Task RunIfNeededAsync() {
if (!await Gate.WaitAsync(0)) return;
try {
var slotDate = GetSlotDate(Now());
await Task.Run(() => Run(slotDate));
} catch {
// Automatic backups dont prevent Elwig from starting or running.
} finally {
Gate.Release();
}
}
private void Run(DateOnly slotDate) {
Directory.CreateDirectory(BackupDirectory);
FileStream lockStream;
try {
lockStream = new FileStream(LockFile, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
} catch (IOException) {
// Another Elwig instance is currently creating/pruning backups.
return;
}
using (lockStream) {
CleanupTemporaryFiles();
var backupFile = GetBackupFile(slotDate);
if (!File.Exists(backupFile)) {
CreateBackup(backupFile);
}
if (File.Exists(backupFile)) {
PruneBackups(slotDate);
}
}
}
private void CreateBackup(string backupFile) {
var id = Guid.NewGuid().ToString("N");
var temporaryDatabase = Path.Combine(BackupDirectory, $".{DatabaseName}.backup-{id}.sqlite3.tmp");
var temporaryArchive = Path.Combine(BackupDirectory, $".{DatabaseName}.backup-{id}.zip.tmp");
try {
var sourceConnectionString = new SqliteConnectionStringBuilder {
DataSource = DatabaseFile,
Mode = SqliteOpenMode.ReadOnly,
Cache = SqliteCacheMode.Default,
Pooling = false,
}.ToString();
var destinationConnectionString = new SqliteConnectionStringBuilder {
DataSource = temporaryDatabase,
Mode = SqliteOpenMode.ReadWriteCreate,
Cache = SqliteCacheMode.Default,
Pooling = false,
}.ToString();
using (var source = new SqliteConnection(sourceConnectionString))
using (var destination = new SqliteConnection(destinationConnectionString)) {
source.Open();
destination.Open();
source.BackupDatabase(destination);
using var check = destination.CreateCommand();
check.CommandText = "PRAGMA quick_check";
if (!string.Equals(check.ExecuteScalar()?.ToString(), "ok", StringComparison.OrdinalIgnoreCase)) {
throw new InvalidDataException("The automatic database backup failed its SQLite integrity check.");
}
}
using (var archive = ZipFile.Open(temporaryArchive, ZipArchiveMode.Create)) {
archive.CreateEntryFromFile(temporaryDatabase, "database.sqlite3", CompressionLevel.SmallestSize);
}
try {
File.Move(temporaryArchive, backupFile, false);
} catch (IOException) when (File.Exists(backupFile)) {
// A completed backup won a publish race. Its time slot is satisfied.
}
} finally {
DeleteFile(temporaryDatabase);
DeleteFile(temporaryArchive);
}
}
private void CleanupTemporaryFiles() {
foreach (var file in Directory.EnumerateFiles(BackupDirectory, $".{DatabaseName}.backup-*.tmp")) {
DeleteFile(file);
}
}
internal void PruneBackups(DateOnly slotDate) {
var backups = GetManagedBackups().ToArray();
var retained = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
var dailyStart = slotDate.AddDays(-(DailyBackupCount - 1));
foreach (var backup in backups.Where(b => b.Date >= dailyStart && b.Date <= slotDate)) {
retained.Add(backup.File);
}
var daysSinceMonday = ((int)slotDate.DayOfWeek + 6) % 7;
var currentWeekStart = slotDate.AddDays(-daysSinceMonday);
for (var i = 1; i <= WeeklyBackupCount; i++) {
var weekStart = currentWeekStart.AddDays(-7 * i);
RetainNewest(backups, retained, weekStart, weekStart.AddDays(7));
}
var currentMonthStart = new DateOnly(slotDate.Year, slotDate.Month, 1);
foreach (var month in backups
.Where(b => b.Date < currentMonthStart)
.GroupBy(b => (b.Date.Year, b.Date.Month))) {
retained.Add(month.OrderByDescending(b => b.Date).First().File);
}
// Clock corrections should not cause future-dated backups to be deleted.
foreach (var backup in backups.Where(b => b.Date > slotDate)) {
retained.Add(backup.File);
}
foreach (var backup in backups.Where(b => !retained.Contains(b.File))) {
DeleteFile(backup.File);
}
}
private static void RetainNewest(
IEnumerable<(string File, DateOnly Date)> backups,
ISet<string> retained,
DateOnly start,
DateOnly end
) {
var newest = backups
.Where(b => b.Date >= start && b.Date < end)
.OrderByDescending(b => b.Date)
.FirstOrDefault();
if (newest.File != null) retained.Add(newest.File);
}
private IEnumerable<(string File, DateOnly Date)> GetManagedBackups() {
foreach (var file in Directory.EnumerateFiles(BackupDirectory, $"{BackupPrefix}*.sqlite3.zip")) {
var name = Path.GetFileName(file);
if (!name.StartsWith(BackupPrefix, StringComparison.OrdinalIgnoreCase) ||
!name.EndsWith(".sqlite3.zip", StringComparison.OrdinalIgnoreCase)) {
continue;
}
var dateText = name[BackupPrefix.Length..^".sqlite3.zip".Length];
if (DateOnly.TryParseExact(dateText, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out var date)) {
yield return (file, date);
}
}
}
private string GetBackupFile(DateOnly date) {
return Path.Combine(BackupDirectory, $"{BackupPrefix}{date:yyyy-MM-dd}.sqlite3.zip");
}
private static void DeleteFile(string file) {
try {
File.Delete(file);
} catch {
// Cleanup and retention are best-effort and will be retried later.
}
}
internal static DateOnly GetSlotDate(DateTime timestamp) {
return DateOnly.FromDateTime(timestamp.Hour >= 3 ? timestamp : timestamp.AddDays(-1));
}
}
}
+9 -25
View File
@@ -18,11 +18,9 @@ namespace Elwig.Helpers.Export {
}
public static async Task ExportSqlite(string filename, bool zipFile) {
var tmp = filename + ".tmp";
try {
File.Delete(tmp);
if (zipFile) {
using var zip = ZipFile.Open(tmp, ZipArchiveMode.Create);
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)) {
@@ -48,20 +46,14 @@ namespace Elwig.Helpers.Export {
var db = zip.CreateEntryFromFile(App.Config.DatabaseFile, "database.sqlite3", CompressionLevel.SmallestSize);
} else {
File.Copy(App.Config.DatabaseFile, tmp);
}
File.Move(tmp, filename, true);
} finally {
File.Delete(tmp);
File.Copy(App.Config.DatabaseFile, filename, true);
}
}
public static async Task ExportSql(string filename, bool zipFile) {
var tmp = filename + ".tmp";
try {
File.Delete(tmp);
if (zipFile) {
using var zip = ZipFile.Open(tmp, ZipArchiveMode.Create);
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)) {
@@ -90,14 +82,10 @@ namespace Elwig.Helpers.Export {
await ExportSql(writer);
}
} else {
using var stream = File.OpenWrite(tmp);
using var stream = File.OpenWrite(filename);
using var writer = new StreamWriter(stream, Utils.UTF8);
await ExportSql(writer);
}
File.Move(tmp, filename, true);
} finally {
File.Delete(tmp);
}
}
public static async Task ExportSql(StreamWriter writer) {
@@ -212,7 +200,7 @@ namespace Elwig.Helpers.Export {
}
}
public static async Task ImportSqlite(string filename, bool zipFile = false, bool keepSource = true) {
public static async Task ImportSqlite(string filename, bool zipFile = false) {
if (zipFile) {
var newName = Path.ChangeExtension(App.Config.DatabaseFile, ".new.sqlite3");
try {
@@ -221,7 +209,7 @@ namespace Elwig.Helpers.Export {
foreach (var entry in zip.Entries) {
if (entry.Name.EndsWith(".sqlite3")) {
entry.ExtractToFile(newName);
await ImportSqlite(newName, keepSource: false);
await ImportSqlite(newName);
return;
}
}
@@ -233,11 +221,7 @@ namespace Elwig.Helpers.Export {
var oldName = Path.ChangeExtension(App.Config.DatabaseFile, ".old.sqlite3");
File.Move(App.Config.DatabaseFile, oldName, true);
if (keepSource) {
File.Copy(filename, App.Config.DatabaseFile, false);
} else {
File.Move(filename, App.Config.DatabaseFile, false);
}
using var cnx = await AppDbContext.ConnectAsync();
await cnx.ExecuteBatch("VACUUM");
@@ -250,7 +234,7 @@ namespace Elwig.Helpers.Export {
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, keepSource: false);
await ImportSqlite(newName);
} finally {
if (File.Exists(newName)) File.Delete(newName);
}
+23 -40
View File
@@ -10,6 +10,7 @@ using System.IO.Compression;
using System.Linq;
using System.Text.Json.Nodes;
using System.Threading.Tasks;
using System.Windows;
namespace Elwig.Helpers.Export {
public static class ElwigData {
@@ -35,16 +36,14 @@ namespace Elwig.Helpers.Export {
public static async Task Import(IEnumerable<string> filenames, ImportMode mode) {
try {
Dictionary<string, Branch> branches;
Dictionary<int, AT_Kg> kgs;
Dictionary<int, int> currentDids;
Dictionary<string, int> currentLsNrs;
Dictionary<int, List<WbRd>> currentWbRde;
Dictionary<int, WbKg> currentWbKgs;
Dictionary<int, AT_Kg> kgs;
List<WbGl> currentWbGls;
using (var ctx = new AppDbContext()) {
branches = await ctx.FetchBranches().ToDictionaryAsync(b => b.ZwstId);
kgs = await ctx.Katastralgemeinden.ToDictionaryAsync(k => k.KgNr);
currentDids = await ctx.Deliveries
.GroupBy(d => d.Year)
.ToDictionaryAsync(g => g.Key, g => g.Max(d => d.DId));
@@ -53,8 +52,8 @@ namespace Elwig.Helpers.Export {
currentWbRde = await ctx.WbRde
.GroupBy(r => r.KgNr)
.ToDictionaryAsync(g => g.Key, g => g.ToList());
currentWbKgs = await ctx.WbKgs.ToDictionaryAsync(k => k.KgNr);
currentWbGls = await ctx.WbGls.ToListAsync();
kgs = await ctx.Katastralgemeinden.Include(k => k.WbKg).ToDictionaryAsync(k => k.KgNr);
}
var data = new List<(
@@ -123,7 +122,6 @@ namespace Elwig.Helpers.Export {
var obj = JsonNode.Parse(line)!.AsObject();
var (k, g) = obj.ToWbKg(currentWbGls);
r.WbKgs.Add(k);
currentWbKgs[k.KgNr] = k;
if (g != null) {
currentWbGls[g.GlNr] = g;
r.WbGls.Add(g);
@@ -137,7 +135,7 @@ namespace Elwig.Helpers.Export {
string? line;
while ((line = await reader.ReadLineAsync()) != null) {
var obj = JsonNode.Parse(line)!.AsObject();
var (m, b, telNrs, emailAddrs, timestamps) = obj.ToMember(kgs, currentWbKgs);
var (m, b, telNrs, emailAddrs, timestamps) = obj.ToMember(kgs);
r.Members.Add(m);
if (b != null) r.BillingAddresses.Add(b);
r.TelephoneNumbers.AddRange(telNrs);
@@ -165,7 +163,7 @@ namespace Elwig.Helpers.Export {
string? line;
while ((line = await reader.ReadLineAsync()) != null) {
var obj = JsonNode.Parse(line)!.AsObject();
var (contract, areaCom, wbrd, timestamps) = obj.ToAreaCom(kgs, currentWbKgs, currentWbRde);
var (contract, areaCom, wbrd, timestamps) = obj.ToAreaCom(currentWbRde);
r.Contracts.Add(contract);
r.AreaCommitments.Add(areaCom);
if (wbrd != null) {
@@ -184,7 +182,7 @@ namespace Elwig.Helpers.Export {
string? line;
while ((line = await reader.ReadLineAsync()) != null) {
var obj = JsonNode.Parse(line)!.AsObject();
var (contract, areaComs, wbrd, timestamps) = obj.ToAreaComContract(kgs, currentWbKgs, currentWbRde);
var (contract, areaComs, wbrd, timestamps) = obj.ToAreaComContract(currentWbRde);
r.Contracts.Add(contract);
r.AreaCommitments.AddRange(areaComs.Select(v => v.Item1));
if (wbrd != null) {
@@ -205,7 +203,7 @@ namespace Elwig.Helpers.Export {
string? line;
while ((line = await reader.ReadLineAsync()) != null) {
var obj = JsonNode.Parse(line)!.AsObject();
var (d, parts, mods, rde, timestamps) = obj.ToDelivery(currentLsNrs, currentDids, kgs, currentWbKgs, currentWbRde);
var (d, parts, mods, rde, timestamps) = obj.ToDelivery(currentLsNrs, currentDids, kgs, currentWbRde);
r.Deliveries.Add(d);
r.DeliveryParts.AddRange(parts.Select(p => p.Item1));
r.Modifiers.AddRange(mods);
@@ -638,13 +636,11 @@ namespace Elwig.Helpers.Export {
["zwstid"] = m.ZwstId,
["lfbis_nr"] = m.LfbisNr,
["ustid_nr"] = m.UstIdNr,
["ooc_id"] = m.OrganicOperatorId,
["org_auth_code"] = m.OrganicAuthorityCode,
["juridical_pers"] = m.IsJuridicalPerson,
["full_delivery"] = m.IsFullDelivery,
["accounting"] = m.IsAccounting,
["volllieferant"] = m.IsVollLieferant,
["buchführend"] = m.IsBuchführend,
["organic"] = m.IsOrganic,
["officer"] = m.IsOfficer,
["funktionär"] = m.IsFunktionär,
["active"] = m.IsActive,
["deceased"] = m.IsDeceased,
["iban"] = m.Iban,
@@ -684,11 +680,11 @@ namespace Elwig.Helpers.Export {
};
}
public static (Member, BillingAddr?, List<MemberTelNr>, List<MemberEmailAddr>, (DateTime CreatedAt, DateTime ModifiedAt)?) ToMember(this JsonNode json, Dictionary<int, AT_Kg> kgs, Dictionary<int, WbKg> currentWbKgs) {
public static (Member, BillingAddr?, List<MemberTelNr>, List<MemberEmailAddr>, (DateTime CreatedAt, DateTime ModifiedAt)?) ToMember(this JsonNode json, Dictionary<int, AT_Kg> kgs) {
var mgnr = json["mgnr"]!.AsValue().GetValue<int>();
var kgnr = json["default_kgnr"]?.AsValue().GetValue<int>();
if (kgnr != null && !currentWbKgs.Values.Any(k => k.KgNr == kgnr)) {
throw new KeyNotFoundException($"Für KG {(kgs.TryGetValue(kgnr.Value, out var k) ? k.Name : "?")} ({kgnr:00000}) ist noch keine Großlage festgelegt!\n(Stammdaten \u2192 Herkunftshierarchie)");
if (kgnr != null && !kgs.Values.Any(k => k.WbKg?.KgNr == kgnr)) {
throw new ArgumentException($"Für KG {(kgs.TryGetValue(kgnr.Value, out var k) ? k.Name : "?")} ({kgnr:00000}) ist noch keine Großlage festgelegt!\n(Stammdaten → Herkunftshierarchie)");
}
var createdAt = json["created_at"]?.AsValue().GetValue<string>();
var modifiedAt = json["modified_at"]?.AsValue().GetValue<string>();
@@ -712,13 +708,11 @@ namespace Elwig.Helpers.Export {
ZwstId = json["zwstid"]?.AsValue().GetValue<string>(),
LfbisNr = json["lfbis_nr"]?.AsValue().GetValue<string>(),
UstIdNr = json["ustid_nr"]?.AsValue().GetValue<string>(),
OrganicOperatorId = json["ooc_id"]?.AsValue().GetValue<string>(),
OrganicAuthorityCode = json["org_auth_code"]?.AsValue().GetValue<string>(),
IsJuridicalPerson = json["juridical_pers"]?.AsValue().GetValue<bool>() ?? false,
IsFullDelivery = json["full_delivery"]?.AsValue().GetValue<bool>() ?? json["volllieferant"]?.AsValue().GetValue<bool>() ?? false,
IsAccounting = json["accounting"]?.AsValue().GetValue<bool>() ?? json["buchführend"]?.AsValue().GetValue<bool>() ?? false,
IsVollLieferant = json["volllieferant"]?.AsValue().GetValue<bool>() ?? false,
IsBuchführend = json["buchführend"]?.AsValue().GetValue<bool>() ?? false,
IsOrganic = json["organic"]?.AsValue().GetValue<bool>() ?? false,
IsOfficer = json["officer"]?.AsValue().GetValue<bool>() ?? json["funktionär"]?.AsValue().GetValue<bool>() ?? false,
IsFunktionär = json["funktionär"]?.AsValue().GetValue<bool>() ?? false,
IsActive = json["active"]?.AsValue().GetValue<bool>() ?? false,
IsDeceased = json["deceased"]?.AsValue().GetValue<bool>() ?? false,
Iban = json["iban"]?.AsValue().GetValue<string>(),
@@ -766,8 +760,7 @@ namespace Elwig.Helpers.Export {
["reason"] = h.Reason,
["source"] = h.Source,
["shares"] = h.Shares,
["signed_company"] = h.CompanyHasSigned,
["signed_member"] = h.MemberHasSigned,
["signed"] = h.MemberHasSigned,
["value_per_share"] = h.ValuePerShare,
["currency"] = h.CurrencyCode,
["deduct_year"] = h.DeductYear,
@@ -787,8 +780,7 @@ namespace Elwig.Helpers.Export {
Reason = json["reason"]!.AsValue().GetValue<string>(),
Source = json["source"]!.AsValue().GetValue<string>(),
Shares = json["shares"]!.AsValue().GetValue<int>(),
CompanyHasSigned = json["signed_company"]?.AsValue().GetValue<bool>() ?? false,
MemberHasSigned = json["signed_member"]?.AsValue().GetValue<bool>() ?? false,
MemberHasSigned = json["signed"]?.AsValue().GetValue<bool>() ?? false,
ValuePerShare = json["value_per_share"]?.AsValue().GetValue<decimal>(),
CurrencyCode = json["currency"]?.AsValue().GetValue<string>(),
DeductYear = json["deduct_year"]?.AsValue().GetValue<int>(),
@@ -823,13 +815,10 @@ namespace Elwig.Helpers.Export {
};
}
public static (AreaComContract, List<(AreaCom, (DateTime CreatedAt, DateTime ModifiedAt)?)>, WbRd?, (DateTime CreatedAt, DateTime ModifiedAt)?) ToAreaComContract(this JsonNode json, Dictionary<int, AT_Kg> kgs, Dictionary<int, WbKg> currentWbKgs, Dictionary<int, List<WbRd>> riede) {
public static (AreaComContract, List<(AreaCom, (DateTime CreatedAt, DateTime ModifiedAt)?)>, WbRd?, (DateTime CreatedAt, DateTime ModifiedAt)?) ToAreaComContract(this JsonNode json, Dictionary<int, List<WbRd>> riede) {
var kgnr = json["kgnr"]!.AsValue().GetValue<int>();
var ried = json["ried"]?.AsValue().GetValue<string>();
var fbnr = json["fbnr"]!.AsValue()!.GetValue<int>();
if (!currentWbKgs.Values.Any(k => k.KgNr == kgnr)) {
throw new KeyNotFoundException($"Für KG {(kgs.TryGetValue(kgnr, out var k) ? k.Name : "?")} ({kgnr:00000}) ist noch keine Großlage festgelegt!\n(Stammdaten \u2192 Herkunftshierarchie)");
}
WbRd? rd = null;
bool newRd = false;
if (ried != null) {
@@ -877,12 +866,9 @@ namespace Elwig.Helpers.Export {
DateTime.ParseExact(modifiedAt, "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None)));
}
public static (AreaComContract, AreaCom, WbRd?, (DateTime CreatedAt, DateTime ModifiedAt)?) ToAreaCom(this JsonNode json, Dictionary<int, AT_Kg> kgs, Dictionary<int, WbKg> currentWbKgs, Dictionary<int, List<WbRd>> riede) {
public static (AreaComContract, AreaCom, WbRd?, (DateTime CreatedAt, DateTime ModifiedAt)?) ToAreaCom(this JsonNode json, Dictionary<int, List<WbRd>> riede) {
var kgnr = json["kgnr"]!.AsValue().GetValue<int>();
var ried = json["ried"]?.AsValue().GetValue<string>();
if (!currentWbKgs.Values.Any(k => k.KgNr == kgnr)) {
throw new KeyNotFoundException($"Für KG {(kgs.TryGetValue(kgnr, out var k) ? k.Name : "?")} ({kgnr:00000}) ist noch keine Großlage festgelegt!\n(Stammdaten \u2192 Herkunftshierarchie)");
}
WbRd? rd = null;
bool newRd = false;
if (ried != null) {
@@ -961,7 +947,7 @@ namespace Elwig.Helpers.Export {
};
if (p.IsSplCheck) obj["spl_check"] = p.IsSplCheck;
if (p.IsHandPicked != null) obj["hand_picked"] = p.IsHandPicked;
if (p.IsContracted != null) obj["contracted"] = p.IsContracted;
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.Acid != null) obj["acid"] = p.Acid;
@@ -971,7 +957,7 @@ namespace Elwig.Helpers.Export {
return obj;
}
public static (Delivery, List<(DeliveryPart, (DateTime CreatedAt, DateTime ModifiedAt)?)>, List<DeliveryPartModifier>, List<WbRd>, (DateTime CreatedAt, DateTime ModifiedAt)?) ToDelivery(this JsonNode json, Dictionary<string, int> currentLsNrs, Dictionary<int, int> currentDids, Dictionary<int, AT_Kg> kgs, Dictionary<int, WbKg> currentWbKgs, Dictionary<int, List<WbRd>> riede) {
public static (Delivery, List<(DeliveryPart, (DateTime CreatedAt, DateTime ModifiedAt)?)>, List<DeliveryPartModifier>, List<WbRd>, (DateTime CreatedAt, DateTime ModifiedAt)?) ToDelivery(this JsonNode json, Dictionary<string, int> currentLsNrs, Dictionary<int, int> currentDids, Dictionary<int, AT_Kg> kgs, Dictionary<int, List<WbRd>> riede) {
var year = json["year"]!.AsValue().GetValue<int>();
var lsnr = json["lsnr"]!.AsValue().GetValue<string>();
var did = currentLsNrs.GetValueOrDefault(lsnr, -1);
@@ -997,9 +983,6 @@ namespace Elwig.Helpers.Export {
}, [.. json["parts"]!.AsArray().Select(p => p!.AsObject()).Select<JsonObject, (DeliveryPart, (DateTime, DateTime)?)>(p => {
var kgnr = p["kgnr"]?.AsValue().GetValue<int>();
var ried = p["ried"]?.AsValue().GetValue<string>();
if (kgnr != null && !currentWbKgs.Values.Any(k => k.KgNr == kgnr)) {
throw new KeyNotFoundException($"Für KG {(kgs.TryGetValue(kgnr.Value, out var k) ? k.Name : "?")} ({kgnr:00000}) ist noch keine Großlage festgelegt!\n(Stammdaten \u2192 Herkunftshierarchie)");
}
WbRd? rd = null;
if (ried != null && kgnr != null) {
var rde = riede.GetValueOrDefault(kgnr.Value, []);
@@ -1035,7 +1018,7 @@ namespace Elwig.Helpers.Export {
Comment = p["comment"]?.AsValue().GetValue<string>(),
IsSplCheck = p["spl_check"]?.AsValue().GetValue<bool>() ?? false,
IsHandPicked = p["hand_picked"]?.AsValue().GetValue<bool>(),
IsContracted = p["contracted"]?.AsValue().GetValue<bool>() ?? 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>(),
Acid = p["acid"]?.AsValue().GetValue<double>(),
+4 -46
View File
@@ -1,7 +1,6 @@
using Microsoft.Data.Sqlite;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.IO.Hashing;
@@ -13,7 +12,6 @@ using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace Elwig.Helpers {
public static partial class Extensions {
@@ -136,39 +134,11 @@ namespace Elwig.Helpers {
return await cmd.ExecuteScalarAsync();
}
public static async Task QuickCheck(this SqliteConnection cnx) {
using var cmd = cnx.CreateCommand();
cmd.CommandText = "PRAGMA quick_check";
using var reader = await cmd.ExecuteReaderAsync();
var list = new List<string>();
while (await reader.ReadAsync()) {
list.Add(reader.GetString(0));
}
if (list.Count != 1 || list[0] != "ok") {
throw new FileFormatException($"Integrity problems ({list.Count}):\n" + string.Join("\n", list.Take(50)));
}
}
public static async Task IntegrityCheck(this SqliteConnection cnx) {
using var cmd = cnx.CreateCommand();
cmd.CommandText = "PRAGMA integrity_check";
using var reader = await cmd.ExecuteReaderAsync();
var list = new List<string>();
while (await reader.ReadAsync()) {
list.Add(reader.GetString(0));
}
if (list.Count != 1 || list[0] != "ok") {
throw new FileFormatException($"Integrity problems ({list.Count}):\n" + string.Join("\n", list.Take(50)));
}
}
public static async Task ForeignKeyCheck(this SqliteConnection cnx) {
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 Table, long RowId, string Parent, long FkId)>();
var list = new List<(string, long, string, long)>();
while (await reader.ReadAsync()) {
var table = reader.GetString(0);
var rowid = reader.GetInt64(1);
@@ -176,11 +146,7 @@ namespace Elwig.Helpers {
var fkid = reader.GetInt64(3);
list.Add((table, rowid, parent, fkid));
}
if (list.Count > 0) {
throw new InvalidDataException($"Foreign key violations ({list.Count}):\n" + string.Join("\n", list.Take(50)
.Select(v => $"{v.Table} - {v.RowId} - {v.Parent} - {v.FkId}")));
}
return [.. list];
}
public static IEnumerable<T> Join<T>(this IEnumerable<T> src, Func<T> separatorFactory) {
@@ -193,25 +159,17 @@ namespace Elwig.Helpers {
}
}
public static void AddToolTipCell(this Grid grid, string text, int row, int col, int colSpan = 1, bool bold = false, bool alignRight = false, bool alignCenter = false, Brush? color = null) {
public static void AddToolTipCell(this Grid grid, string text, int row, int col, int colSpan = 1, bool bold = false, bool alignRight = false, bool alignCenter = false) {
var tb = new TextBlock() {
Text = text,
TextAlignment = alignRight ? TextAlignment.Right : alignCenter ? TextAlignment.Center : TextAlignment.Left,
Margin = new(0, 12 * row, 0, 0),
FontWeight = bold ? FontWeights.Bold : FontWeights.Normal,
};
if (color != null) tb.Foreground = color;
tb.SetValue(Grid.ColumnProperty, col);
tb.SetValue(Grid.ColumnSpanProperty, colSpan);
grid.Children.Add(tb);
}
public static (int Year, int Week) GetYearAndWeek(this DateTime date) {
return (ISOWeek.GetYear(date), ISOWeek.GetWeekOfYear(date));
}
public static (int Year, int Tertial) GetYearAndTertial(this DateTime date) {
return (date.Month <= 7 ? date.Year - 1 : date.Year, date.Month == 12 || date.Month <= 3 ? 2 : date.Month <= 7 ? 3 : 1);
}
}
}
-303
View File
@@ -1,303 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
namespace Elwig.Helpers {
public static partial class Normalizer {
[GeneratedRegex(@"(?=(?:(?:bundes)?straße|gasse|weg|platz|allee|ring|zeile?|steig|hof|markt|kai|ufer|brücke|tor|stiege|promenade|gang|siedlung)\b)|[\s-]+", RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase)]
private static partial Regex GeneratedStreetNameWordsRegex();
private static readonly Regex StreetNameWordsRegex = GeneratedStreetNameWordsRegex();
private static readonly HashSet<string> StreetTypes = [
"Straße", "Gasse", "Weg", "Platz", "Allee", "Ring", "Zeile", "Zeil", "Steig", "Hof",
"Markt", "Kai", "Ufer", "Brücke", "Tor", "Stiege", "Promenade", "Gang", "Siedlung"];
private static readonly HashSet<string> StreetArticles = ["der", "die", "das", "des", "dem", "den"];
private static readonly HashSet<string> StreetPrepositions = [
"an", "am", "auf", "aus", "bei", "beim", "hinter", "hinterm", "in", "im", "ins", "nach",
"neben", "über", "unter", "von", "vom", "van", "vor", "zu", "zum", "zur", "zwischen",
"durch", "mit"];
private static readonly HashSet<string> StreetNumbers = [ "Zwei", "Drei", "Vier", "Fünf", "Sechs", "Sieben" ];
private static readonly HashSet<string> StreetAdjectives = [
"alter", "alte", "alten", "altem", "altes",
"äußere", "äußere", "äußeren", "äußerem", "äußeres",
// "breiter", "breite", "breiten", "breitem", "breites",
"dritter", "dritte", "dritten", "drittem", "drittes",
"erster", "erste", "ersten", "erstem", "erstes",
"großer", "große", "großen", "großem", "großes",
"hoher", "hohe", "hohen", "hohem", "hohes",
"innerer", "innere", "inneren", "innerem", "inneres",
"kleiner", "kleine", "kleinen", "kleinem", "kleines",
"kurzer", "kurze", "kurzen", "kurzem", "kurzes",
"langer", "lange", "langen", "langem", "langes",
"linker", "linke", "linken", "linkem", "linkes",
"mittlerer", "mittlere", "mittleren", "mittlerem", "mittleres",
"neuer", "neue", "neuen", "neuem", "neues",
"oberer", "obere", "oberen", "oberem", "oberes",
"rechter", "rechte", "rechten", "rechtem", "rechtes",
"schmaler", "schmale", "schmalen", "schmalem", "schmales",
"schöner", "schöne", "schönen", "schönem", "schönes",
"unterer", "untere", "unteren", "unterem", "unteres",
"hinterer", "hintere", "hinteren", "hinterem", "hinteres",
"vorderer", "vordere", "vorderen", "vorderem", "vorderes",
"runder", "runde", "runden", "rundem", "rundes",
"kalter", "kalte", "kalten", "kaltem", "kaltes"];
private static readonly HashSet<string> StreetLastNames = [
"Habsburger", "Lothringer", "Leitzenberger", "Luyderer", "Preiner", "Radinger", "Seefelder", "Staribacher", "Gschmeidler",
"Hannover", "Münster", "Salzgitter", "Speyer", "Trier"];
private static readonly HashSet<string> StreetPersonTitles = [
"St.", "Familie",
"Dr.", "DDr.", "Hofrat", "Baurat", "Kommerzialrat", "Dir.", "Ing.", "Prof.", "Mag.", "DI", "OSR", "Präsident",
"Landeshauptmann", "LH", "Bürgermeister", "Bgm.", "Minister",
"Kaiser", "Kaiserin", "König", "Königin", "Erzherzog", "Erzherzogin", "Herzog", "Fürst", "Graf", "Gräfin", "Markgraf", "Kronprinz", "Prinz", "Ritter", "Freiherr", "Lord",
"Abt", "Bischof", "Propst", "Dechant", "Kardinal", "Monsignore", "Pfarrer", "Pater", "Prälat",
"Oberst"];
private static readonly HashSet<string> StreetGivenNames = [
"Adalbert", "Adam", "Adele", "Adelheid", "Adolf", "Adolph", "Adrian", "Albert", "Albrecht", "Alexander", "Alfons", "Alfred", "Alois", "Aloisia",
"Andreas", "Andrea", "Andre", "Anna", "Anton", "Arnold", "Arthur", "August", "Augustin", "Augustine", "Agnes", "Angelika", "Ada", "Adelheid", "Anni", "Anita",
"Barbara", "Beate", "Beatrix", "Benedikt", "Bernhard", "Berta", "Bertha", "Berthold", "Brüder", "Bruno", "Brigitte",
"Camillo", "Carl", "Caspar", "Catharina", "Christian", "Christine", "Christof", "Christoph", "Clara", "Clemens", "Conrad", "Claus", "Camillo", "Claudia",
"Daniel", "Dietmar", "Dietrich",
"Edgar", "Edi", "Edith", "Edmund", "Egon", "Elsa", "Eduard", "Emmerich", "Erhard", "Erich", "Ernst", "Erwin", "Eugen", "Ewald", "Eberhard",
"Elisabeth", "Emanuel", "Emerich", "Emil", "Emma", "Engelbert", "Elias",
"Franz", "Ferdinand", "Friedrich", "Felix", "Florian", "Fritz", "Franziska", "Fred",
"Georg", "Gregor", "Gustav", "Gabriel", "Gebrüder", "Gabriele", "Gerhard", "Gerhart", "Gertrude", "Gottfried", "Gottlieb", "Grete",
"Günther", "Günter",
"Hans", "Hanns", "Heinrich", "Heinz", "Helmut", "Helmuth", "Hermann", "Herta", "Herbert", "Hubert", "Harald", "Horst", "Helene", "Helga",
"Hieronymus", "Hilde", "Hugo",
"Isabelle", "Ignaz", "Ilse", "Ingeborg", "Isidor",
"Josef", "Josefine", "Joseph", "Johann", "Johanna", "Johan", "Johannes", "Hannes", "Harry", "Jakob", "Jacob", "Jan", "Julian", "Julius", "Julia", "Jürgen",
"Karl", "Kasimir", "Konrad", "Klemens", "Klara", "Katharina", "Kurt", "Kaspar", "Klaus", "Koloman", "Konstantin", "Killian",
"Leopold", "Leo", "Lorenz", "Lothar", "Louise", "Ludmilla", "Ludwig", "Lukas", "Ladislaus", "Lambert", "Laurenz", "Liese",
"Lise", "Lilly", "Lina", "Lothar", "Lotte", "Luise", "Leonhard", "Lotte", "Martha",
"Maria", "Marie", "Michael", "Martin", "Max", "Maximilian", "Manuel", "Manuela", "Moritz", "Marianne", "Manfred", "Marc",
"Mathias", "Matthias", "Matthäus",
"Margarete", "Margarethe",
"Nico", "Niko", "Niklas", "Niclas", "Nikolaus", "Norbert",
"Otto", "Ottokar", "Oskar", "Olga", "Oswald", "Othmar",
"Paul", "Pauline", "Patrick", "Pepi", "Peter", "Philipp", "Philip", "Petrus",
"Robert", "Rudolf", "Richard", "Ruprecht", "Raffael", "Rolf", "Roman", "Rosa", "Rosalia", "Rupert", "Raimund",
"Sigmund", "Siegfried", "Simon", "Stanislaus", "Stefan", "Stephan", "Sepp", "Samuel", "Sebastian", "Susi",
"Theodor", "Thomas", "Theresia", "Thaddäus", "Theo", "Theophil", "Tina", "Titus", "Toni", "Trude",
"Ullrich", "Ulrich", "Udo",
"Viktor", "Vinzenz", "Victor",
"Wolfgang", "Willibald", "Wilhelm", "Willhelm", "Wilhelmine", "Walter", "Walther", "Wenzel", "Werner", "Willi",
"Zacharias"];
private static readonly HashSet<string> LocalityNames = [
"Groß-Enzersdorf",
"Groß Burgstall", "Klein Eberharts", "Klein-Engersdorf", "Groß-Enzersdorf", "Klein-Erlauf",
"Groß Gerungs", "Klein Gundholz", "Klein-Harras", "Klein-Heinrichschlag", "Groß-Höbarten",
"Klein-Jetzelsdorf", "Klein-Mariazell", "Groß Meinharts", "Klein-Meiseldorf", "Groß-Neusiedl", "Klein-Neusiedl", "Klein-Pöchlarn",
"Groß-Radischen", "Klein-Radischen", "Groß Raßberg", "Klein Reinprechts", "Klein-Reinprechtsdorf", "Groß-Reipersdorf", "Klein-Ruprechts",
"Groß-Schollach", "Klein-Schollach", "Groß-Schweinbarth", "Groß-Siegharts", "Klein-Siegharts", "Groß Sierning",
"Klein-Ulrichschlag", "Klein Weinberg", "Klein Wetzles", "Klein-Wien",
];
private static bool IsGivenName(this string word) {
return StreetGivenNames.Contains(word);
}
private static bool IsFamilyName(this string word) {
if (StreetLastNames.Contains(word))
return true;
return false;
}
private static bool IsPersonalName(this string word) {
return word.IsGivenName() || word.IsFamilyName();
}
private static bool IsGeographicalDerivativeName(this string word) {
if (!word.EndsWith("er") || word.IsPersonalName() || word == "Weißer")
return false;
return word.StartsWith("St. ") || word.StartsWith("Ober ") || word.StartsWith("Unter ") || word.StartsWith("Maria") ||
word.EndsWith("sdorfer") || word.EndsWith("ndorfer") || word.EndsWith("ldorfer") ||
word.EndsWith("felder") ||
word.EndsWith("sthaler") || word.EndsWith("nthaler") || word.EndsWith("lthaler") ||
word.EndsWith("dauer") || word.EndsWith("lauer") || word.EndsWith("mauer") || word.EndsWith("nauer") || word.EndsWith("ßauer") ||
word.EndsWith("lbacher") || word.EndsWith("nbacher") || word.EndsWith("ßbacher") ||
word.EndsWith("ringer") || word.EndsWith("singer") ||
word.EndsWith("sbrunner") || word.EndsWith("nbrunner") || word.EndsWith("lbrunner") || word.EndsWith("abrunner") || word.EndsWith("ingbrunner") ||
word.EndsWith("sburger") || word.EndsWith("nburger") || word.EndsWith("mburger") || word.EndsWith("lburger") || word.EndsWith("neuburger") ||
word.EndsWith("berger") ||
word.EndsWith("winkler") ||
word.EndsWith("lsteiner") || word.EndsWith("nsteiner") ||
word.EndsWith("städter") ||
word.EndsWith("stättner") || word.EndsWith("stettner") ||
word.EndsWith("brücker") ||
word.EndsWith("further") || word.EndsWith("furter") ||
word.EndsWith("aaer") ||
word.EndsWith("seer") || word.EndsWith("leer") ||
word.EndsWith("tzner") ||
word.EndsWith("zeller") ||
word.EndsWith("rther") ||
word.EndsWith("sdner") ||
word.EndsWith("gerner") || word.EndsWith("berner") ||
word.EndsWith("frieder") ||
word.EndsWith("litzer") || word.EndsWith("mitzer") || word.EndsWith("eutzer") ||
word.EndsWith("loner") ||
word.EndsWith("skirchner") || word.EndsWith("nkirchner") || word.EndsWith("ingkirchner") ||
word.EndsWith("ziger") ||
word.EndsWith("ließer") ||
word.EndsWith("gerer") ||
word.EndsWith("kreuzer") ||
word == "Wiener" || word == "Brünner" || word == "Znaimer" || word == "Triester" || word == "Prager" || word == "Berliner" || word == "Basler" ||
word == "Retzer" || word == "Tullner" || word == "Badner" ||
word == "Gruber" || word == "Sulzer" || word == "Harraser" || word == "Dörfleser" || word == "Neusiedler" ||
word == "Dornauer" || word == "Siebenhauser" || word == "Alser" ||
word == "Bockenheimer";
}
public static string NormalizeAddress(string address, string? locality = null) {
var idx = address.IndexOf(',');
if (idx >= 0) address = address[..idx];
var (name, nr) = Utils.SplitAddress(address);
return (NormalizeStreetName(name, locality) + " " + nr).Trim();
}
public static string NormalizeStreetName(string name, string? locality = null) {
name = name.Trim().ToLowerInvariant();
if (name == "") {
return "";
} else if (name == "nr.") {
if (locality == null)
return "Nr.";
name = locality.Trim().ToLowerInvariant();
}
name = name.Replace("hautp", "haupt")
.Replace("leop.", "leopold ").Replace("ferd.", "ferdinand ").Replace("gottfr.", "gottfried ")
.Replace("heinr.", "heinrich").Replace("joh.", "johann ").Replace("jos.", "josef ")
.Replace("msgr.", "monsignore ").Replace("pf.", "pfarrer ")
.Replace("präs.", "präsident ");
name = name.Replace("str.", "straße").Replace("strasse", "straße")
.Replace("bruecke", "brücke").Replace("pl.", "platz")
.Replace("gr.", "groß").Replace("kl.", "klein")
.Replace("sankt-", "st.").Replace("sankt ", "st.")
.Replace("wr.", "wiener ")
.Replace(".", ". ");
List<string> words = [.. StreetNameWordsRegex.Split(name)
.Where(w => !string.IsNullOrWhiteSpace(w))
.Select(w => StreetArticles.Contains(w) || StreetPrepositions.Contains(w) ? w : string.Concat(w[0..1].ToUpper(), w.AsSpan(1)))
.Select(w => w == "Ddr." ? "DDr." : w == "Lh" || w == "Osr" ? w.ToUpper() : w)
];
if (words[0] == "Di") words[0] = "DI";
var temp = "|" + string.Join('|', words) + "|";
temp = temp.Replace("|Dipl.|Ing.|", "|DI|").Replace("|Dipl|Ing.|", "|DI|")
.Replace("|Kaiser|Ebersdorf|", "|Kaiser-Ebersdorf|")
.Replace("|Kalk|Deutz|", "|Kalk-Deutz|").Replace("|Kalk|Deutzer|", "|Kalk-Deutzer|")
.Replace("|Hohe|Wand|", "|Hohe Wand|").Replace("|Hohen|Wand|", "|Hohen Wand|").Replace("|Hohewand|", "|Hohe Wand|")
.Replace("|Alten|Markt|", "|Altenmarkt|")
.Replace("|Kirch|Hof|", "|Kirchhof|").Replace("|Bisc|Hof|", "|Bischof|")
.Replace("|Wiener|Neustadt|", "|Wiener Neustadt|").Replace("|Wiener|Neustädter|", "|Wiener Neustädter|")
.Replace("|St.|Pölten|", "|St. Pölten|").Replace("|St.|Pöltner|", "|St. Pöltner|")
.Replace("|Gross|", "|Groß|")
.Replace("|Nr|", "|Nr.|").Replace("|Und|", "|und|");
words = [.. temp.Trim('|').Split('|')];
if (words.Count > 1 && (words[0] == "Groß" || words[0] == "Klein") && !StreetTypes.Contains(words[1])) {
var w = words[0] + words[1].ToLowerInvariant();
words.RemoveRange(0, 2);
words.Insert(0, w);
}
if (words[0].StartsWith("Groß") || words[0].StartsWith("Klein")) {
var repl = LocalityNames.FirstOrDefault(n => n.Replace(" ", "").Replace("-", "").Equals(words[0], StringComparison.InvariantCultureIgnoreCase));
if (repl != null) words[0] = repl;
}
if (words.Count > 2 && words[^2] == "in") {
// remove suffix "in ..."
words.RemoveRange(words.Count - 2, 2);
}
char sep = name.Contains('-') ? '-' : ' ';
if (words.Count <= 1) {
// single word
} else if (StreetTypes.Contains(words[0]) && !StreetTypes.Contains(words[^1])) {
// "Straße der ..." / "Straße des ..."
sep = ' ';
} else if (StreetTypes.Contains(words[^1])) {
// "... Straße" / "...straße"
var type = words[^1];
var isCompound = true;
var isAdjective = StreetAdjectives.Contains(words[^2].ToLowerInvariant());
var isGeographical = false;
var isPerson = false;
var geo = words.FindLastIndex(IsGeographicalDerivativeName);
if (geo >= 0 && geo < words.Count - 2 && words[^2] != "Haupt" && words[^2] != "Bundes" && words[^2] != "Keller") {
isPerson = true;
isGeographical = true;
} else if (words.Any(w => w.Contains(' ') && !w.IsGeographicalDerivativeName())) {
isPerson = true;
isGeographical = true;
} else if (StreetNumbers.Contains(words[0])) {
isPerson = true;
isGeographical = true;
} else if (!StreetPrepositions.Contains(words[0]) && !StreetArticles.Contains(words[0]) && words.FindIndex(StreetPrepositions.Contains) > 0) {
isPerson = true;
isGeographical = true;
}
if (words.Count(w => w.Contains('.')) >= 2 || words.Contains("van") || words.Contains("von") || words.Contains("St.") ||
StreetPersonTitles.Contains(words[0]) || words.Any(w => w.IsGivenName()))
{
isPerson = true;
}
if (!isPerson && isAdjective || StreetArticles.Contains(words[^2]) || StreetPrepositions.Contains(words[^2])) {
isCompound = false;
}
if (!isPerson && words[^2].EndsWith("er") && !StreetLastNames.Contains(words[^2])) {
isGeographical = IsGeographicalDerivativeName(words[^2]);
} else if (words.Count >= 3 && words.Contains("Bad")) {
isPerson = true;
isGeographical = true;
}
sep = isPerson ? '-' : ' ';
if (isPerson && words.Count == 2 && !isGeographical) {
isPerson = false;
isCompound = true;
}
if (isGeographical || isPerson) {
isCompound = false;
}
if (isCompound) {
var w = words[^2] + type.ToLowerInvariant();
words.RemoveRange(words.Count - 2, 2);
words.Add(w);
}
if (isPerson) {
words = [.. words.Select(w => w.Replace(' ', '-'))];
}
} else {
// unknown
}
if (sep == '-' && StreetPrepositions.Contains(words[0]) && words[0] != "von" && words[0] != "van") {
sep = ' ';
int i;
for (i = 0; StreetPrepositions.Contains(words[i]) && i < words.Count; i++);
var word = string.Join('-', words.Skip(i));
words = [.. words.Take(i).Append(word)];
}
var norm = string.Join(sep, words);
return string.Concat(norm[0..1].ToUpperInvariant(), norm.AsSpan(1));
}
}
}
+7 -3
View File
@@ -1,17 +1,20 @@
using Elwig.Services;
using Elwig.Windows;
using System;
using System.Threading.Tasks;
namespace Elwig.Helpers.Printing {
public static class Pdf {
public static void Init(Action? evtHandler = null) {
public static Task Init(Action? evtHandler = null) {
PdfiumNative.FPDF_InitLibrary();
evtHandler?.Invoke();
return Task.CompletedTask;
}
public static void Cleanup() {
public static Task Cleanup() {
PdfiumNative.FPDF_DestroyLibrary();
return Task.CompletedTask;
}
public static void Show(TempFile file, string title) {
@@ -28,13 +31,14 @@ namespace Elwig.Helpers.Printing {
});
}
public static void Print(string path, int copies = 1, bool doublePaged = false) {
public static Task Print(string path, int copies = 1, bool doublePaged = false) {
try {
var printer = new PdfPrinter();
printer.Print(path, copies, doublePaged);
} catch (Exception exc) {
InteractionService.ShowException("Fehler beim Drucken", "Beim Drucken ist ein Fehler aufgetreten", exc);
}
return Task.CompletedTask;
}
}
}
+7 -44
View File
@@ -45,6 +45,7 @@ namespace Elwig.Helpers {
public static int CurrentNextSeason => DateTime.Now.Year - (DateTime.Now.Month <= 3 ? 1 : 0);
public static int CurrentLastSeason => DateTime.Now.Year - (DateTime.Now.Month <= 6 ? 1 : 0);
public static int FollowingSeason => DateTime.Now.Year + (DateTime.Now.Month >= 11 ? 1 : 0);
public static DateTime Today => (DateTime.Now.Hour >= 3) ? DateTime.Today : DateTime.Today.AddDays(-1);
[GeneratedRegex("^serial://([A-Za-z0-9]+):([0-9]+)(,([5-9]),([NOEMSnoems]),(0|1|1\\.5|2|))?$", RegexOptions.Compiled)]
private static partial Regex GeneratedSerialRegex();
@@ -303,11 +304,6 @@ namespace Elwig.Helpers {
return d.ShowDialog() == true ? (d.Weight, d.Reason) : null;
}
public static int? ShowTareCorrectionDialog(int? actualTare, int? targetTare = null) {
var d = new TareCorrectionDialog(actualTare, targetTare);
return d.ShowDialog() == true ? d.TargetTare - d.ActualTare : null;
}
public static (string?, int[])? ShowDeliverySplittingDialog(Delivery delivery) {
var d = new DeliverySplittingDialog(delivery);
return d.ShowDialog() == true ? (d.MgNr?.ToString() ?? d.LsNr, d.Weights ?? []) : null;
@@ -323,7 +319,7 @@ namespace Elwig.Helpers {
}
public class Footer {
private readonly List<List<List<object>>> Items = [[[]]];
private readonly List<List<object>> Items = [[]];
private readonly string LineBreak;
private readonly string Separator;
@@ -334,7 +330,7 @@ namespace Elwig.Helpers {
public Footer Item(object? text) {
if (text == null) return this;
Items[^1][^1].Add(text);
Items[^1].Add(text);
return this;
}
@@ -342,38 +338,13 @@ namespace Elwig.Helpers {
return text == null ? this : Item($"{name}: {text}");
}
public Footer NextGroup() {
Items[^1].Add([]);
return this;
}
public Footer NextLine() {
Items.Add([[]]);
return this;
}
public Footer RebalanceLines() {
for (int i = 0; i < Items.Count - 1; i++) {
var groups = Items[i];
var nextGroups = Items[i + 1];
if (groups.Count <= 1) continue;
var g = groups[^1];
var gl = g.Sum(i => (i is Text txt ? txt.GetText().Length : i.ToString()?.Length ?? 0) + Separator.Length);
var l1a = groups.SelectMany(g => g).Sum(i => (i is Text txt ? txt.GetText().Length : i.ToString()?.Length ?? 0) + Separator.Length) - Separator.Length;
var l2a = nextGroups.SelectMany(g => g).Sum(i => (i is Text txt ? txt.GetText().Length : i.ToString()?.Length ?? 0) + Separator.Length) - Separator.Length;
var l1b = l1a - gl;
var l2b = l2a + gl;
if (Math.Abs(l1b - l2b) <= Math.Abs(l1a - l2a)) {
Items[i].Remove(g);
Items[i + 1].Insert(0, g);
i--;
}
}
Items.Add([]);
return this;
}
public override string ToString() {
return string.Join(LineBreak, Items.Select(l => string.Join(Separator, l.SelectMany(g => g).ToString())));
return string.Join(LineBreak, Items.Select(l => string.Join(Separator, l.ToString())));
}
public IList<ILeafElement> ToLeafElements() {
@@ -382,13 +353,11 @@ namespace Elwig.Helpers {
foreach (var line in Items) {
if (!first1) l.Add(new Text(LineBreak));
var first2 = true;
foreach (var group in line) {
foreach (var item in group) {
foreach (var item in line) {
if (!first2) l.Add(new Text(Separator));
l.Add(item as ILeafElement ?? new Text(item.ToString() ?? ""));
first2 = false;
}
}
first1 = false;
}
return l;
@@ -567,7 +536,6 @@ namespace Elwig.Helpers {
msg.From.Add(new MailboxAddress(App.Client.NameFull, App.Config.Smtp.Value.From));
msg.To.AddRange(member.EmailAddresses.OrderBy(a => a.Nr).Select(a => new MailboxAddress(member.AdministrativeName, a.Address)));
msg.Subject = subject;
msg.Date = DateTime.Now;
var body = new Multipart("mixed") {
new TextPart("plain") { Text = text }
};
@@ -702,7 +670,7 @@ namespace Elwig.Helpers {
p[2],
int.Parse(p[3]),
p[4],
[.. p[5].Split(',').Select(a => a.Replace(" | ", "\n"))],
p[5].Split(',').Select(a => a.Replace(" | ", "\n")).ToArray(),
p[6],
p[7].Split(',')
));
@@ -744,10 +712,5 @@ namespace Elwig.Helpers {
var filename = Path.Combine(App.MailsPath, $"{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{NormalizeFileName(subject)}.txt");
await File.WriteAllTextAsync(filename, $"# {subject}\r\n# Vorgesehene Empfänger: {recipients}\r\n\r\n" + body, Utils.UTF8);
}
public static string GetTitle(string window, IEnumerable<string> filterNames, IEnumerable<string> filter) {
var f = string.Join(" / ", filterNames.Union(filter.Select(f => $"\"{f}\"")));
return window + (f.Length == 0 ? "" : ": " + f) + " - Elwig";
}
}
}
+9 -68
View File
@@ -623,37 +623,6 @@ namespace Elwig.Helpers {
return new(true, null);
}
public static ValidationResult CheckOrganicOperatorId(TextBox input, bool required) {
string text = "";
int pos = input.CaretIndex;
for (int i = 0, v = 0; i < input.Text.Length; i++) {
char ch = input.Text[i];
if (char.IsAsciiDigit(ch)) {
if (v == 3 && text[^1] != '-')
text += "-";
v++;
text += ch;
}
if (i == input.CaretIndex - 1) {
pos = text.Length;
} else if (v >= 10) {
break;
}
}
input.Text = text;
input.CaretIndex = pos;
if (text.Length == 0) {
return required ? new(false, "OOC-ID ist nicht optional") : new(true, null);
} else if (!text.StartsWith("040-") || text.Length != 11) {
return new(false, "OOC-ID ist ungültig");
}
return new(true, null);
}
public static ValidationResult CheckOrganicAuthorityCode(TextBox input, bool required) {
string text = "";
int pos = input.CaretIndex;
@@ -662,18 +631,15 @@ namespace Elwig.Helpers {
if (v < 2 && char.IsAsciiLetter(ch)) {
v++;
text += ch;
} else if ((v == 2 || v == 5) && ch == '-' && text[^1] != '-') {
text += ch;
} else if (v >= 2 && v <= 4 && char.IsLetter(ch)) {
if (v == 2 && text[^1] != '-')
text += "-";
if (text.StartsWith("AT")) {
if (v == 2 && ch == 'B' || v == 3 && ch == 'I' || v == 4 && ch == 'O') {
} else if ((v == 2 || v == 6) && ch == '-') {
v++;
text += ch;
}
} else if (text.StartsWith("DE")) {
if (v == 2 && ch == 'Ö' || v == 3 && ch == 'K' || v == 4 && ch == 'O') {
} else if (v >= 2 && char.IsLetterOrDigit(ch)) {
if (text.StartsWith("AT")) {
if (v == 3 && ch == 'B' || v == 4 && ch == 'I' || v == 5 && ch == 'O') {
v++;
text += ch;
} else if (v > 6 && char.IsAsciiDigit(ch)) {
v++;
text += ch;
}
@@ -681,16 +647,11 @@ namespace Elwig.Helpers {
v++;
text += ch;
}
} else if (v >= 5 && v <= 7 && char.IsAsciiDigit(ch)) {
if (v == 5 && text[^1] != '-')
text += "-";
v++;
text += ch;
}
if (i == input.CaretIndex - 1) {
pos = text.Length;
} else if ((text.StartsWith("AT") || text.StartsWith("DE")) && v >= 10) {
} else if (text.StartsWith("AT") && v >= 10) {
break;
}
}
@@ -701,7 +662,7 @@ namespace Elwig.Helpers {
if (text.Length == 0)
return required ? new(false, "Bio-Kontrollstellen-Code ist nicht optional") : new(true, null);
if (text.StartsWith("AT") || text.StartsWith("DE")) {
if (text.StartsWith("AT")) {
if (text.Length != 10) {
return new(false, "Bio-Kontrollstellen-Code ist ungültig");
}
@@ -711,25 +672,5 @@ namespace Elwig.Helpers {
return new(true, null);
}
public static ValidationResult CheckAddress(TextBox input, bool required, string? locality = null) {
var text = input.Text;
var (name, nr) = Utils.SplitAddress(text);
if (!string.IsNullOrWhiteSpace(nr)) {
var street = Normalizer.NormalizeStreetName(name.Replace(",", ""), locality);
var idx = input.CaretIndex;
input.Text = $"{street} {nr}".Trim();
if (idx >= (text.Length - nr.Length)) {
input.CaretIndex = street.Length + (idx - (text.Length - nr.Length)) + 1;
} else if (idx > 0) {
input.CaretIndex = idx;
}
}
if (text.Length == 0)
return required ? new(false, "Adresse ist nicht optional") : new(true, null);
return new(true, null);
}
}
}
+1 -1
View File
@@ -61,7 +61,7 @@ namespace Elwig.Helpers.Weighing {
throw new WeighingException($"Fehler {error}: {msg}");
} else if (error[0] == '3') {
switch (error[1]) {
case '1': msg = "Übertragungsfehler"; break;
case '1': msg = "Übertragunsfehler"; break;
case '2': msg = "Ungültiger Befehl"; break;
case '3': msg = "Ungültiger Parameter"; break;
}
+3 -3
View File
@@ -25,7 +25,7 @@ namespace Elwig.Models.Dtos {
("BillingPlz", "PLZ", null, 10),
("BillingLocality", "Ort", null, 60),
("LfbisNr", "Betr.-Nr.", null, 20),
("IsAccounting", "buchf.", null, 15),
("IsBuchführend", "buchf.", null, 15),
("IsOrganic", "Bio", null, 15),
("IsActive", "aktiv", null, 15),
("EntryDate", "Eintritt", null, 20),
@@ -83,7 +83,7 @@ namespace Elwig.Models.Dtos {
public string? Bic;
public int? AreaCommitment;
public (string VtrgId, int Area)[] AreaCommitmentsFiltered;
public bool IsAccounting;
public bool IsBuchführend;
public bool IsOrganic;
public bool IsActive;
public DateOnly? EntryDate;
@@ -118,7 +118,7 @@ namespace Elwig.Models.Dtos {
UstIdNr = m.UstIdNr;
Iban = m.Iban != null ? Utils.FormatIban(m.Iban) : null;
Bic = m.Bic;
IsAccounting = m.IsAccounting;
IsBuchführend = m.IsBuchführend;
IsOrganic = m.IsOrganic;
IsActive = m.IsActive;
EntryDate = m.EntryDate;
+36 -36
View File
@@ -18,9 +18,9 @@ namespace Elwig.Models.Dtos {
("Cultivation", "Bewirt.", null, 20),
("QualityLevel", "Qualitätsstufe", null, 30),
("Oe", "Gradation", "°Oe", 20),
("UnCtrd", "ungebunden", "kg|€/kg|€/kg", 60),
("LowCtrd", "attributlos gebunden", "kg|€/kg|€/kg", 60),
("Ctrd", "gebunden", "kg|€/kg|€/kg", 60),
("Ungeb", "ungebunden", "kg|€/kg|€/kg", 60),
("LowGeb", "attributlos gebunden", "kg|€/kg|€/kg", 60),
("Geb", "gebunden", "kg|€/kg|€/kg", 60),
("Amount", "Gesamt", "€", 25),
];
@@ -31,9 +31,9 @@ namespace Elwig.Models.Dtos {
string? Cultivation,
string QualityLevel,
double Oe,
(int Weight, decimal? MinPrice, decimal? MaxPrice) UnCtrd,
(int Weight, decimal? MinPrice, decimal? MaxPrice) LowCtrd,
(int Weight, decimal? MinPrice, decimal? MaxPrice) Ctrd,
(int Weight, decimal? MinPrice, decimal? MaxPrice) Ungeb,
(int Weight, decimal? MinPrice, decimal? MaxPrice) LowGeb,
(int Weight, decimal? MinPrice, decimal? MaxPrice) Geb,
decimal Amount
);
@@ -44,9 +44,9 @@ namespace Elwig.Models.Dtos {
public static async Task<PaymentVariantSummaryData> ForPaymentVariant(PaymentVar v, DbSet<PaymentVariantSummaryRow> table) {
return new(v, (await FromDbSet(table, v.Year, v.AvNr))
.Select(r => new PaymentRow(r.Type, r.Variety, r.Attribute, r.Cultivation, r.QualityLevel, r.Oe,
(r.WeightUnCtrd, r.MinPriceUnCtrd != null ? Utils.DecFromDb(r.MinPriceUnCtrd.Value, v.Season.Precision) : null, r.MaxPriceUnCtrd != null ? Utils.DecFromDb(r.MaxPriceUnCtrd.Value, v.Season.Precision) : null),
(r.WeightLowCtrd, r.MinPriceLowCtrd != null ? Utils.DecFromDb(r.MinPriceLowCtrd.Value, v.Season.Precision) : null, r.MaxPriceLowCtrd != null ? Utils.DecFromDb(r.MaxPriceLowCtrd.Value, v.Season.Precision) : null),
(r.WeightCtrd, r.MinPriceCtrd != null ? Utils.DecFromDb(r.MinPriceCtrd.Value, v.Season.Precision) : null, r.MaxPriceCtrd != null ? Utils.DecFromDb(r.MaxPriceCtrd.Value, v.Season.Precision) : null),
(r.WeightUngeb, r.MinPriceUngeb != null ? Utils.DecFromDb(r.MinPriceUngeb.Value, v.Season.Precision) : null, r.MaxPriceUngeb != null ? Utils.DecFromDb(r.MaxPriceUngeb.Value, v.Season.Precision) : null),
(r.WeightLowGeb, r.MinPriceLowGeb != null ? Utils.DecFromDb(r.MinPriceLowGeb.Value, v.Season.Precision) : null, r.MaxPriceLowGeb != null ? Utils.DecFromDb(r.MaxPriceLowGeb.Value, v.Season.Precision) : null),
(r.WeightGeb, r.MinPriceGeb != null ? Utils.DecFromDb(r.MinPriceGeb.Value, v.Season.Precision) : null, r.MaxPriceGeb != null ? Utils.DecFromDb(r.MaxPriceGeb.Value, v.Season.Precision) : null),
Utils.DecFromDb(r.Amount, v.Season.Precision)))
.ToArray());
}
@@ -59,15 +59,15 @@ namespace Elwig.Models.Dtos {
c.name AS cultivation,
q.name AS quality_level,
ROUND(kmw * (4.54 + 0.022 * kmw)) AS oe,
SUM(IIF(w.discr = '_', w.value, 0)) AS weight_unctrd,
MIN(IIF(w.discr = '_', b.price, NULL)) AS min_price_unctrd,
MAX(IIF(w.discr = '_', b.price, NULL)) AS max_price_unctrd,
SUM(IIF(w.discr NOT IN (COALESCE(p.attrid, ''), '_'), w.value, 0)) AS weight_lowctrd,
MIN(IIF(w.discr NOT IN (COALESCE(p.attrid, ''), '_'), b.price, NULL)) AS min_price_lowctrd,
MAX(IIF(w.discr NOT IN (COALESCE(p.attrid, ''), '_'), b.price, NULL)) AS max_price_lowctrd,
SUM(IIF(w.discr = COALESCE(p.attrid, ''), w.value, 0)) AS weight_ctrd,
MIN(IIF(w.discr = COALESCE(p.attrid, ''), b.price, NULL)) AS min_price_ctrd,
MAX(IIF(w.discr = COALESCE(p.attrid, ''), b.price, NULL)) AS max_price_ctrd,
SUM(IIF(w.discr = '_', w.value, 0)) AS weight_ungeb,
MIN(IIF(w.discr = '_', b.price, NULL)) AS min_price_ungeb,
MAX(IIF(w.discr = '_', b.price, NULL)) AS max_price_ungeb,
SUM(IIF(w.discr NOT IN (COALESCE(p.attrid, ''), '_'), w.value, 0)) AS weight_lowgeb,
MIN(IIF(w.discr NOT IN (COALESCE(p.attrid, ''), '_'), b.price, NULL)) AS min_price_lowgeb,
MAX(IIF(w.discr NOT IN (COALESCE(p.attrid, ''), '_'), b.price, NULL)) AS max_price_lowgeb,
SUM(IIF(w.discr = COALESCE(p.attrid, ''), w.value, 0)) AS weight_geb,
MIN(IIF(w.discr = COALESCE(p.attrid, ''), b.price, NULL)) AS min_price_geb,
MAX(IIF(w.discr = COALESCE(p.attrid, ''), b.price, NULL)) AS max_price_geb,
SUM(b.amount) AS amount
FROM payment_delivery_part_bucket b
LEFT JOIN delivery_part_bucket w ON (w.year, w.did, w.dpnr, w.bktnr) = (b.year, b.did, b.dpnr, b.bktnr)
@@ -97,24 +97,24 @@ namespace Elwig.Models.Dtos {
public required string QualityLevel { get; set; }
[Column("oe")]
public double Oe { get; set; }
[Column("weight_unctrd")]
public int WeightUnCtrd { get; set; }
[Column("min_price_unctrd")]
public long? MinPriceUnCtrd { get; set; }
[Column("max_price_unctrd")]
public long? MaxPriceUnCtrd { get; set; }
[Column("weight_lowctrd")]
public int WeightLowCtrd { get; set; }
[Column("min_price_lowctrd")]
public long? MinPriceLowCtrd { get; set; }
[Column("max_price_lowctrd")]
public long? MaxPriceLowCtrd { get; set; }
[Column("weight_ctrd")]
public int WeightCtrd { get; set; }
[Column("min_price_ctrd")]
public long? MinPriceCtrd { get; set; }
[Column("max_price_ctrd")]
public long? MaxPriceCtrd { get; set; }
[Column("weight_ungeb")]
public int WeightUngeb { get; set; }
[Column("min_price_ungeb")]
public long? MinPriceUngeb { get; set; }
[Column("max_price_ungeb")]
public long? MaxPriceUngeb { get; set; }
[Column("weight_lowgeb")]
public int WeightLowGeb { get; set; }
[Column("min_price_lowgeb")]
public long? MinPriceLowGeb { get; set; }
[Column("max_price_lowgeb")]
public long? MaxPriceLowGeb { get; set; }
[Column("weight_geb")]
public int WeightGeb { get; set; }
[Column("min_price_geb")]
public long? MinPriceGeb { get; set; }
[Column("max_price_geb")]
public long? MaxPriceGeb { get; set; }
[Column("amount")]
public long Amount { get; set; }
}
+6 -6
View File
@@ -13,7 +13,7 @@ namespace Elwig.Models.Dtos {
("AttrId", "Attr.", null, 10),
("CultId", "Bewirt.", null, 15),
("QualId", "Qual.", null, 15),
("Contracted", "gebunden", null, 20),
("Geb", "gebunden", null, 20),
("Weight", "Menge", "kg", 20),
];
@@ -28,12 +28,12 @@ namespace Elwig.Models.Dtos {
private static async Task<IEnumerable<WeightBreakdownRow>> FromDbSet(DbSet<WeightBreakdownRow> table, int year, string? zwstid) {
zwstid = zwstid == null ? "NULL" : $"'{zwstid}'";
return await table.FromSqlRaw($"""
SELECT type, sortid, attrid, cultid, v.qualid, contracted, SUM(weight) AS weight
SELECT type, sortid, attrid, cultid, v.qualid, geb, SUM(weight) AS weight
FROM v_stat_total v
LEFT JOIN wine_quality_level q ON q.qualid = v.qualid
WHERE year = {year} AND ({zwstid} IS NULL OR zwstid = {zwstid})
GROUP BY type, sortid, attrid, cultid, v.qualid, contracted
ORDER BY type DESC, sortid, attrid, cultid, q.min_kmw, contracted
GROUP BY type, sortid, attrid, cultid, v.qualid, geb
ORDER BY type DESC, sortid, attrid, cultid, q.min_kmw, geb
""").ToListAsync();
}
}
@@ -50,8 +50,8 @@ namespace Elwig.Models.Dtos {
public string? CultId { get; set; }
[Column("qualid")]
public required string QualId { get; set; }
[Column("contracted")]
public required string Contracted { get; set; }
[Column("geb")]
public required string Geb { get; set; }
[Column("weight")]
public int Weight { get; set; }
}
+4 -5
View File
@@ -91,8 +91,8 @@ namespace Elwig.Models.Entities {
[Column("hand_picked")]
public bool? IsHandPicked { get; set; }
[Column("contracted")]
public bool? IsContracted { get; set; }
[Column("gebunden")]
public bool? IsGebunden { get; set; }
[Column("unloading")]
public string? Unloading { get; set; }
@@ -124,7 +124,7 @@ namespace Elwig.Models.Entities {
[Column("weighing_data")]
public string? WeighingData { get; set; }
[NotMapped]
public (string? ScaleId, string? Id, int? Gross, int? Tare, int? TareCorrection, int? Net, DateOnly? Date, TimeOnly? Time) WeighingInfo {
public (string? ScaleId, string? Id, int? Gross, int? Tare, int? Net, DateOnly? Date, TimeOnly? Time) WeighingInfo {
get {
try {
var obj = JsonNode.Parse(WeighingData!)!.AsObject();
@@ -133,13 +133,12 @@ namespace Elwig.Models.Entities {
obj["id"]?.AsValue().GetValue<string>(),
obj["gross_weight"]?.AsValue().GetValue<int>(),
obj["tare_weight"]?.AsValue().GetValue<int>(),
obj["tare_correction"]?.AsValue().GetValue<int>(),
obj["net_weight"]?.AsValue().GetValue<int>(),
DateOnly.TryParseExact(obj["date"]?.AsValue().GetValue<string>(), "yyyy-MM-dd", out var d) ? d : null,
TimeOnly.TryParseExact(obj["time"]?.AsValue().GetValue<string>(), ["HH:mm:ss", "HH:mm"], out var t) ? t : null
);
} catch {
return (null, null, null, null, null, null, null, null);
return (null, null, null, null, null, null, null);
}
}
}
@@ -38,8 +38,6 @@ namespace Elwig.Models.Entities {
[Column("cultid")]
public string? CultId { get; set; }
[NotMapped]
public bool IsOrganic => Cultivation?.IsOrganic ?? false;
[Column("max_weight")]
public int? MaxWeight { get; set; }
+6 -12
View File
@@ -96,26 +96,20 @@ namespace Elwig.Models.Entities {
[Column("ustid_nr")]
public string? UstIdNr { get; set; }
[Column("ooc_id")]
public string? OrganicOperatorId { get; set; }
[Column("org_auth_code")]
public string? OrganicAuthorityCode { get; set; }
[Column("juridical_pers")]
public bool IsJuridicalPerson { get; set; }
[Column("full_delivery")]
public bool IsFullDelivery { get; set; }
[Column("volllieferant")]
public bool IsVollLieferant { get; set; }
[Column("accounting")]
public bool IsAccounting { get; set; }
[Column("buchführend")]
public bool IsBuchführend { get; set; }
[Column("organic")]
public bool IsOrganic { get; set; }
[Column("officer")]
public bool IsOfficer { get; set; }
[Column("funktionär")]
public bool IsFunktionär { get; set; }
[Column("active")]
public bool IsActive { get; set; }
+1 -4
View File
@@ -76,10 +76,7 @@ namespace Elwig.Models.Entities {
[Column("shares")]
public int Shares { get; set; }
[Column("signed_company")]
public bool CompanyHasSigned { get; set; }
[Column("signed_member")]
[Column("signed")]
public bool MemberHasSigned { get; set; }
[Column("value_per_share")]
+1 -1
View File
@@ -107,7 +107,7 @@ namespace Elwig.Models.Entities {
[Column("calc_mode")]
public int CalcMode { get; set; }
[NotMapped]
public bool Billing_HonorContracted {
public bool Billing_HonorGebunden {
get => (CalcMode & 0x1) != 0;
set => CalcMode = value ? CalcMode | 0x1 : CalcMode & ~0x1;
}
-3
View File
@@ -11,9 +11,6 @@ namespace Elwig.Models.Entities {
[Column("name")]
public required string Name { get; set; }
[Column("organic")]
public bool IsOrganic { get; set; }
[Column("description")]
public string? Description { get; set; }
@@ -97,12 +97,6 @@
{"type": "number"},
{"$ref": "#/definitions/curve_data"}
]
},
"contracted": {
"anyOf": [
{"type": "number"},
{"$ref": "#/definitions/curve_data"}
]
}
}
},
-65
View File
@@ -1,65 +0,0 @@
-- schema version 41 to 42
ALTER TABLE member ADD COLUMN ooc_id TEXT CHECK (ooc_id REGEXP '^[0-9]{3}-[0-9]{7}$') DEFAULT NULL;
ALTER TABLE member ADD COLUMN org_auth_code TEXT CHECK (org_auth_code REGEXP '^[A-Z]{2}-[A-ZÖØ]{3}-[0-9]{2,3}(-[A-Z]{2})?$') DEFAULT NULL;
ALTER TABLE wine_cultivation ADD COLUMN organic INTEGER NOT NULL CHECK (organic IN (TRUE, FALSE)) DEFAULT FALSE;
ALTER TABLE member_history RENAME COLUMN signed TO signed_member;
ALTER TABLE member_history ADD COLUMN signed_company INTEGER NOT NULL CHECK (signed_company IN (TRUE, FALSE)) DEFAULT FALSE;
PRAGMA writable_schema = ON;
UPDATE sqlite_schema SET sql = REPLACE(REPLACE(REPLACE(sql, 'funktionär', 'officer '), 'buchführend', 'accounting '), 'volllieferant', 'full_delivery')
WHERE type = 'table' AND name = 'member';
UPDATE sqlite_schema SET sql = REPLACE(sql, 'gebunden ', 'contracted')
WHERE type = 'table' AND name = 'delivery_part';
UPDATE sqlite_schema SET sql = REPLACE(sql, 'gebunden', 'contracted')
WHERE type = 'view' AND name = 'v_delivery';
UPDATE sqlite_schema SET sql = REPLACE(sql, 'volllieferant', 'full_delivery')
WHERE type = 'view' AND name = 'v_bki_member';
UPDATE sqlite_schema SET sql = REPLACE(sql, ' geb', ' contracted')
WHERE type = 'view' AND name = 'v_stat_total';
UPDATE sqlite_schema SET sql = REPLACE(sql, 'gebunden', 'contracted')
WHERE type = 'view' AND (name = 'v_payment_bucket_strict' OR name = 'v_payment_bucket' OR name = 'v_under_delivery_bucket');
PRAGMA schema_version = 4101;
PRAGMA writable_schema = OFF;
UPDATE client_parameter SET value = '0' WHERE param = 'ENABLE_TIME_TRIGGERS';
UPDATE member SET org_auth_code = UPPER(SUBSTR(a.name, -11, 10))
FROM member m JOIN member_billing_address a ON a.mgnr = m.mgnr
WHERE m.mgnr = member.mgnr AND a.name LIKE '%AT-BIO-___)';
UPDATE member SET org_auth_code = UPPER(suffix) WHERE suffix LIKE 'AT-BIO-___';
UPDATE wine_cultivation SET organic = TRUE WHERE name LIKE '%bio%' OR name LIKE '%org%' OR description LIKE '%AT-BIO-%';
UPDATE wine_cultivation SET description = NULL WHERE description LIKE '%AT-BIO-%';
UPDATE wine_cultivation SET description = 'Biologische Produktion' WHERE organic;
UPDATE delivery_schedule SET cultid = (SELECT cultid FROM wine_cultivation WHERE organic LIMIT 1) WHERE description LIKE '%Bio%';
UPDATE client_parameter SET param = 'CLIENT_ORGANIC_AUTHORITYCODE' WHERE param = 'CLIENT_ORGANIC_AUTHORITY';
UPDATE member_telephone_number SET comment = NULL WHERE comment = '';
UPDATE member_email_address SET comment = NULL WHERE comment = '';
UPDATE member SET address = 'Untere Weißgerberstraße' WHERE address = 'U. Weißgasse Straße';
UPDATE member SET address = 'Edgar-Penzig-Franz-Straße' WHERE address = 'Edgar-Penzing-Franz-Straße';
UPDATE member
SET address = NORMALIZE_ADDRESS(address, (SELECT o.name FROM AT_plz_dest p JOIN AT_ort o ON o.okz = p.okz WHERE p.id = member.postal_dest))
WHERE address != NORMALIZE_ADDRESS(address, (SELECT o.name FROM AT_plz_dest p JOIN AT_ort o ON o.okz = p.okz WHERE p.id = member.postal_dest));
UPDATE member_billing_address
SET address = NORMALIZE_ADDRESS(address, (SELECT o.name FROM AT_plz_dest p JOIN AT_ort o ON o.okz = p.okz WHERE p.id = member_billing_address.postal_dest))
WHERE address != NORMALIZE_ADDRESS(address, (SELECT o.name FROM AT_plz_dest p JOIN AT_ort o ON o.okz = p.okz WHERE p.id = member_billing_address.postal_dest));
UPDATE client_parameter SET value = '1' WHERE param = 'ENABLE_TIME_TRIGGERS';
-2
View File
@@ -43,8 +43,6 @@ namespace Elwig.Services {
public static async Task<(List<string>, IQueryable<AreaComContract>, IQueryable<AreaCom>, List<string>)> GetFilters(this AreaComAdminViewModel vm, AppDbContext ctx) {
List<string> filterNames = [];
IQueryable<AreaCom> areaComQuery = ctx.AreaCommitments.Where(a => a.MgNr == vm.FilterMember.MgNr).OrderBy(a => a.FbNr);
filterNames.Add(vm.FilterMember.AdministrativeName);
if (vm.FilterSeason is int season) {
areaComQuery = Utils.ActiveAreaCommitments(areaComQuery, season);
filterNames.Add($"laufend {season}");
-133
View File
@@ -1,133 +0,0 @@
using Elwig.Helpers;
using Elwig.Helpers.Export;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Input;
namespace Elwig.Services {
public static class BackupService {
public static bool IsAnyBackupUpToDate {
get {
var lastDbWrite = File.GetLastWriteTime(App.Config.DatabaseFile);
lastDbWrite += new TimeSpan(0, 0, -1);
return Directory.GetFiles(App.Config.BackupPath, "????-??-??_??-??-??.*.zip")
.Any(n => DateTime.ParseExact(Path.GetFileName(n)[..19], "yyyy-MM-dd_HH-mm-ss", CultureInfo.InvariantCulture, DateTimeStyles.None) >= lastDbWrite);
}
}
public static async Task TryDatabaseBackup() {
if (IsAnyBackupUpToDate) return;
await BackupDatabase();
PruneBackups();
}
public static async Task BackupDatabase() {
await Database.ExportSql(Path.Combine(App.Config.BackupPath, $"{File.GetLastWriteTime(App.Config.DatabaseFile):yyyy-MM-dd_HH-mm-ss}.sql.zip"), true);
}
public static void PruneBackups() {
var retain = new HashSet<string>();
var backups = Directory.GetFiles(App.Config.BackupPath, "????-??-??_??-??-??.*.zip")
.Select(n => (FileName: n, Timestamp: DateTime.ParseExact(Path.GetFileName(n)[..19], "yyyy-MM-dd_HH-mm-ss", CultureInfo.InvariantCulture, DateTimeStyles.None)))
.OrderByDescending(t => t.Timestamp).ToArray();
DateTime now;
// retain hourly backups
now = DateTime.Now;
for (int i = 0; i < App.Config.BackupRetainHours; i++, now = now.AddHours(-1)) {
foreach (var b in backups) {
if (b.Timestamp.Date == now.Date && b.Timestamp.Hour == now.Hour) {
retain.Add(b.FileName);
break;
}
}
}
// retain daily backups
now = DateTime.Now;
for (int i = 0; i < App.Config.BackupRetainDays; i++, now = now.AddDays(-1)) {
foreach (var b in backups) {
if (b.Timestamp.Date == now.Date) {
retain.Add(b.FileName);
break;
}
}
}
// retain weekly backups
now = DateTime.Now;
for (int i = 0; i < App.Config.BackupRetainWeeks; i++, now = now.AddDays(-7)) {
foreach (var b in backups) {
if (b.Timestamp.GetYearAndWeek() == now.GetYearAndWeek()) {
retain.Add(b.FileName);
break;
}
}
}
// retain monthly backups
now = DateTime.Now;
for (int i = 0; i < App.Config.BackupRetainMonths; i++, now = now.AddMonths(-1)) {
foreach (var b in backups) {
if (b.Timestamp.Year == now.Year && b.Timestamp.Month == now.Month) {
retain.Add(b.FileName);
break;
}
}
}
// retain tertial backups
now = new DateTime(DateTime.Now.Year + 1, 3, 1);
for (int i = 0; i < 600; i++, now = now.AddMonths(-4)) {
foreach (var b in backups) {
if (b.Timestamp.GetYearAndTertial() == now.GetYearAndTertial()) {
retain.Add(b.FileName);
break;
}
}
}
// delete non-retained files
foreach (var b in backups) {
if (retain.Contains(b.FileName)) continue;
try {
File.Delete(b.FileName);
} catch { }
}
// delete temp files
foreach (var f in Directory.GetFiles(App.Config.BackupPath, "*.tmp")) {
try {
File.Delete(f);
} catch { }
}
}
public static async Task RestoreDatabase() {
try {
var d = new OpenFileDialog() {
Title = "Datenbank wiederherstellen - Elwig",
DefaultDirectory = App.Config.BackupPath,
InitialDirectory = App.Config.BackupPath,
DefaultExt = "sql.zip",
Filter = "SQLite-Datenbank (*.sqlite3, *.sqlite3.zip, *.sql, *.sql.zip)|*.sqlite3;*.sqlite3.zip;*.sql;*.sql.zip",
};
if (d.ShowDialog() == true) {
if (!InteractionService.AskContinue("Datenbank wiederherstellen", "Soll die Datenbank wirklich unwiederruflich durch die wiederhergestellte Version ersetzt werden?"))
return;
Mouse.OverrideCursor = Cursors.Wait;
await App.ReplaceDatabase(d.FileName);
}
} catch (Exception exc) {
InteractionService.ShowException(exc);
}
Mouse.OverrideCursor = null;
}
}
}
+1 -2
View File
@@ -45,8 +45,7 @@ namespace Elwig.Services {
deliveryAncmtQuery = deliveryAncmtQuery.Where(a => a.Year == s.Year && a.DsNr == s.DsNr);
filterNames.Add($"{s.Date:dd.MM.yyyy} – {s.Branch.Name} – {s.Description}");
} else {
var today = DateTime.Today;
deliveryAncmtQuery = deliveryAncmtQuery.Where(a => a.Year == vm.FilterSeason && (!vm.FilterOnlyUpcoming || a.Schedule.DateString.CompareTo(today.ToString("yyyy-MM-dd")) >= 0));
deliveryAncmtQuery = deliveryAncmtQuery.Where(a => a.Year == vm.FilterSeason && (!vm.FilterOnlyUpcoming || a.Schedule.DateString.CompareTo(Utils.Today.ToString("yyyy-MM-dd")) >= 0));
filterNames.Add($"{vm.FilterSeason}");
}
+2 -3
View File
@@ -49,9 +49,8 @@ namespace Elwig.Services {
filterNames.Add($"{vm.FilterSeason}");
}
if (vm.FilterOnlyUpcoming) {
var today = DateTime.Today;
deliveryScheduleQuery = deliveryScheduleQuery.Where(s => s.DateString.CompareTo(today.ToString("yyyy-MM-dd")) >= 0);
filterNames.Add($"ab {today:dd.MM.yyyy}");
deliveryScheduleQuery = deliveryScheduleQuery.Where(s => s.DateString.CompareTo(Utils.Today.ToString("yyyy-MM-dd")) >= 0);
filterNames.Add($"ab {Utils.Today:dd.MM.yyyy}");
}
var filterVar = new List<string>();
+68 -166
View File
@@ -1,21 +1,19 @@
using Elwig.Documents;
using Elwig.Helpers;
using Elwig.Helpers.Export;
using Elwig.Helpers;
using Elwig.Models.Dtos;
using Elwig.Models.Entities;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System;
using Elwig.ViewModels;
using iText.Commons.Internal.Runtime;
using LinqKit;
using System.Globalization;
using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Media;
namespace Elwig.Services {
public static class DeliveryService {
@@ -37,13 +35,8 @@ namespace Elwig.Services {
vm.SortId = "";
vm.GradationKmwString = "";
vm.Weight = null;
vm.ActualTare = null;
vm.TargetTare = null;
vm.Tare = null;
vm.WeightString = "";
vm.IsManualWeighing = false;
vm.PartComment = "";
vm.TemperatureString = "";
vm.AcidString = "";
@@ -58,11 +51,7 @@ namespace Elwig.Services {
vm.WineKg = ControlUtils.GetItemFromSourceWithPk(vm.WineKgSource, p.KgNr) as AT_Kg;
vm.WineRd = ControlUtils.GetItemFromSourceWithPk(vm.WineRdSource, p.KgNr, p.RdNr) as WbRd;
vm.WineOrigin = ControlUtils.GetItemFromSourceWithPk(vm.WineOriginSource, p.HkId) as WineOrigin;
vm.Weight = p.Weight;
vm.ActualTare = p.WeighingInfo.Tare;
vm.TargetTare = vm.ActualTare + p.WeighingInfo.TareCorrection;
vm.Tare = vm.TargetTare ?? (vm.ActualTare is int t && t != 0 ? t : null);
vm.WeightString = $"{p.Weight:N0}";
vm.IsManualWeighing = p.IsManualWeighing;
vm.IsNetWeight = p.IsNetWeight;
@@ -75,7 +64,7 @@ namespace Elwig.Services {
vm.TemperatureString = (p.Temperature != null) ? $"{p.Temperature:N1}" : "";
vm.AcidString = (p.Acid != null) ? $"{p.Acid:N1}" : "";
vm.IsHandPicked = p.IsHandPicked;
vm.IsContracted = p.IsContracted;
vm.IsGebunden = p.IsGebunden;
vm.Unloading = p.Unloading;
vm.ScaleTerminalId = p.ScaleTerminalId;
@@ -83,45 +72,6 @@ namespace Elwig.Services {
vm.ManualWeighingReason = p.WeighingReason;
}
public static (DateTime From, DateTime To)? GetFilterToday(DateTime today, IEnumerable<DateTime> timestamps) {
var filtered = timestamps.Where(t => t >= today.AddDays(-1) && t < today.AddDays(1)).Order().ToArray();
if (filtered.Length == 0) return null;
var latest = filtered.Last();
var since = filtered.Cast<DateTime>().Reverse().Aggregate(latest, (s, c) => s.Subtract(c).TotalHours <= 6 ? c : s);
latest += new TimeSpan(0, 1, -latest.Minute, -latest.Second, -latest.Millisecond, -latest.Microsecond);
since += new TimeSpan(0, 0, -since.Minute, -since.Second, -since.Millisecond, -since.Microsecond);
if (since.Subtract(today) <= new TimeSpan(-6, 0, 0) && latest.Subtract(today) < new TimeSpan(0, 0, 0))
return null;
return (since, latest);
}
private static async Task<(Expression<Func<Delivery, bool>>, string)> GetFilterToday(AppDbContext ctx) {
var today = DateTime.Today;
var timestamps = (await ctx.Deliveries
.Where(d => d.DateString.CompareTo(today.AddDays(-1).ToString("yyyy-MM-dd")) >= 0)
.OrderBy(d => d.DateString).ThenBy(d => d.TimeString)
.Select(d => d.DateString + " " + d.TimeString)
.ToListAsync())
.Select(s => DateTime.TryParseExact(s, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.None, out var dt) ? (DateTime?)dt : null)
.Where(t => t.HasValue)
.Cast<DateTime>()
.ToArray();
var res = GetFilterToday(today, timestamps);
if (!res.HasValue) {
return (_ => false, today.ToString("dd.MM.yyyy"));
} else {
var from = res.Value.From;
var to = res.Value.To;
return (d => (d.DateString == from.ToString("yyyy-MM-dd") && (d.TimeString == null || d.TimeString.CompareTo(from.ToString("HH:mm:ss")) >= 0)) ||
(d.DateString.CompareTo(from.ToString("yyyy-MM-dd")) > 0),
from.Date == to.Date ? from.ToString("dd.MM.yyyy") : $"{from:dd.MM.yyyy \\a\\b HH:mm} / {to:dd.MM.yyyy \\b\\i\\s HH:mm}");
}
}
public static async Task<(List<string>, IQueryable<Delivery>, IQueryable<DeliveryPart>, Predicate<DeliveryPart>, List<string>)> GetFilters(this DeliveryAdminViewModel vm, AppDbContext ctx) {
List<string> filterNames = [];
IQueryable<Delivery> deliveryQuery = ctx.Deliveries;
@@ -134,9 +84,10 @@ namespace Elwig.Services {
filterNames.Add(vm.FilterMember.AdministrativeName);
}
if (vm.FilterTodayOnly) {
var (pred, name) = await GetFilterToday(ctx);
deliveryQuery = deliveryQuery.Where(pred);
filterNames.Add(name);
deliveryQuery = deliveryQuery
.Where(d => (d.DateString == Utils.Today.ToString("yyyy-MM-dd") && (d.TimeString == null || d.TimeString.CompareTo("03:00:00") > 0)) ||
(d.DateString == Utils.Today.AddDays(1).ToString("yyyy-MM-dd") && (d.TimeString == null || d.TimeString.CompareTo("03:00:00") <= 0)));
filterNames.Add(Utils.Today.ToString("dd.MM.yyyy"));
} else if (!vm.FilterAllSeasons) {
deliveryQuery = deliveryQuery.Where(d => d.Year == vm.FilterSeason);
filterNames.Add($"{vm.FilterSeason}");
@@ -181,19 +132,19 @@ namespace Elwig.Services {
filter.RemoveAt(i--);
filterNames.Add("Weißweinsorten");
} else if (e.Length >= 3 && e.Length <= 8 && "gebunden".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
prd = prd.And(p => p.IsContracted == true);
prd = prd.And(p => p.IsGebunden == true);
filter.RemoveAt(i--);
filterNames.Add("gebunden");
} else if (e.Length >= 4 && e.Length <= 9 && "!gebunden".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
prd = prd.And(p => p.IsContracted != true);
prd = prd.And(p => p.IsGebunden != true);
filter.RemoveAt(i--);
filterNames.Add("nicht gebunden");
} else if (e.Length >= 5 && e.Length <= 10 && "ungebunden".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
prd = prd.And(p => p.IsContracted == false);
prd = prd.And(p => p.IsGebunden == false);
filter.RemoveAt(i--);
filterNames.Add("ungebunden");
} else if (e.Length >= 6 && e.Length <= 11 && "!ungebunden".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
prd = prd.And(p => p.IsContracted != false);
prd = prd.And(p => p.IsGebunden != false);
filter.RemoveAt(i--);
filterNames.Add("nicht ungebunden");
} else if (e.Length >= 5 && e.Length <= 8 && "handlese".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
@@ -556,7 +507,7 @@ namespace Elwig.Services {
IsNetWeight = vm.IsNetWeight,
IsHandPicked = vm.IsHandPicked,
IsContracted = vm.IsContracted,
IsGebunden = vm.IsGebunden,
Unloading = vm.Unloading,
Temperature = vm.Temperature,
Acid = vm.Acid,
@@ -779,9 +730,10 @@ namespace Elwig.Services {
query = q;
filterNames.AddRange(f);
} else if (subject == ExportSubject.FromToday) {
var (pred, name) = await GetFilterToday(ctx);
query = ctx.Deliveries.Where(pred).SelectMany(d => d.Parts);
filterNames.Add(name);
var date = $"{Utils.Today:yyyy-MM-dd}";
query = ctx.DeliveryParts
.Where(p => p.Delivery.DateString == date);
filterNames.Add($"{Utils.Today:dd.MM.yyyy}");
} else if (subject == ExportSubject.FromSeasonAndBranch) {
query = ctx.DeliveryParts
.Where(p => p.Year == Utils.CurrentLastSeason && p.Delivery.ZwstId == App.ZwstId);
@@ -853,9 +805,10 @@ namespace Elwig.Services {
query = q;
filterNames.AddRange(f);
} else if (subject == ExportSubject.FromToday) {
var (pred, name) = await GetFilterToday(ctx);
query = ctx.Deliveries.Where(pred).SelectMany(d => d.Parts);
filterNames.Add(name);
var date = $"{Utils.Today:yyyy-MM-dd}";
query = ctx.DeliveryParts
.Where(p => p.Delivery.DateString == date);
filterNames.Add($"{Utils.Today:dd.MM.yyyy}");
} else {
throw new ArgumentException("Invalid value for ExportSubject");
}
@@ -977,40 +930,30 @@ namespace Elwig.Services {
}
}
private static void AddWeightToolTipRow(Grid grid, int row, string? h1, string? h2, string? h3, int weight, int? total1, int? total2, int total3, string? type) {
var bold = h3 == null;
var color = type == "R" ? Brushes.Firebrick : type == "W" ? Brushes.ForestGreen : null;
if (h1 != null) grid.AddToolTipCell(h1 + ":", row, 0, (h2 == null) ? (h3 == null) ? 3 : 2 : 1, bold: bold, color: color);
if (h2 != null) grid.AddToolTipCell(h2 + ":", row, 1, (h3 == null) ? 2 : 1, bold: bold, color: color);
if (h3 != null) grid.AddToolTipCell(h3 + ":", row, 2, 1, bold: bold, color: color);
grid.AddToolTipCell($"{weight:N0} kg", row, 3, bold: bold, alignRight: true, color: color);
private static void AddWeightToolTipRow(Grid grid, int row, string? h1, string? h2, int weight, int? total1, int total2) {
var bold = h2 == null;
if (h1 != null) grid.AddToolTipCell(h1 + ":", row, 0, (h2 == null) ? 2 : 1, bold);
if (h2 != null) grid.AddToolTipCell(h2 + ":", row, 1, 1, bold);
grid.AddToolTipCell($"{weight:N0} kg", row, 2, bold: bold, alignRight: true);
if (total1 != null && total1 != 0)
grid.AddToolTipCell($"{weight * 100.0 / total1:N1} %", row, 4, bold: bold, alignRight: true, color: color);
if (total2 != null && total2 != 0)
grid.AddToolTipCell($"{weight * 100.0 / total2:N1} %", row, 5, bold: bold, alignRight: true, color: color);
if (total3 != 0)
grid.AddToolTipCell($"{weight * 100.0 / total3:N1} %", row, 6, bold: bold, alignRight: true, color: color);
grid.AddToolTipCell($"{weight * 100.0 / total1:N1} %", row, 3, bold: bold, alignRight: true);
if (total2 != 0)
grid.AddToolTipCell($"{weight * 100.0 / total2:N1} %", row, 4, bold: bold, alignRight: true);
}
private static void AddGradationToolTipRow(Grid grid, int row, string? h1, string? h2, string? h3, double min, double avg, double max, string? type) {
var bold = h3 == null;
var color = type == "R" ? Brushes.Firebrick : type == "W" ? Brushes.ForestGreen : null;
if (h1 != null) grid.AddToolTipCell(h1 + ":", row, 0, (h2 == null) ? (h3 == null) ? 3 : 2 : 1, bold: bold, color: color);
if (h2 != null) grid.AddToolTipCell(h2 + ":", row, 1, (h3 == null) ? 2 : 1, bold: bold, color: color);
if (h3 != null) grid.AddToolTipCell(h3 + ":", row, 2, bold: bold, color: color);
grid.AddToolTipCell($"{min:N1}°", row, 3, bold: bold, alignRight: true, color: color);
grid.AddToolTipCell($"{avg:N1}°", row, 4, bold: bold, alignRight: true, color: color);
grid.AddToolTipCell($"{max:N1}°", row, 5, bold: bold, alignRight: true, color: color);
private static void AddGradationToolTipRow(Grid grid, int row, string? h1, string? h2, double min, double avg, double max) {
var bold = h2 == null;
if (h1 != null) grid.AddToolTipCell(h1 + ":", row, 0, (h2 == null) ? 2 : 1, bold);
if (h2 != null) grid.AddToolTipCell(h2 + ":", row, 1, bold: bold);
grid.AddToolTipCell($"{min:N1}°", row, 2, bold: bold, alignRight: true);
grid.AddToolTipCell($"{avg:N1}°", row, 3, bold: bold, alignRight: true);
grid.AddToolTipCell($"{max:N1}°", row, 4, bold: bold, alignRight: true);
}
private static string? GetGroupName(params string?[] parts) {
return parts.All(p => p == null) ? null : string.Join(" / ", parts.Where(p => p != null));
}
public static async Task<(string WeightText, (string?, string?, string?, int, int?, int?, int, string?)[] WeightGrid, string GradationText, (string?, string?, string?, double, double, double, string?)[] GradationGrid)> GenerateToolTipData(IQueryable<DeliveryPart> deliveryParts) {
var wGrid = new List<(string?, string?, string?, int, int?, int?, int, string?)>();
public static async Task<(string WeightText, (string?, string?, int, int?, int)[] WeightGrid, string GradationText, (string?, string?, double, double, double)[] GradationGrid)> GenerateToolTipData(IQueryable<DeliveryPart> deliveryParts) {
var wGrid = new List<(string?, string?, int, int?, int)>();
var wText = "-";
var gGrid = new List<(string?, string?, string?, double, double, double, string?)>();
var gGrid = new List<(string?, string?, double, double, double)>();
var gText = "-";
var stat = (await deliveryParts.GroupBy(p => 0)
@@ -1025,11 +968,11 @@ namespace Elwig.Services {
.Single();
wText = $"{stat.Weight:N0} kg";
wGrid.Add(("Menge", null, null, stat.Weight, null, null, stat.Weight, null));
wGrid.Add(("Menge", null, stat.Weight, null, stat.Weight));
if (stat.Min != null && stat.Max != null) {
gText = $"{stat.Min:N1}° / {stat.Avg:N1}° / {stat.Max:N1}°";
gGrid.Add(("Gradation", null, null, stat.Min.Value, stat.Avg, stat.Max.Value, null));
gGrid.Add(("Gradation", null, stat.Min.Value, stat.Avg, stat.Max.Value));
var attrGroups = await deliveryParts
.GroupBy(p => new { Attr = p.Attribute!.Name, Cult = p.Cultivation!.Name })
@@ -1046,10 +989,9 @@ namespace Elwig.Services {
.ThenBy(g => g.Cult)
.ToListAsync();
var sortGroups = await deliveryParts
.GroupBy(p => new { p.SortId, p.Variety.Type })
.GroupBy(p => p.SortId)
.Select(g => new {
g.Key.SortId,
g.Key.Type,
SortId = g.Key,
Weight = g.Sum(p => p.Weight),
Min = g.Min(p => p.Kmw),
Avg = g.Sum(p => p.Kmw * p.Weight) / g.Sum(p => p.Weight),
@@ -1062,13 +1004,11 @@ namespace Elwig.Services {
.GroupBy(p => new {
Attr = p.Attribute!.Name,
Cult = p.Cultivation!.Name,
p.Variety.Type,
p.SortId,
})
.Select(g => new {
g.Key.Attr,
g.Key.Cult,
g.Key.Type,
g.Key.SortId,
Weight = g.Sum(p => p.Weight),
Min = g.Min(p => p.Kmw),
@@ -1078,62 +1018,27 @@ namespace Elwig.Services {
.OrderByDescending(g => g.Weight)
.ThenBy(g => g.Attr)
.ThenBy(g => g.Cult)
.ThenBy(g => g.Type)
.ThenBy(g => g.SortId)
.ToListAsync();
foreach (var attrG in attrGroups) {
var name = GetGroupName(attrG.Attr, attrG.Cult);
var typeGroups = groups.Where(g => g.Attr == attrG.Attr && g.Cult == attrG.Cult)
.GroupBy(g => g.Type)
.Select(g => new { Type = g.Key, Weight = g.Sum(p => p.Weight) })
.OrderByDescending(g => g.Weight).ThenBy(g => g.Type)
.ToList();
wGrid.Add((name, null, null, attrG.Weight, null, attrG.Weight, stat.Weight, typeGroups.Count == 1 ? typeGroups.First().Type : null));
if (typeGroups.Count == 1) {
var name = attrG.Attr == null && attrG.Cult == null ? null : attrG.Attr + (attrG.Attr != null && attrG.Cult != null ? " / " : "") + attrG.Cult;
wGrid.Add((name, null, attrG.Weight, attrG.Weight, stat.Weight));
foreach (var g in groups.Where(g => g.Attr == attrG.Attr && g.Cult == attrG.Cult).OrderByDescending(g => g.Weight).ThenBy(g => g.SortId)) {
wGrid.Add((null, null, g.SortId, g.Weight, null, attrG.Weight, stat.Weight, null));
}
} else {
foreach (var t in typeGroups) {
wGrid.Add((null, t.Type == "R" ? "Rot" : "Weiß", null, t.Weight, t.Weight, attrG.Weight, stat.Weight, t.Type));
foreach (var g in groups.Where(g => g.Attr == attrG.Attr && g.Cult == attrG.Cult && g.Type == t.Type).OrderByDescending(g => g.Weight).ThenBy(g => g.SortId)) {
wGrid.Add((null, null, g.SortId, g.Weight, t.Weight, attrG.Weight, stat.Weight, null));
}
}
wGrid.Add((null, g.SortId, g.Weight, attrG.Weight, stat.Weight));
}
}
foreach (var attrG in attrGroups) {
var name = GetGroupName(attrG.Attr, attrG.Cult);
var typeGroups = groups.Where(g => g.Attr == attrG.Attr && g.Cult == attrG.Cult)
.GroupBy(g => g.Type)
.Select(g => new {
Type = g.Key,
Weight = g.Sum(p => p.Weight),
Min = g.Min(p => p.Min),
Avg = g.Sum(p => p.Avg * p.Weight) / g.Sum(p => p.Weight),
Max = g.Max(p => p.Max),
})
.OrderByDescending(g => g.Weight).ThenBy(g => g.Type)
.ToList();
gGrid.Add((name, null, null, attrG.Min, attrG.Avg, attrG.Max, typeGroups.Count == 1 ? typeGroups.First().Type : null));
if (typeGroups.Count == 1) {
var name = attrG.Attr == null && attrG.Cult == null ? null : attrG.Attr + (attrG.Attr != null && attrG.Cult != null ? " / " : "") + attrG.Cult;
gGrid.Add((name, null, attrG.Min, attrG.Avg, attrG.Max));
foreach (var g in groups.Where(g => g.Attr == attrG.Attr && g.Cult == attrG.Cult).OrderByDescending(g => g.Avg).ThenBy(g => g.SortId)) {
gGrid.Add((null, null, g.SortId, g.Min, g.Avg, g.Max, null));
}
} else {
foreach (var t in typeGroups) {
gGrid.Add((null, t.Type == "R" ? "Rot" : "Weiß", null, t.Min, t.Avg, t.Max, t.Type));
foreach (var g in groups.Where(g => g.Attr == attrG.Attr && g.Cult == attrG.Cult && g.Type == t.Type).OrderByDescending(g => g.Avg).ThenBy(g => g.SortId)) {
gGrid.Add((null, null, g.SortId, g.Min, g.Avg, g.Max, null));
}
}
gGrid.Add((null, g.SortId, g.Min, g.Avg, g.Max));
}
}
if (attrGroups.Count == 1) {
var g = attrGroups.First();
var name = GetGroupName(g.Attr, g.Cult);
var name = g.Attr == null && g.Cult == null ? null : g.Attr + (g.Attr != null && g.Cult != null ? " / " : "") + g.Cult;
if (name != null) {
wText += $" [{name}]";
gText += $" [{name}]";
@@ -1144,43 +1049,40 @@ namespace Elwig.Services {
}
} else if (attrGroups.Count <= 4) {
wText += $" = {string.Join(" + ", attrGroups.Select(g => $"{g.Weight:N0} kg ({(double)g.Weight / stat.Weight:0%})" + (GetGroupName(g.Attr, g.Cult) is string s ? $" [{s}]" : "")))}";
gText += $" = {string.Join(" + ", attrGroups.Select(g => $"{g.Min:N1}/{g.Avg:N1}/{g.Max:N1}" + (GetGroupName(g.Attr, g.Cult) is string s ? $" [{s}]" : "")))}";
wText += $" = {string.Join(" + ", attrGroups.Select(g => $"{g.Weight:N0} kg ({(double)g.Weight / stat.Weight:0%})" + (g.Attr == null && g.Cult == null ? "" : $" [{g.Attr}{(g.Attr != null && g.Cult != null ? " / " : "")}{g.Cult}]")))}";
gText += $" = {string.Join(" + ", attrGroups.Select(g => $"{g.Min:N1}/{g.Avg:N1}/{g.Max:N1}" + (g.Attr == null && g.Cult == null ? "" : $" [{g.Attr}{(g.Attr != null && g.Cult != null ? " / " : "")}{g.Cult}]")))}";
}
}
return (wText, wGrid.ToArray(), gText, gGrid.ToArray());
}
public static (Grid WeightGrid, Grid GradationGrid) GenerateToolTip((string?, string?, string?, int, int?, int?, int, string?)[] weightData, (string?, string?, string?, double, double, double, string?)[] gradationData) {
public static (Grid WeightGrid, Grid GradationGrid) GenerateToolTip((string?, string?, int, int?, int)[] weightData, (string?, string?, double, double, double)[] gradationData) {
var wGrid = new Grid();
wGrid.ColumnDefinitions.Add(new() { Width = new(10) });
wGrid.ColumnDefinitions.Add(new() { Width = new(10) });
wGrid.ColumnDefinitions.Add(new() { Width = new(60) });
wGrid.ColumnDefinitions.Add(new() { Width = new(80) });
wGrid.ColumnDefinitions.Add(new() { Width = new(80) });
wGrid.ColumnDefinitions.Add(new() { Width = new(50) });
wGrid.ColumnDefinitions.Add(new() { Width = new(50) });
wGrid.ColumnDefinitions.Add(new() { Width = new(50) });
int rowNum = 0;
foreach (var row in weightData) {
if (rowNum != 0 && row.Item2 == null && row.Item3 == null) rowNum++;
AddWeightToolTipRow(wGrid, rowNum++, row.Item1, row.Item2, row.Item3, row.Item4, row.Item5, row.Item6, row.Item7, row.Item8);
if (rowNum != 0 && row.Item2 == null) rowNum++;
AddWeightToolTipRow(wGrid, rowNum++, row.Item1, row.Item2, row.Item3, row.Item4, row.Item5);
}
var gGrid = new Grid();
gGrid.ColumnDefinitions.Add(new() { Width = new(10) });
gGrid.ColumnDefinitions.Add(new() { Width = new(10) });
gGrid.ColumnDefinitions.Add(new() { Width = new(80) });
gGrid.ColumnDefinitions.Add(new() { Width = new(60) });
gGrid.ColumnDefinitions.Add(new() { Width = new(35) });
gGrid.ColumnDefinitions.Add(new() { Width = new(35) });
gGrid.ColumnDefinitions.Add(new() { Width = new(35) });
gGrid.AddToolTipCell("Min.", 0, 3, alignCenter: true);
gGrid.AddToolTipCell("⌀", 0, 4, alignCenter: true);
gGrid.AddToolTipCell("Max.", 0, 5, alignCenter: true);
gGrid.AddToolTipCell("Min.", 0, 2, alignCenter: true);
gGrid.AddToolTipCell("⌀", 0, 3, alignCenter: true);
gGrid.AddToolTipCell("Max.", 0, 4, alignCenter: true);
rowNum = 1;
foreach (var row in gradationData) {
if (rowNum != 1 && row.Item2 == null && row.Item3 == null) rowNum++;
AddGradationToolTipRow(gGrid, rowNum++, row.Item1, row.Item2, row.Item3, row.Item4, row.Item5, row.Item6, row.Item7);
if (rowNum != 1 && row.Item2 == null) rowNum++;
AddGradationToolTipRow(gGrid, rowNum++, row.Item1, row.Item2, row.Item3, row.Item4, row.Item5);
}
return (wGrid, gGrid);
-28
View File
@@ -1,4 +1,3 @@
using Microsoft.Data.Sqlite;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
@@ -118,35 +117,8 @@ namespace Elwig.Services {
public static void ShowException(string title, string? text, Exception exc, bool showExcType = false, bool isError = true) {
text = text == null ? "" : text + (text.EndsWith('.') || text.EndsWith('!') || text.EndsWith('?') ? "" : ":") + "\n\n";
if ((exc.InnerException ?? exc) is SqliteException sql) {
if (sql.SqliteErrorCode == 5 || sql.SqliteErrorCode == 6) {
// SQLITE_BUSY / SQLITE_LOCKED
text += "Die Datenbank wurde gerade von einem anderen Gerät/Prozess verwendet. Bitte noch einmal versuchen!\n\n" + sql.Message;
} else if (sql.SqliteErrorCode == 19) {
// SQLITE_CONSTRAINT
switch (sql.SqliteExtendedErrorCode) {
case 1555: // SQLITE_CONSTRAINT_PRIMARYKEY - indicating that a PRIMARY KEY constraint failed
case 2067: // SQLITE_CONSTRAINT_UNIQUE - indicating that a UNIQUE constraint failed
case 2579: // SQLITE_CONSTRAINT_ROWID - indicating that a rowid is not unique
text += "Dieser Datensatz existiert bereits!\n\n";
break;
case 787: // SQLITE_CONSTRAINT_FOREIGNKEY - indicating that a foreign key constraint failed
case 1299: // SQLITE_CONSTRAINT_NOTNULL - indicating that a NOT NULL constraint failed
case 275: // SQLITE_CONSTRAINT_CHECK - indicating that a CHECK constraint failed
case 1811: // SQLITE_CONSTRAINT_TRIGGER - indicating that a RAISE function within a trigger fired, causing the SQL statement to abort
case 531: // SQLITE_CONSTRAINT_COMMITHOOK - indicating that a commit hook callback returned non-zero that thus caused the SQL statement to be rolled back
text += "Der Datensatz ist inkonsistent!\n\n";
break;
}
text += sql.Message;
} else {
text += exc.Message + (showExcType ? $" ({exc.GetType().Name})" : "");
if (exc.InnerException != null) text += "\n\n" + exc.InnerException.Message;
}
} else {
text += exc.Message + (showExcType ? $" ({exc.GetType().Name})" : "");
if (exc.InnerException != null) text += "\n\n" + exc.InnerException.Message;
}
if (isError) {
ShowError(title, text);
} else {
@@ -3,7 +3,6 @@ using Elwig.Models;
using Elwig.Models.Entities;
using Elwig.ViewModels;
using Microsoft.EntityFrameworkCore;
using System;
using System.Linq;
using System.Threading.Tasks;
@@ -12,7 +11,7 @@ namespace Elwig.Services {
public static async Task InitInputs(this MemberBusinessSharesViewModel vm) {
using var ctx = new AppDbContext();
vm.DateNoticeString = $"{DateTime.Today:dd.MM.yyyy}";
vm.DateNoticeString = $"{Utils.Today:dd.MM.yyyy}";
vm.ValuePerShare = (await ctx.Seasons.OrderBy(s => s.Year).LastOrDefaultAsync())?.BusinessShareValue;
}
@@ -26,7 +25,6 @@ namespace Elwig.Services {
vm.DateEffective = h.DateEffective;
vm.Reason = h.Reason + (h.Reason == MemberHistory.REASON_TRANSFER ? $"_{(h.ToMgNr == mgnr ? "from" : "to")}" : "");
vm.Shares = h.Shares;
vm.CompanyHasSigned = h.CompanyHasSigned;
vm.MemberHasSigned = h.MemberHasSigned;
vm.ValuePerShare = h.ValuePerShare;
vm.OtherMgNr = h.FromMgNr != null && h.FromMgNr != mgnr ? h.FromMgNr : h.ToMgNr != null && h.ToMgNr != mgnr ? h.ToMgNr : null;
@@ -64,7 +62,6 @@ namespace Elwig.Services {
Reason = vm.Reason?.Split("_")[0] ?? MemberHistory.REASON_CONVERT,
Source = "manual",
Shares = vm.Shares ?? 0,
CompanyHasSigned = vm.CompanyHasSigned,
MemberHasSigned = vm.MemberHasSigned,
ValuePerShare = vm.ValuePerShare,
CurrencyCode = vm.ValuePerShare != null ? "EUR" : null,
+20 -102
View File
@@ -10,7 +10,6 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Media;
namespace Elwig.Services {
public static class MemberService {
@@ -20,7 +19,6 @@ namespace Elwig.Services {
};
public static async Task InitInputs(this MemberAdminViewModel vm) {
vm.IsMemberSelectedOrCreating = true;
using var ctx = new AppDbContext();
vm.MgNr = await ctx.NextMgNr();
vm.EntryDate = DateTime.Now.ToString("dd.MM.yyyy");
@@ -33,7 +31,6 @@ namespace Elwig.Services {
public static void ClearInputs(this MemberAdminViewModel vm) {
vm.IsMemberSelected = false;
vm.IsMemberSelectedOrCreating = false;
vm.MemberHasEmail = false;
vm.MemberCanSendEmail = false;
vm.EnableMemberReferenceButton = false;
@@ -52,15 +49,10 @@ namespace Elwig.Services {
vm.ModifiedAtShort = "-";
vm.ExportedAt = "-";
vm.ImportedAt = "-";
vm.OrganicState = null;
vm.OrganicColor = Brushes.Black;
vm.OrganicDetails = "-";
vm.OrganicToolTip = null;
}
public static void FillInputs(this MemberAdminViewModel vm, Member m) {
vm.IsMemberSelected = true;
vm.IsMemberSelectedOrCreating = true;
vm.MgNr = m.MgNr;
vm.PredecessorMgNr = m.PredecessorMgNr;
vm.IsJuridicalPerson = m.IsJuridicalPerson;
@@ -114,9 +106,7 @@ namespace Elwig.Services {
vm.UstIdNr = m.UstIdNr;
vm.LfbisNr = m.LfbisNr;
vm.OrganicOperatorId = m.OrganicOperatorId;
vm.OrganicAuthorityCode = m.OrganicAuthorityCode;
vm.IsAccounting = m.IsAccounting;
vm.IsBuchführend = m.IsBuchführend;
vm.IsOrganic = m.IsOrganic;
var billingAddr = m.BillingAddress;
@@ -150,8 +140,8 @@ namespace Elwig.Services {
vm.DefaultKg = (AT_Kg?)ControlUtils.GetItemFromSourceWithPk(vm.DefaultKgSource, m.DefaultKgNr);
vm.Comment = m.Comment;
vm.IsActive = m.IsActive;
vm.IsFullDelivery = m.IsFullDelivery;
vm.IsOfficer = m.IsOfficer;
vm.IsVollLieferant = m.IsVollLieferant;
vm.IsFunktionär = m.IsFunktionär;
vm.ContactViaPost = m.ContactViaPost;
vm.ContactViaEmail = m.ContactViaEmail;
@@ -197,9 +187,10 @@ namespace Elwig.Services {
.GroupBy(d => d.Year)
.ToDictionaryAsync(g => g.Key, g => g.Any());
await App.MainDispatcher.BeginInvoke(() => {
if (m.MgNr != vm.MgNr)
return;
await App.MainDispatcher.BeginInvoke(() => {
var (d1Grid, _) = DeliveryService.GenerateToolTip(d1GridData, []);
var (d2Grid, _) = DeliveryService.GenerateToolTip(d2GridData, []);
var grid = AreaComService.GenerateToolTip(gridData);
@@ -212,76 +203,13 @@ namespace Elwig.Services {
vm.StatusAreaCommitmentInfo = $"{Utils.CurrentLastSeason}";
vm.StatusAreaCommitment = text;
vm.StatusAreaCommitmentToolTip = grid;
vm.MemberHasDeliveries = [.. Enumerable.Range(0, 9999).Select(i => deliveries.GetValueOrDefault(i, false))];
vm.MemberHasDeliveries = Enumerable.Range(0, 9999).Select(i => deliveries.GetValueOrDefault(i, false)).ToList();
});
});
vm.OrganicState = null;
vm.OrganicColor = Brushes.Black;
vm.OrganicToolTip = null;
if (!vm.IsOrganic) {
vm.OrganicDetails = "-";
} else {
vm.OrganicDetails = "...";
Utils.RunBackground("Bio-Zertifikatsdaten laden", async () => {
if (App.MainDispatcher == null) return;
var certs = await OrganicService.GetTracesCertificates(m);
await App.MainDispatcher.BeginInvoke(() => {
if (m.MgNr != vm.MgNr) return;
vm.FillOrganicInputs(certs.FirstOrDefault(c => c.IsValidForWineProduction));
});
});
}
vm.MemberHasEmail = m.EmailAddresses.Count > 0;
vm.MemberCanSendEmail = App.Config.Smtp != null && m.EmailAddresses.Count > 0;
vm.MemberHasDeliveries = [.. Enumerable.Range(0, 9999).Select(i => false)];
}
public static void FillOrganicInputs(this MemberAdminViewModel vm, OrganicService.TracesCertificate? cert) {
vm.OrganicDetails = null;
if (cert == null) {
vm.OrganicState = "Nicht gefunden";
vm.OrganicColor = Brushes.DarkRed;
vm.OrganicToolTip = null;
return;
}
vm.OrganicToolTip = $"""
Zertifikat-Nr.: {cert.Id}
Status: {cert.Status}
Bio-KSt.: {cert.AuthorityCode}
EU Operator-ID: {cert.OperatorId}
Operator: {cert.OperatorName}
Ausgestellt am: {cert.IssuedOn:dd.MM.yyyy}
Aktualisiert am: {cert.LastStatusUpdateOn:dd.MM.yyyy}
Erlischt am: {cert.ExpiresOn:dd.MM.yyyy}
""";
if (cert.IsValidForWineProduction) {
vm.OrganicState = "Gültig";
vm.OrganicDetails = $" ({cert.ExpiresOn:MMM. yyyy})";
vm.OrganicColor = Brushes.DarkGreen;
} else if (cert.IsValid) {
vm.OrganicState = "Gültig";
vm.OrganicDetails = $" ({cert.ExpiresOn:MMM. yyyy})";
vm.OrganicColor = Brushes.OrangeRed;
} else {
vm.OrganicColor = Brushes.DarkRed;
switch (cert.Status) {
case OrganicService.TracesStatus.ISSUED:
vm.OrganicState = "Ausgestellt";
vm.OrganicDetails = $" ({cert.LastStatusUpdateOn:MMM. yyyy})"; break;
case OrganicService.TracesStatus.SUSPENDED:
vm.OrganicState = "Gesperrt";
vm.OrganicDetails = $" ({cert.LastStatusUpdateOn:MMM. yyyy})"; break;
case OrganicService.TracesStatus.EXPIRED:
vm.OrganicState = "Ausgelaufen";
vm.OrganicDetails = $" ({cert.LastStatusUpdateOn:MMM. yyyy})"; break;
case OrganicService.TracesStatus.WITHDRAWN:
vm.OrganicState = "Widerrufen";
vm.OrganicDetails = $" ({cert.LastStatusUpdateOn:MMM. yyyy})"; break;
}
}
vm.MemberHasDeliveries = Enumerable.Range(0, 9999).Select(i => false).ToList();
}
public static async Task<(List<string>, IQueryable<Member>, List<string>)> GetFilters(this MemberAdminViewModel vm, AppDbContext ctx) {
@@ -319,11 +247,11 @@ namespace Elwig.Services {
filter.RemoveAt(i--);
filterNames.Add("inaktive Mitglieder");
} else if (e.Length >= 5 && e.Length <= 10 && "funktionär".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
memberQuery = memberQuery.Where(m => m.IsOfficer);
memberQuery = memberQuery.Where(m => m.IsFunktionär);
filter.RemoveAt(i--);
filterNames.Add("Funktionäre");
} else if (e.Length >= 6 && e.Length <= 11 && e[0] == '!' && "funktionär".StartsWith(e[1..], StringComparison.CurrentCultureIgnoreCase)) {
memberQuery = memberQuery.Where(m => !m.IsOfficer);
memberQuery = memberQuery.Where(m => !m.IsFunktionär);
filter.RemoveAt(i--);
filterNames.Add("Nicht-Funktionäre");
} else if (e.Equals("bio", StringComparison.CurrentCultureIgnoreCase)) {
@@ -334,36 +262,28 @@ namespace Elwig.Services {
memberQuery = memberQuery.Where(m => !m.IsOrganic);
filter.RemoveAt(i--);
filterNames.Add("Nicht-Bio-Betriebe");
} else if (e.Length >= 4 && e.Length <= 14 && "vollablieferer".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
memberQuery = memberQuery.Where(m => m.IsFullDelivery);
filter.RemoveAt(i--);
filterNames.Add("Vollablieferer");
} else if (e.Length >= 4 && e.Length <= 13 && "volllieferant".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
memberQuery = memberQuery.Where(m => m.IsFullDelivery);
memberQuery = memberQuery.Where(m => m.IsVollLieferant);
filter.RemoveAt(i--);
filterNames.Add("Vollablieferer");
} else if (e.Length >= 5 && e.Length <= 15 && e[0] == '!' && "vollablieferer".StartsWith(e[1..], StringComparison.CurrentCultureIgnoreCase)) {
memberQuery = memberQuery.Where(m => !m.IsFullDelivery);
filter.RemoveAt(i--);
filterNames.Add("Nicht-Vollablieferer");
filterNames.Add("Volllieferanten");
} else if (e.Length >= 5 && e.Length <= 14 && e[0] == '!' && "volllieferant".StartsWith(e[1..], StringComparison.CurrentCultureIgnoreCase)) {
memberQuery = memberQuery.Where(m => !m.IsFullDelivery);
memberQuery = memberQuery.Where(m => !m.IsVollLieferant);
filter.RemoveAt(i--);
filterNames.Add("Nicht-Vollablieferer");
filterNames.Add("Nicht-Vollieferanten");
} else if (e.Length >= 5 && e.Length <= 11 && "buchführend".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
memberQuery = memberQuery.Where(m => m.IsAccounting);
memberQuery = memberQuery.Where(m => m.IsBuchführend);
filter.RemoveAt(i--);
filterNames.Add("buchführend");
} else if (e.Length >= 6 && e.Length <= 12 && e[0] == '!' && "buchführend".StartsWith(e[1..], StringComparison.CurrentCultureIgnoreCase)) {
memberQuery = memberQuery.Where(m => !m.IsAccounting);
memberQuery = memberQuery.Where(m => !m.IsBuchführend);
filter.RemoveAt(i--);
filterNames.Add("pauschaliert");
} else if (e.Length >= 8 && e.Length <= 12 && "pauschaliert".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
memberQuery = memberQuery.Where(m => !m.IsAccounting);
memberQuery = memberQuery.Where(m => !m.IsBuchführend);
filter.RemoveAt(i--);
filterNames.Add("pauschaliert");
} else if (e.Length >= 9 && e.Length <= 13 && e[0] == '!' && "pauschaliert".StartsWith(e[1..], StringComparison.CurrentCultureIgnoreCase)) {
memberQuery = memberQuery.Where(m => m.IsAccounting);
memberQuery = memberQuery.Where(m => m.IsBuchführend);
filter.RemoveAt(i--);
filterNames.Add("buchführend");
} else if (e.Equals("email", StringComparison.CurrentCultureIgnoreCase)) {
@@ -635,9 +555,7 @@ namespace Elwig.Services {
UstIdNr = string.IsNullOrWhiteSpace(vm.UstIdNr) ? null : vm.UstIdNr,
LfbisNr = string.IsNullOrWhiteSpace(vm.LfbisNr) ? null : vm.LfbisNr,
OrganicOperatorId = string.IsNullOrWhiteSpace(vm.OrganicOperatorId) ? null : vm.OrganicOperatorId,
OrganicAuthorityCode = string.IsNullOrWhiteSpace(vm.OrganicAuthorityCode) ? null : vm.OrganicAuthorityCode,
IsAccounting = vm.IsAccounting,
IsBuchführend = vm.IsBuchführend,
IsOrganic = vm.IsOrganic,
EntryDateString = string.IsNullOrWhiteSpace(vm.EntryDate) ? null : string.Join("-", vm.EntryDate.Split(".").Reverse()),
@@ -648,8 +566,8 @@ namespace Elwig.Services {
SharesDormant = App.Client.HasRedWhite ? vm.BusinessShares3 ?? 0 : vm.BusinessShares2 ?? 0,
AccountingNr = string.IsNullOrWhiteSpace(vm.AccountingNr) ? null : vm.AccountingNr,
IsActive = vm.IsActive,
IsFullDelivery = vm.IsFullDelivery,
IsOfficer = vm.IsOfficer,
IsVollLieferant = vm.IsVollLieferant,
IsFunktionär = vm.IsFunktionär,
ZwstId = vm.Branch?.ZwstId,
DefaultKgNr = vm.DefaultKg?.KgNr,
Comment = string.IsNullOrWhiteSpace(vm.Comment) ? null : vm.Comment,
-162
View File
@@ -1,162 +0,0 @@
using Elwig.Helpers;
using Elwig.Models.Entities;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Web;
namespace Elwig.Services {
public static class OrganicService {
public const string TRACES_API_URL = "https://webgate.ec.europa.eu/tracesnt/directory/publication/organic-operator/for/query";
public const string TRACES_PDF_URL_PREFIX = "https://webgate.ec.europa.eu/tracesnt/directory/publication/organic-operator/digitally-signed/";
public enum TracesStatus {
ISSUED, SUSPENDED, WITHDRAWN, EXPIRED
}
public enum TracesActivity {
PREPARATION, EXPORT, IMPORT, STORING, PRODUCTION, DISTRIBUTION, DISTRIBUTION_PLACING_ON_THE_MARKET
}
public enum TracesCategoryOfProduct {
UNPROCESSED_PLANT_PRODUCTS_INCLUDING_SEEDS, LIVESTOCK_AND_UNPROCESSED_LIVESTOCK_PRODUCTS, ALGAE_AND_UNPROCESSED_AQUACULTURE_PRODUCTS,
PROCESSED_AGRICULTURAL_PRODUCTS_INCLUDING_AQUACULTURE_FOR_USE_AS_FOOD, FEED, WINE, OTHER_PRODUCTS_NOT_COVERED_BY_PREVIOUS_CATEGORIES
}
public record TracesCertificate {
public required string Id { get; init; }
public required string AuthorityCode { get; init; }
public required string OperatorId { get; init; }
public required string OperatorName { get; init; }
public required TracesActivity[] Activities { get; init; }
public required TracesCategoryOfProduct[] CategoriesOfProduct { get; init; }
public required DateOnly IssuedOn { get; init; }
public required DateOnly ExpiresOn { get; init; }
public required DateOnly LastStatusUpdateOn { get; init; }
public required TracesStatus Status { get; init; }
public string PdfUrl => TRACES_PDF_URL_PREFIX + Id + ".pdf";
public bool IsValid => Status == TracesStatus.ISSUED && IssuedOn.ToDateTime(new()) <= DateTime.Today && ExpiresOn.ToDateTime(new()) >= DateTime.Today;
public bool IsValidForWineProduction => IsValid && Activities.Contains(TracesActivity.PRODUCTION) &&
(CategoriesOfProduct.Contains(TracesCategoryOfProduct.UNPROCESSED_PLANT_PRODUCTS_INCLUDING_SEEDS) || CategoriesOfProduct.Contains(TracesCategoryOfProduct.WINE));
}
private static readonly Dictionary<int, (DateTime Timestamp, TracesCertificate[] Certificates)> _memberCerts = [];
public async static Task<TracesCertificate[]> GetTracesCertificates(Member m, bool? tryNameAndAddress = null) {
if (_memberCerts.TryGetValue(m.MgNr, out var entry) && entry.Timestamp >= DateTime.Now.AddDays(-1))
return entry.Certificates;
var certs = await FetchTracesCertificates(m, tryNameAndAddress);
_memberCerts[m.MgNr] = (DateTime.Now, certs);
return certs;
}
private async static Task<JsonArray> TryFetchTracesCertificates(Dictionary<string, string> query) {
var q = HttpUtility.ParseQueryString("");
q.Add("sort", "-issuedOn");
q.Add("countryCode", "AT");
foreach (var (k, v) in query) {
q.Add(k, v);
}
using var client = Utils.GetHttpClient();
using var res = await client.GetAsync($"{TRACES_API_URL}?{q}");
res.EnsureSuccessStatusCode();
var resJson = JsonNode.Parse(await res.Content.ReadAsStringAsync());
return resJson?.AsArray() ?? throw new JsonException();
}
public static Task<TracesCertificate[]> FetchTracesCertificates(Member m, bool? tryNameAndAddress = null) {
return FetchTracesCertificates(m.OrganicOperatorId, m.LfbisNr,
(tryNameAndAddress ?? m.IsOrganic) ? m.BillingAddress is BillingAddr a ?
(a.FullName, a.Address, $"{a.PostalDest.AtPlz?.Plz}") :
(m.FullName, m.Address, $"{m.PostalDest.AtPlz?.Plz}") :
null);
}
public async static Task<TracesCertificate[]> FetchTracesCertificates(string? oocId = null, string? lfbisNr = null, (string Name, string Address, string PostalCode)? address = null) {
bool searchedByName = false;
JsonArray jsonCerts = [];
if (jsonCerts.Count == 0 && oocId != null) {
jsonCerts = await TryFetchTracesCertificates(new Dictionary<string, string> {
{ "operatorIdentifierType", "ooc_identifier" },
{ "operatorIdentifierSearchOperator", "STRICT" },
{ "operatorIdentifier", oocId },
});
}
if (jsonCerts.Count == 0 && lfbisNr != null) {
jsonCerts = await TryFetchTracesCertificates(new Dictionary<string, string> {
{ "operatorIdentifierType", "comp_reg" },
{ "operatorIdentifierSearchOperator", "STRICT" },
{ "operatorIdentifier", lfbisNr.TrimStart('0') },
});
}
if (jsonCerts.Count == 0 && address != null) {
var query = $"{Regex.Replace(address.Value.Name, @"\(.*?\)", "")} {address.Value.Address}";
jsonCerts = await TryFetchTracesCertificates(new Dictionary<string, string> {
{ "operatorPostalCode", address.Value.PostalCode },
{ "query", query.Length > 40 ? query[..query.LastIndexOf(' ', 40)] : query },
});
searchedByName = true;
}
if (jsonCerts.Count == 0)
return [];
TracesCertificate[] certs = [.. jsonCerts.Select(j => new TracesCertificate {
Id = j!["reference"]?.GetValue<string>() ?? throw new Exception(),
AuthorityCode = j["issuingBody"]?["code"]?.GetValue<string>() ?? throw new Exception(),
OperatorId = j["operatorIdentifier"]?.GetValue<string>() ?? throw new Exception(),
OperatorName = j["operator"]?["name"]?.GetValue<string>() ?? throw new Exception(),
Activities = [.. j["activities"]?.AsArray().Select(a => Enum.Parse<TracesActivity>(a?["id"]?.GetValue<string>().ToUpper().Replace("_IMPORT", "IMPORT") ?? throw new Exception())) ?? []],
CategoriesOfProduct = [.. j["categoriesOfProduct"]?.AsArray().Select(c => Enum.Parse<TracesCategoryOfProduct>(c?["id"]?.GetValue<string>() ?? throw new Exception())) ?? []],
IssuedOn = DateOnly.FromDateTime(DateTime.ParseExact(j["issuedOn"]?.GetValue<string>() ?? throw new Exception(), "yyyy-MM-ddTHH:mm:ss.fffK", CultureInfo.InvariantCulture, DateTimeStyles.None)),
ExpiresOn = DateOnly.ParseExact(j["expiresOn"]?.GetValue<string>() ?? throw new Exception(), "yyyy-MM-dd"),
LastStatusUpdateOn = DateOnly.FromDateTime(DateTime.ParseExact(j["lastStatusUpdateDateTime"]?.GetValue<string>() ?? throw new Exception(), "yyyy-MM-ddTHH:mm:ss.fffK", CultureInfo.InvariantCulture, DateTimeStyles.None)),
Status = Enum.Parse<TracesStatus>(j["status"]?["id"]?.GetValue<string>() ?? throw new Exception()),
})];
return (!searchedByName || certs.Where(c => c.Status == TracesStatus.ISSUED).Select(c => c.OperatorId).ToHashSet().Count == 1) ? certs : [];
}
public static string? GetTracesSearchUrl(Member m, bool? tryNameAndAddress = null) {
return GetTracesSearchUrl(m.OrganicOperatorId, m.LfbisNr,
(tryNameAndAddress ?? m.IsOrganic) ? m.BillingAddress is BillingAddr a ?
(a.FullName, a.Address, $"{a.PostalDest.AtPlz?.Plz}") :
(m.FullName, m.Address, $"{m.PostalDest.AtPlz?.Plz}") :
null);
}
public static string? GetTracesSearchUrl(string? oocId = null, string? lfbisNr = null, (string Name, string Address, string PostalCode)? address = null) {
var baseUrl = "https://webgate.ec.europa.eu/tracesnt/directory/publication/organic-operator/index";
if (oocId != null) {
return $"{baseUrl}#!?countryCode=AT&operatorIdentifierType=ooc_identifier&operatorIdentifierSearchOperator=STRICT&operatorIdentifier={oocId}&states=ISSUED";
} else if (lfbisNr != null) {
return $"{baseUrl}#!?countryCode=AT&operatorIdentifierType=comp_reg&operatorIdentifierSearchOperator=STRICT&operatorIdentifier={lfbisNr.TrimStart('0')}&states=ISSUED";
} else if (address != null) {
return $"{baseUrl}#!?countryCode=AT&operatorPostalCode={address?.PostalCode}&query={address?.Name.Replace(' ', '+')}+{address?.Address.Replace(' ', '+')}&states=ISSUED";
} else {
return null;
}
}
public static string? GetEasyCertSearchUrl(string lfbisNr) {
var baseUrl = "https://www.easy-cert.com/htm/suchergebnis.htm";
return $"{baseUrl}?CountryCode=AT&CustomerNumber={lfbisNr.TrimStart('0')}";
}
public static string? GetBiocSearchUrl(string lfbisNr) {
var baseUrl = "https://www.bioc.info/search/producersearchresult";
return $"{baseUrl}?producerSearch[country]=a1e51f85-27b5-a1e3-65f7-561569884d38&producerSearch[operatorId]={lfbisNr.TrimStart('0')}";
}
}
}
+2 -2
View File
@@ -159,10 +159,10 @@ namespace Elwig.Services {
foreach (int mgnr in currentPayments.Keys) {
var c = currentPayments[mgnr];
var l = lastPayments.GetValueOrDefault(mgnr);
vatSum += (c.Amount - (l?.Amount ?? 0)) * (decimal)(c.Member.IsAccounting ? v.Season.VatNormal : v.Season.VatFlatrate);
vatSum += (c.Amount - (l?.Amount ?? 0)) * (decimal)(c.Member.IsBuchführend ? v.Season.VatNormal : v.Season.VatFlatrate);
}
} else {
vatSum = currentPayments.Sum(e => e.Value.Amount * (decimal)(e.Value.Member.IsAccounting ? v.Season.VatNormal : v.Season.VatFlatrate));
vatSum = currentPayments.Sum(e => e.Value.Amount * (decimal)(e.Value.Member.IsBuchführend ? v.Season.VatNormal : v.Season.VatFlatrate));
}
vatText = $"~{vatSum:N2} {sym}";
deductionText = $"- {sym}";
+23 -23
View File
@@ -8,94 +8,94 @@ namespace Elwig.ViewModels {
public partial class AreaComAdminViewModel : ObservableObject {
[ObservableProperty]
public partial string Title { get; set; } = "Flächenbindungen - Elwig";
private string _title = "Flächenbindungen - Elwig";
public required Member FilterMember { get; set; }
[ObservableProperty]
public partial string? SearchQuery { get; set; } = "";
private string? _searchQuery = "";
public List<string> TextFilter {
get => [.. SearchQuery?.ToLower().Split(' ').ToList().FindAll(e => e.Length > 0) ?? []];
set => SearchQuery = string.Join(' ', value.Where(e => e.Length > 0));
}
[ObservableProperty]
public partial string? FilterSeasonString { get; set; }
private string? _filterSeasonString;
public int? FilterSeason {
get => int.TryParse(FilterSeasonString, out var year) ? year : null;
set => FilterSeasonString = $"{value}";
}
[ObservableProperty]
public partial string? FbNrString { get; set; }
private string? _fbNrString;
public int? FbNr {
get => int.TryParse(FbNrString, out var mgnr) ? mgnr : null;
set => FbNrString = $"{value}";
}
[ObservableProperty]
public partial string? MgNrString { get; set; }
private string? _mgNrString;
public int? MgNr {
get => int.TryParse(MgNrString, out var mgnr) ? mgnr : null;
set => MgNrString = $"{value}";
}
[ObservableProperty]
public partial string? YearFromString { get; set; }
private string? _yearFromString;
public int? YearFrom {
get => int.TryParse(YearFromString, out var year) ? year : null;
set => YearFromString = $"{value}";
}
[ObservableProperty]
public partial string? YearToString { get; set; }
private string? _yearToString;
public int? YearTo {
get => int.TryParse(YearToString, out var year) ? year : null;
set => YearToString = $"{value}";
}
[ObservableProperty]
public partial string? Period { get; set; }
private string? _period;
[ObservableProperty]
public partial AreaComType? AreaComType { get; set; }
private AreaComType? _areaComType;
[ObservableProperty]
public partial IEnumerable<AreaComType> AreaComTypeSource { get; set; } = [];
private IEnumerable<AreaComType> _areaComTypeSource = [];
[ObservableProperty]
public partial object? WineCultObj { get; set; }
private object? _wineCultObj;
public WineCult? WineCult {
get => WineCultObj as WineCult;
set => WineCultObj = value ?? WineCultSource.FirstOrDefault();
}
[ObservableProperty]
public partial IEnumerable<object> WineCultSource { get; set; } = [];
private IEnumerable<object> _wineCultSource = [];
[ObservableProperty]
public partial string? Comment { get; set; }
private string? _comment;
[ObservableProperty]
public partial AT_Kg? Kg { get; set; }
private AT_Kg? _kg;
[ObservableProperty]
public partial IEnumerable<AT_Kg> KgSource { get; set; } = [];
private IEnumerable<AT_Kg> _kgSource = [];
[ObservableProperty]
public partial object? RdObj { get; set; }
private object? _rdObj;
public WbRd? Rd {
get => RdObj as WbRd;
set => RdObj = value ?? RdSource.FirstOrDefault();
}
[ObservableProperty]
public partial IEnumerable<object> RdSource { get; set; } = [];
private IEnumerable<object> _rdSource = [];
[ObservableProperty]
public partial string? GstNr { get; set; }
private string? _gstNr;
[ObservableProperty]
public partial string? AreaString { get; set; }
private string? _areaString;
public int? Area {
get => int.TryParse(AreaString, out var area) ? area : null;
set => AreaString = $"{value}";
}
[ObservableProperty]
public partial string StatusAreaCommitments { get; set; } = "-";
private string _statusAreaCommitments = "-";
[ObservableProperty]
public partial string StatusContracts { get; set; } = "-";
private string _statusContracts = "-";
[ObservableProperty]
public partial string StatusArea { get; set; } = "-";
private string _statusArea = "-";
[ObservableProperty]
public partial Grid? StatusAreaToolTip { get; set; }
private Grid? _statusAreaToolTip;
}
}
+61 -69
View File
@@ -9,175 +9,167 @@ using System.Windows.Controls;
namespace Elwig.ViewModels {
public partial class DeliveryAdminViewModel : ObservableObject {
public bool IsReceipt { get; set; } = false;
public bool IsReceipt = false;
[ObservableProperty]
public partial string Title { get; set; } = "Lieferungen - Elwig";
private string _title = "Lieferungen - Elwig";
public Member? FilterMember { get; set; }
[ObservableProperty]
public partial string? SearchQuery { get; set; } = "";
private string? _searchQuery = "";
public List<string> TextFilter => [.. SearchQuery?.ToLower().Split(' ').ToList().FindAll(e => e.Length > 0) ?? []];
[ObservableProperty]
public partial string? LastScaleError { get; set; }
private string? _lastScaleError;
[ObservableProperty]
public partial string? ManualWeighingReason { get; set; }
private string? _manualWeighingReason;
[ObservableProperty]
public partial string? ScaleTerminalId { get; set; }
private string? _scaleTerminalId;
[ObservableProperty]
public partial string? WeighingData { get; set; }
private string? _weighingData;
[ObservableProperty]
public partial bool FilterTodayOnly { get; set; }
private bool _filterTodayOnly;
[ObservableProperty]
public partial bool FilterAllSeasons { get; set; }
private bool _filterAllSeasons;
[ObservableProperty]
public partial bool EnableAllSeasons { get; set; }
private bool _enableAllSeasons;
[ObservableProperty]
public partial string? FilterSeasonString { get; set; }
private string? _filterSeasonString;
public int? FilterSeason {
get => int.TryParse(FilterSeasonString, out var year) ? year : null;
set => FilterSeasonString = $"{value}";
}
[ObservableProperty]
public partial Delivery? SelectedDelivery { get; set; }
private Delivery? _selectedDelivery;
[ObservableProperty]
public partial IEnumerable<Delivery> Deliveries { get; set; } = [];
private IEnumerable<Delivery> _deliveries = [];
[ObservableProperty]
public partial string? MgNrString { get; set; }
private string? _mgNrString;
public int? MgNr {
get => int.TryParse(MgNrString, out var mgnr) ? mgnr : null;
set => MgNrString = $"{value}";
}
[ObservableProperty]
public partial Member? Member { get; set; }
private Member? _member;
[ObservableProperty]
public partial IEnumerable<Member> MemberSource { get; set; } = [];
private IEnumerable<Member> _memberSource = [];
[ObservableProperty]
public partial string? MemberAddress { get; set; }
private string? _memberAddress;
[ObservableProperty]
public partial string? LsNr { get; set; }
private string? _lsNr;
[ObservableProperty]
public partial string? Date { get; set; }
private string? _date;
[ObservableProperty]
public partial string? Time { get; set; }
private string? _time;
[ObservableProperty]
public partial Branch? Branch { get; set; }
private Branch? _branch;
[ObservableProperty]
public partial IEnumerable<Branch> BranchSource { get; set; } = [];
private IEnumerable<Branch> _branchSource = [];
[ObservableProperty]
public partial string? Comment { get; set; }
private string? _comment;
[ObservableProperty]
public partial string? SortId { get; set; }
private string? _sortId;
[ObservableProperty]
public partial WineVar? WineVar { get; set; }
private WineVar? _wineVar;
[ObservableProperty]
public partial IEnumerable<WineVar> WineVarSource { get; set; } = [];
private IEnumerable<WineVar> _wineVarSource = [];
[ObservableProperty]
public partial object? WineAttrObj { get; set; }
private object? _wineAttrObj;
public WineAttr? WineAttr {
get => WineAttrObj as WineAttr;
set => WineAttrObj = value ?? WineAttrSource.FirstOrDefault();
}
[ObservableProperty]
public partial IEnumerable<object> WineAttrSource { get; set; } = [];
private IEnumerable<object> _wineAttrSource = [];
[ObservableProperty]
public partial object? WineCultObj { get; set; }
private object? _wineCultObj;
public WineCult? WineCult {
get => WineCultObj as WineCult;
set => WineCultObj = value ?? WineCultSource.FirstOrDefault();
}
[ObservableProperty]
public partial IEnumerable<object> WineCultSource { get; set; } = [];
private IEnumerable<object> _wineCultSource = [];
[ObservableProperty]
public partial string? GradationOeString { get; set; }
private string? _gradationOeString;
public double? GradationOe {
get => double.TryParse(GradationOeString, out var oe) ? oe : null;
set => GradationOeString = $"{value:0}";
}
[ObservableProperty]
public partial string? GradationKmwString { get; set; }
private string? _gradationKmwString;
public double? GradationKmw {
get => double.TryParse(GradationKmwString, out var kmw) ? kmw : null;
set => GradationKmwString = $"{value:0.0}";
}
[ObservableProperty]
public partial WineQualLevel? WineQualityLevel { get; set; }
private WineQualLevel? _wineQualityLevel;
[ObservableProperty]
public partial IEnumerable<WineQualLevel> WineQualityLevelSource { get; set; } = [];
private IEnumerable<WineQualLevel> _wineQualityLevelSource = [];
[ObservableProperty]
public partial bool Abgewertet { get; set; }
private bool _abgewertet;
[ObservableProperty]
public partial string? WeightString { get; set; }
private string? _weightString;
public int? Weight {
get => int.TryParse(WeightString?.Replace(Utils.GroupSeparator, ""), out var w) ? w : null;
set => WeightString = $"{value:N0}";
}
[ObservableProperty]
public partial string? TareString { get; set; } = "-";
public int? Tare {
get => int.TryParse(TareString?.Replace(Utils.GroupSeparator, "").Replace(" kg", ""), out var w) ? w : null;
set => TareString = value == null ? "-" : $"{value:N0} kg{(TargetTare != null ? "*" : "")}";
}
public int? ActualTare { get; set; }
public int? TargetTare { get; set; }
private bool _isManualWeighing;
[ObservableProperty]
public partial bool IsManualWeighing { get; set; }
[ObservableProperty]
public partial bool? IsNetWeightValue { get; set; } = false;
private bool? _isNetWeightValue = false;
public bool IsNetWeight {
get => IsNetWeightValue ?? false;
set => IsNetWeightValue = value;
}
[ObservableProperty]
public partial WineOrigin? WineOrigin { get; set; }
private WineOrigin? _wineOrigin;
[ObservableProperty]
public partial IEnumerable<WineOrigin> WineOriginSource { get; set; } = [];
private IEnumerable<WineOrigin> _wineOriginSource = [];
[ObservableProperty]
public partial object? WineKgObj { get; set; }
private object? _wineKgObj;
public AT_Kg? WineKg {
get => WineKgObj as AT_Kg;
set => WineKgObj = value ?? WineKgSource.FirstOrDefault();
}
[ObservableProperty]
public partial IEnumerable<object> WineKgSource { get; set; } = [];
private IEnumerable<object> _wineKgSource = [];
[ObservableProperty]
public partial object? WineRdObj { get; set; }
private object? _wineRdObj;
public WbRd? WineRd {
get => WineRdObj as WbRd;
set => WineRdObj = value ?? WineRdSource.FirstOrDefault();
}
[ObservableProperty]
public partial IEnumerable<object> WineRdSource { get; set; } = [];
private IEnumerable<object> _wineRdSource = [];
[ObservableProperty]
public partial bool? IsContracted { get; set; }
private bool? _isGebunden;
public ObservableCollection<Modifier> Modifiers { get; set; } = [];
[ObservableProperty]
public partial IEnumerable<Modifier> ModifiersSource { get; set; } = [];
private IEnumerable<Modifier> _modifiersSource = [];
[ObservableProperty]
public partial string? PartComment { get; set; }
private string? _partComment;
[ObservableProperty]
public partial string? TemperatureString { get; set; }
private string? _temperatureString;
public double? Temperature {
get => double.TryParse(TemperatureString, out var t) ? t : null;
set => TemperatureString = $"{value:0.0}";
}
[ObservableProperty]
public partial string? AcidString { get; set; }
private string? _acidString;
public double? Acid {
get => double.TryParse(AcidString, out var a) ? a : null;
set => AcidString = $"{value:0.0}";
}
[ObservableProperty]
public partial bool? IsHandPicked { get; set; }
private bool? _isHandPicked;
public string? Unloading {
get => IsUnloadingDumper ? DeliveryPart.Dumper : IsUnloadingPumped ? DeliveryPart.Pumped : IsUnloadingBox ? DeliveryPart.Box : null;
@@ -191,28 +183,28 @@ namespace Elwig.ViewModels {
}
}
[ObservableProperty]
public partial bool IsUnloadingDumper { get; set; }
private bool _isUnloadingDumper;
[ObservableProperty]
public partial bool IsUnloadingPumped { get; set; }
private bool _isUnloadingPumped;
[ObservableProperty]
public partial bool IsUnloadingBox { get; set; }
private bool _isUnloadingBox;
[ObservableProperty]
public partial bool IsUnloadingOther { get; set; }
private bool _isUnloadingOther;
[ObservableProperty]
public partial string StatusMembers { get; set; } = "-";
private string _statusMembers = "-";
[ObservableProperty]
public partial string StatusDeliveries { get; set; } = "-";
private string _statusDeliveries = "-";
[ObservableProperty]
public partial string StatusVarieties { get; set; } = "-";
private string _statusVarieties = "-";
[ObservableProperty]
public partial string StatusWeight { get; set; } = "-";
private string _statusWeight = "-";
[ObservableProperty]
public partial string StatusGradation { get; set; } = "-";
private string _statusGradation = "-";
[ObservableProperty]
public partial Grid? StatusWeightToolTip { get; set; }
private Grid? _statusWeightToolTip;
[ObservableProperty]
public partial Grid? StatusGradationToolTip { get; set; }
private Grid? _statusGradationToolTip;
}
}
+26 -29
View File
@@ -9,80 +9,77 @@ namespace Elwig.ViewModels {
public partial class DeliveryAncmtAdminViewModel : ObservableObject {
[ObservableProperty]
public partial string Title { get; set; } = "Anmeldungen - Elwig";
[ObservableProperty]
public partial string? SearchQuery { get; set; } = "";
private string? _searchQuery = "";
public List<string> TextFilter => [.. SearchQuery?.ToLower().Split(' ').ToList().FindAll(e => e.Length > 0) ?? []];
[ObservableProperty]
public partial bool FilterOnlyUpcoming { get; set; }
private bool _filterOnlyUpcoming;
[ObservableProperty]
public partial bool FilterFromAllSchedules { get; set; }
private bool _filterFromAllSchedules;
[ObservableProperty]
public partial string? FilterSeasonString { get; set; }
private string? _filterSeasonString;
public int? FilterSeason {
get => int.TryParse(FilterSeasonString, out var year) ? year : null;
set => FilterSeasonString = $"{value}";
}
[ObservableProperty]
public partial DeliveryAncmt? SelectedDeliveryAncmt { get; set; }
private DeliveryAncmt? _selectedDeliveryAncmt;
[ObservableProperty]
public partial IEnumerable<DeliveryAncmt> DeliveryAncmts { get; set; } = [];
private IEnumerable<DeliveryAncmt> _deliveryAncmts = [];
[ObservableProperty]
public partial DeliverySchedule? SelectedDeliverySchedule { get; set; }
private DeliverySchedule? _selectedDeliverySchedule;
[ObservableProperty]
public partial IEnumerable<DeliverySchedule> DeliverySchedules { get; set; } = [];
private IEnumerable<DeliverySchedule> _deliverySchedules = [];
[ObservableProperty]
public partial bool EnableSearchInputs { get; set; } = true;
private bool _enableSearchInputs = true;
[ObservableProperty]
public partial string? MgNrString { get; set; }
private string? _mgNrString;
public int? MgNr {
get => int.TryParse(MgNrString, out var mgnr) ? mgnr : null;
set => MgNrString = $"{value}";
}
[ObservableProperty]
public partial Member? Member { get; set; }
private Member? _member;
[ObservableProperty]
public partial IEnumerable<Member> MemberSource { get; set; } = [];
private IEnumerable<Member> _memberSource = [];
[ObservableProperty]
public partial string? MemberAddress { get; set; }
private string? _memberAddress;
[ObservableProperty]
public partial DeliverySchedule? DeliverySchedule { get; set; }
private DeliverySchedule? _deliverySchedule;
[ObservableProperty]
public partial IEnumerable<DeliverySchedule> DeliveryScheduleSource { get; set; } = [];
private IEnumerable<DeliverySchedule> _deliveryScheduleSource = [];
[ObservableProperty]
public partial string? SortId { get; set; }
private string? _sortId;
[ObservableProperty]
public partial WineVar? WineVariety { get; set; }
private WineVar? _wineVariety;
[ObservableProperty]
public partial IEnumerable<WineVar> WineVarietySource { get; set; } = [];
private IEnumerable<WineVar> _wineVarietySource = [];
[ObservableProperty]
public partial string? WeightString { get; set; }
private string? _weightString;
public int? Weight {
get => int.TryParse(WeightString, out var w) ? w : null;
set => WeightString = $"{value}";
}
[ObservableProperty]
public partial string StatusAncmts { get; set; } = "-";
private string _statusAncmts = "-";
[ObservableProperty]
public partial string StatusWeight { get; set; } = "-";
private string _statusWeight = "-";
[ObservableProperty]
public partial string StatusAncmtCreated { get; set; } = "-";
private string _statusAncmtCreated = "-";
[ObservableProperty]
public partial string StatusAncmtModified { get; set; } = "-";
private string _statusAncmtModified = "-";
[ObservableProperty]
public partial Grid? StatusWeightToolTip { get; set; }
private Grid? _statusWeightToolTip;
[ObservableProperty]
public partial Visibility ControlButtonsVisibility { get; set; } = Visibility.Visible;
private Visibility _controlButtonsVisibility = Visibility.Visible;
[ObservableProperty]
public partial Visibility EditingButtonsVisibility { get; set; } = Visibility.Hidden;
private Visibility _editingButtonsVisibility = Visibility.Hidden;
}
}
@@ -10,76 +10,76 @@ namespace Elwig.ViewModels {
public partial class DeliveryScheduleAdminViewModel : ObservableObject {
[ObservableProperty]
public partial string? SearchQuery { get; set; } = "";
private string? _searchQuery = "";
public List<string> TextFilter => [.. SearchQuery?.ToLower().Split(' ').ToList().FindAll(e => e.Length > 0) ?? []];
[ObservableProperty]
public partial bool FilterOnlyUpcoming { get; set; }
private bool _filterOnlyUpcoming;
[ObservableProperty]
public partial string? FilterSeasonString { get; set; }
private string? _filterSeasonString;
public int? FilterSeason {
get => int.TryParse(FilterSeasonString, out var year) ? year : null;
set => FilterSeasonString = $"{value}";
}
[ObservableProperty]
public partial DeliverySchedule? SelectedDeliverySchedule { get; set; }
private DeliverySchedule? _selectedDeliverySchedule;
[ObservableProperty]
public partial IEnumerable<DeliverySchedule> DeliverySchedules { get; set; } = [];
private IEnumerable<DeliverySchedule> _deliverySchedules = [];
[ObservableProperty]
public partial bool EnableSearchInputs { get; set; } = true;
private bool _enableSearchInputs = true;
[ObservableProperty]
public partial string DateString { get; set; } = "";
private string _dateString = "";
public DateOnly? Date {
get => DateOnly.TryParseExact(DateString, "dd.MM.yyyy", out var d) ? d : null;
set => DateString = $"{value:dd.MM.yyyy}";
}
[ObservableProperty]
public partial Branch? Branch { get; set; }
private Branch? _branch;
[ObservableProperty]
public partial IEnumerable<Branch> BranchSource { get; set; } = [];
private IEnumerable<Branch> _branchSource = [];
[ObservableProperty]
public partial string Description { get; set; } = "";
private string _description = "";
[ObservableProperty]
public partial string? MaxWeightString { get; set; } = "";
private string? _maxWeightString = "";
public int? MaxWeight {
get => int.TryParse(MaxWeightString, out var w) ? w : null;
set => MaxWeightString = $"{value}";
}
[ObservableProperty]
public partial bool IsCancelled { get; set; }
private bool _isCancelled;
public ObservableCollection<WineVar> MainVarieties { get; set; } = [];
[ObservableProperty]
public partial IEnumerable<WineVar> MainVarietiesSource { get; set; } = [];
private IEnumerable<WineVar> _mainVarietiesSource = [];
public ObservableCollection<WineVar> OtherVarieties { get; set; } = [];
[ObservableProperty]
public partial IEnumerable<WineVar> OtherVarietiesSource { get; set; } = [];
private IEnumerable<WineVar> _otherVarietiesSource = [];
[ObservableProperty]
public partial IEnumerable<object> AttributeSource { get; set; } = [];
private IEnumerable<object> _attributeSource = [];
[ObservableProperty]
public partial object? AttributeObj { get; set; }
private object? _attributeObj;
public WineAttr? Attribute {
get => AttributeObj as WineAttr;
set => AttributeObj = value ?? AttributeSource.FirstOrDefault();
}
[ObservableProperty]
public partial IEnumerable<object> CultivationSource { get; set; } = [];
private IEnumerable<object> _cultivationSource = [];
[ObservableProperty]
public partial object? CultivationObj { get; set; }
private object? _cultivationObj;
public WineCult? Cultivation {
get => CultivationObj as WineCult;
set => CultivationObj = value ?? CultivationSource.FirstOrDefault();
}
[ObservableProperty]
public partial string AncmtFromDateString { get; set; } = "";
private string _ancmtFromDateString = "";
public DateOnly? AncmtFromDate {
get => DateOnly.TryParseExact(AncmtFromDateString, "dd.MM.yyyy", out var d) ? d : null;
set => AncmtFromDateString = $"{value:dd.MM.yyyy}";
}
[ObservableProperty]
public partial string AncmtFromTimeString { get; set; } = "";
private string _ancmtFromTimeString = "";
public TimeOnly? AncmtFromTime {
get => TimeOnly.TryParseExact(AncmtFromTimeString, "HH:mm", out var t) ? t : null;
set => AncmtFromTimeString = $"{value:HH:mm}";
@@ -92,13 +92,13 @@ namespace Elwig.ViewModels {
}
}
[ObservableProperty]
public partial string AncmtToDateString { get; set; } = "";
private string _ancmtToDateString = "";
public DateOnly? AncmtToDate {
get => DateOnly.TryParseExact(AncmtToDateString, "dd.MM.yyyy", out var d) ? d : null;
set => AncmtToDateString = $"{value:dd.MM.yyyy}";
}
[ObservableProperty]
public partial string AncmtToTimeString { get; set; } = "";
private string _ancmtToTimeString = "";
public TimeOnly? AncmtToTime {
get => TimeOnly.TryParseExact(AncmtToTimeString, "HH:mm", out var t) ? t : null;
set => AncmtToTimeString = $"{value:HH:mm}";
@@ -112,8 +112,8 @@ namespace Elwig.ViewModels {
}
[ObservableProperty]
public partial Visibility ControlButtonsVisibility { get; set; } = Visibility.Visible;
private Visibility _controlButtonsVisibility = Visibility.Visible;
[ObservableProperty]
public partial Visibility EditingButtonsVisibility { get; set; } = Visibility.Hidden;
private Visibility _editingButtonsVisibility = Visibility.Hidden;
}
}
+82 -100
View File
@@ -6,203 +6,185 @@ using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Documents;
namespace Elwig.ViewModels {
public partial class MemberAdminViewModel : ObservableObject {
[ObservableProperty]
public partial string Title { get; set; } = "Mitglieder - Elwig";
public int? TransferPredecessorAreaComs { get; set; } = null;
public int? CancelAreaComs { get; set; } = null;
public int? TransferPredecessorAreaComs = null;
public int? CancelAreaComs = null;
public ObservableCollection<KeyValuePair<string, string>> PhoneNrTypes { get; set; } = new(Utils.PhoneNrTypes);
[ObservableProperty]
public partial string? SearchQuery { get; set; } = "";
private string? _searchQuery = "";
public List<string> TextFilter => [.. SearchQuery?.ToLower().Split(' ').ToList().FindAll(e => e.Length > 0) ?? []];
[ObservableProperty]
public partial bool ShowOnlyActiveMembers { get; set; } = true;
private bool _showOnlyActiveMembers = true;
[ObservableProperty]
public partial Member? SelectedMember { get; set; }
private Member? _selectedMember;
[ObservableProperty]
public partial IEnumerable<Member> Members { get; set; } = [];
private IEnumerable<Member> _members = [];
[ObservableProperty]
public partial bool IsMemberSelected { get; set; }
private bool _isMemberSelected;
[ObservableProperty]
public partial bool IsMemberSelectedOrCreating { get; set; }
private bool _memberHasEmail;
[ObservableProperty]
public partial bool MemberHasEmail { get; set; }
private bool _memberCanSendEmail;
[ObservableProperty]
public partial bool MemberCanSendEmail { get; set; }
private bool _enableMemberReferenceButton;
[ObservableProperty]
public partial bool EnableMemberReferenceButton { get; set; }
private bool _enableSearchInputs = true;
[ObservableProperty]
public partial bool EnableSearchInputs { get; set; } = true;
[ObservableProperty]
public partial IEnumerable<bool> MemberHasDeliveries { get; set; } = [.. Enumerable.Range(0, 9999).Select(i => false)];
private IEnumerable<bool> _memberHasDeliveries = [.. Enumerable.Range(0, 9999).Select(i => false)];
[ObservableProperty]
public partial bool MemberListOrderByMgNr { get; set; }
private bool _memberListOrderByMgNr;
[ObservableProperty]
public partial bool MemberListOrderByName { get; set; }
private bool _memberListOrderByName;
[ObservableProperty]
public partial bool MemberListOrderByOrt { get; set; }
private bool _memberListOrderByOrt;
[ObservableProperty]
public partial string? MgNrString { get; set; }
private string? _mgNrString;
public int? MgNr {
get => int.TryParse(MgNrString, out var mgnr) ? mgnr : null;
set => MgNrString = $"{value}";
}
[ObservableProperty]
public partial string? PredecessorMgNrString { get; set; }
private string? _predecessorMgNrString;
public int? PredecessorMgNr {
get => int.TryParse(PredecessorMgNrString, out var mgnr) ? mgnr : null;
set => PredecessorMgNrString = $"{value}";
}
[ObservableProperty]
public partial bool IsJuridicalPerson { get; set; }
private bool _isJuridicalPerson;
[ObservableProperty]
public partial string? Prefix { get; set; }
private string? _prefix;
[ObservableProperty]
public partial string? GivenName { get; set; }
private string? _givenName;
[ObservableProperty]
public partial string? Name { get; set; }
private string? _name;
[ObservableProperty]
public partial string? Suffix { get; set; }
private string? _suffix;
[ObservableProperty]
public partial string? ForTheAttentionOf { get; set; }
private string? _forTheAttentionOf;
[ObservableProperty]
public partial string? Birthday { get; set; }
private string? _birthday;
[ObservableProperty]
public partial string? Age { get; set; }
private string? _age;
[ObservableProperty]
public partial bool IsDeceased { get; set; }
private bool _isDeceased;
[ObservableProperty]
public partial string? Address { get; set; }
private string? _address;
[ObservableProperty]
public partial string? PlzString { get; set; }
private string? _plzString;
public int? Plz {
get => int.TryParse(PlzString, out var plz) ? plz : null;
set => PlzString = $"{value}";
}
[ObservableProperty]
public partial AT_PlzDest? Ort { get; set; }
private AT_PlzDest? _ort;
[ObservableProperty]
public partial IEnumerable<AT_PlzDest> OrtSource { get; set; } = [];
private IEnumerable<AT_PlzDest> _ortSource = [];
[ObservableProperty]
public partial string? BillingName { get; set; }
private string? _billingName;
[ObservableProperty]
public partial string? BillingAddress { get; set; }
private string? _billingAddress;
[ObservableProperty]
public partial string? BillingPlzString { get; set; }
private string? _billingPlzString;
public int? BillingPlz {
get => int.TryParse(BillingPlzString, out var plz) ? plz : null;
set => BillingPlzString = $"{value}";
}
[ObservableProperty]
public partial AT_PlzDest? BillingOrt { get; set; }
private AT_PlzDest? _billingOrt;
[ObservableProperty]
public partial IEnumerable<AT_PlzDest> BillingOrtSource { get; set; } = [];
private IEnumerable<AT_PlzDest> _billingOrtSource = [];
[ObservableProperty]
public partial string? Iban { get; set; }
private string? _iban;
[ObservableProperty]
public partial string? Bic { get; set; }
private string? _bic;
[ObservableProperty]
public partial string? UstIdNr { get; set; }
private string? _ustIdNr;
[ObservableProperty]
public partial string? LfbisNr { get; set; }
private string? _lfbisNr;
[ObservableProperty]
public partial string? OrganicOperatorId { get; set; }
private bool _isBuchführend;
[ObservableProperty]
public partial string? OrganicAuthorityCode { get; set; }
[ObservableProperty]
public partial bool IsAccounting { get; set; }
[ObservableProperty]
public partial bool IsOrganic { get; set; }
private bool _isOrganic;
[ObservableProperty]
public partial string? OrganicState { get; set; }
private string? _entryDate;
[ObservableProperty]
public partial string? OrganicDetails { get; set; } = "-";
private string? _exitDate;
[ObservableProperty]
public partial Brush? OrganicColor { get; set; } = Brushes.Black;
[ObservableProperty]
public partial string? OrganicToolTip { get; set; }
[ObservableProperty]
public partial string? EntryDate { get; set; }
[ObservableProperty]
public partial string? ExitDate { get; set; }
[ObservableProperty]
public partial string? BusinessShares1String { get; set; }
private string? _businessShares1String;
public int? BusinessShares1 {
get => int.TryParse(BusinessShares1String, out var shares) ? shares : null;
set => BusinessShares1String = $"{value}";
}
[ObservableProperty]
public partial string? BusinessShares2String { get; set; }
private string? _businessShares2String;
public int? BusinessShares2 {
get => int.TryParse(BusinessShares2String, out var shares) ? shares : null;
set => BusinessShares2String = $"{value}";
}
[ObservableProperty]
public partial string? BusinessShares3String { get; set; }
private string? _businessShares3String;
public int? BusinessShares3 {
get => int.TryParse(BusinessShares3String, out var shares) ? shares : null;
set => BusinessShares3String = $"{value}";
}
[ObservableProperty]
public partial string? AccountingNr { get; set; }
private string? _accountingNr;
[ObservableProperty]
public partial bool IsActive { get; set; }
private bool _isActive;
[ObservableProperty]
public partial bool IsFullDelivery { get; set; }
private bool _isVollLieferant;
[ObservableProperty]
public partial bool IsOfficer { get; set; }
private bool _isFunktionär;
[ObservableProperty]
public partial Branch? Branch { get; set; }
private Branch? _branch;
[ObservableProperty]
public partial IEnumerable<Branch> BranchSource { get; set; } = [];
private IEnumerable<Branch> _branchSource = [];
[ObservableProperty]
public partial AT_Kg? DefaultKg { get; set; }
private AT_Kg? _defaultKg;
[ObservableProperty]
public partial IEnumerable<AT_Kg> DefaultKgSource { get; set; } = [];
private IEnumerable<AT_Kg> _defaultKgSource = [];
[ObservableProperty]
public partial string? Comment { get; set; }
private string? _comment;
[ObservableProperty]
public partial bool ContactViaPost { get; set; }
private bool _contactViaPost;
[ObservableProperty]
public partial bool ContactViaEmail { get; set; }
private bool _contactViaEmail;
[ObservableProperty]
public partial string CreatedAt { get; set; } = "-";
private string _createdAt = "-";
[ObservableProperty]
public partial string ModifiedAt { get; set; } = "-";
private string _modifiedAt = "-";
[ObservableProperty]
public partial string ModifiedAtShort { get; set; } = "-";
private string _modifiedAtShort = "-";
[ObservableProperty]
public partial string ExportedAt { get; set; } = "-";
private string _exportedAt = "-";
[ObservableProperty]
public partial string ImportedAt { get; set; } = "-";
private string _importedAt = "-";
public ObservableCollection<string?> EmailAddresses { get; private set; } = [null, null, null, null, null, null, null, null, null];
public partial class PhoneNr(int? type = null, string? number = null, string? comment = null) : ObservableObject {
[ObservableProperty]
public partial int Type { get; set; } = type ?? -1;
public int _type = type ?? -1;
[ObservableProperty]
public partial string? Number { get; set; } = number;
public string? _number = number;
[ObservableProperty]
public partial string? Comment { get; set; } = comment;
public string? _comment = comment;
public override bool Equals(object? obj) {
return obj is PhoneNr nr && Type == nr.Type && Number == nr.Number && Comment == nr.Comment;
@@ -215,37 +197,37 @@ namespace Elwig.ViewModels {
public ObservableCollection<PhoneNr> PhoneNrs { get; private set; } = [new(), new(), new(), new(), new(), new(), new(), new(), new()];
[ObservableProperty]
public partial string StatusMembers { get; set; } = "-";
private string _statusMembers = "-";
[ObservableProperty]
public partial string? StatusMembersToolTip { get; set; }
private string? _statusMembersToolTip;
[ObservableProperty]
public partial TextBlock? StatusBusinessShares { get; set; }
private TextBlock? _statusBusinessShares;
[ObservableProperty]
public partial string StatusDeliveriesLastSeason { get; set; } = "-";
private string _statusDeliveriesLastSeason = "-";
[ObservableProperty]
public partial string StatusDeliveriesLastSeasonInfo { get; set; } = "letzte Saison";
private string _statusDeliveriesLastSeasonInfo = "letzte Saison";
[ObservableProperty]
public partial Grid? StatusDeliveriesLastSeasonToolTip { get; set; }
private Grid? _statusDeliveriesLastSeasonToolTip;
[ObservableProperty]
public partial string StatusDeliveriesThisSeason { get; set; } = "-";
private string _statusDeliveriesThisSeason = "-";
[ObservableProperty]
public partial string StatusDeliveriesThisSeasonInfo { get; set; } = "aktuelle Saison";
private string _statusDeliveriesThisSeasonInfo = "aktuelle Saison";
[ObservableProperty]
public partial Grid? StatusDeliveriesThisSeasonToolTip { get; set; }
private Grid? _statusDeliveriesThisSeasonToolTip;
[ObservableProperty]
public partial string StatusAreaCommitment { get; set; } = "-";
private string _statusAreaCommitment = "-";
[ObservableProperty]
public partial Grid? StatusAreaCommitmentToolTip { get; set; }
private Grid? _statusAreaCommitmentToolTip;
[ObservableProperty]
public partial string StatusAreaCommitmentInfo { get; set; } = "aktuelle Saison";
private string _statusAreaCommitmentInfo = "aktuelle Saison";
[ObservableProperty]
public partial Visibility ControlButtonsVisibility { get; set; } = Visibility.Visible;
private Visibility _controlButtonsVisibility = Visibility.Visible;
[ObservableProperty]
public partial Visibility EditingButtonsVisibility { get; set; } = Visibility.Hidden;
private Visibility _editingButtonsVisibility = Visibility.Hidden;
[ObservableProperty]
public partial Visibility PersonalNameVisibility { get; set; } = Visibility.Visible;
private Visibility _personalNameVisibility = Visibility.Visible;
[ObservableProperty]
public partial Visibility JuridicalNameVisibility { get; set; } = Visibility.Hidden;
private Visibility _juridicalNameVisibility = Visibility.Hidden;
}
}
@@ -8,71 +8,69 @@ namespace Elwig.ViewModels {
public partial class MemberBusinessSharesViewModel : ObservableObject {
[ObservableProperty]
public partial string Title { get; set; } = "Geschäftsanteilbewegungen - Elwig";
private string _title = "Geschäftsanteilbewegungen - Elwig";
public required Member FilterMember { get; set; }
[ObservableProperty]
public partial MemberHistory? SelectedHistoryEntry { get; set; }
private MemberHistory? _selectedHistoryEntry;
[ObservableProperty]
public partial IEnumerable<MemberHistory> History { get; set; } = [];
private IEnumerable<MemberHistory> _history = [];
[ObservableProperty]
public partial string? DateNoticeString { get; set; }
private string? _dateNoticeString;
public DateOnly? DateNotice {
get => DateOnly.TryParseExact(DateNoticeString, "dd.MM.yyyy", out var d) ? d : null;
set => DateNoticeString = $"{value:dd.MM.yyyy}";
}
[ObservableProperty]
public partial string? DateEffectiveString { get; set; }
private string? _dateEffectiveString;
public DateOnly? DateEffective {
get => DateOnly.TryParseExact(DateEffectiveString, "dd.MM.yyyy", out var d) ? d : null;
set => DateEffectiveString = $"{value:dd.MM.yyyy}";
}
[ObservableProperty]
public partial string? Reason { get; set; }
private string? _reason;
[ObservableProperty]
public partial string? SharesString { get; set; }
private string? _sharesString;
public int? Shares {
get => int.TryParse(SharesString, out var shares) ? shares : null;
set => SharesString = $"{value}";
}
[ObservableProperty]
public partial string? OtherMgNrString { get; set; }
private string? _otherMgNrString;
public int? OtherMgNr {
get => int.TryParse(OtherMgNrString, out var mgnr) ? mgnr : null;
set => OtherMgNrString = $"{value}";
}
[ObservableProperty]
public partial string? DeductYearString { get; set; }
private string? _deductYearString;
public int? DeductYear {
get => int.TryParse(DeductYearString, out var year) ? year : null;
set => DeductYearString = $"{value}";
}
[ObservableProperty]
public partial bool Deduct { get; set; }
private bool _deduct;
[ObservableProperty]
public partial bool CompanyHasSigned { get; set; }
private bool _memberHasSigned;
[ObservableProperty]
public partial bool MemberHasSigned { get; set; }
[ObservableProperty]
public partial string? ValuePerShareString { get; set; }
private string? _valuePerShareString;
public decimal? ValuePerShare {
get => decimal.TryParse(ValuePerShareString, out var v) ? v : null;
set => ValuePerShareString = $"{value:0.00}";
}
[ObservableProperty]
public partial string? TotalAmount { get; set; }
private string? _totalAmount;
[ObservableProperty]
public partial string? Comment { get; set; }
private string? _comment;
[ObservableProperty]
public partial Visibility ControlButtonsVisibility { get; set; } = Visibility.Visible;
private Visibility _controlButtonsVisibility = Visibility.Visible;
[ObservableProperty]
public partial Visibility EditingButtonsVisibility { get; set; } = Visibility.Hidden;
private Visibility _editingButtonsVisibility = Visibility.Hidden;
[ObservableProperty]
public partial Visibility PersonalNameVisibility { get; set; } = Visibility.Visible;
private Visibility _personalNameVisibility = Visibility.Visible;
[ObservableProperty]
public partial Visibility JuridicalNameVisibility { get; set; } = Visibility.Hidden;
private Visibility _juridicalNameVisibility = Visibility.Hidden;
}
}
+35 -35
View File
@@ -9,87 +9,87 @@ namespace Elwig.ViewModels {
public partial class PaymentVariantsViewModel : ObservableObject {
[ObservableProperty]
public partial PaymentVar? SelectedPaymentVariant { get; set; }
private PaymentVar? _selectedPaymentVariant;
[ObservableProperty]
public partial IEnumerable<PaymentVar> PaymentVariants { get; set; } = [];
private IEnumerable<PaymentVar> _paymentVariants = [];
public BillingData? BillingData { get; set; }
public bool SeasonLocked { get; set; } = false; // never locked
public bool WeightModifierChanged { get; set; }
public BillingData? BillingData;
public bool SeasonLocked = false; // never locked
public bool WeightModifierChanged;
[ObservableProperty]
public partial string Name { get; set; } = "";
private string _name = "";
[ObservableProperty]
public partial string Comment { get; set; } = "";
private string _comment = "";
[ObservableProperty]
public partial string DateString { get; set; } = "";
private string _dateString = "";
public DateOnly? Date {
get => DateOnly.TryParseExact(DateString, "dd.MM.yyyy", out var d) ? d : null;
set => DateString = $"{value:dd.MM.yyyy}";
}
[ObservableProperty]
public partial string TransferDateString { get; set; } = "";
private string _transferDateString = "";
public DateOnly? TransferDate {
get => DateOnly.TryParseExact(TransferDateString, "dd.MM.yyyy", out var d) ? d : null;
set => TransferDateString = $"{value:dd.MM.yyyy}";
}
[ObservableProperty]
public partial string WeightModifierString { get; set; } = "";
private string _weightModifierString = "";
public double? WeightModifier {
get => double.TryParse(WeightModifierString, out var d) ? d : null;
set => WeightModifierString = $"{value}";
}
[ObservableProperty]
public partial string Data { get; set; } = "";
private string _data = "";
[ObservableProperty]
public partial bool ConsiderModifiers { get; set; }
private bool _considerModifiers;
[ObservableProperty]
public partial bool ConsiderPenalties { get; set; }
private bool _considerPenalties;
[ObservableProperty]
public partial bool ConsiderPenalty { get; set; }
private bool _considerPenalty;
[ObservableProperty]
public partial bool ConsiderAuto { get; set; }
private bool _considerAuto;
[ObservableProperty]
public partial bool ConsiderCustom { get; set; }
private bool _considerCustom;
[ObservableProperty]
public partial bool IsPaymentVariantSelected { get; set; }
private bool _isPaymentVariantSelected;
[ObservableProperty]
public partial bool IsReadOnly { get; set; } = true;
private bool _isReadOnly = true;
[ObservableProperty]
public partial bool DataIsReadOnly { get; set; } = true;
private bool _dataIsReadOnly = true;
[ObservableProperty]
public partial bool IsEnabled { get; set; } = false;
private bool _isEnabled = false;
[ObservableProperty]
public partial bool SaveIsEnabled { get; set; } = false;
private bool _saveIsEnabled = false;
[ObservableProperty]
public partial bool DeleteIsEnabled { get; set; } = false;
private bool _deleteIsEnabled = false;
[ObservableProperty]
public partial bool CalculateIsEnabled { get; set; } = false;
private bool _calculateIsEnabled = false;
[ObservableProperty]
public partial bool ExportIsEnabled { get; set; } = false;
private bool _exportIsEnabled = false;
[ObservableProperty]
public partial bool CommitIsEnabled { get; set; } = false;
private bool _commitIsEnabled = false;
[ObservableProperty]
public partial Visibility CommitVisibility { get; set; } = Visibility.Visible;
private Visibility _commitVisibility = Visibility.Visible;
[ObservableProperty]
public partial bool RevertIsEnabled { get; set; } = false;
private bool _revertIsEnabled = false;
[ObservableProperty]
public partial Visibility RevertVisibility { get; set; } = Visibility.Hidden;
private Visibility _revertVisibility = Visibility.Hidden;
[ObservableProperty]
public partial string Arrow { get; set; } = "\xF0AF";
private string _arrow = "\xF0AF";
[ObservableProperty]
public partial string EditText { get; set; } = "Bearbeiten";
private string _editText = "Bearbeiten";
[ObservableProperty]
public partial string StatusModifierSum { get; set; } = "-";
private string _statusModifierSum = "-";
[ObservableProperty]
public partial string StatusTotalSum { get; set; } = "-";
private string _statusTotalSum = "-";
[ObservableProperty]
public partial string StatusVatSum { get; set; } = "-";
private string _statusVatSum = "-";
[ObservableProperty]
public partial string StatusDeductionSum { get; set; } = "-";
private string _statusDeductionSum = "-";
[ObservableProperty]
public partial string StatusPaymentSum { get; set; } = "-";
private string _statusPaymentSum = "-";
}
}
+2 -26
View File
@@ -108,20 +108,12 @@ namespace Elwig.Windows {
LockInputs();
}
public void TryClose() {
var evt = new CancelEventArgs();
OnClosing(this, evt);
if (!evt.Cancel) Close();
}
private void OnClosing(object? sender, CancelEventArgs evt) {
if (!IsClosing && (IsCreating || IsEditing) && HasChanged) {
try {
if ((IsCreating || IsEditing) && HasChanged) {
if (!InteractionService.AskConfirmation("Schließen bestätigen", "Soll das Fenster wirklich geschlossen werden?")) {
evt.Cancel = true;
return;
}
} catch { }
}
IsClosing = true;
}
@@ -442,7 +434,7 @@ namespace Elwig.Windows {
UpdateButtons();
}
protected void TextBox_TextChanged(object sender, TextChangedEventArgs? evt) {
protected void TextBox_TextChanged(object sender, RoutedEventArgs? evt) {
var input = (Control)sender;
var tb = input as TextBox;
if (SenderIsRequired(input) && tb?.Text.Length == 0) {
@@ -584,14 +576,6 @@ namespace Elwig.Windows {
InputLostFocus((TextBox)sender, Validator.CheckLfbisNr);
}
protected void OrganicOperatorIdInput_TextChanged(object sender, TextChangedEventArgs? evt) {
InputTextChanged((TextBox)sender, Validator.CheckOrganicOperatorId);
}
protected void OrganicOperatorIdInput_LostFocus(object sender, RoutedEventArgs? evt) {
InputLostFocus((TextBox)sender, Validator.CheckOrganicOperatorId);
}
protected void OrganicAuthorityCodeInput_TextChanged(object sender, TextChangedEventArgs? evt) {
InputTextChanged((TextBox)sender, Validator.CheckOrganicAuthorityCode);
}
@@ -611,13 +595,5 @@ namespace Elwig.Windows {
protected void AreaComTypeDetailsButton_Click(object sender, RoutedEventArgs? evt) {
App.FocusBaseDataAreaComType();
}
protected void AddressInput_TextChanged(object sender, TextChangedEventArgs? evt) {
if ((IsCreating || IsEditing) && sender is TextBox b) {
InputTextChanged(b, (i, r) => Validator.CheckAddress(i, r));
} else {
TextBox_TextChanged(sender, evt);
}
}
}
}
+5 -4
View File
@@ -23,6 +23,7 @@ namespace Elwig.Windows {
CommandBindings.Add(new CommandBinding(CtrlF, FocusSearchInput));
using var ctx = new AppDbContext();
ViewModel.FilterMember = ctx.Members.Find(mgnr) ?? throw new ArgumentException("MgNr argument has invalid value");
ViewModel.Title = $"Flächenbindungen - {ViewModel.FilterMember.AdministrativeName} - Elwig";
ExemptInputs = [
AreaCommitmentList, RevisionList,
NewAreaCommitmentButton, EditAreaCommitmentButton, DeleteAreaCommitmentButton, SaveButton,
@@ -50,9 +51,9 @@ namespace Elwig.Windows {
var cursor = Mouse.OverrideCursor != null;
if (!cursor) Mouse.OverrideCursor = Cursors.Wait;
var query = (vm.SearchQuery, vm.FilterSeason);
var (filterNames, filter, contracts, areaComs, areaComCount, stat) = await Task.Run(async () => {
var (filter, contracts, areaComs, areaComCount, stat) = await Task.Run(async () => {
using var ctx = new AppDbContext();
var (filterNames, contractQuery, areaComQuery, filter) = await vm.GetFilters(ctx);
var (_, contractQuery, areaComQuery, filter) = await vm.GetFilters(ctx);
var contracts = await contractQuery
.Include(c => c.Revisions).ThenInclude(a => a.Member)
.ToListAsync();
@@ -72,12 +73,11 @@ namespace Elwig.Windows {
var season = await ctx.FetchSeasons().FirstOrDefaultAsync();
var stat = await AreaComService.GenerateToolTipData(areaComQuery, season?.MaxKgPerHa ?? 10_000);
return (filterNames, filter, contracts, areaComs, areaComCount, stat);
return (filter, contracts, areaComs, areaComCount, stat);
});
if (!cursor) Mouse.OverrideCursor = null;
if (query != (ViewModel.SearchQuery, ViewModel.FilterSeason)) return;
ViewModel.Title = Utils.GetTitle("Flächenbindungen", filterNames, filter);
ControlUtils.RenewItemsSource(AreaCommitmentList, contracts,
AreaCommitmentList_SelectionChanged, ViewModel.TextFilter.Count > 0 ? ControlUtils.RenewSourceDefault.IfOnly : ControlUtils.RenewSourceDefault.None, !updateSort);
RefreshInputs();
@@ -164,6 +164,7 @@ namespace Elwig.Windows {
return;
}
ViewModel.FilterMember = m;
ViewModel.Title = $"Flächenbindungen - {ViewModel.FilterMember.AdministrativeName} - Elwig";
ControlUtils.RenewItemsSource(KgInput, await ctx.WbKgs
.Include(k => k.AtKg.WbKg!.Rds)
+13 -23
View File
@@ -90,7 +90,7 @@
<Label Content="Adresse:"
VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="0" Margin="10,160,0,10"/>
<TextBox x:Name="ClientAddressInput"
TextChanged="AddressInput_TextChanged"
TextChanged="TextBox_TextChanged"
VerticalAlignment="Top" HorizontalAlignment="Stretch" Grid.Column="1" Margin="0,160,10,10"/>
<Label Content="PLZ/Ort:"
@@ -109,29 +109,23 @@
<TextBox x:Name="ClientBicInput" Margin="0,250,10,0" Grid.Column="1"
TextChanged="BicInput_TextChanged" LostFocus="BicInput_LostFocus"/>
<Label Content="Betriebs-Nr.:"
VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="2" Margin="10,100,0,10"/>
<TextBox x:Name="ClientLfbisNrInput"
VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="3" Margin="0,100,10,10" Width="64"
TextChanged="LfbisNrInput_TextChanged" LostFocus="LfbisNrInput_LostFocus"/>
<Label Content="UID:"
VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="2" Margin="10,130,0,10"/>
VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="2" Margin="10,100,0,10"/>
<TextBox x:Name="ClientUstIdNrInput"
VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="3" Margin="0,130,10,10" Width="96"
VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="3" Margin="0,100,10,10" Width="96"
TextChanged="UstIdNrInput_TextChanged" LostFocus="UstIdNrInput_LostFocus"/>
<Label Content="Bio-KSt.:" ToolTip="Bio-Konstrollstelle"
VerticalAlignment="Top" HorizontalAlignment="Right" Grid.Column="3" Margin="10,100,110,10"/>
<TextBox x:Name="ClientOrganicAuthorityCodeInput"
VerticalAlignment="Top" HorizontalAlignment="Right" Grid.Column="3" Margin="10,100,10,10" Width="91"
TextChanged="OrganicAuthorityCodeInput_TextChanged" LostFocus="OrganicAuthorityCodeInput_LostFocus"/>
<Label Content="Betriebs-Nr.:"
VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="2" Margin="10,130,0,10"/>
<TextBox x:Name="ClientLfbisNrInput"
VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="3" Margin="0,130,10,10" Width="64"
TextChanged="LfbisNrInput_TextChanged" LostFocus="LfbisNrInput_LostFocus"/>
<Label Content="OOC-ID:" ToolTip="Bio-EU-Operator-ID / Organic Operator Certificate ID"
<Label Content="Bio-Kontrollstelle:"
VerticalAlignment="Top" HorizontalAlignment="Right" Grid.Column="3" Margin="10,130,110,10"/>
<TextBox x:Name="ClientOrganicOperatorIdInput"
VerticalAlignment="Top" HorizontalAlignment="Right" Grid.Column="3" Margin="10,130,10,10" Width="91"
TextChanged="OrganicOperatorIdInput_TextChanged" LostFocus="OrganicOperatorIdInput_LostFocus"/>
<TextBox x:Name="ClientOrganicAuthorityInput"
VerticalAlignment="Top" HorizontalAlignment="Right" Grid.Column="3" Margin="10,130,10,10" Width="90"
TextChanged="OrganicAuthorityCodeInput_TextChanged" LostFocus="OrganicAuthorityCodeInput_LostFocus"/>
<Label Content="Telefon-Nr.:"
VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="2" Margin="10,160,0,10"/>
@@ -326,10 +320,6 @@
<Label Content="Beschreibung:" Margin="10,70,0,10"/>
<TextBox x:Name="WineCultivationDescriptionInput" Grid.Column="1" Margin="0,70,10,10"
TextChanged="WineCultivation_Changed"/>
<CheckBox x:Name="WineCultivationOrganicInput" Content="Bio" Grid.Column="1" Margin="0,105,10,10"
Checked="WineCultivation_Changed" Unchecked="WineCultivation_Changed"
HorizontalAlignment="Left" VerticalAlignment="Top"/>
</Grid>
</Grid>
</TabItem>
@@ -574,7 +564,7 @@
<CheckBox x:Name="ParameterAvoidUnderDeliveriesInput" Content="Unterlieferungen durch Abzug bei &quot;besseren&quot; Flächenbindungen vermeiden"
VerticalAlignment="Top" HorizontalAlignment="Left" Margin="10,30,10,10"
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"/>
<CheckBox x:Name="ParameterHonorContractedInput" Margin="10,50,10,10" VerticalAlignment="Top"
<CheckBox x:Name="ParameterHonorGebundenInput" Margin="10,50,10,10" VerticalAlignment="Top"
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed">
<TextBlock>Bei Lieferungen das Feld <Italic>Gebunden</Italic> berücksichtigen</TextBlock>
</CheckBox>
@@ -72,12 +72,10 @@ namespace Elwig.Windows {
WineCultivationIdInput.Text = "";
WineCultivationNameInput.Text = "";
WineCultivationDescriptionInput.Text = "";
WineCultivationOrganicInput.IsChecked = false;
} else {
WineCultivationIdInput.Text = cult.CultId;
WineCultivationNameInput.Text = cult.Name;
WineCultivationDescriptionInput.Text = cult.Description;
WineCultivationOrganicInput.IsChecked = cult.IsOrganic;
}
_cultUpdate = false;
}
@@ -107,8 +105,7 @@ namespace Elwig.Windows {
_cultChanged = _cultChanged ||
WineCultivationIdInput.Text != cult.CultId ||
WineCultivationNameInput.Text != cult.Name ||
WineCultivationDescriptionInput.Text != (cult.Description ?? "") ||
WineCultivationOrganicInput.IsChecked != cult.IsOrganic;
WineCultivationDescriptionInput.Text != (cult.Description ?? "");
var old = _cultIds.GetValueOrDefault(cult);
var id = WineCultivationIdInput.Text ?? "";
@@ -116,8 +113,7 @@ namespace Elwig.Windows {
cult.CultId = id;
cult.Name = WineCultivationNameInput.Text ?? "";
cult.Description = WineCultivationDescriptionInput.Text ?? "";
cult.IsOrganic = WineCultivationOrganicInput.IsChecked ?? false;
if (string.IsNullOrWhiteSpace(cult.Description)) cult.Description = null;
if (cult.Description.Length == 0) cult.Description = null;
CollectionViewSource.GetDefaultView(_cultList).Refresh();
UpdateButtons();
+5 -9
View File
@@ -25,7 +25,7 @@ namespace Elwig.Windows {
BranchAddressInput, BranchPhoneNrInput, BranchFaxNrInput, BranchMobileNrInput,
WineAttributeIdInput, WineAttributeNameInput, WineAttributeActiveInput,
WineAttributeMaxKgPerHaInput, WineAttributeStrictInput, WineAttributeFillLowerInput,
WineCultivationIdInput, WineCultivationNameInput, WineCultivationDescriptionInput, WineCultivationOrganicInput,
WineCultivationIdInput, WineCultivationNameInput, WineCultivationDescriptionInput,
AreaCommitmentTypeIdInput, AreaCommitmentTypeWineVariantInput, AreaCommitmentTypeWineAttributeInput,
AreaCommitmentTypeMinKgPerHaInput, AreaCommitmentTypePenaltyPerKgInput,
AreaCommitmentTypePenaltyInput, AreaCommitmentTypePenaltyNoneInput,
@@ -67,7 +67,6 @@ namespace Elwig.Windows {
WineCultivationIdInput.IsReadOnly = true;
WineCultivationNameInput.IsReadOnly = true;
WineCultivationDescriptionInput.IsReadOnly = true;
WineCultivationOrganicInput.IsEnabled = false;
AreaCommitmentTypeWineVariantInput.IsEnabled = false;
AreaCommitmentTypeWineAttributeInput.IsEnabled = false;
@@ -116,7 +115,6 @@ namespace Elwig.Windows {
WineCultivationIdInput.IsReadOnly = false;
WineCultivationNameInput.IsReadOnly = false;
WineCultivationDescriptionInput.IsReadOnly = false;
WineCultivationOrganicInput.IsEnabled = true;
AreaCommitmentTypeWineVariantInput.IsEnabled = true;
AreaCommitmentTypeWineAttributeInput.IsEnabled = true;
@@ -331,8 +329,7 @@ namespace Elwig.Windows {
ClientBicInput.Text = p.Bic;
ClientUstIdNrInput.Text = p.UstIdNr;
ClientLfbisNrInput.Text = p.LfbisNr;
ClientOrganicOperatorIdInput.Text = p.OrganicOperatorId;
ClientOrganicAuthorityCodeInput.Text = p.OrganicAuthorityCode;
ClientOrganicAuthorityInput.Text = p.OrganicAuthority;
ClientPhoneNrInput.Text = p.PhoneNr;
ClientFaxNrInput.Text = p.FaxNr;
ClientEmailAddressInput.Text = p.EmailAddress;
@@ -352,7 +349,7 @@ namespace Elwig.Windows {
ParameterBusinessShareHistoryInput.IsChecked = p.EnableMemberHistory;
ParameterAllowAttrIntoLowerInput.IsChecked = s?.Billing_AllowAttrsIntoLower ?? false;
ParameterAvoidUnderDeliveriesInput.IsChecked = s?.Billing_AvoidUnderDeliveries ?? false;
ParameterHonorContractedInput.IsChecked = s?.Billing_HonorContracted ?? false;
ParameterHonorGebundenInput.IsChecked = s?.Billing_HonorGebunden ?? false;
ParameterExportEbicsVersion.SelectedIndex = p.ExportEbicsVersion - 3;
ParameterExportEbicsAddress.SelectedIndex = p.ExportEbicsAddress;
@@ -372,8 +369,7 @@ namespace Elwig.Windows {
p.Bic = string.IsNullOrWhiteSpace(ClientBicInput.Text) ? null : ClientBicInput.Text;
p.UstIdNr = string.IsNullOrWhiteSpace(ClientUstIdNrInput.Text) ? null : ClientUstIdNrInput.Text;
p.LfbisNr = string.IsNullOrWhiteSpace(ClientLfbisNrInput.Text) ? null : ClientLfbisNrInput.Text;
p.OrganicOperatorId = string.IsNullOrWhiteSpace(ClientOrganicOperatorIdInput.Text) ? null : ClientOrganicOperatorIdInput.Text;
p.OrganicAuthorityCode = string.IsNullOrWhiteSpace(ClientOrganicAuthorityCodeInput.Text) ? null : ClientOrganicAuthorityCodeInput.Text;
p.OrganicAuthority = string.IsNullOrWhiteSpace(ClientOrganicAuthorityInput.Text) ? null : ClientOrganicAuthorityInput.Text;
p.PhoneNr = string.IsNullOrWhiteSpace(ClientPhoneNrInput.Text) ? null : ClientPhoneNrInput.Text;
p.FaxNr = string.IsNullOrWhiteSpace(ClientFaxNrInput.Text) ? null : ClientFaxNrInput.Text;
p.EmailAddress = string.IsNullOrWhiteSpace(ClientEmailAddressInput.Text) ? null : ClientEmailAddressInput.Text;
@@ -406,7 +402,7 @@ namespace Elwig.Windows {
s.Billing_AllowAttrsIntoLower = ParameterAllowAttrIntoLowerInput.IsChecked ?? false;
s.Billing_AvoidUnderDeliveries = ParameterAvoidUnderDeliveriesInput.IsChecked ?? false;
s.Billing_HonorContracted = ParameterHonorContractedInput.IsChecked ?? false;
s.Billing_HonorGebunden = ParameterHonorGebundenInput.IsChecked ?? false;
ctx.Update(s);
await ctx.SaveChangesAsync();
} catch { }
+7 -7
View File
@@ -138,9 +138,9 @@
<Label Content="Oechsle:" Margin="10,10,0,0" Grid.Column="0"/>
<ctrl:UnitTextBox x:Name="OechsleInput" Unit="°Oe" TextChanged="OechsleInput_TextChanged" IsEnabled="False"
Grid.Column="1" Width="52" Margin="0,10,0,0" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<CheckBox x:Name="ContractedInput" Content="Geb." IsEnabled="False"
<CheckBox x:Name="GebInput" Content="Geb." IsEnabled="False"
Grid.Column="1" Margin="0,15,10,0" HorizontalAlignment="Right" VerticalAlignment="Top"
Checked="ContractedInput_Changed" Unchecked="ContractedInput_Changed"/>
Checked="GebInput_Changed" Unchecked="GebInput_Changed"/>
<Label Content="Preis:" Margin="10,40,0,0" Grid.Column="0"/>
<ctrl:UnitTextBox x:Name="PriceInput" Unit="€/kg" TextChanged="PriceInput_TextChanged" IsEnabled="False"
@@ -148,16 +148,16 @@
</Grid>
</GroupBox>
<GroupBox Header="Gebunden-Aufschlag" Grid.Row="1" Margin="0,5,5,5">
<GroupBox Header="Gebunden Aufschlag" Grid.Row="1" Margin="0,5,5,5">
<Grid>
<StackPanel Margin="10,10,0,0">
<RadioButton x:Name="ContractedTypeFixed" GroupName="ContractedType" Checked="ContractedType_Checked" IsEnabled="False">Fix</RadioButton>
<RadioButton x:Name="ContractedTypeGraph" GroupName="ContractedType" Checked="ContractedType_Checked" IsEnabled="False">Frei</RadioButton>
<RadioButton x:Name="ContractedTypeNone" GroupName="ContractedType" Checked="ContractedType_Checked" IsEnabled="False">Nein</RadioButton>
<RadioButton x:Name="GebundenTypeFixed" GroupName="GebundenType" Checked="GebundenType_Checked" IsEnabled="False">Fix</RadioButton>
<RadioButton x:Name="GebundenTypeGraph" GroupName="GebundenType" Checked="GebundenType_Checked" IsEnabled="False">Frei</RadioButton>
<RadioButton x:Name="GebundenTypeNone" GroupName="GebundenType" Checked="GebundenType_Checked" IsEnabled="False">Nein</RadioButton>
</StackPanel>
<ctrl:UnitTextBox x:Name="ContractedFlatBonus" Unit="€/kg" TextChanged="ContractedFlatBonus_TextChanged" IsEnabled="False"
<ctrl:UnitTextBox x:Name="GebundenFlatBonus" Unit="€/kg" TextChanged="GebundenFlatBonus_TextChanged" IsEnabled="False"
Width="90" Margin="5,5,5,5" HorizontalAlignment="Right" VerticalAlignment="Top" Grid.Column="1"/>
</Grid>
</GroupBox>
+91 -91
View File
@@ -15,8 +15,8 @@ using Elwig.Services;
namespace Elwig.Windows {
public partial class ChartWindow : ContextWindow {
public static readonly Color ColorUnContracted = Colors.Blue;
public static readonly Color ColorContracted = Colors.Gold;
public static readonly Color ColorUngebunden = Colors.Blue;
public static readonly Color ColorGebunden = Colors.Gold;
public readonly int Year;
public readonly int AvNr;
@@ -27,20 +27,20 @@ namespace Elwig.Windows {
private bool Updating = false;
private Scatter? DataPlot;
private Scatter? ContractedPlot;
private Scatter? GebundenPlot;
private Marker? HighlightedPointPlot;
private Marker? PrimaryMarkedPointPlot;
private Marker? SecondaryMarkedPointPlot;
private Text? TooltipPlot;
private static readonly LegendItem
UnContractedLegend = new() {
LabelText = "UnContracted", LineWidth = 1, LineColor = ColorUnContracted,
MarkerStyle = new(MarkerShape.FilledCircle, 5, ColorUnContracted)
UngebundenLegend = new() {
LabelText = "Ungebunden", LineWidth = 1, LineColor = ColorUngebunden,
MarkerStyle = new(MarkerShape.FilledCircle, 5, ColorUngebunden)
},
ContractedLegend = new() {
LabelText = "Contracted", LineWidth = 1, LineColor = ColorContracted,
MarkerStyle = new(MarkerShape.FilledCircle, 5, ColorContracted)
GebundenLegend = new() {
LabelText = "Gebunden", LineWidth = 1, LineColor = ColorGebunden,
MarkerStyle = new(MarkerShape.FilledCircle, 5, ColorGebunden)
},
LdwLegend = new() {
LabelText = "68 °Oe (LDW)", LineWidth = 2, LineColor = Colors.Red, MarkerStyle = MarkerStyle.None
@@ -75,7 +75,7 @@ namespace Elwig.Windows {
Season = ctx.Seasons.Find(year) ?? throw new ArgumentException("Season not found");
CurrencySymbol = Season.Currency.Symbol ?? Season.Currency.Code;
PriceInput.Unit = $"{CurrencySymbol}/kg";
ContractedFlatBonus.Unit = $"{CurrencySymbol}/kg";
GebundenFlatBonus.Unit = $"{CurrencySymbol}/kg";
PaymentVar = ctx.PaymentVariants.Find(year, avnr) ?? throw new ArgumentException("PaymentVar not found");
Title = $"{PaymentVar.Name} - Lese {year} - Elwig";
LockContext = true;
@@ -100,7 +100,7 @@ namespace Elwig.Windows {
Season = await ctx.FetchSeasons(Year).SingleOrDefaultAsync() ?? throw new ArgumentException("Season not found");
CurrencySymbol = Season.Currency.Symbol ?? Season.Currency.Code;
PriceInput.Unit = $"{CurrencySymbol}/kg";
ContractedFlatBonus.Unit = $"{CurrencySymbol}/kg";
GebundenFlatBonus.Unit = $"{CurrencySymbol}/kg";
try {
var data = EditBillingData.FromJson(PaymentVar.Data, await Utils.GetVaributes(ctx, Year));
@@ -148,10 +148,10 @@ namespace Elwig.Windows {
CopyButton.IsEnabled = true;
DeleteButton.IsEnabled = true;
EnableTextBox(OechsleInput);
ContractedInput.IsEnabled = SelectedGraphEntry?.ContractedGraph != null;
ContractedTypeFixed.IsEnabled = true;
ContractedTypeGraph.IsEnabled = true;
ContractedTypeNone.IsEnabled = true;
GebInput.IsEnabled = SelectedGraphEntry?.GebundenGraph != null;
GebundenTypeFixed.IsEnabled = true;
GebundenTypeGraph.IsEnabled = true;
GebundenTypeNone.IsEnabled = true;
VaributeInput.IsEnabled = true;
AbgewertetInput.IsEnabled = true;
EnableOptionButtons();
@@ -160,7 +160,7 @@ namespace Elwig.Windows {
CopyButton.IsEnabled = false;
DeleteButton.IsEnabled = false;
DisableTextBox(OechsleInput);
ContractedInput.IsEnabled = false;
GebInput.IsEnabled = false;
DisableOptionButtons();
}
if (!PaymentVar.TestVariant) {
@@ -168,9 +168,9 @@ namespace Elwig.Windows {
CopyButton.IsEnabled = false;
DeleteButton.IsEnabled = false;
DisableTextBox(PriceInput);
ContractedTypeFixed.IsEnabled = false;
ContractedTypeGraph.IsEnabled = false;
ContractedTypeNone.IsEnabled = false;
GebundenTypeFixed.IsEnabled = false;
GebundenTypeGraph.IsEnabled = false;
GebundenTypeNone.IsEnabled = false;
VaributeInput.IsEnabled = false;
AbgewertetInput.IsEnabled = false;
}
@@ -181,15 +181,15 @@ namespace Elwig.Windows {
FillingInputs = true;
AbgewertetInput.IsChecked = SelectedGraphEntry?.Abgewertet;
if (SelectedGraphEntry?.ContractedFlatBonus is double bonus) {
ContractedTypeFixed.IsChecked = true;
ContractedFlatBonus.Text = $"{bonus}";
} else if (SelectedGraphEntry?.ContractedGraph != null) {
ContractedTypeGraph.IsChecked = true;
ContractedFlatBonus.Text = "";
if (SelectedGraphEntry?.GebundenFlatBonus is double bonus) {
GebundenTypeFixed.IsChecked = true;
GebundenFlatBonus.Text = $"{bonus}";
} else if (SelectedGraphEntry?.GebundenGraph != null) {
GebundenTypeGraph.IsChecked = true;
GebundenFlatBonus.Text = "";
} else {
ContractedTypeNone.IsChecked = true;
ContractedFlatBonus.Text = "";
GebundenTypeNone.IsChecked = true;
GebundenFlatBonus.Text = "";
}
ControlUtils.SelectItems(VaributeInput, SelectedGraphEntry?.Vaributes ?? []);
@@ -208,21 +208,21 @@ namespace Elwig.Windows {
private void InitPlot() {
RefreshGradationLines();
if (SelectedGraphEntry?.ContractedGraph != null) {
ContractedPlot = OechslePricePlot.Plot.Add.Scatter(SelectedGraphEntry.ContractedGraph.DataX, SelectedGraphEntry.ContractedGraph.DataY);
ContractedPlot.LineStyle.Color = ColorContracted;
ContractedPlot.Color = ColorContracted;
ContractedPlot.MarkerStyle = new MarkerStyle(MarkerShape.FilledCircle, 9, ColorContracted);
if (SelectedGraphEntry?.GebundenGraph != null) {
GebundenPlot = OechslePricePlot.Plot.Add.Scatter(SelectedGraphEntry.GebundenGraph.DataX, SelectedGraphEntry.GebundenGraph.DataY);
GebundenPlot.LineStyle.Color = ColorGebunden;
GebundenPlot.Color = ColorGebunden;
GebundenPlot.MarkerStyle = new MarkerStyle(MarkerShape.FilledCircle, 9, ColorGebunden);
}
if (SelectedGraphEntry != null) {
DataPlot = OechslePricePlot.Plot.Add.Scatter(SelectedGraphEntry.DataGraph.DataX, SelectedGraphEntry.DataGraph.DataY);
DataPlot.LineStyle.Color = ColorUnContracted;
DataPlot.Color = ColorUnContracted;
DataPlot.MarkerStyle = new MarkerStyle(MarkerShape.FilledCircle, 9, ColorUnContracted);
DataPlot.LineStyle.Color = ColorUngebunden;
DataPlot.Color = ColorUngebunden;
DataPlot.MarkerStyle = new MarkerStyle(MarkerShape.FilledCircle, 9, ColorUngebunden);
}
OechslePricePlot.Plot.Axes.SetLimits(Math.Min(GraphEntry.MinX, GraphEntry.MinXCtrd) - 1, GraphEntry.MaxX + 1, -0.1, 1.5);
OechslePricePlot.Plot.Axes.SetLimits(Math.Min(GraphEntry.MinX, GraphEntry.MinXGeb) - 1, GraphEntry.MaxX + 1, -0.1, 1.5);
HighlightedPointPlot = OechslePricePlot.Plot.Add.Marker(0, 0, MarkerShape.OpenCircle, 10, Colors.Red);
HighlightedPointPlot.IsVisible = false;
@@ -250,9 +250,9 @@ namespace Elwig.Windows {
OechslePricePlot.Plot.Remove(DataPlot);
DataPlot = null;
}
if (ContractedPlot != null) {
OechslePricePlot.Plot.Remove(ContractedPlot);
ContractedPlot = null;
if (GebundenPlot != null) {
OechslePricePlot.Plot.Remove(GebundenPlot);
GebundenPlot = null;
}
OechslePricePlot.Plot.Clear();
OechslePricePlot.Reset();
@@ -365,8 +365,8 @@ namespace Elwig.Windows {
OechslePricePlot.Plot.Legend.ManualItems.Add(LdwLegend);
OechslePricePlot.Plot.Legend.ManualItems.Add(QuwLegend);
OechslePricePlot.Plot.Legend.ManualItems.Add(KabLegend);
OechslePricePlot.Plot.Legend.ManualItems.Add(UnContractedLegend);
if (SelectedGraphEntry?.ContractedGraph != null) OechslePricePlot.Plot.Legend.ManualItems.Add(ContractedLegend);
OechslePricePlot.Plot.Legend.ManualItems.Add(UngebundenLegend);
if (SelectedGraphEntry?.GebundenGraph != null) OechslePricePlot.Plot.Legend.ManualItems.Add(GebundenLegend);
}
private void HideLegend() {
@@ -408,10 +408,10 @@ namespace Elwig.Windows {
UpdateSelectedPoint();
}
private void ContractedInput_Changed(object sender, RoutedEventArgs evt) {
private void GebInput_Changed(object sender, RoutedEventArgs evt) {
if (Updating)
return;
var sel = ContractedInput.IsChecked == true ? SelectedGraphEntry?.ContractedGraph : SelectedGraphEntry?.DataGraph;
var sel = GebInput.IsChecked == true ? SelectedGraphEntry?.GebundenGraph : SelectedGraphEntry?.DataGraph;
if (sel != ActiveGraph) ChangeActiveGraph(sel);
UpdateSelectedPoint();
}
@@ -424,7 +424,7 @@ namespace Elwig.Windows {
PrimaryMarkedPointPlot?.Location = new Coordinates(PrimaryMarkedPointPlot.Location.X, price);
SetHasChanged();
OechslePricePlot.Refresh();
CheckContractedTypeFixed();
CheckGebundenTypeFixed();
}
}
}
@@ -436,7 +436,7 @@ namespace Elwig.Windows {
ActiveGraph.FlattenGraphLeft(PrimaryMarkedPoint);
SetHasChanged();
OechslePricePlot.Refresh();
CheckContractedTypeFixed();
CheckGebundenTypeFixed();
}
private void RightFlatButton_Click(object sender, RoutedEventArgs evt) {
@@ -446,7 +446,7 @@ namespace Elwig.Windows {
ActiveGraph.FlattenGraphRight(PrimaryMarkedPoint);
SetHasChanged();
OechslePricePlot.Refresh();
CheckContractedTypeFixed();
CheckGebundenTypeFixed();
}
private void InterpolateButton_Click(object sender, RoutedEventArgs evt) {
@@ -456,7 +456,7 @@ namespace Elwig.Windows {
ActiveGraph.InterpolateGraph(PrimaryMarkedPoint, SecondaryMarkedPoint);
SetHasChanged();
OechslePricePlot.Refresh();
CheckContractedTypeFixed();
CheckGebundenTypeFixed();
}
private void LinearIncreaseButton_Click(object sender, RoutedEventArgs e) {
@@ -470,7 +470,7 @@ namespace Elwig.Windows {
ActiveGraph.LinearIncreaseGraphToEnd(PrimaryMarkedPoint, priceIncrease.Value);
SetHasChanged();
OechslePricePlot.Refresh();
CheckContractedTypeFixed();
CheckGebundenTypeFixed();
}
private void OechslePricePlot_MouseDown(object sender, MouseEventArgs e) {
@@ -500,7 +500,7 @@ namespace Elwig.Windows {
if (Highlighted.Graph != null) {
Updating = true;
OechsleInput.Text = Highlighted.Graph.GetOechsleAt(Highlighted.Index).ToString();
ContractedInput.IsChecked = Highlighted.Graph == SelectedGraphEntry?.ContractedGraph;
GebInput.IsChecked = Highlighted.Graph == SelectedGraphEntry?.GebundenGraph;
PriceInput.Text = Math.Round(Highlighted.Graph.GetPriceAt(Highlighted.Index), Season.Precision).ToString();
Updating = false;
}
@@ -509,14 +509,14 @@ namespace Elwig.Windows {
} else {
PrimaryMarkedPoint = -1;
SecondaryMarkedPoint = -1;
if (SelectedGraphEntry?.ContractedGraph != null) {
if (SelectedGraphEntry?.GebundenGraph != null) {
ChangeActiveGraph(null);
}
ChangeMarker(PrimaryMarkedPointPlot, false);
ChangeMarker(SecondaryMarkedPointPlot, false);
OechsleInput.Text = "";
ContractedInput.IsChecked = false;
GebInput.IsChecked = false;
PriceInput.Text = "";
DisableTextBox(PriceInput);
@@ -549,7 +549,7 @@ namespace Elwig.Windows {
}
var mouseOnData = MouseOnPlot(DataPlot, GetMouseCoordinates(e.GetPosition(OechslePricePlot)));
var mouseOnContracted = MouseOnPlot(ContractedPlot, GetMouseCoordinates(e.GetPosition(OechslePricePlot)));
var mouseOnGebunden = MouseOnPlot(GebundenPlot, GetMouseCoordinates(e.GetPosition(OechslePricePlot)));
Highlighted = LastHighlighted;
@@ -560,13 +560,13 @@ namespace Elwig.Windows {
HoverActive = true;
if (SelectedGraphEntry?.DataGraph is Graph g)
HandleTooltip(mouseOnData.Value.X, mouseOnData.Value.Y, mouseOnData.Value.Index, g, e.GetPosition(OechslePricePlot), e is MouseWheelEventArgs);
} else if (mouseOnContracted != null) {
ChangeMarker(HighlightedPointPlot, true, mouseOnContracted.Value.X, mouseOnContracted.Value.Y);
} else if (mouseOnGebunden != null) {
ChangeMarker(HighlightedPointPlot, true, mouseOnGebunden.Value.X, mouseOnGebunden.Value.Y);
HighlightedPointPlot?.IsVisible = true;
HoverChanged = true ^ HoverActive;
HoverActive = true;
if (SelectedGraphEntry?.ContractedGraph is Graph g)
HandleTooltip(mouseOnContracted.Value.X, mouseOnContracted.Value.Y, mouseOnContracted.Value.Index, g, e.GetPosition(OechslePricePlot), e is MouseWheelEventArgs);
if (SelectedGraphEntry?.GebundenGraph is Graph g)
HandleTooltip(mouseOnGebunden.Value.X, mouseOnGebunden.Value.Y, mouseOnGebunden.Value.Index, g, e.GetPosition(OechslePricePlot), e is MouseWheelEventArgs);
} else {
ChangeMarker(HighlightedPointPlot, false);
HoverChanged = false ^ HoverActive;
@@ -699,25 +699,25 @@ namespace Elwig.Windows {
private void ChangeActiveGraph(Graph? g) {
if (g != null && g == SelectedGraphEntry?.DataGraph) {
EnableTextBox(OechsleInput);
if (SelectedGraphEntry?.ContractedGraph != null) ChangeLineWidth(DataPlot, 4);
ChangeLineWidth(ContractedPlot, 1);
ContractedInput.IsEnabled = SelectedGraphEntry?.ContractedGraph != null;
ContractedInput.IsChecked = false;
} else if (g != null && g == SelectedGraphEntry?.ContractedGraph) {
if (SelectedGraphEntry?.GebundenGraph != null) ChangeLineWidth(DataPlot, 4);
ChangeLineWidth(GebundenPlot, 1);
GebInput.IsEnabled = SelectedGraphEntry?.GebundenGraph != null;
GebInput.IsChecked = false;
} else if (g != null && g == SelectedGraphEntry?.GebundenGraph) {
EnableTextBox(OechsleInput);
ChangeLineWidth(ContractedPlot, 4);
ChangeLineWidth(GebundenPlot, 4);
ChangeLineWidth(DataPlot, 1);
ContractedInput.IsEnabled = SelectedGraphEntry?.ContractedGraph != null;
ContractedInput.IsChecked = true;
GebInput.IsEnabled = SelectedGraphEntry?.GebundenGraph != null;
GebInput.IsChecked = true;
} else {
DisableTextBox(OechsleInput);
DisableTextBox(PriceInput);
OechsleInput.Text = "";
ContractedInput.IsEnabled = false;
ContractedInput.IsChecked = false;
GebInput.IsEnabled = false;
GebInput.IsChecked = false;
PriceInput.Text = "";
ChangeLineWidth(DataPlot, 1);
ChangeLineWidth(ContractedPlot, 1);
ChangeLineWidth(GebundenPlot, 1);
}
ActiveGraph = g;
}
@@ -730,11 +730,11 @@ namespace Elwig.Windows {
RefreshInputs();
}
private void ContractedFlatBonus_TextChanged(object sender, TextChangedEventArgs e) {
private void GebundenFlatBonus_TextChanged(object sender, TextChangedEventArgs e) {
if (FillingInputs) return;
var r = Validator.CheckDecimal(ContractedFlatBonus, true, 2, Season.Precision);
var r = Validator.CheckDecimal(GebundenFlatBonus, true, 2, Season.Precision);
if (r.IsValid && SelectedGraphEntry != null) {
SelectedGraphEntry.ContractedFlatBonus = double.Parse(ContractedFlatBonus.Text);
SelectedGraphEntry.GebundenFlatBonus = double.Parse(GebundenFlatBonus.Text);
ResetPlot();
InitPlot();
}
@@ -795,37 +795,37 @@ namespace Elwig.Windows {
GraphList.Items.Refresh();
}
private void ContractedType_Checked(object sender, RoutedEventArgs e) {
private void GebundenType_Checked(object sender, RoutedEventArgs e) {
if (FillingInputs) return;
if (SelectedGraphEntry == null) {
DisableTextBox(ContractedFlatBonus);
DisableTextBox(GebundenFlatBonus);
return;
}
if (ContractedTypeNone.IsChecked == true) {
SelectedGraphEntry.RemoveContractedGraph();
DisableTextBox(ContractedFlatBonus);
} else if (ContractedTypeFixed.IsChecked == true) {
SelectedGraphEntry.ContractedFlatBonus = double.TryParse(ContractedFlatBonus.Text, out var val) ? val : 0.1;
SelectedGraphEntry.AddContractedGraph();
EnableTextBox(ContractedFlatBonus);
} else if (ContractedTypeGraph.IsChecked == true) {
SelectedGraphEntry.AddContractedGraph();
DisableTextBox(ContractedFlatBonus);
if (GebundenTypeNone.IsChecked == true) {
SelectedGraphEntry.RemoveGebundenGraph();
DisableTextBox(GebundenFlatBonus);
} else if (GebundenTypeFixed.IsChecked == true) {
SelectedGraphEntry.GebundenFlatBonus = double.TryParse(GebundenFlatBonus.Text, out var val) ? val : 0.1;
SelectedGraphEntry.AddGebundenGraph();
EnableTextBox(GebundenFlatBonus);
} else if (GebundenTypeGraph.IsChecked == true) {
SelectedGraphEntry.AddGebundenGraph();
DisableTextBox(GebundenFlatBonus);
}
SetHasChanged();
RefreshInputs();
}
private void CheckContractedTypeFixed() {
private void CheckGebundenTypeFixed() {
FillingInputs = true;
if (SelectedGraphEntry?.ContractedFlatBonus is double bonus) {
ContractedTypeFixed.IsChecked = true;
ContractedFlatBonus.Text = $"{bonus}";
EnableTextBox(ContractedFlatBonus);
} else if (SelectedGraphEntry?.ContractedGraph != null) {
ContractedTypeGraph.IsChecked = true;
ContractedFlatBonus.Text = "";
DisableTextBox(ContractedFlatBonus);
if (SelectedGraphEntry?.GebundenFlatBonus is double bonus) {
GebundenTypeFixed.IsChecked = true;
GebundenFlatBonus.Text = $"{bonus}";
EnableTextBox(GebundenFlatBonus);
} else if (SelectedGraphEntry?.GebundenGraph != null) {
GebundenTypeGraph.IsChecked = true;
GebundenFlatBonus.Text = "";
DisableTextBox(GebundenFlatBonus);
}
FillingInputs = false;
}
+8 -17
View File
@@ -398,8 +398,7 @@
<Grid Grid.Row="1" Grid.Column="2">
<Grid.RowDefinitions>
<RowDefinition Height="0.625*"/>
<RowDefinition Height="0.8125*"/>
<RowDefinition Height="0.0625*"/>
<RowDefinition Height="0.875*"/>
<RowDefinition Height="0.875*"/>
<RowDefinition Height="0.25*"/>
<RowDefinition Height="*"/>
@@ -435,7 +434,7 @@
</Grid>
</GroupBox>
<GroupBox Header="Lieferung" Grid.Column="0" Grid.Row="1" Grid.RowSpan="4" Margin="5,5,5,5">
<GroupBox Header="Lieferung" Grid.Column="0" Grid.Row="1" Grid.RowSpan="3" Margin="5,5,5,5">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
@@ -518,7 +517,6 @@
<ComboBox x:Name="CultivationInput" SelectedItem="{Binding WineCultObj, Mode=TwoWay}" ItemsSource="{Binding WineCultSource, Mode=TwoWay}"
Grid.Row="1" Grid.Column="2" Margin="0,40,10,10"
DisplayMemberPath="Name"
SelectionChanged="CultivationInput_SelectionChanged"
KeyUp="Input_KeyUp"/>
</Grid>
</GroupBox>
@@ -555,7 +553,7 @@
</Grid>
</GroupBox>
<GroupBox Header="Menge" Grid.Column="1" Grid.Row="2" Grid.RowSpan="2" Margin="5,5,5,5">
<GroupBox Header="Menge" Grid.Column="1" Grid.Row="2" Margin="5,5,5,5">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="70"/>
@@ -567,23 +565,16 @@
TextChanged="WeightInput_TextChanged"
Grid.Column="1" Width="70" Margin="0,10,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<Label Content="Tara:" Margin="10,40,10,10"/>
<TextBlock x:Name="Tare" Text="{Binding TareString}" Width="40"
Grid.Column="1" Margin="30,44,10,10" TextAlignment="Center" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<CheckBox x:Name="ManualWeighingInput" IsChecked="{Binding IsManualWeighing, Mode=TwoWay}"
Content="Handwiegung" IsEnabled="False"
VerticalAlignment="Top" HorizontalAlignment="Left" Margin="10,75,10,10" Grid.Column="0" Grid.ColumnSpan="2"
VerticalAlignment="Top" HorizontalAlignment="Left" Margin="10,45,10,10" Grid.Column="0" Grid.ColumnSpan="2"
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"/>
<CheckBox x:Name="GerebeltGewogenInput" IsChecked="{Binding IsNetWeightValue, Mode=TwoWay}"
Content="Gerebelt gewogen" IsThreeState="True"
VerticalAlignment="Top" HorizontalAlignment="Left" Margin="10,100,10,10" Grid.Column="0" Grid.ColumnSpan="2"
VerticalAlignment="Top" HorizontalAlignment="Left" Margin="10,75,10,10" Grid.Column="0" Grid.ColumnSpan="2"
Checked="GerebeltGewogenInput_Changed" Unchecked="GerebeltGewogenInput_Changed" Indeterminate="GerebeltGewogenInput_Changed"/>
<Button x:Name="CorrectTareButton" Content="Tara korrigieren" Width="120" Visibility="Hidden"
Click="CorrectTareButton_Click"
VerticalAlignment="Top" HorizontalAlignment="Right" Margin="10,10,10,10" Grid.Column="2"/>
<Button x:Name="WeighingAButton" Content="Wiegen A" Width="120"
Click="WeighingButton_Click"
VerticalAlignment="Top" HorizontalAlignment="Right" Margin="10,10,10,10" Grid.Column="2"/>
@@ -602,7 +593,7 @@
</Grid>
</GroupBox>
<GroupBox Header="Sonstiges" Grid.Column="1" Grid.Row="4" Grid.RowSpan="2" Margin="5,5,5,10">
<GroupBox Header="Sonstiges" Grid.Column="1" Grid.Row="3" Grid.RowSpan="2" Margin="5,5,5,10">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
@@ -655,7 +646,7 @@
</Grid>
</GroupBox>
<GroupBox Header="Herkunft" Grid.Column="0" Grid.Row="5" Margin="5,5,5,10">
<GroupBox Header="Herkunft" Grid.Column="0" Grid.Row="4" Margin="5,5,5,10">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
@@ -682,7 +673,7 @@
Margin="0,70,10,10" Grid.Column="1"
DisplayMemberPath="Name"/>
<CheckBox x:Name="ContractedInput" IsChecked="{Binding IsContracted, Mode=TwoWay}"
<CheckBox x:Name="GebundenInput" IsChecked="{Binding IsGebunden, Mode=TwoWay}"
Content="Gebunden" Margin="10,105,0,0" Grid.Column="0" Grid.ColumnSpan="2" IsThreeState="True"
VerticalAlignment="Top" HorizontalAlignment="Left"
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed" Indeterminate="CheckBox_Changed"/>
+18 -106
View File
@@ -9,7 +9,6 @@ using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json.Nodes;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
@@ -104,7 +103,6 @@ namespace Elwig.Windows {
WeighingBButton.Visibility = Visibility.Hidden;
WeighingCButton.Visibility = Visibility.Hidden;
WeighingDButton.Visibility = Visibility.Hidden;
DisableWeighingButtons();
}
Menu_Statistics_WineQuality_ModeOe.IsChecked = false;
@@ -128,6 +126,7 @@ namespace Elwig.Windows {
this() {
using var ctx = new AppDbContext();
ViewModel.FilterMember = ctx.Members.Find(mgnr) ?? throw new ArgumentException("MgNr argument has invalid value");
ViewModel.Title = $"Lieferungen - {ViewModel.FilterMember.AdministrativeName} - Elwig";
ViewModel.EnableAllSeasons = true;
}
@@ -140,7 +139,7 @@ namespace Elwig.Windows {
if (await ctx.FetchSeasons(Utils.CurrentYear).SingleOrDefaultAsync() == null) {
InteractionService.ShowWarning("Saison noch nicht erstellt",
"Die Saison für das aktuelle Jahr wurde noch nicht erstellt. Neue Lieferungen können nicht abgespeichert werden.\n\n" +
"(Stammdaten \u2192 Saisons \u2192 Neu anlegen...)");
"(Stammdaten -> Saisons -> Neu anlegen...)");
}
}
}
@@ -356,11 +355,11 @@ namespace Elwig.Windows {
}
if (App.Client.IsMatzen || App.Client.IsWinzerkeller || App.Client.IsBaden || App.Client.IsWeinland) {
ContractedInput.IsEnabled = false;
SetDefaultValue(ContractedInput, null);
GebundenInput.IsEnabled = false;
SetDefaultValue(GebundenInput, null);
} else {
ContractedInput.IsEnabled = true;
UnsetDefaultValue(ContractedInput);
GebundenInput.IsEnabled = true;
UnsetDefaultValue(GebundenInput);
}
}
@@ -376,7 +375,7 @@ namespace Elwig.Windows {
ViewModel.IsNetWeight = App.Config.WeighingMode == WeighingMode.Net;
ViewModel.IsHandPicked = App.Config.WeighingMode != WeighingMode.Net ? true : null;
ViewModel.Unloading = null;
ViewModel.IsContracted = null;
ViewModel.IsGebunden = null;
InitialDefaultInputs();
//WineQualityLevelInput.IsEnabled = false; // disable wine quality level input in Übernahme
@@ -420,9 +419,9 @@ namespace Elwig.Windows {
var cursor = Mouse.OverrideCursor != null;
if (!cursor) Mouse.OverrideCursor = Cursors.Wait;
var query = (vm.SearchQuery, vm.FilterSeason, vm.FilterAllSeasons, vm.FilterTodayOnly);
var (filterNames, filter, deliveries, deliveryPartsNum, varieties, members, stat) = await Task.Run(async () => {
var (filter, deliveries, deliveryPartsNum, varieties, members, stat) = await Task.Run(async () => {
using var ctx = new AppDbContext();
var (filterNames, deliveryQuery, deliveryPartsQuery, predicate, filter) = await vm.GetFilters(ctx);
var (_, deliveryQuery, deliveryPartsQuery, predicate, filter) = await vm.GetFilters(ctx);
var deliveries = await deliveryQuery
.Include(d => d.Parts).ThenInclude(p => p.PartModifiers).ThenInclude(m => m.Modifier)
.Include(d => d.Parts).ThenInclude(p => p.Variety)
@@ -451,13 +450,11 @@ namespace Elwig.Windows {
var members = await deliveryQuery.Select(d => d.Member).Distinct().IgnoreAutoIncludes().ToListAsync();
var stat = await DeliveryService.GenerateToolTipData(deliveryPartsQuery);
return (filterNames, filter, deliveries, deliveryPartsNum, varieties, members, stat);
return (filter, deliveries, deliveryPartsNum, varieties, members, stat);
});
if (!cursor) Mouse.OverrideCursor = null;
if (query != (ViewModel.SearchQuery, ViewModel.FilterSeason, ViewModel.FilterAllSeasons, ViewModel.FilterTodayOnly)) return;
if (!ViewModel.IsReceipt)
ViewModel.Title = Utils.GetTitle("Lieferungen", filterNames, filter);
ControlUtils.RenewItemsSource(DeliveryList, deliveries,
DeliveryList_SelectionChanged, ViewModel.TextFilter.Count > 0 ? ControlUtils.RenewSourceDefault.IfOnly : ControlUtils.RenewSourceDefault.None, !updateSort);
await RefreshDeliveryParts();
@@ -491,6 +488,7 @@ namespace Elwig.Windows {
return;
}
ViewModel.FilterMember = m;
ViewModel.Title = $"Lieferungen - {ViewModel.FilterMember.AdministrativeName} - Elwig";
}
int year = 0;
@@ -614,34 +612,14 @@ namespace Elwig.Windows {
ClearOriginalValues();
ClearDefaultValues();
ViewModel.FillInputs(p);
CorrectTareButton.Visibility = !ViewModel.IsReceipt && ((ViewModel.ActualTare is int t && t != 0) || ViewModel.IsUnloadingBox) ? Visibility.Visible : Visibility.Hidden;
FinishInputFilling();
}
new protected void ClearInputs(bool validate = false) {
ViewModel.ClearInputs();
CorrectTareButton.Visibility = Visibility.Hidden;
base.ClearInputs(validate);
}
private void CorrectTareButton_Click(object sender, RoutedEventArgs evt) {
var lastCorrection = (ViewModel.TargetTare ?? ViewModel.ActualTare ?? 0) - (ViewModel.ActualTare ?? 0);
var correction = Utils.ShowTareCorrectionDialog(ViewModel.ActualTare, ViewModel.TargetTare);
if (correction == null) return;
ViewModel.Weight += lastCorrection - correction;
if (ViewModel.WeighingData is string s) {
ViewModel.TargetTare = correction == 0 ? null : (ViewModel.ActualTare ?? 0) + correction;
ViewModel.Tare = ViewModel.TargetTare ?? ViewModel.ActualTare;
var obj = JsonNode.Parse(s)!.AsObject();
if (correction == 0) {
obj.Remove("tare_correction");
} else {
obj["tare_correction"] = correction;
}
ViewModel.WeighingData = obj.ToJsonString(Utils.JsonOpts);
}
}
private void WeighingButton_Click(object sender, RoutedEventArgs evt) {
int index = Array.IndexOf(WeighingButtons, sender as Button);
if (index >= 0) WeighingButton_Click(index);
@@ -673,18 +651,12 @@ namespace Elwig.Windows {
private void OnWeighingResult(IScale scale, WeighingResult res) {
if ((res.NetWeight ?? 0) > 0 && res.FullWeighingId != null) {
ViewModel.Weight = res.NetWeight;
ViewModel.ActualTare = res.TareWeight;
ViewModel.TargetTare = null;
ViewModel.Tare = ViewModel.ActualTare is int t && t != 0 ? t : null;
ViewModel.ScaleTerminalId = scale.ScaleTerminalId;
ViewModel.WeighingData = res.ToJson().ToJsonString();
ViewModel.ManualWeighingReason = null;
ManualWeighingInput.IsChecked = false;
} else {
ViewModel.Weight = null;
ViewModel.ActualTare = null;
ViewModel.TargetTare = null;
ViewModel.Tare = null;
ViewModel.ScaleTerminalId = null;
ViewModel.WeighingData = null;
}
@@ -713,7 +685,7 @@ namespace Elwig.Windows {
private async void TodayOnlyInput_Changed(object sender, RoutedEventArgs evt) {
if (!HasContextLoaded) return;
if (TodayOnlyInput.IsChecked == true && AllSeasonsInput.IsChecked == false) {
ViewModel.FilterSeason = DateTime.Today.Year;
ViewModel.FilterSeason = Utils.Today.Year;
ViewModel.FilterTodayOnly = true;
}
await RefreshList();
@@ -774,12 +746,12 @@ namespace Elwig.Windows {
MgNrInput.CaretIndex = caret;
}
private async void MgNrInput_LostFocus(object sender, RoutedEventArgs evt) {
private void MgNrInput_LostFocus(object sender, RoutedEventArgs evt) {
var valid = InputLostFocus((TextBox)sender, Validator.CheckMgNr);
ControlUtils.SelectItemWithPk(MemberInput, valid ? ViewModel.MgNr : null);
}
private async void MemberInput_SelectionChanged(object? sender, SelectionChangedEventArgs? evt) {
private void MemberInput_SelectionChanged(object? sender, SelectionChangedEventArgs? evt) {
var m = MemberInput.SelectedItem as Member;
ViewModel.MgNr = m?.MgNr;
ViewModel.MemberAddress = m?.FullAddress;
@@ -796,8 +768,6 @@ namespace Elwig.Windows {
SetDefaultValue(WineKgInput);
ComboBox_SelectionChanged(WineKgInput, null);
}
if (IsCreating && Mouse.OverrideCursor == null)
await CheckOrganic();
}
private void EmptyScale() {
@@ -807,9 +777,6 @@ namespace Elwig.Windows {
}
private async void NewDeliveryPartButton_Click(object sender, RoutedEventArgs evt) {
if (!await CheckOrganic(true))
return;
FinishButton.IsEnabled = false;
NewDeliveryPartButton.IsEnabled = false;
Mouse.OverrideCursor = Cursors.Wait;
@@ -829,7 +796,7 @@ namespace Elwig.Windows {
} catch (Exception exc) {
InteractionService.ShowDbException("Lieferung aktualisieren", exc);
FinishButton.IsEnabled = true;
NewDeliveryPartButton.IsEnabled = true;
SaveButton.IsEnabled = true;
Mouse.OverrideCursor = null;
DeliveryPartList.IsEnabled = true;
return;
@@ -838,18 +805,14 @@ namespace Elwig.Windows {
EmptyScale();
await EnsureContextRenewed();
Mouse.OverrideCursor = null;
ControlUtils.SelectItemWithPk(DeliveryList, p?.Year, p?.DId);
DeliveryPartList.SelectedItem = null;
DeliveryPartList.ScrollIntoView(DeliveryPartList.ItemsSource.Cast<object>().LastOrDefault());
InitialInputs();
Mouse.OverrideCursor = null;
}
private async void FinishButton_Click(object sender, RoutedEventArgs evt) {
if (!await CheckOrganic(true))
return;
FinishButton.IsEnabled = false;
NewDeliveryPartButton.IsEnabled = false;
Mouse.OverrideCursor = Cursors.Wait;
@@ -869,7 +832,7 @@ namespace Elwig.Windows {
} catch (Exception exc) {
InteractionService.ShowDbException("Lieferung aktualisieren", exc);
FinishButton.IsEnabled = true;
NewDeliveryPartButton.IsEnabled = true;
SaveButton.IsEnabled = true;
Mouse.OverrideCursor = null;
DeliveryPartList.IsEnabled = true;
return;
@@ -1008,8 +971,6 @@ namespace Elwig.Windows {
DeliveryList.IsEnabled = false;
DeliveryPartList.IsEnabled = false;
if (!ViewModel.IsReceipt)
EnableWeighingButtons();
HideNewEditDeleteButtons();
ShowSaveResetCancelButtons();
UnlockInputs();
@@ -1047,9 +1008,6 @@ namespace Elwig.Windows {
}
private async void SaveButton_Click(object? sender, RoutedEventArgs? evt) {
if (!await CheckOrganic(true))
return;
SaveButton.IsEnabled = false;
Mouse.OverrideCursor = Cursors.Wait;
@@ -1076,8 +1034,6 @@ namespace Elwig.Windows {
DeliveryList.IsEnabled = true;
DeliveryPartList.IsEnabled = true;
if (!ViewModel.IsReceipt)
DisableWeighingButtons();
HideSaveResetCancelButtons();
ShowNewEditDeleteButtons();
LockInputs();
@@ -1111,8 +1067,6 @@ namespace Elwig.Windows {
DeliveryList.IsEnabled = true;
DeliveryPartList.IsEnabled = true;
if (!ViewModel.IsReceipt)
DisableWeighingButtons();
HideSaveResetCancelButtons();
ShowNewEditDeleteButtons();
RefreshInputs();
@@ -1217,7 +1171,6 @@ namespace Elwig.Windows {
}
private void DisableWeighingButtons() {
CorrectTareButton.IsEnabled = false;
WeighingManualButton.IsEnabled = false;
WeighingAButton.IsEnabled = false;
WeighingBButton.IsEnabled = false;
@@ -1226,7 +1179,6 @@ namespace Elwig.Windows {
}
private void EnableWeighingButtons() {
CorrectTareButton.IsEnabled = true;
WeighingManualButton.IsEnabled = true;
var n = App.CommandScales.Count;
WeighingAButton.IsEnabled = n > 0 && App.CommandScales[0].IsReady;
@@ -1421,15 +1373,13 @@ namespace Elwig.Windows {
private void UnloadingInput_Checked(object sender, RoutedEventArgs evt) {
if (!IsEditing && !IsCreating) return;
if (!ViewModel.IsReceipt)
CorrectTareButton.Visibility = (ViewModel.ActualTare is int t && t != 0) || ViewModel.IsUnloadingBox ? Visibility.Visible : Visibility.Hidden;
var mod = ViewModel.Modifiers.ToList();
var source = ViewModel.ModifiersSource.ToList();
if (App.Client.IsMatzen) {
var kl = mod.Where(m => m.Name.StartsWith("Klasse ")).Select(m => m.ModId).LastOrDefault("_")[0];
if (ViewModel.IsUnloadingPumped && (kl == 'A' || kl == '_')) {
kl = 'B';
} else if (ViewModel.IsUnloadingDumper && (kl == 'B' || kl == '_')) {
} else if (ViewModel.IsUnloadingDumper && kl == '_') {
kl = 'A';
} else {
kl = '_';
@@ -1551,43 +1501,5 @@ namespace Elwig.Windows {
if (MemberInput.SelectedItem is not Member m) return;
App.FocusMember(m.MgNr);
}
private async void CultivationInput_SelectionChanged(object sender, RoutedEventArgs evt) {
if (IsCreating && Mouse.OverrideCursor == null)
await CheckOrganic();
}
private async Task<bool> CheckOrganic(bool confirm = false) {
if (MemberInput.SelectedValue is not Member m || CultivationInput.SelectedItem is not WineCult c) {
return true;
} else if (c.IsOrganic) {
if (m.IsOrganic) {
var valid = true;
if (IsCreating) {
try {
var certs = await OrganicService.GetTracesCertificates(m);
valid = certs.Any(c => c.IsValidForWineProduction);
} catch { }
}
if (valid)
return true;
if (confirm) {
return InteractionService.AskConfirmation("Kein gültiges Bio-Zertifikat", "Soll die Bio-Lieferung wirklich gespeichert werden,\nobwohl für das Mitglied kein gültiges Bio-Zertifikat gefunden werden konnte?");
} else {
InteractionService.ShowWarning("Kein gültiges Bio-Zertifikat", "Achtung! Für diesen Bio-Betrieb konnte kein gültiges Bio-Zertifikat gefunden werden!");
}
return false;
} else {
if (confirm) {
return InteractionService.AskConfirmation("Kein Bio-Betrieb", "Soll die Bio-Lieferung wirklich gespeichert werden, obwohl das Mitglied keinen Bio-Betrieb hat?");
} else {
InteractionService.ShowWarning("Kein Bio-Betrieb", "Achtung! Bio-Lieferung ohne Bio-Betrieb!");
}
return false;
}
} else {
return true;
}
}
}
}
+1 -1
View File
@@ -8,7 +8,7 @@
xmlns:local="clr-namespace:Elwig.Windows"
xmlns:vm="clr-namespace:Elwig.ViewModels"
xmlns:ctrl="clr-namespace:Elwig.Controls"
Title="{Binding Title}" Height="700" Width="980" MinWidth="600" MinHeight="400">
Title="Anmeldungen - Elwig" Height="700" Width="980" MinWidth="600" MinHeight="400">
<Window.DataContext>
<vm:DeliveryAncmtAdminViewModel/>
</Window.DataContext>
+5 -32
View File
@@ -91,9 +91,8 @@ namespace Elwig.Windows {
.ToListAsync();
list.ForEach(v => v.Schedule.AnnouncedWeightOverride = v.AnnouncedWeight);
var deliverySchedules = list.Select(v => v.Schedule).ToList();
var today = DateTime.Today;
ControlUtils.RenewItemsSource(DeliveryScheduleList, deliverySchedules
.Where(s => !ViewModel.FilterOnlyUpcoming || s.DateString.CompareTo(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);
ControlUtils.RenewItemsSource(DeliveryScheduleInput, deliverySchedules, DeliveryScheduleInput_SelectionChanged);
}
@@ -103,9 +102,9 @@ namespace Elwig.Windows {
var cursor = Mouse.OverrideCursor != null;
if (!cursor) Mouse.OverrideCursor = Cursors.Wait;
var query = (vm.SearchQuery, vm.FilterSeason, vm.FilterOnlyUpcoming, vm.FilterOnlyUpcoming);
var (filterNames, filter, deliveryAncmts, stat) = await Task.Run(async () => {
var (filter, deliveryAncmts, stat) = await Task.Run(async () => {
using var ctx = new AppDbContext();
var (filterNames, deliveryAncmtQuery, filter) = await vm.GetFilters(ctx);
var (_, deliveryAncmtQuery, filter) = await vm.GetFilters(ctx);
var deliveryAncmts = await deliveryAncmtQuery.ToListAsync();
if (filter.Count > 0 && deliveryAncmts.Count > 0) {
@@ -130,12 +129,11 @@ namespace Elwig.Windows {
var stat = await DeliveryAncmtService.GenerateToolTipData(deliveryAncmtQuery);
return (filterNames, filter, deliveryAncmts, stat);
return (filter, deliveryAncmts, stat);
});
if (!cursor) Mouse.OverrideCursor = null;
if (query != (ViewModel.SearchQuery, ViewModel.FilterSeason, ViewModel.FilterOnlyUpcoming, ViewModel.FilterOnlyUpcoming)) return;
ViewModel.Title = Utils.GetTitle("Anmeldungen", filterNames, filter);
ControlUtils.RenewItemsSource(DeliveryAncmtList, deliveryAncmts,
DeliveryAncmtList_SelectionChanged, ViewModel.TextFilter.Count > 0 ? ControlUtils.RenewSourceDefault.IfOnly : ControlUtils.RenewSourceDefault.None, !updateSort);
if (updateSort && DeliveryAncmtList.SelectedItem != null)
@@ -208,28 +206,8 @@ namespace Elwig.Windows {
}
}
private bool CheckOrganic(bool confirm = false) {
if (DeliveryScheduleInput.SelectedItem is not DeliverySchedule s || MemberInput.SelectedItem is not Member m) {
return true;
} else if (s.IsOrganic) {
if (m.IsOrganic) {
return true;
} else {
if (confirm) {
return InteractionService.AskConfirmation("Kein Bio-Betrieb", "Soll die Bio-Anmeldung wirklich gespeichert werden, obwohl das Mitglied keinen Bio-Betrieb hat?");
} else {
InteractionService.ShowWarning("Kein Bio-Betrieb", "Achtung! Bio-Anmeldung ohne Bio-Betrieb!");
}
}
return false;
} else {
return true;
}
}
private void DeliveryScheduleInput_SelectionChanged(object sender, RoutedEventArgs evt) {
if (IsEditing || IsCreating)
CheckOrganic();
}
private async void OnlyUpcomingInput_Changed(object sender, RoutedEventArgs evt) {
@@ -278,8 +256,6 @@ namespace Elwig.Windows {
var m = MemberInput.SelectedItem as Member;
ViewModel.MgNr = m?.MgNr;
ViewModel.MemberAddress = m?.FullAddress;
if (IsCreating)
CheckOrganic();
}
protected override void ShortcutNew() {
@@ -356,9 +332,6 @@ namespace Elwig.Windows {
}
private async void SaveButton_Click(object? sender, RoutedEventArgs? evt) {
if (!CheckOrganic(true))
return;
Mouse.OverrideCursor = Cursors.Wait;
SaveButton.IsEnabled = false;
+4 -4
View File
@@ -167,14 +167,14 @@
Margin="180,225,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Checked="MemberInput_Checked"/>
<Label Content="Funktionär:" x:Name="MemberOfficerLabel" Margin="10,250,0,10"/>
<RadioButton x:Name="MemberOfficerYesInput" Content="Ja" GroupName="MemberOfficer"
<Label Content="Funktionär:" x:Name="MemberFunktionärLabel" Margin="10,250,0,10"/>
<RadioButton x:Name="MemberFunktionärYesInput" Content="Ja" GroupName="MemberFunktionär"
Margin="80,255,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Checked="MemberInput_Checked"/>
<RadioButton x:Name="MemberOfficerNoInput" Content="Nein" GroupName="MemberOfficer"
<RadioButton x:Name="MemberFunktionärNoInput" Content="Nein" GroupName="MemberFunktionär"
Margin="125,255,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Checked="MemberInput_Checked"/>
<RadioButton x:Name="MemberOfficerIndifferentInput" Content="Egal" GroupName="MemberOfficer"
<RadioButton x:Name="MemberFunktionärIndifferentInput" Content="Egal" GroupName="MemberFunktionär"
Margin="180,255,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Checked="MemberInput_Checked"/>
+12 -14
View File
@@ -108,7 +108,7 @@ namespace Elwig.Windows {
public MailWindow(int? year = null) {
InitializeComponent();
using (var ctx = new AppDbContext()) {
Year = year ?? ctx.Seasons.OrderByDescending(s => s.Year).FirstOrDefault()?.Year ?? DateTime.Today.Year;
Year = year ?? ctx.Seasons.OrderByDescending(s => s.Year).FirstOrDefault()?.Year ?? Utils.Today.Year;
Title = $"Rundschreiben - Lese {Year} - Elwig";
}
@@ -122,7 +122,7 @@ namespace Elwig.Windows {
RecipientsActiveMembersInput.IsChecked = true;
MemberOrganicIndifferentInput.IsChecked = true;
MemberOfficerIndifferentInput.IsChecked = true;
MemberFunktionärIndifferentInput.IsChecked = true;
DeliveryConfirmationFooterInput.Text = App.Client.TextDeliveryConfirmation;
CreditNoteFooterInput.Text = App.Client.TextCreditNote;
@@ -150,7 +150,7 @@ namespace Elwig.Windows {
PostalSender1.Text = App.Client.Sender1;
PostalSender2.Text = App.Client.Sender2;
PostalLocation.Text = App.BranchLocation;
PostalDate.Text = $"{DateTime.Today:dd.MM.yyyy}";
PostalDate.Text = $"{Utils.Today:dd.MM.yyyy}";
EmailSubjectInput.Text = App.Client.TextEmailSubject ?? "Rundschreiben";
EmailBodyInput.Text = App.Client.TextEmailBody ?? "Sehr geehrtes Mitglied,\n\nim Anhang finden Sie das aktuelle Rundschreiben.\n\nIhre Winzergenossenschaft\n";
}
@@ -408,10 +408,10 @@ namespace Elwig.Windows {
MemberOrganicYesInput.Visibility = vis;
MemberOrganicNoInput.Visibility = vis;
MemberOrganicIndifferentInput.Visibility = vis;
MemberOfficerLabel.Visibility = vis;
MemberOfficerYesInput.Visibility = vis;
MemberOfficerNoInput.Visibility = vis;
MemberOfficerIndifferentInput.Visibility = vis;
MemberFunktionärLabel.Visibility = vis;
MemberFunktionärYesInput.Visibility = vis;
MemberFunktionärNoInput.Visibility = vis;
MemberFunktionärIndifferentInput.Visibility = vis;
MemberAreaComInput.Visibility = RecipientsAreaComMembersInput.IsChecked == true ? Visibility.Visible : Visibility.Hidden;
MemberAreaComLabel.Visibility = RecipientsAreaComMembersInput.IsChecked == true ? Visibility.Visible : Visibility.Hidden;
MemberDeliveryAncmtInput.Visibility = RecipientsDeliveryAncmtMembersInput.IsChecked == true ? Visibility.Visible : Visibility.Hidden;
@@ -438,7 +438,7 @@ namespace Elwig.Windows {
private void Date_LostFocus(object sender, RoutedEventArgs evt) {
var res = Validator.CheckDate((TextBox)sender, true);
if (!res.IsValid) ((TextBox)sender).Text = $"{DateTime.Today:dd.MM.yyyy}";
if (!res.IsValid) ((TextBox)sender).Text = $"{Utils.Today:dd.MM.yyyy}";
}
private async Task UpdateRecipients(AppDbContext ctx) {
@@ -459,10 +459,10 @@ namespace Elwig.Windows {
} else if (MemberOrganicNoInput.IsChecked == true) {
query = query.Where(m => !m.IsOrganic);
}
if (MemberOfficerYesInput.IsChecked == true) {
query = query.Where(m => m.IsOfficer);
} else if (MemberOfficerNoInput.IsChecked == true) {
query = query.Where(m => !m.IsOfficer);
if (MemberFunktionärYesInput.IsChecked == true) {
query = query.Where(m => m.IsFunktionär);
} else if (MemberFunktionärNoInput.IsChecked == true) {
query = query.Where(m => !m.IsFunktionär);
}
if (RecipientsAreaComMembersInput.IsChecked == true) {
@@ -937,7 +937,6 @@ namespace Elwig.Windows {
Mouse.OverrideCursor = Cursors.Wait;
var subject = EmailSubjectInput.Text;
var text = EmailBodyInput.Text;
var date = DateTime.Now;
await Task.Run(async () => {
await Utils.AddSentMailBody(subject, text, EmailDocuments.Count);
foreach (var (m, docs) in EmailDocuments) {
@@ -945,7 +944,6 @@ namespace Elwig.Windows {
msg.From.Add(new MailboxAddress(App.Client.NameFull, App.Config.Smtp.Value.From));
msg.To.AddRange(m.EmailAddresses.OrderBy(a => a.Nr).Select(a => new MailboxAddress(m.AdministrativeName, a.Address)));
msg.Subject = subject;
msg.Date = date;
var body = new Multipart("mixed") {
new TextPart("plain") { Text = text }
};
+3 -3
View File
@@ -301,12 +301,12 @@
<TextBlock Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2">Ungebunden:</TextBlock>
<TextBlock Grid.Row="1" Grid.Column="1" TextAlignment="Right" x:Name="SeasonStatMembersTotal">-</TextBlock>
<TextBlock Grid.Row="2" Grid.Column="1" TextAlignment="Right" x:Name="SeasonStatMembersCtrd">-</TextBlock>
<TextBlock Grid.Row="2" Grid.Column="1" TextAlignment="Right" x:Name="SeasonStatMembersGeb">-</TextBlock>
<TextBlock Grid.Row="3" Grid.Column="1" TextAlignment="Right">-</TextBlock>
<TextBlock Grid.Row="1" Grid.Column="2" TextAlignment="Right" x:Name="SeasonStatWeightTotal">-</TextBlock>
<TextBlock Grid.Row="2" Grid.Column="2" TextAlignment="Right" x:Name="SeasonStatWeightCtrd">-</TextBlock>
<TextBlock Grid.Row="3" Grid.Column="2" TextAlignment="Right" x:Name="SeasonStatWeightUnCtrd">-</TextBlock>
<TextBlock Grid.Row="2" Grid.Column="2" TextAlignment="Right" x:Name="SeasonStatWeightGeb">-</TextBlock>
<TextBlock Grid.Row="3" Grid.Column="2" TextAlignment="Right" x:Name="SeasonStatWeightUngeb">-</TextBlock>
<TextBlock Grid.Row="1" Grid.Column="3" TextAlignment="Right">-</TextBlock>
<TextBlock Grid.Row="2" Grid.Column="3" TextAlignment="Right" x:Name="SeasonStatArea">-</TextBlock>
+30 -16
View File
@@ -52,21 +52,20 @@ namespace Elwig.Windows {
private void Window_Closing(object sender, CancelEventArgs evt) {
if (App.NumWindows > 1 && !App.ForceShutdown) {
foreach (var w in Application.Current.Windows.Cast<Window>().Where(w => w is AdministrationWindow adm && (adm.IsEditing || adm.IsCreating))) {
foreach (var w in App.Current.Windows.Cast<Window>().Where(w => ((w as AdministrationWindow)?.IsEditing ?? false) || ((w as AdministrationWindow)?.IsCreating ?? false))) {
try {
w.Close();
} catch { }
}
Thread.Sleep(100);
if (App.NumWindows > 1) {
var areAdminWindowsOpen = Application.Current.Windows.Cast<Window>().Any(w => w is AdministrationWindow adm && (adm.IsEditing || adm.IsCreating));
if (areAdminWindowsOpen && !InteractionService.AskConfirmation("Elwig beenden", "Es sind noch weitere Fenster geöffnet.\nSollen alle Fenster geschlossen werden?")) {
if (App.NumWindows > 1 && !App.Current.Windows.Cast<Window>().Any(w => ((w as AdministrationWindow)?.IsEditing ?? false) || ((w as AdministrationWindow)?.IsCreating ?? false))) {
if (!InteractionService.AskConfirmation("Elwig beenden", "Es sind noch weitere Fenster geöffnet.\nSollen alle Fenster geschlossen werden?")) {
evt.Cancel = true;
return;
} else {
Application.Current.Shutdown();
}
}
}
App.CurrentApp.ShutdownGracefully();
}
private void Menu_Help_About_Click(object sender, RoutedEventArgs evt) {
@@ -163,7 +162,7 @@ namespace Elwig.Windows {
private async void Menu_Database_Backup_Click(object sender, RoutedEventArgs evt) {
try {
var filename = InteractionService.SaveFile("Datenbank-Sicherung", $"database_{DateTime.Today:yyyy-MM-dd}", "sql.zip");
var filename = InteractionService.SaveFile("Datenbank-Sicherung", $"database_{Utils.Today:yyyy-MM-dd}", "sql.zip");
if (filename != null) {
if (!filename.EndsWith(".sql.zip")) filename += ".sql.zip";
Mouse.OverrideCursor = Cursors.Wait;
@@ -178,7 +177,22 @@ namespace Elwig.Windows {
}
private async void Menu_Database_Restore_Click(object sender, RoutedEventArgs evt) {
await BackupService.RestoreDatabase();
try {
var d = new OpenFileDialog() {
Title = "Datenbank wiederherstellen - Elwig",
DefaultExt = "sql.zip",
Filter = "SQLite-Datenbank (*.sqlite3, *.sqlite3.zip, *.sql, *.sql.zip)|*.sqlite3;*.sqlite3.zip;*.sql;*.sql.zip",
};
if (d.ShowDialog() == true) {
if (!InteractionService.AskContinue("Datenbank wiederherstellen", "Soll die Datenbank wirklich unwiederruflich durch die wiederhergestellte Version ersetzt werden?"))
return;
Mouse.OverrideCursor = Cursors.Wait;
await App.ReplaceDatabase(d.FileName);
}
} catch (Exception exc) {
InteractionService.ShowException(exc);
}
Mouse.OverrideCursor = null;
}
private async void SyncButton_Click(object sender, RoutedEventArgs evt) {
@@ -406,26 +420,26 @@ namespace Elwig.Windows {
BreakdownMemberVarietyButton.IsEnabled = valid;
SeasonStatMembersTotal.Text = "-";
SeasonStatMembersCtrd.Text = "-";
SeasonStatMembersGeb.Text = "-";
SeasonStatWeightTotal.Text = "-";
SeasonStatWeightCtrd.Text = "-";
SeasonStatWeightUnCtrd.Text = "-";
SeasonStatWeightGeb.Text = "-";
SeasonStatWeightUngeb.Text = "-";
SeasonStatArea.Text = "-";
if (valid) {
await Task.Run(async () => {
var membersTotal = await ctx.Deliveries.Where(d => d.Year == year).Select(d => d.Member).Distinct().CountAsync();
var areaComs = Utils.ActiveAreaCommitments(ctx.AreaCommitments, year!.Value);
var membersCtrd = await areaComs.Select(c => c.Member).Distinct().CountAsync();
var membersGeb = await areaComs.Select(c => c.Member).Distinct().CountAsync();
var weightTotal = await ctx.DeliveryParts.Where(p => p.Year == year).SumAsync(p => p.Weight);
var ctrdWeight = await ctx.DeliveryPartBuckets.Where(b => b.Year == year && b.Discr != "_").SumAsync(b => b.Value);
var gebWeight = await ctx.DeliveryPartBuckets.Where(b => b.Year == year && b.Discr != "_").SumAsync(b => b.Value);
var area = await areaComs.SumAsync(c => c.Area);
await App.MainDispatcher.BeginInvoke(() => {
if (year != SeasonInput.Value) return;
SeasonStatMembersTotal.Text = $"{membersTotal:N0}";
SeasonStatMembersCtrd.Text = $"{membersCtrd:N0}";
SeasonStatMembersGeb.Text = $"{membersGeb:N0}";
SeasonStatWeightTotal.Text = $"{weightTotal:N0} kg";
SeasonStatWeightCtrd.Text = $"{ctrdWeight:N0} kg";
SeasonStatWeightUnCtrd.Text = $"{weightTotal - ctrdWeight:N0} kg";
SeasonStatWeightGeb.Text = $"{gebWeight:N0} kg";
SeasonStatWeightUngeb.Text = $"{weightTotal - gebWeight:N0} kg";
SeasonStatArea.Text = $"{area:N0} m²";
});
});
+39 -73
View File
@@ -5,7 +5,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Elwig.Windows"
xmlns:vm="clr-namespace:Elwig.ViewModels"
Title="{Binding Title}" Height="700" Width="1250" MinHeight="650" MinWidth="1150">
Title="Mitglieder - Elwig" Height="700" Width="1250" MinHeight="650" MinWidth="1150">
<Window.DataContext>
<vm:MemberAdminViewModel/>
</Window.DataContext>
@@ -204,7 +204,7 @@
<Bold>Aktiv</Bold>: aktiv, !Aktiv (nicht-aktiv)<LineBreak/>
<Bold>Bio-Betrieb</Bold>: BIO, !bio (ausgenommen Bio)<LineBreak/>
<Bold>Buchführend</Bold>: buchf[ührend], Pauschal[iert], !buchf[ührend]<LineBreak/>
<Bold>Vollablieferer</Bold>: voll[ablieferer], voll[lieferant], !Voll[lieferant] (nicht-Vollablieferer)<LineBreak/>
<Bold>Volllieferant</Bold>: voll[lieferant], !Voll[lieferant] (nicht-Volllieferant)<LineBreak/>
<Bold>Funktionär</Bold>: Funkt[ionär], !funkt[ionär] (nicht-Funktionär)<LineBreak/>
<Bold>Telefon-Nr.</Bold>: z.B. +436641234, ....<LineBreak/>
<Bold>Kontaktdaten</Bold>: email (mind. 1 E-Mail-Adr.), telnr (mind. 1 Tel.-Nr.), !email (keine E-Mail-Adr.), !telnr (keine Tel.-Nr.)<LineBreak/>
@@ -371,7 +371,7 @@
<Label Content="Adresse:" Margin="10,130,0,0"/>
<TextBox x:Name="AddressInput" Text="{Binding Address, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,130,10,0" Grid.Column="1" Grid.ColumnSpan="3"
TextChanged="AddressInput_TextChanged"/>
TextChanged="TextBox_TextChanged"/>
<Label Content="PLZ/Ort:" Margin="10,160,0,0" Grid.Column="0"/>
<TextBox x:Name="PlzInput" Margin="0,160,0,0" Text="{Binding PlzString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
@@ -379,7 +379,6 @@
TextChanged="PlzInput_TextChanged" LostFocus="PlzInput_LostFocus" Tag="PLZ"/>
<ComboBox x:Name="OrtInput" SelectedItem="{Binding Ort, Mode=TwoWay}" ItemsSource="{Binding OrtSource, Mode=TwoWay}"
ItemTemplate="{StaticResource PostalDestTemplate}" TextSearch.TextPath="Ort.Name"
SelectionChanged="OrtInput_SelectionChanged"
Margin="47,160,10,0" Grid.Column="1" Grid.ColumnSpan="3"/>
</Grid>
</GroupBox>
@@ -548,48 +547,35 @@
<GroupBox Header="Betrieb" Grid.Column="1" Grid.Row="0" Grid.RowSpan="1" Margin="5,5,5,5">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="85"/>
<ColumnDefinition Width="69"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="55"/>
<ColumnDefinition Width="101"/>
<ColumnDefinition Width="90"/>
<ColumnDefinition Width="150"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Label Content="Betriebs-Nr.:" Margin="10,10,0,0" Grid.Column="0"/>
<TextBox x:Name="LfbisNrInput" Text="{Binding LfbisNr, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,10,5,0" Grid.Column="1" Width="64" HorizontalAlignment="Left" TextAlignment="Right"
TextChanged="LfbisNrInput_TextChanged" LostFocus="LfbisNrInput_LostFocus"/>
<Label Content="UID:" Margin="10,40,0,0" Grid.Column="0" ToolTip="USt-IdNr. / Umsatzsteuer-Identifikationsnummer"/>
<Label Content="UID:" Margin="10,10,0,0" Grid.Column="0"/>
<TextBox x:Name="UstIdNrInput" Text="{Binding UstIdNr, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,40,5,0" Grid.Column="0" Grid.ColumnSpan="2" Width="96" HorizontalAlignment="Right"
Margin="0,10,10,0" Grid.Column="1" Width="96" HorizontalAlignment="Left"
TextChanged="UstIdNrInput_TextChanged" LostFocus="UstIdNrInput_LostFocus"/>
<CheckBox x:Name="OrganicInput" Content="Bio" IsChecked="{Binding IsOrganic, Mode=TwoWay}" IsEnabled="False"
Checked="OrganicInput_Changed" Unchecked="OrganicInput_Changed"
Grid.Column="2" HorizontalAlignment="Left" Margin="5,15,0,0" VerticalAlignment="Top"/>
<Label Content="Betriebs-Nr.:" Margin="10,40,0,0" Grid.Column="0"/>
<TextBox x:Name="LfbisNrInput" Text="{Binding LfbisNr, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,40,10,0" Grid.Column="1" Width="64" HorizontalAlignment="Left" TextAlignment="Right"
TextChanged="LfbisNrInput_TextChanged" LostFocus="LfbisNrInput_LostFocus"/>
<CheckBox x:Name="AccountingInput" Content="Buchführend" IsChecked="{Binding IsAccounting, Mode=TwoWay}" IsEnabled="False"
<CheckBox x:Name="BuchführendInput" Content="Buchführend" IsChecked="{Binding IsBuchführend, Mode=TwoWay}" IsEnabled="False"
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"
Grid.Column="2" HorizontalAlignment="Left" Margin="5,45,0,0" VerticalAlignment="Top"/>
Grid.Column="2" HorizontalAlignment="Left" Margin="10,15,0,0" VerticalAlignment="Top"/>
<Label Content="Kontrollstelle:" Margin="0,10,5,0" Grid.Column="2" Grid.ColumnSpan="2" HorizontalAlignment="Right" ToolTip="Bio-Kontrollstelle"/>
<TextBox x:Name="OrganicAuthorityCodeInput" Text="{Binding OrganicAuthorityCode, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,10,10,0" Grid.Column="4" Width="91" HorizontalAlignment="Left"
TextChanged="OrganicAuthorityCodeInput_TextChanged" LostFocus="OrganicAuthorityCodeInput_LostFocus"/>
<Label Content="OOC-ID:" Margin="0,40,0,0" Grid.Column="3" HorizontalAlignment="Left" ToolTip="Bio-EU-Operator-ID / Organic Operator Certificate ID"/>
<TextBox x:Name="OrganicOperatorIdInput" Text="{Binding OrganicOperatorId, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,40,10,0" Grid.Column="4" Width="91" HorizontalAlignment="Left"
TextChanged="OrganicOperatorIdInput_TextChanged" LostFocus="OrganicOperatorIdInput_LostFocus"/>
<CheckBox x:Name="OrganicInput" Content="Bio" IsChecked="{Binding IsOrganic, Mode=TwoWay}" IsEnabled="False"
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"
Grid.Column="2" HorizontalAlignment="Left" Margin="10,45,0,0" VerticalAlignment="Top"/>
<Button x:Name="OrganicButton" Content="easy-cert.com" IsEnabled="{Binding IsMemberSelected}"
Height="25" FontSize="12"
Click="OrganicButton_Click"
Grid.Column="2" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="60,40,0,0"/>
</Grid>
</GroupBox>
<GroupBox Grid.Column="1" Grid.Row="1" Grid.RowSpan="2" Margin="5,5,5,5">
<GroupBox.Header>
<TextBlock>Rechnungsadresse (optional)
<Run FontSize="10">für Lieferschein, Anlfrg.-Bstng., Tr.-Gutschr.</Run>
</TextBlock>
</GroupBox.Header>
<GroupBox Header="Rechnungsadresse (optional)" Grid.Column="1" Grid.Row="1" Grid.RowSpan="2" Margin="5,5,5,5">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="65"/>
@@ -604,7 +590,7 @@
<Label Content="Adresse:" Margin="10,40,0,0" Grid.Column="0"/>
<TextBox x:Name="BillingAddressInput" Text="{Binding BillingAddress, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,40,10,0" Grid.Column="1"
TextChanged="AddressInput_TextChanged"/>
TextChanged="TextBox_TextChanged"/>
<Label Content="PLZ/Ort:" Margin="10,70,0,0" Grid.Column="0"/>
<TextBox x:Name="BillingPlzInput" Text="{Binding BillingPlzString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
@@ -612,7 +598,6 @@
TextChanged="PlzInput_TextChanged" LostFocus="PlzInput_LostFocus" Tag="PLZ"/>
<ComboBox x:Name="BillingOrtInput" SelectedItem="{Binding BillingOrt, Mode=TwoWay}" ItemsSource="{Binding BillingOrtSource, Mode=TwoWay}"
ItemTemplate="{StaticResource PostalDestTemplate}" TextSearch.TextPath="Ort.Name"
SelectionChanged="OrtInput_SelectionChanged"
Margin="47,70,10,0" Grid.Column="1"/>
</Grid>
</GroupBox>
@@ -620,8 +605,7 @@
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120"/>
<ColumnDefinition Width="90"/>
<ColumnDefinition Width="90"/>
<ColumnDefinition Width="120"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
@@ -635,7 +619,7 @@
Margin="0,40,10,0" Width="78" Grid.Column="1" HorizontalAlignment="Left" TextAlignment="Right"
TextChanged="DateInput_TextChanged" LostFocus="DateInput_LostFocus"/>
<Label Content="BH-Konto:" Margin="10,70,0,0" Grid.Column="0" ToolTip="Buchhaltungskonto"/>
<Label Content="BH-Konto:" Margin="10,70,0,0" Grid.Column="0"/>
<TextBox x:Name="AccountingNrInput" Text="{Binding AccountingNr, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,70,10,0" Width="63" Grid.Column="1" HorizontalAlignment="Left"
TextChanged="TextBox_TextChanged"/>
@@ -658,64 +642,46 @@
<CheckBox x:Name="ActiveInput" Content="Aktiv" IsChecked="{Binding IsActive, Mode=TwoWay}" IsEnabled="False"
Checked="ActiveInput_Changed" Unchecked="ActiveInput_Changed"
Grid.Column="2" HorizontalAlignment="Left" Margin="0,15,0,0" VerticalAlignment="Top"/>
Grid.Column="2" HorizontalAlignment="Left" Margin="10,15,0,0" VerticalAlignment="Top"/>
<CheckBox x:Name="FullDeliveryInput" Content="Vollablieferer" IsChecked="{Binding IsFullDelivery, Mode=TwoWay}" IsEnabled="False"
<CheckBox x:Name="VollLieferantInput" Content="Volllieferant" IsChecked="{Binding IsVollLieferant, Mode=TwoWay}" IsEnabled="False"
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"
Grid.Column="2" HorizontalAlignment="Left" Margin="0,45,0,0" VerticalAlignment="Top"/>
Grid.Column="2" HorizontalAlignment="Left" Margin="10,45,0,0" VerticalAlignment="Top"/>
<CheckBox x:Name="OfficerInput" Content="Funktionär" IsChecked="{Binding IsOfficer, Mode=TwoWay}" IsEnabled="False"
<CheckBox x:Name="FunkionärInput" Content="Funktionär" IsChecked="{Binding IsFunktionär, Mode=TwoWay}" IsEnabled="False"
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"
Grid.Column="2" HorizontalAlignment="Left" Margin="0,75,0,0" VerticalAlignment="Top"/>
<Label Content="Bio-Zertifikate:" Margin="0,-2.5,20,0" Grid.Column="3" HorizontalAlignment="Right"/>
<Button x:Name="OrganicTracesButton" IsEnabled="{Binding IsMemberSelectedOrCreating}" ToolTip="{Binding OrganicToolTip}"
Click="OrganicTracesButton_Click"
HorizontalAlignment="Right" Margin="0,20,10,0" Width="100" Padding="0" Height="35" VerticalAlignment="Top" Grid.Column="2" Grid.ColumnSpan="2" HorizontalContentAlignment="Stretch">
<StackPanel Orientation="Vertical">
<TextBlock FontSize="12" TextAlignment="Center" VerticalAlignment="Top" Margin="0,0,0,-3">EU TRACES</TextBlock>
<TextBlock FontSize="10" TextAlignment="Center" VerticalAlignment="Bottom" Margin="0,0,0,0">
<Run Text="{Binding OrganicState}" FontWeight="Bold" Foreground="{Binding OrganicColor}"/><Run Text="{Binding OrganicDetails}"/>
</TextBlock>
</StackPanel>
</Button>
<Button x:Name="OrganicEasyCertButton" IsEnabled="{Binding IsMemberSelectedOrCreating}" Content="Easy-Cert"
Click="OrganicEasyCertButton_Click"
HorizontalAlignment="Right" Margin="0,60,10,0" Width="100" Height="30" VerticalAlignment="Top" Grid.Column="2" Grid.ColumnSpan="2"/>
<Button x:Name="OrganicBiocButton" IsEnabled="{Binding IsMemberSelectedOrCreating}" Content="BioC"
Click="OrganicBiocButton_Click"
HorizontalAlignment="Right" Margin="0,95,10,0" Width="100" Height="30" VerticalAlignment="Top" Grid.Column="2" Grid.ColumnSpan="2"/>
Grid.Column="2" HorizontalAlignment="Left" Margin="10,75,0,0" VerticalAlignment="Top"/>
<Label Content="Stamm-Zwst.:" Margin="10,130,0,0" Grid.Column="0"/>
<ComboBox x:Name="BranchInput" SelectedItem="{Binding Branch, Mode=TwoWay}" ItemsSource="{Binding BranchSource, Mode=TwoWay}"
DisplayMemberPath="Name" TextSearch.TextPath="Name"
Margin="0,130,10,0" Grid.Column="1" Grid.ColumnSpan="3"/>
Margin="0,130,10,0" Grid.Column="1" Grid.ColumnSpan="2"/>
<Label Content="Stammgemeinde:" Margin="10,160,0,0" Grid.Column="0"/>
<ComboBox x:Name="DefaultKgInput" SelectedItem="{Binding DefaultKg, Mode=TwoWay}" ItemsSource="{Binding DefaultKgSource, Mode=TwoWay}"
DisplayMemberPath="Name" TextSearch.TextPath="Name"
Margin="0,160,40,10" Grid.Column="1" Grid.ColumnSpan="3"/>
Margin="0,160,40,10" Grid.Column="1" Grid.ColumnSpan="2"/>
<Button x:Name="KgDetailsButton" Content="&#xE712;" FontFamily="Segoe MDL2 Assets" FontSize="14" Padding="0,1,0,0"
Click="KgDetailsButton_Click"
Grid.Column="3" VerticalAlignment="Top" HorizontalAlignment="Right" Width="25" Height="25" Margin="10,160,10,10"/>
Grid.Column="2" VerticalAlignment="Top" HorizontalAlignment="Right" Width="25" Height="25" Margin="10,160,10,10"/>
<Label Content="Anmerkung:" Margin="10,190,0,0" Grid.Column="0"/>
<TextBox x:Name="CommentInput" Text="{Binding Comment, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,190,10,70" Grid.Column="1" Grid.ColumnSpan="3" FontSize="12"
Margin="0,190,10,70" Grid.Column="1" Grid.ColumnSpan="2" FontSize="12"
TextChanged="TextBox_TextChanged"
VerticalAlignment="Stretch" Height="auto" AcceptsReturn="True" TextWrapping="Wrap" VerticalScrollBarVisibility="Visible"/>
<Label Content="Kontaktart:" Margin="10,10,0,40" Grid.Column="0" VerticalAlignment="Bottom"/>
<CheckBox x:Name="ContactPostalInput" Content="Post" IsChecked="{Binding ContactViaPost, Mode=TwoWay}" IsEnabled="False"
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"
HorizontalAlignment="Left" Margin="0,0,0,45" VerticalAlignment="Bottom" Grid.Column="1" Grid.ColumnSpan="3"/>
HorizontalAlignment="Left" Margin="0,0,0,45" VerticalAlignment="Bottom" Grid.Column="1" Grid.ColumnSpan="2"/>
<CheckBox x:Name="ContactEmailInput" Content="E-Mail" IsChecked="{Binding ContactViaEmail, Mode=TwoWay}" IsEnabled="False"
Checked="ContactEmailInput_Changed" Unchecked="ContactEmailInput_Changed"
HorizontalAlignment="Left" Margin="60,0,0,45" VerticalAlignment="Bottom" Grid.Column="1" Grid.ColumnSpan="3"/>
HorizontalAlignment="Left" Margin="60,0,0,45" VerticalAlignment="Bottom" Grid.Column="1" Grid.ColumnSpan="2"/>
<Label Content="Zuletzt geändert:" Margin="10,10,0,10" Grid.Column="0" VerticalAlignment="Bottom"/>
<TextBlock x:Name="LastModified" Text="{Binding ModifiedAtShort}"
Margin="0,10,0,15" Grid.Column="1" Grid.ColumnSpan="2" TextWrapping="NoWrap" VerticalAlignment="Bottom">
Margin="0,10,0,15" Grid.Column="1" TextWrapping="NoWrap" VerticalAlignment="Bottom">
<TextBlock.ToolTip>
<Grid>
<Grid.ColumnDefinitions>
@@ -742,7 +708,7 @@
<Button x:Name="DeliveryButton" IsEnabled="{Binding IsMemberSelected}"
Click="DeliveryButton_Click"
HorizontalAlignment="Right" Margin="10,00,10,37" Width="160" VerticalAlignment="Bottom" Grid.ColumnSpan="4" HorizontalContentAlignment="Stretch">
HorizontalAlignment="Right" Margin="10,00,10,37" Width="160" VerticalAlignment="Bottom" Grid.ColumnSpan="3" HorizontalContentAlignment="Stretch">
<Grid>
<TextBlock Margin="0,0,10,0" TextAlignment="Center">Lieferungen</TextBlock>
<TextBlock FontFamily="Segoe MDL2 Assets" FontSize="16" Text="&#xE8A7;"
@@ -751,7 +717,7 @@
</Button>
<Button x:Name="AreaCommitmentButton" IsEnabled="{Binding IsMemberSelected}"
Click="AreaCommitmentButton_Click"
HorizontalAlignment="Right" Margin="10,10,10,5" Width="160" VerticalAlignment="Bottom" Grid.ColumnSpan="4" HorizontalContentAlignment="Stretch">
HorizontalAlignment="Right" Margin="10,10,10,5" Width="160" VerticalAlignment="Bottom" Grid.ColumnSpan="3" HorizontalContentAlignment="Stretch">
<Grid>
<TextBlock Margin="0,0,15,0" TextAlignment="Center">Flächenbindungen</TextBlock>
<TextBlock FontFamily="Segoe MDL2 Assets" FontSize="16" Text="&#xE8A7;"
+15 -102
View File
@@ -147,9 +147,9 @@ namespace Elwig.Windows {
var cursor = Mouse.OverrideCursor != null;
if (!cursor) Mouse.OverrideCursor = Cursors.Wait;
var query = (vm.SearchQuery, vm.ShowOnlyActiveMembers);
var (filterNames, members, stat, filter) = await Task.Run(async () => {
var (members, stat) = await Task.Run(async () => {
using var ctx = new AppDbContext();
var (filterNames, memberQuery, filter) = await vm.GetFilters(ctx);
var (_, memberQuery, filter) = await vm.GetFilters(ctx);
var members = await memberQuery
.Include(m => m.EmailAddresses)
.Include(m => m.TelephoneNumbers)
@@ -184,12 +184,11 @@ namespace Elwig.Windows {
SharesActive = g.Sum(m => m.Shares + m.SharesRed + m.SharesWhite),
}).ToListAsync()).Select(g => (g.Count, g.Shares, g.SharesRed, g.SharesWhite, g.SharesDormant, g.SharesTotal, g.SharesActive)).ToList();
return (filterNames, members, stat[0], filter);
return (members, stat[0]);
});
if (!cursor) Mouse.OverrideCursor = null;
if (query != (ViewModel.SearchQuery, ViewModel.ShowOnlyActiveMembers)) return;
ViewModel.Title = Utils.GetTitle("Mitglieder", filterNames, filter);
ControlUtils.RenewItemsSource(MemberList, members,
MemberList_SelectionChanged, ViewModel.TextFilter.Count > 0 ? ControlUtils.RenewSourceDefault.IfOnly : ControlUtils.RenewSourceDefault.None, !updateSort);
if (updateSort && MemberList.SelectedItem != null)
@@ -503,8 +502,6 @@ namespace Elwig.Windows {
UnlockInputs();
UpdateContactInfoVisibility(true);
ViewModel.EnableSearchInputs = false;
UpdateOrganic();
}
protected override void ShortcutDelete() {
@@ -968,13 +965,23 @@ namespace Elwig.Windows {
}
}
private void OrganicButton_Click(object sender, RoutedEventArgs evt) {
if (ViewModel.SelectedMember is not Member m) return;
var url = "https://www.easy-cert.com/htm/suchergebnis.htm?" +
//$"CustomerNumber={m.LfbisNr}&" +
$"Name={(m.BillingAddress?.FullName ?? m.FullName).Replace(' ', '+')}&" +
$"PostalCode={(m.BillingAddress?.PostalDest ?? m.PostalDest).AtPlz?.Plz}";
Process.Start(new ProcessStartInfo(url) {
UseShellExecute = true,
});
}
private void MemberReferenceButton_Click(object sender, RoutedEventArgs evt) {
if (ViewModel.SelectedMember is not Member m || m.PredecessorMgNr == null) return;
FocusMember((int)m.PredecessorMgNr);
}
private async void ActiveInput_Changed(object sender, RoutedEventArgs evt) {
CheckBox_Changed(sender, evt);
if (MemberList.SelectedItem is not Member m)
return;
if ((IsEditing || IsCreating) && ViewModel.IsActive == false && ViewModel.MgNr is int mgnr) {
@@ -989,6 +996,7 @@ namespace Elwig.Windows {
}
}
}
CheckBox_Changed(sender, evt);
}
private void JuridicalPersonInput_Changed(object sender, RoutedEventArgs evt) {
@@ -1011,100 +1019,5 @@ namespace Elwig.Windows {
ValidateRequiredInputs();
UpdateButtons();
}
new protected void AddressInput_TextChanged(object sender, TextChangedEventArgs? evt) {
if ((IsCreating || IsEditing) && sender is TextBox b) {
InputTextChanged(b, (i, r) => Validator.CheckAddress(i, r, b == BillingAddressInput ? ViewModel.BillingOrt?.Ort.Name : ViewModel.Ort?.Ort.Name));
} else {
TextBox_TextChanged(sender, evt);
}
}
private void OrtInput_SelectionChanged(object sender, SelectionChangedEventArgs? evt) {
if (!IsCreating && !IsEditing)
return;
if (sender == BillingOrtInput) {
InputTextChanged(BillingAddressInput, (i, r) => Validator.CheckAddress(i, r, ViewModel.BillingOrt?.Ort.Name));
} else {
InputTextChanged(AddressInput, (i, r) => Validator.CheckAddress(i, r, ViewModel.Ort?.Ort.Name));
}
}
private void OrganicInput_Changed(object sender, RoutedEventArgs evt) {
CheckBox_Changed(sender, evt);
if (IsEditing || IsCreating) {
UpdateOrganic();
}
}
private new void LfbisNrInput_TextChanged(object sender, TextChangedEventArgs evt) {
base.LfbisNrInput_TextChanged(sender, evt);
if (IsEditing || IsCreating) {
UpdateOrganic();
}
}
private void UpdateOrganic() {
if (!ViewModel.IsOrganic || string.IsNullOrWhiteSpace(ViewModel.LfbisNr) || !GetInputValid(LfbisNrInput)) {
ViewModel.OrganicState = null;
ViewModel.OrganicColor = Brushes.Black;
ViewModel.OrganicDetails = "-";
ViewModel.OrganicToolTip = null;
return;
} else {
ViewModel.OrganicState = null;
ViewModel.OrganicColor = Brushes.Black;
ViewModel.OrganicToolTip = null;
ViewModel.OrganicDetails = "...";
var lfbisNr = ViewModel.LfbisNr;
Utils.RunBackground("Bio-Zertifikatsdaten laden", async () => {
if (App.MainDispatcher == null) return;
var certs = await OrganicService.FetchTracesCertificates(lfbisNr: lfbisNr);
await App.MainDispatcher.BeginInvoke(() => {
if (certs.Length == 0) {
ViewModel.FillOrganicInputs(null);
} else {
var cert = certs[0];
ViewModel.FillOrganicInputs(cert);
ViewModel.OrganicAuthorityCode = cert.AuthorityCode;
ViewModel.OrganicOperatorId = cert.OperatorId;
}
});
});
}
}
private void OrganicTracesButton_Click(object sender, RoutedEventArgs evt) {
string? url = null;
if ((IsCreating || IsEditing) && !string.IsNullOrWhiteSpace(ViewModel.LfbisNr) && GetInputValid(LfbisNrInput)) {
url = OrganicService.GetTracesSearchUrl(lfbisNr: ViewModel.LfbisNr);
} else if (ViewModel.SelectedMember is Member m) {
url = OrganicService.GetTracesSearchUrl(m);
}
if (url != null)
Process.Start(new ProcessStartInfo(url) { UseShellExecute = true });
}
private void OrganicEasyCertButton_Click(object sender, RoutedEventArgs evt) {
string? url = null;
if ((IsCreating || IsEditing) && !string.IsNullOrWhiteSpace(ViewModel.LfbisNr) && GetInputValid(LfbisNrInput)) {
url = OrganicService.GetEasyCertSearchUrl(ViewModel.LfbisNr);
} else if (ViewModel.SelectedMember is Member m && m.LfbisNr != null) {
url = OrganicService.GetEasyCertSearchUrl(m.LfbisNr);
}
if (url != null)
Process.Start(new ProcessStartInfo(url) { UseShellExecute = true });
}
private void OrganicBiocButton_Click(object sender, RoutedEventArgs evt) {
string? url = null;
if ((IsCreating || IsEditing) && !string.IsNullOrWhiteSpace(ViewModel.LfbisNr) && GetInputValid(LfbisNrInput)) {
url = OrganicService.GetBiocSearchUrl(ViewModel.LfbisNr);
} else if (ViewModel.SelectedMember is Member m && m.LfbisNr != null) {
url = OrganicService.GetBiocSearchUrl(m.LfbisNr);
}
if (url != null)
Process.Start(new ProcessStartInfo(url) { UseShellExecute = true });
}
}
}
@@ -173,11 +173,8 @@
Margin="0,100,10,0" Width="78" Grid.Column="1" HorizontalAlignment="Left" TextAlignment="Right"
TextChanged="DateNoticeInput_TextChanged" LostFocus="DateInput_LostFocus"/>
<CheckBox x:Name="HasCompanySignedInput" IsChecked="{Binding CompanyHasSigned, Mode=TwoWay}" Content="Von WG unterfertigt"
Margin="88,105,10,0" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Top"
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"/>
<CheckBox x:Name="HasMemberSignedInput" IsChecked="{Binding MemberHasSigned, Mode=TwoWay}" Content="Von Mg. unterfertigt"
Margin="88,135,10,0" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Top"
Margin="88,105,10,0" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="TOp"
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"/>
<Label Content="Wirksam:" Margin="10,130,0,0" Grid.Column="0"/>
@@ -198,7 +198,7 @@ namespace Elwig.Windows {
int mgnr;
try {
mgnr = await ViewModel.UpdateMemberHistory(ViewModel.SelectedHistoryEntry?.HistNr, IsEditing || ViewModel.DateNotice >= DateOnly.FromDateTime(DateTime.Today).AddDays(-14));
mgnr = await ViewModel.UpdateMemberHistory(ViewModel.SelectedHistoryEntry?.HistNr, IsEditing || ViewModel.DateNotice >= DateOnly.FromDateTime(Utils.Today).AddDays(-14));
App.HintContextChange();
} catch (Exception exc) {
InteractionService.ShowDbException("Geschäftsanteilbewegung aktualisieren", exc);
-1
View File
@@ -13,6 +13,5 @@ Data and configuration folder
C:\ProgramData\Elwig\
- config.ini : main configuration file
- database.sqlite3 : stores all data
- backups\ : (automatic) backups of the database
- imported.txt : list of all imported *.elwig.zip files to not automatically import them again
- mails\ : sent/outgoing email log
+2 -11
View File
@@ -3,22 +3,15 @@
; Only needed, if more than one branch is stored in database
;branch = Zweigstelle
;debug = true
;weighing = gross ; gross/net/box
[database]
; Relative or absolute path to database file
file = database.sqlite3
; Enables automatic compressed database backups
backup = true
; Enables database logging
;log = db.log
[backup]
;auto = false
;path = backups
;retain_hours = 36
;retain_days = 8
;retain_weeks = 6
;retain_months = 18
[update]
url = https://elwig.at/files/elwig/latest
auto = true
@@ -47,8 +40,6 @@ auto = true
;limit = 3500
; Enables scale logging
;log = waage.log
; Opt-out of auto time synchronization at startup
;synctime = false
;[scale.B]
;type = Avery-Async
+2 -2
View File
@@ -13,7 +13,7 @@ About
**Product:** Elwig
**Description:** Electronic Management for Vintners' Cooperatives
**Type:** ERP system
**Version:** 1.1.2.2 ([Changelog](./CHANGELOG.md))
**Version:** 1.1.1.1 ([Changelog](./CHANGELOG.md))
**License:** [GNU General Public License 3.0 (GPLv3)](./LICENSE)
**Website:** https://elwig.at/
**Source code:** https://git.necronda.net/winzer/elwig
@@ -33,7 +33,7 @@ Packaging: [WiX Toolset](https://www.firegiant.com/wixtoolset/)
**Produkt:** Elwig
**Beschreibung:** Elektronische Winzergenossenschaftsverwaltung
**Typ:** Warenwirtschaftssystem (ERP-System)
**Version:** 1.1.2.2 ([Änderungsprotokoll](./CHANGELOG.md))
**Version:** 1.1.1.1 ([Änderungsprotokoll](./CHANGELOG.md))
**Lizenz:** [GNU General Public License 3.0 (GPLv3)](./LICENSE)
**Website:** https://elwig.at/
**Quellcode:** https://git.necronda.net/winzer/elwig
+11
View File
@@ -1,5 +1,6 @@
using Elwig;
using Elwig.Helpers;
using Elwig.Helpers.Billing;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using System.Reflection;
@@ -25,6 +26,16 @@ namespace Tests {
App.SetBranch(ctx.Branches.Include(b => b.PostalDest).Single());
}
[OneTimeSetUp]
public async Task Setup_3_BillingData() {
await BillingData.Init();
}
[OneTimeSetUp]
public void Setup_4_Culture() {
Utils.OverrideCulture();
}
[OneTimeTearDown]
public async Task TeardownDatabase() {
AppDbContext.ConnectionStringOverride = null;
@@ -67,10 +67,7 @@ namespace Tests.E2ETests {
window.FindElement(By.WpfId("MemberInput")).SendKeys("Mustermann Max");
window.FindElement(By.WpfId("WineVarietyInput")).SelectItem("Zweigelt");
window.FindElement(By.WpfId("GradationKmwInput")).SendKeys("18");
window.FindElement(By.WpfId("WeighingManualButton")).Click();
var dialog = Session.CreateWindowDriver("ManualWeighingDialog");
dialog.FindElement(By.WpfId("WeightInput")).SendKeys("2468");
dialog.FindElement(By.WpfId("ConfirmButton")).Click();
window.FindElement(By.Name("Wiegen")).Click();
FinishDeliveryNote(window);
window.Close();
}
@@ -79,7 +76,7 @@ namespace Tests.E2ETests {
public void Test_3_AttributeCultivationModifier() {
var window = OpenReceiptWindow();
window.FindElement(By.WpfId("MgNrInput")).SendKeys("102" + Keys.Enter + "GVK");
window.FindElement(By.WpfId("CultivationInput")).SelectItem("KIP");
window.FindElement(By.WpfId("CultivationInput")).SelectItem("Bio");
window.FindElement(By.WpfId("GradationOeInput")).SendKeys("73" + Keys.Enter + Keys.Enter);
FinishDeliveryNote(window);
window.Close();
+3 -14
View File
@@ -20,18 +20,7 @@ namespace Tests.E2ETests {
Session.App.FindElement(By.Name("Mitglieder")).Click();
Thread.Sleep(Utils.WINDOW_OPEN_SLEEP);
var window = Session.CreateWindowDriver("MemberAdminWindow");
Assert.That(window.Title, Is.EqualTo("Mitglieder: aktive Mitglieder - Elwig"));
window.Close();
});
}
[Test]
public void Test_Open_DeliveryAncmtWindow() {
Assert.DoesNotThrow(() => {
Session.App.FindElement(By.Name("Anmeldungen")).Click();
Thread.Sleep(Utils.WINDOW_OPEN_SLEEP);
var window = Session.CreateWindowDriver("DeliveryAncmtWindow");
Assert.That(window.Title, Is.EqualTo($"Anmeldungen: {DateTime.Today.Year} - Elwig"));
Assert.That(window.Title, Is.EqualTo("Mitglieder - Elwig"));
window.Close();
});
}
@@ -42,7 +31,7 @@ namespace Tests.E2ETests {
Session.App.FindElement(By.Name("Lieferungen")).Click();
Thread.Sleep(Utils.WINDOW_OPEN_SLEEP);
var window = Session.CreateWindowDriver("DeliveryAdminWindow");
Assert.That(window.Title, Is.EqualTo($"Lieferungen: {DateTime.Now.Year} - Elwig"));
Assert.That(window.Title, Is.EqualTo("Lieferungen - Elwig"));
window.Close();
});
}
@@ -64,7 +53,7 @@ namespace Tests.E2ETests {
Session.App.FindElement(By.Name("Rundschreiben")).Click();
Thread.Sleep(Utils.WINDOW_OPEN_SLEEP);
var window = Session.CreateWindowDriver("MailWindow");
Assert.That(window.Title, Is.EqualTo($"Rundschreiben - Lese {DateTime.Today.Year} - Elwig"));
Assert.That(window.Title, Is.EqualTo($"Rundschreiben - Lese {Elwig.Helpers.Utils.Today.Year} - Elwig"));
window.Close();
});
}
+13 -13
View File
@@ -57,10 +57,10 @@ namespace Tests.E2ETests {
Window.FindElement(By.WpfId("IbanInput")).SendKeys("AT611904300234573201");
Window.FindElement(By.WpfId("BicInput")).SendKeys("RLNWATWWWDF");
Window.FindElement(By.WpfId("UstIdNrInput")).SendKeys("ATU01234565");
Window.FindElement(By.WpfId("LfbisNrInput")).SendKeys("0123455");
Window.FindElement(By.WpfId("UstIdNrInput")).SendKeys("ATU66192906"); // TODO: Testdaten?
Window.FindElement(By.WpfId("LfbisNrInput")).SendKeys("1251074"); // TODO: Testdaten?
Window.FindElement(By.WpfId("AccountingInput")).Click();
Window.FindElement(By.WpfId("BuchführendInput")).Click();
Window.FindElement(By.WpfId("OrganicInput")).Click();
Window.FindElement(By.WpfId("BillingNameInput")).SendKeys("Neuling KG");
@@ -68,12 +68,12 @@ namespace Tests.E2ETests {
Window.FindElement(By.WpfId("BillingPlzInput")).SendKeys("2120");
Window.FindElement(By.WpfId("BillingOrtInput")).SelectItem(2);
Window.FindElement(By.WpfId("BusinessShares1Input")).SendKeys("10");
Window.FindElement(By.WpfId("BusinessSharesInput")).SendKeys("10");
Window.FindElement(By.WpfId("BranchInput")).SelectItem("Matzen");
Window.FindElement(By.WpfId("DefaultKgInput")).SelectItem(3);
Window.FindElement(By.WpfId("FullDeliveryInput")).Click();
Window.FindElement(By.WpfId("OfficerInput")).Click();
Window.FindElement(By.WpfId("VollLieferantInput")).Click();
Window.FindElement(By.WpfId("FunkionärInput")).Click();
Window.FindElement(By.WpfId("CommentInput")).SendKeys("Die lieben Mustermänner und Musterfrauen!");
Window.FindElement(By.WpfId("ContactEmailInput")).Click();
@@ -84,15 +84,15 @@ namespace Tests.E2ETests {
Window.FindElement(By.WpfId("SearchInput")).SendKeys("9999");
Thread.Sleep(500);
var memberListRow = Window.FindElement(By.WpfId("MemberList")).FindElement(By.ClassName("DataGridRow"));
using (Assert.EnterMultipleScope()) {
Assert.Multiple(() => {
Assert.That(memberListRow, Is.Not.Null);
Assert.That(memberListRow.FindElement(By.Name("9999 ")), Is.Not.Null);
Assert.That(memberListRow.FindElement(By.Name("Norbert")), Is.Not.Null);
Assert.That(memberListRow.FindElement(By.Name("Neuling")), Is.Not.Null);
}
});
}
[Test, DependsOnTest("Test_1_CreateMember")]
[Test]
public void Test_2_EditMember() {
Window!.FindElement(By.WpfId("SearchInput")).SendKeys("9999");
Thread.Sleep(500);
@@ -104,7 +104,7 @@ namespace Tests.E2ETests {
Window.FindElement(By.WpfId("EditMemberButton")).Click();
var businessSharesInput = Window.FindElement(By.WpfId("BusinessShares1Input"));
var businessSharesInput = Window.FindElement(By.WpfId("BusinessSharesInput"));
Assert.That(businessSharesInput, Is.Not.Null);
var businessShares = int.Parse(businessSharesInput.Text);
@@ -117,7 +117,7 @@ namespace Tests.E2ETests {
Assert.That(newBusinessShares, Is.EqualTo(businessShares + 5));
}
[Test, DependsOnTest("Test_2_EditMember")]
[Test]
public void Test_3_DeleteMember() {
Window!.FindElement(By.WpfId("SearchInput")).SendKeys("9999");
Thread.Sleep(500);
@@ -128,12 +128,12 @@ namespace Tests.E2ETests {
Assert.That(memberListRows, Has.Count.EqualTo(1));
var memberListRow = memberListRows.First();
using (Assert.EnterMultipleScope()) {
Assert.Multiple(() => {
Assert.That(memberListRow, Is.Not.Null);
Assert.That(memberListRow.FindElement(By.Name("9999 ")), Is.Not.Null);
Assert.That(memberListRow.FindElement(By.Name("Norbert")), Is.Not.Null);
Assert.That(memberListRow.FindElement(By.Name("Neuling")), Is.Not.Null);
}
});
Window.FindElement(By.WpfId("DeleteMemberButton")).Click();
var dialog = Session.CreateWindowDriver("DeleteMemberDialog");
-20
View File
@@ -1,20 +0,0 @@
using Elwig.Services;
namespace Tests {
[SetUpFixture]
public class InteractionSetup {
[OneTimeSetUp]
public void Setup() {
InteractionService.Override = (mode, title, text) => {
Assert.Fail($"User interaction requested: {mode} - {title} - {text}");
return null;
};
}
[OneTimeTearDown]
public void Teardown() {
InteractionService.Override = null;
}
}
}
+4 -4
View File
@@ -1,8 +1,8 @@
-- inserts for HelperTests.BillingTest
INSERT INTO wine_cultivation (cultid, name, description, organic) VALUES
('KIP', 'KIP', 'Kontrollierte Integrierte Produktion', FALSE),
('B', 'Bio', 'Biologische Produktion', TRUE);
INSERT INTO wine_cultivation (cultid, name, description) VALUES
('KIP', 'KIP', 'Kontrollierte Integrierte Produktion'),
('B', 'Bio', 'AT-BIO-302');
INSERT INTO wine_attribute (attrid, name, active, max_kg_per_ha, strict, fill_lower) VALUES
('K', 'Kabinett', TRUE, NULL, FALSE, 0),
@@ -60,7 +60,7 @@ INSERT INTO delivery (mgnr, year, did, date, time, zwstid, lnr) VALUES
(101, 2021, 1, '2021-10-01', NULL, 'X', 1),
(101, 2021, 2, '2021-10-01', NULL, 'X', 2),
(101, 2021, 3, '2021-10-01', NULL, 'X', 3);
INSERT INTO delivery_part (year, did, dpnr, sortid, attrid, cultid, weight, kmw, qualid, hkid, kgnr, contracted, net_weight, manual_weighing, spl_check, scale_terminal, weighing_data, weighing_reason) VALUES
INSERT INTO delivery_part (year, did, dpnr, sortid, attrid, cultid, weight, kmw, qualid, hkid, kgnr, gebunden, net_weight, manual_weighing, spl_check, scale_terminal, weighing_data, weighing_reason) VALUES
(2021, 1, 1, 'GV', 'K', NULL, 4000, 17, 'KAB', 'WLNO', 06109, TRUE, TRUE, FALSE, FALSE, NULL, NULL, NULL),
(2021, 1, 2, 'GV', NULL, NULL, 4000, 16, 'QUW', 'WLNO', 06109, FALSE, TRUE, FALSE, FALSE, NULL, NULL, NULL),
(2021, 2, 1, 'GV', NULL, 'B', 4000, 15, 'QUW', 'WLNO', 06109, TRUE, TRUE, FALSE, FALSE, NULL, NULL, NULL),
+2 -2
View File
@@ -1,7 +1,7 @@
-- inserts for DocumentTests
INSERT INTO wine_cultivation (cultid, name, description, organic) VALUES
('B', 'Bio', 'Biologische Produktion', TRUE);
INSERT INTO wine_cultivation (cultid, name, description) VALUES
('B', 'Bio', 'AT-BIO-302');
INSERT INTO wine_attribute (attrid, name, active, max_kg_per_ha, strict, fill_lower) VALUES
('K', 'Kabinett', TRUE, NULL, FALSE, 0);
+3 -3
View File
@@ -1,8 +1,8 @@
-- inserts for E2ETests
INSERT INTO wine_cultivation (cultid, name, description, organic) VALUES
('KIP', 'KIP', 'Kontrollierte Integrierte Produktion', FALSE),
('B', 'Bio', 'Biologische Produktion', TRUE);
INSERT INTO wine_cultivation (cultid, name, description) VALUES
('KIP', 'KIP', 'Kontrollierte Integrierte Produktion'),
('B', 'Bio', 'AT-BIO-302');
INSERT INTO wine_attribute (attrid, name, active, max_kg_per_ha, strict, fill_lower) VALUES
('K', 'Kabinett', TRUE, NULL, FALSE, 0),
+6 -6
View File
@@ -34,7 +34,7 @@ INSERT INTO AT_plz_dest (plz, okz, dest) VALUES
(2122, 05137, 'Riedenthal');
INSERT INTO client_parameter (param, value) VALUES
('CLIENT_NAME_TOKEN', 'WGX'),
('CLIENT_NAME_TOKEN', 'WGT'),
('CLIENT_NAME_SHORT', 'WG Test'),
('CLIENT_NAME', 'Winzergenossenschaft Test'),
('CLIENT_NAME_SUFFIX', NULL),
@@ -66,11 +66,11 @@ INSERT INTO wb_kg (kgnr, glnr) VALUES
(15216, 2),
(15224, 2);
INSERT INTO member (mgnr, given_name, name, zwstid, full_delivery, accounting, country, postal_dest, address, default_kgnr, iban, lfbis_nr, ustid_nr, org_auth_code) VALUES
(101, 'Max', 'Mustermann', 'X', FALSE, FALSE, 40, 222303524, 'Winzerstraße 1', 06109, 'AT811234567890123457', '0123463', NULL , NULL ),
(102, 'Wernhardt', 'Weinbauer', 'X', FALSE, FALSE, 40, 222303524, 'Winzerstraße 2', 06109, 'AT541234567890123458', '0123471', 'ATU12345684', NULL ),
(103, 'Matthäus', 'Musterbauer', 'X', FALSE, FALSE, 40, 212005138, 'Brünner Straße 10', 15224, 'AT271234567890123459', '0123480', NULL , 'AT-BIO-302'),
(104, 'Waltraud', 'Winzer', 'X', FALSE, TRUE , 40, 212005138, 'Wiener Straße 15', 15224, 'AT971234567890123460', '0123498', 'ATU12345693', NULL );
INSERT INTO member (mgnr, given_name, name, zwstid, volllieferant, buchführend, country, postal_dest, address, default_kgnr, iban, lfbis_nr, ustid_nr) VALUES
(101, 'Max', 'Mustermann', 'X', FALSE, FALSE, 40, 222303524, 'Winzerstraße 1', 06109, 'AT811234567890123457', '0123463', NULL ),
(102, 'Wernhardt', 'Weinbauer', 'X', FALSE, FALSE, 40, 222303524, 'Winzerstraße 2', 06109, 'AT541234567890123458', '0123471', 'ATU12345684'),
(103, 'Matthäus', 'Musterbauer', 'X', FALSE, FALSE, 40, 212005138, 'Brünner Straße 10', 15224, 'AT271234567890123459', '0123480', NULL ),
(104, 'Waltraud', 'Winzer', 'X', FALSE, TRUE , 40, 212005138, 'Wiener Straße 15', 15224, 'AT971234567890123460', '0123498', 'ATU12345693');
INSERT INTO member_billing_address (mgnr, name, country, postal_dest, address) VALUES
(102, 'W&B Weinbauer GesbR', 40, 222303524, 'Winzerstraße 2'),
+4 -8
View File
@@ -1,12 +1,13 @@
-- inserts for ServiceTests
INSERT INTO wine_cultivation (cultid, name, description, organic) VALUES
('B', 'Bio', 'Biologische Produktion', TRUE);
INSERT INTO wine_cultivation (cultid, name, description) VALUES
('B', 'Bio', 'AT-BIO-302');
INSERT INTO wine_attribute (attrid, name, active, max_kg_per_ha, strict, fill_lower) VALUES
('K', 'Kabinett', TRUE, NULL, FALSE, 0);
INSERT INTO member (mgnr, given_name, name, zwstid, full_delivery, accounting, country, postal_dest, address, default_kgnr, iban, lfbis_nr, ustid_nr) VALUES
INSERT INTO member (mgnr, given_name, name, zwstid, volllieferant, buchführend, country, postal_dest, address, default_kgnr, iban, lfbis_nr, ustid_nr) VALUES
(201, 'Theodor', 'Testbauer', 'X', FALSE, FALSE, 40, 222303524, 'Teststraße 1', 06109, 'AT811234567890123457', '0123463', NULL ),
(202, 'Thomas', 'Testmann', 'X', FALSE, FALSE, 40, 222303524, 'Teststraße 2', 06109, 'AT541234567890123458', '0123471', 'ATU12345684'),
(203, 'Tina', 'Testwinzer', 'X', FALSE, FALSE, 40, 212005138, 'Teststraße 3', 15224, 'AT271234567890123459', '0123480', NULL ),
@@ -138,8 +139,3 @@ INSERT INTO payment_member (year, avnr, mgnr, net_amount) VALUES
INSERT INTO credit (year, tgnr, mgnr, avnr, net_amount, prev_net_amount, vat, modifiers, prev_modifiers) VALUES
(2021, 1, 203, 1, 10000000, 0, 0.1, 0, 0),
(2021, 2, 204, 1, 10000000, 0, 0.1, 0, 0);
INSERT INTO payment_variant (year, avnr, name, date, transfer_date, test_variant, calc_time, comment, data) VALUES
(2021, 2, 'Berechnen', '2022-01-20', '2022-01-20', TRUE, NULL, NULL, '{"mode":"elwig","version":1,"payment":0.5,"curves":[]}'),
(2021, 3, 'Löschen', '2022-01-20', '2022-01-20', TRUE, NULL, NULL, '{"mode":"elwig","version":1,"payment":0.5,"curves":[]}'),
(2021, 4, 'Duplizieren', '2022-01-21', '2022-01-21', TRUE, NULL, NULL, '{"mode":"elwig","version":1,"payment":0.5,"curves":[]}');
-20
View File
@@ -1,20 +0,0 @@
using Elwig;
using Elwig.Helpers;
using Elwig.Helpers.Billing;
namespace Tests {
[SetUpFixture]
class Setup {
[OneTimeSetUp]
public void Setup_1_Config() {
Utils.OverrideCulture();
App.Config.Debug = true;
}
[OneTimeSetUp]
public async Task Setup_2_Init() {
await BillingData.Init();
}
}
}
+5 -5
View File
@@ -19,16 +19,16 @@
</Target>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.10.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.9.0" />
<PackageReference Include="Appium.WebDriver" Version="4.4.5" />
<PackageReference Include="NReco.PdfRenderer" Version="1.6.0" />
<PackageReference Include="NUnit" Version="5.0.0" />
<PackageReference Include="NUnit3TestAdapter" Version="6.3.0" />
<PackageReference Include="NUnit.Analyzers" Version="4.15.0">
<PackageReference Include="NUnit" Version="4.6.1" />
<PackageReference Include="NUnit3TestAdapter" Version="6.2.0" />
<PackageReference Include="NUnit.Analyzers" Version="4.14.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="10.1.0">
<PackageReference Include="coverlet.collector" Version="10.0.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
@@ -16,7 +16,7 @@ namespace Tests.UnitTests.DocumentTests {
"""));
Assert.That(text, Contains.Substring("0123463")); // Betriebsnummer
Assert.That(text, Contains.Substring("pauschaliert"));
Assert.That(text, Contains.Substring($"Wolkersdorf, am {DateTime.Today:dd.MM.yyyy}"));
Assert.That(text, Contains.Substring($"Wolkersdorf, am {Elwig.Helpers.Utils.Today:dd.MM.yyyy}"));
Assert.That(text, Contains.Substring("Traubengutschrift Max Mustermann – Probevariante"));
Assert.That(text, Contains.Substring("AT81 1234 5678 9012 3457"));
Assert.That(text, Contains.Substring("""
@@ -21,7 +21,7 @@ namespace Tests.UnitTests.DocumentTests {
"""));
Assert.That(text, Contains.Substring("0123463")); // Betriebsnummer
Assert.That(text, Contains.Substring("pauschaliert"));
Assert.That(text, Contains.Substring($"Wolkersdorf, am {DateTime.Today:dd.MM.yyyy}"));
Assert.That(text, Contains.Substring($"Wolkersdorf, am {Elwig.Helpers.Utils.Today:dd.MM.yyyy}"));
Assert.That(text, Contains.Substring("Anlieferungsbestätigung 2020"));
Assert.That(text, Contains.Substring("""
20201001X001 1 Grüner Veltliner QUW 73 15,0 ungeb.: 3 219 3 219 ☑
@@ -8,7 +8,7 @@ namespace Tests.UnitTests.DocumentTests {
public async Task Test_01_OneDeliveryPart() {
using var doc = await DeliveryNote.Initialize(2020, 1);
var text = await Utils.GeneratePdfText(doc);
using (Assert.EnterMultipleScope()) {
Assert.Multiple(() => {
Assert.That(text, Contains.Substring("""
MUSTERMANN Max
Winzerstraße 1
@@ -26,14 +26,14 @@ namespace Tests.UnitTests.DocumentTests {
Waage/Terminal: ?/1, ID: 321 – 09:02, 01.10.2020
Brutto: 3 219 kg – Tara: 0 kg – Netto: 3 219 kg – gerebelt gewogen
"""));
}
});
}
[Test]
public async Task Test_02_TwoDeliveryParts() {
using var doc = await DeliveryNote.Initialize(2020, 4);
var text = await Utils.GeneratePdfText(doc);
using (Assert.EnterMultipleScope()) {
Assert.Multiple(() => {
Assert.That(text, Contains.Substring("""
W&B Weinbauer GesbR
WEINBAUER Wernhardt
@@ -58,14 +58,14 @@ namespace Tests.UnitTests.DocumentTests {
Waage/Terminal: ?/?, ID: ? (gerebelt gewogen)
"""));
Assert.That(text, Contains.Substring("Gesamt: 81 16,5 4 483"));
}
});
}
[Test]
public async Task Test_03_DeliveryPartsWithAttribute() {
using var doc = await DeliveryNote.Initialize(2020, 3);
var text = await Utils.GeneratePdfText(doc);
using (Assert.EnterMultipleScope()) {
Assert.Multiple(() => {
Assert.That(text, Contains.Substring("""
MUSTERMANN Max
Winzerstraße 1
@@ -95,14 +95,14 @@ namespace Tests.UnitTests.DocumentTests {
Waage/Terminal: ?/?, ID: ? (gerebelt gewogen)
"""));
Assert.That(text, Contains.Substring("Gesamt: 81 16,5 6 970"));
}
});
}
[Test]
public async Task Test_04_DeliveryPartsWithCultivation() {
using var doc = await DeliveryNote.Initialize(2020, 7);
var text = await Utils.GeneratePdfText(doc);
using (Assert.EnterMultipleScope()) {
Assert.Multiple(() => {
Assert.That(text, Contains.Substring("""
MUSTERBAUER Matthäus
Brünner Straße 10
@@ -115,20 +115,20 @@ namespace Tests.UnitTests.DocumentTests {
Assert.That(text, Contains.Substring("Das Mitglied erklärt, dass die gelieferte Ware dem österreichischen Weingesetz entspricht"));
Assert.That(text, Contains.Substring("""
1 Grüner Veltliner Wein 80 16,3 3 198
Bewirtschaftung: Bio (Biologische Produktion) – Kontrollstelle: AT-BIO-302
Bewirtschaftung: Bio (AT-BIO-302)
Herkunft: Österreich
/ Wolkersdorfer Hochleithen / Wolkersdorf im Weinviertel / KG Wolkersdorf
Waage/Terminal: ?/?, ID: ? (gerebelt gewogen)
"""));
Assert.That(text, Contains.Substring("""
2 Grüner Veltliner Qualitätswein 75 15,4 2 134
Bewirtschaftung: Bio (Biologische Produktion) – Kontrollstelle: AT-BIO-302
Bewirtschaftung: Bio (AT-BIO-302)
Herkunft: Österreich / Weinland / Niederösterreich
/ Wolkersdorfer Hochleithen / Wolkersdorf im Weinviertel / KG Wolkersdorf
Waage/Terminal: ?/?, ID: ? (gerebelt gewogen)
"""));
Assert.That(text, Contains.Substring("Gesamt: 78 15,9 5 332"));
}
});
}
[Test]
+4 -4
View File
@@ -24,13 +24,13 @@ namespace Tests.UnitTests.DocumentTests {
}
[OneTimeSetUp]
public void SetupPrinting() {
Pdf.Init();
public async Task SetupPrinting() {
await Pdf.Init();
}
[OneTimeTearDown]
public void TeardownPrinting() {
Pdf.Cleanup();
public async Task TeardownPrinting() {
await Pdf.Cleanup();
}
}
}
+20 -20
View File
@@ -27,17 +27,17 @@ namespace Tests.UnitTests.HelperTests {
};
}
private static void TestCalcOe(PaymentBillingData data, string bucket, double oe, decimal expected, string? qualid = null, bool ctrd = false) {
private static void TestCalcOe(PaymentBillingData data, string bucket, double oe, decimal expected, string? qualid = null, bool geb = false) {
var (sortid, attrid, cultid) = GetSortIdAttrId(bucket);
var kmw = Utils.OeToKmw(oe);
var v = data.CalculatePrice(sortid, attrid, cultid, qualid ?? GetQualId(kmw), ctrd, oe, kmw);
var v = data.CalculatePrice(sortid, attrid, cultid, qualid ?? GetQualId(kmw), geb, oe, kmw);
Assert.That(Math.Round(v, 6), Is.EqualTo(expected));
}
private static void TestCalcKmw(PaymentBillingData data, string bucket, double kmw, decimal expected, string? qualid = null, bool ctrd = false) {
private static void TestCalcKmw(PaymentBillingData data, string bucket, double kmw, decimal expected, string? qualid = null, bool geb = false) {
var (sortid, attrid, cultid) = GetSortIdAttrId(bucket);
var oe = Utils.KmwToOe(kmw);
var v = data.CalculatePrice(sortid, attrid, cultid, qualid ?? GetQualId(kmw), ctrd, oe, kmw);
var v = data.CalculatePrice(sortid, attrid, cultid, qualid ?? GetQualId(kmw), geb, oe, kmw);
Assert.That(Math.Round(v, 6), Is.EqualTo(expected));
}
@@ -84,11 +84,11 @@ namespace Tests.UnitTests.HelperTests {
TestCalcOe(data, "GV", 80, 0.85m);
TestCalcOe(data, "GV", 83, 1.00m);
TestCalcOe(data, "GV", 90, 1.00m);
TestCalcOe(data, "GV", 73, 0.60m, ctrd: true);
TestCalcOe(data, "GV", 74, 0.65m, ctrd: true);
TestCalcOe(data, "GV", 80, 0.95m, ctrd: true);
TestCalcOe(data, "GV", 83, 1.10m, ctrd: true);
TestCalcOe(data, "GV", 90, 1.10m, ctrd: true);
TestCalcOe(data, "GV", 73, 0.60m, geb: true);
TestCalcOe(data, "GV", 74, 0.65m, geb: true);
TestCalcOe(data, "GV", 80, 0.95m, geb: true);
TestCalcOe(data, "GV", 83, 1.10m, geb: true);
TestCalcOe(data, "GV", 90, 1.10m, geb: true);
}
}
@@ -298,7 +298,7 @@ namespace Tests.UnitTests.HelperTests {
"73oe": 0.5,
"17kmw": 0.6
},
"contracted": 0.1
"geb": 0.1
}, {
"id": 2,
"mode": "kmw",
@@ -306,7 +306,7 @@ namespace Tests.UnitTests.HelperTests {
"15kmw": 0.6,
"17kmw": 0.7
},
"contracted": {
"geb": {
"73oe": 0.65,
"17kmw": 0.80
}
@@ -318,21 +318,21 @@ namespace Tests.UnitTests.HelperTests {
TestCalcKmw(data, "GVS", 15.0, 0.50m);
TestCalcKmw(data, "GVS", 16.0, 0.55m);
TestCalcKmw(data, "GVS", 17.0, 0.60m);
TestCalcKmw(data, "GVS", 15.0, 0.60m, ctrd: true);
TestCalcKmw(data, "GVS", 16.0, 0.65m, ctrd: true);
TestCalcKmw(data, "GVS", 17.0, 0.70m, ctrd: true);
TestCalcKmw(data, "GVS", 15.0, 0.60m, geb: true);
TestCalcKmw(data, "GVS", 16.0, 0.65m, geb: true);
TestCalcKmw(data, "GVS", 17.0, 0.70m, geb: true);
TestCalcKmw(data, "GVK", 15.0, 0.60m);
TestCalcKmw(data, "GVK", 16.0, 0.65m);
TestCalcKmw(data, "GVK", 17.0, 0.70m);
TestCalcKmw(data, "GVK", 15.0, 0.65m, ctrd: true);
TestCalcKmw(data, "GVK", 16.0, 0.725m, ctrd: true);
TestCalcKmw(data, "GVK", 17.0, 0.80m, ctrd: true);
TestCalcKmw(data, "GVK", 15.0, 0.65m, geb: true);
TestCalcKmw(data, "GVK", 16.0, 0.725m, geb: true);
TestCalcKmw(data, "GVK", 17.0, 0.80m, geb: true);
TestCalcKmw(data, "WRS", 15.0, 0.70m);
TestCalcKmw(data, "WRS", 16.0, 0.75m);
TestCalcKmw(data, "WRS", 17.0, 0.80m);
TestCalcKmw(data, "WRS", 15.0, 0.80m, ctrd: true);
TestCalcKmw(data, "WRS", 16.0, 0.875m, ctrd: true);
TestCalcKmw(data, "WRS", 17.0, 0.95m, ctrd: true);
TestCalcKmw(data, "WRS", 15.0, 0.80m, geb: true);
TestCalcKmw(data, "WRS", 16.0, 0.875m, geb: true);
TestCalcKmw(data, "WRS", 17.0, 0.95m, geb: true);
}
}
Loaded 100 of 112 files, more files were not shown because too many files have changed in this diff. Show more