Compare commits

...

35 Commits

Author SHA1 Message Date
c61c2e3fcd [] AreaComAdminWindow: Add dialog for modifying/deleting 2025-07-09 18:14:27 +02:00
267aa3d47c Dialogs: Rename AreaComDialog to AreaComTransferDialog 2025-07-09 16:56:08 +02:00
7e9a27c75d Services: Move App.HintContextChange() to Windows 2025-07-09 16:07:47 +02:00
53d82604a1 AreaComAdminWindow: Enhance visual appearance 2025-07-09 00:39:01 +02:00
bb65a1f20e [] CreditNote: Add longer custom text to bottom 2025-07-08 16:06:12 +02:00
c6748055fd [] Windows: Use red and green color to indicate type of WineVariety 2025-07-08 15:27:13 +02:00
e6746f76b1 Windows: Small fixes 2025-07-08 15:27:13 +02:00
e9f389b885 DeliveryService: Fix spacing in tooltip 2025-07-08 15:27:13 +02:00
919ab3356d [] MailWindow: Use Task.Run() 2025-07-08 15:27:13 +02:00
39060f6a1e [] PaymentAdjustmentWindow: Use Task.Run() 2025-07-08 15:26:57 +02:00
070dda1bde [] ChartWindow: Use Task.Run() 2025-07-07 23:53:08 +02:00
b6bfc60ab8 [] DeliveryScheduleAdminWindow: Use Task.Run() 2025-07-07 23:39:55 +02:00
8aaa22fcb4 [] DeliveryAncmtAdminWindow: Use Task.Run() 2025-07-07 23:36:08 +02:00
64832e9a53 [] PaymentVariantsWindow: Use Task.Run() 2025-07-07 23:31:03 +02:00
7c9844e277 [] MainWindow: Use Task.Run() 2025-07-07 22:45:28 +02:00
19d2208fc3 [] AreaComAdminWindow: Use Task.Run() 2025-07-07 22:45:28 +02:00
38d0ff969d BaseDataWindow: Use Cursors.Wait instead of Cursors.AppStarting 2025-07-07 22:45:28 +02:00
fb2b998d1b [] DeliveryAdminWindow: Use Task.Run() 2025-07-07 22:45:28 +02:00
10d5f49f63 [] MemberAdminWinodw: Use Task.Run() 2025-07-07 22:45:28 +02:00
41811925be PaymentVariantsWindow: Add ViewModel and Service 2025-07-07 22:44:30 +02:00
97300b6e30 [] MailLogWindow: Fix initial loading 2025-07-03 13:03:01 +02:00
c6c8fd9b68 ChartWindow: Automatically calculate variant when saved 2025-07-03 13:03:01 +02:00
913129f155 PaymentVariantsWindow: Add estimates for uncommited variants 2025-07-03 13:02:57 +02:00
953532cae4 MemberService: Filter area commitments by CurrentLastSeason instead of CurrentYear 2025-06-24 13:31:58 +02:00
267797b55d AreaComDialog: Fix property name (MaintainYearFrom) 2025-06-24 13:30:04 +02:00
4234c7f994 Elwig: Add ITime/XTime to entities and allow to export/import CTime/MTime 2025-06-17 18:06:05 +02:00
3493ff6df1 Tests: Add UnitTests folder 2025-06-03 20:57:53 +02:00
623f55f5b0 App: Rename ExePath to InstallPath 2025-05-27 11:43:34 +02:00
b580e1bf79 App: Use environment variables for paths 2025-05-26 15:18:32 +02:00
b08ca63bed [] Documents: Move Documents install folder from ProgramData to Program Files 2025-05-26 15:12:49 +02:00
6a5f4cefa9 [] PaymentVariantSummary: Add 'attributlos gebunden' columns 2025-05-23 15:43:39 +02:00
0f3ce39f35 Elwig: Use 'Menge' instead of 'Gewicht' where applicable 2025-05-20 15:55:11 +02:00
336aef5c70 CreditNoteDeliveryData: Include WeighingModifier only if delivery modifiers are considered 2025-05-20 13:09:29 +02:00
0dff3986b7 PaymentVariantsWindow: Add note, that modifiers include Rebelzuschlag 2025-05-20 12:07:28 +02:00
318fb5dc7b Bump version to 0.13.9 2025-05-05 10:41:18 +02:00
114 changed files with 2251 additions and 1360 deletions
CHANGELOG.md
Elwig
App.xamlApp.xaml.cs
Dialogs
Documents
Elwig.csproj
Helpers
Models
Resources
Services
ViewModels
Windows
fetch-resources.bat
Installer
Tests

@@ -3,6 +3,19 @@ Changelog
=========
[v0.13.9][v0.13.9] (2025-05-05) {#v0.13.9}
------------------------------------------
### Sonstiges {#v0.13.9-misc}
* Abhängigkeiten aktualisiert. (bf0db37872, 4af2fa256e, d1c07ee92a, 41c5288fc5)
* Automatisches Aktualisieren der Synchroisations-URL (`https://elwig.at/clients/` -> `https://sync.elwig.at/`). (e50e7337e6)
[v0.13.9]: https://git.necronda.net/winzer/elwig/releases/tag/v0.13.9
[v0.13.8][v0.13.8] (2025-02-21) {#v0.13.8}
------------------------------------------

@@ -30,13 +30,13 @@
<DataTemplate x:Key="WineVarietyTemplateCollapsed">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding Name}" Foreground="{Binding Color}"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="WineVarietyTemplateExpanded">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding SortId}" MinWidth="36" Margin="0,0,10,0"/>
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding SortId}" Foreground="{Binding Color}" MinWidth="36" Margin="0,0,10,0"/>
<TextBlock Text="{Binding Name}" Foreground="{Binding Color}"/>
<TextBlock Text="{Binding CommentFormat}" FontSize="10" VerticalAlignment="Bottom" Margin="0,0,0,2"/>
</StackPanel>
</DataTemplate>

@@ -25,10 +25,13 @@ namespace Elwig {
private readonly DispatcherTimer _autoUpdateTimer = new() { Interval = TimeSpan.FromHours(1) };
public static readonly string DataPath = @"C:\ProgramData\Elwig\";
public static readonly string DataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Elwig");
public static readonly string MailsPath = Path.Combine(DataPath, "mails");
public static readonly string ConfigPath = Path.Combine(DataPath, "config.ini");
public static readonly string ExePath = @"C:\Program Files\Elwig\";
public static readonly string InstallPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "Elwig");
public static readonly string DocumentsPath = (Assembly.GetEntryAssembly()?.Location.Contains(@"\bin\") ?? false) ?
Path.Combine(Assembly.GetEntryAssembly()!.Location.Split(@"\bin\")[0], "../Elwig/Documents") :
Path.Combine(InstallPath, "resources/Documents");
public static readonly string TempPath = Path.Combine(Path.GetTempPath(), "Elwig");
public static Config Config { get; private set; } = new(ConfigPath);
@@ -197,10 +200,12 @@ namespace Elwig {
var ch = CurrentLastWrite;
if (ch > CurrentApp.LastChanged)
CurrentApp.LastChanged = ch;
foreach (Window w in CurrentApp.Windows) {
if (w is not ContextWindow c) continue;
MainDispatcher.BeginInvoke(c.HintContextChange);
}
MainDispatcher.Invoke(() => {
foreach (Window w in CurrentApp.Windows) {
if (w is not ContextWindow c) continue;
MainDispatcher.BeginInvoke(c.HintContextChange);
}
});
}
private void OnAutoUpdateTimer(object? sender, EventArgs? evt) {

@@ -0,0 +1,71 @@
<Window x:Class="Elwig.Dialogs.AreaComModifyDialog"
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"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
Title="Flächenbindungen bearbeiten" Height="220" Width="450">
<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>
<TextBlock x:Name="QuestionBlock1" TextAlignment="Center" Margin="0,10,0,0"
HorizontalAlignment="Center" VerticalAlignment="Top">
Soll die Flächenbindung (<Run Text="{Binding Area}"/> m², <Run Text="{Binding OrigYearFrom}"/><Run Text="{Binding OrigYearTo}"/>) rückwirkend bearbeitet werden,<LineBreak/>
oder erst ab der angegebenen Saison?
</TextBlock>
<TextBlock x:Name="QuestionBlock2" TextAlignment="Center" Margin="0,10,0,0" Visibility="Hidden"
HorizontalAlignment="Center" VerticalAlignment="Top">
Soll die Flächenbindung (<Run Text="{Binding Area}"/> m², <Run Text="{Binding OrigYearFrom}"/><Run Text="{Binding OrigYearTo}"/>) rückwirkend gelöscht werden,<LineBreak/>
oder erst ab der angegebenen Saison?
</TextBlock>
<Label x:Name="SeasonLabel" Content="Saison:" Margin="0,50,100,0"
HorizontalAlignment="Center" VerticalAlignment="Top"/>
<ctrl:IntegerUpDown x:Name="SeasonInput" Width="56" Height="25" Margin="0,50,0,0" FontSize="14"
Minimum="1900" Maximum="9999"
HorizontalAlignment="Center" VerticalAlignment="Top"
TextChanged="SeasonInput_TextChanged"/>
<CheckBox x:Name="RetroactiveInput" Content="Rückwirkend bearbeiten" Margin="0,80,0,0"
HorizontalAlignment="Center" VerticalAlignment="Top"
Checked="RetroactiveInput_Changed" Unchecked="RetroactiveInput_Changed"
IsChecked="{Binding ModifyRetroactively}"/>
<TextBlock x:Name="DescBlock1" Margin="0,105,0,0" TextAlignment="Center"
HorizontalAlignment="Center" VerticalAlignment="Top">
Die Flächenbindung bleibt bis inkl. Saison <Bold><Run x:Name="CancelSeason1"/></Bold> unverändert,<LineBreak/>
und wird ab inkl. Saison <Bold><Run x:Name="NewSeason1"/></Bold> in geänderter Form übernommen.
</TextBlock>
<TextBlock x:Name="DescBlock2" Margin="0,105,0,0" TextAlignment="Center" Visibility="Hidden"
HorizontalAlignment="Center" VerticalAlignment="Top">
Die Flächenbindung bleibt bis inklusive Saison <Bold><Run x:Name="CancelSeason2"/></Bold> gültig.
</TextBlock>
<Button x:Name="ConfirmButton" Content="Bestätigen" Margin="10,10,115,10" Grid.Column="1"
Click="ConfirmButton_Click"/>
<Button x:Name="CancelButton" Content="Abbrechen" Margin="10,10,10,10" Grid.Column="1" IsCancel="True"/>
</Grid>
</Window>

@@ -0,0 +1,62 @@
using Elwig.Helpers;
using System.Windows;
using System.Windows.Controls;
namespace Elwig.Dialogs {
public partial class AreaComModifyDialog : Window {
public int? YearTo { get; set; }
public bool ModifyRetroactively { get; set; }
public string OrigYearFrom { get; set; }
public string OrigYearTo { get; set; }
public string Area { get; set; }
public AreaComModifyDialog(int? yearFrom, int? yearTo, int area, bool delete) {
Area = $"{area:N0}";
OrigYearFrom = $"{yearFrom}";
OrigYearTo = $"{yearTo}";
InitializeComponent();
Title = delete ? "Flächenbindung löschen" : "Flächenbindung bearbeiten";
RetroactiveInput.Content = delete ? "Rückwirkend löschen" : "Rückwirkend bearbeiten";
if (delete) {
QuestionBlock1.Visibility = Visibility.Hidden;
QuestionBlock2.Visibility = Visibility.Visible;
DescBlock1.Visibility = Visibility.Hidden;
DescBlock2.Visibility = Visibility.Visible;
}
if ((yearTo.HasValue && yearTo < Utils.CurrentNextSeason) || (yearFrom.HasValue && yearFrom >= Utils.CurrentNextSeason)) {
RetroactiveInput.IsChecked = true;
} else {
SeasonInput.Text = $"{Utils.CurrentNextSeason}";
}
}
private void SeasonInput_TextChanged(object sender, TextChangedEventArgs evt) {
YearTo = SeasonInput.Value! - 1;
CancelSeason1.Text = $"{YearTo}";
CancelSeason2.Text = $"{YearTo}";
NewSeason1.Text = $"{YearTo + 1}";
}
private void RetroactiveInput_Changed(object sender, RoutedEventArgs evt) {
if (ModifyRetroactively) {
SeasonInput.IsEnabled = false;
SeasonInput.Text = "";
YearTo = null;
DescBlock1.Visibility = Visibility.Hidden;
DescBlock2.Visibility = Visibility.Hidden;
} else {
SeasonInput.IsEnabled = true;
SeasonInput.Text = $"{Utils.CurrentNextSeason}";
DescBlock1.Visibility = QuestionBlock1.Visibility;
DescBlock2.Visibility = QuestionBlock2.Visibility;
}
}
private void ConfirmButton_Click(object sender, RoutedEventArgs evt) {
DialogResult = true;
Close();
}
}
}

@@ -1,4 +1,4 @@
<Window x:Class="Elwig.Dialogs.AreaComDialog"
<Window x:Class="Elwig.Dialogs.AreaComTransferDialog"
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"
@@ -51,7 +51,7 @@
<CheckBox x:Name="CopyYearToInput" Content="Beginn der Laufzeit von Vorgänger übernehmen" Margin="0,80,0,0"
HorizontalAlignment="Center" VerticalAlignment="Top"
Checked="CopyYearToInput_Changed" Unchecked="CopyYearToInput_Changed"
IsChecked="{Binding MaintainYearTo}"/>
IsChecked="{Binding MaintainYearFrom}"/>
<TextBlock x:Name="DescBlock1" Margin="0,105,0,0" TextAlignment="Center"
HorizontalAlignment="Center" VerticalAlignment="Top">

@@ -3,16 +3,16 @@ using System.Windows;
using System.Windows.Controls;
namespace Elwig.Dialogs {
public partial class AreaComDialog : Window {
public partial class AreaComTransferDialog : Window {
public int CancelSeason { get; set; }
public int SuccessorSeason => CancelSeason + 1;
public bool MaintainYearTo { get; set; }
public bool MaintainYearFrom { get; set; }
public string AreaComNum { get; set; }
public string Area { get; set; }
public AreaComDialog(string name, int areaComNum, int area) {
public AreaComTransferDialog(string name, int areaComNum, int area) {
CancelSeason = Utils.FollowingSeason - 1;
AreaComNum = $"{areaComNum:N0}";
Area = $"{area:N0}";
@@ -29,7 +29,7 @@ namespace Elwig.Dialogs {
SeasonLabel.Margin = new(0, 40, 100, 0);
}
public AreaComDialog(string name, string successorName, int areaComNum, int area) {
public AreaComTransferDialog(string name, string successorName, int areaComNum, int area) {
CancelSeason = Utils.FollowingSeason - 1;
AreaComNum = $"{areaComNum:N0}";
Area = $"{area:N0}";
@@ -43,13 +43,13 @@ namespace Elwig.Dialogs {
CancelSeason = (int)SeasonInput.Value!;
CancelSeason1.Text = $"{CancelSeason}";
CancelSeason2.Text = $"{CancelSeason}";
TransferSeason.Text = MaintainYearTo ? "" : $"{SuccessorSeason}";
DescBlock1Season.Text = MaintainYearTo ? "dem originalen Beginn der FB" : "inkl. Saison ";
TransferSeason.Text = MaintainYearFrom ? "" : $"{SuccessorSeason}";
DescBlock1Season.Text = MaintainYearFrom ? "dem originalen Beginn der FB" : "inkl. Saison ";
}
private void CopyYearToInput_Changed(object sender, RoutedEventArgs evt) {
TransferSeason.Text = MaintainYearTo ? "" : $"{SuccessorSeason}";
DescBlock1Season.Text = MaintainYearTo ? "dem originalen Beginn der FB" : "inkl. Saison ";
TransferSeason.Text = MaintainYearFrom ? "" : $"{SuccessorSeason}";
DescBlock1Season.Text = MaintainYearFrom ? "dem originalen Beginn der FB" : "inkl. Saison ";
}
private void ConfirmButton_Click(object sender, RoutedEventArgs evt) {

@@ -2,7 +2,7 @@
@inherits TemplatePage<Elwig.Documents.BusinessDocument>
@model Elwig.Documents.BusinessDocument
@{ Layout = "Document"; }
<link rel="stylesheet" href="file:///@Raw(Model.DataPath)\resources\BusinessDocument.css"/>
<link rel="stylesheet" href="file:///@Raw(Model.DocumentsPath)\BusinessDocument.css"/>
<div class="info-wrapper">
<div class="address-wrapper">
<div class="sender">

@@ -3,7 +3,7 @@
@inherits TemplatePage<Elwig.Documents.CreditNote>
@model Elwig.Documents.CreditNote
@{ Layout = "BusinessDocument"; }
<link rel="stylesheet" href="file:///@Raw(Model.DataPath)\resources\CreditNote.css"/>
<link rel="stylesheet" href="file:///@Raw(Model.DocumentsPath)\CreditNote.css" />
<main>
<h1>@Model.Title</h1>
<table class="credit">
@@ -136,7 +136,10 @@
}
</tbody>
<tbody style="break-inside: avoid;">
@{ decimal penalty = 0; }
@{
decimal penalty = 0;
string? comment = null;
}
@if (Model.MemberUnderDeliveries != null && Model.MemberUnderDeliveries.Count() > 0) {
<tr class="small">
@@ -158,7 +161,13 @@
penalty += Model.MemberAutoBusinessSharesAmount;
}
@if (Model.CustomPayment?.Amount != null) {
@Raw(FormatRow(Model.CustomPayment.Comment ?? ((Model.CustomPayment.Amount.Value) < 0 ? "Weitere Abzüge" : "Weitere Zuschläge"), Model.CustomPayment.Amount.Value, add: true));
comment = Model.CustomPayment.Comment;
string text = (Model.CustomPayment.Amount.Value < 0 ? "Weitere Abzüge" : "Weitere Zuschläge") + (comment != null ? "*" : "");
if (comment != null && comment!.Length <= 30) {
text = comment;
comment = null;
}
@Raw(FormatRow(text, Model.CustomPayment.Amount.Value, add: true));
penalty += Model.CustomPayment.Amount.Value;
}
@@ -176,6 +185,9 @@
}
</tbody>
</table>
@if (comment != null) {
<p>* @comment</p>
}
<p>Überweisung erfolgt auf Konto @(Elwig.Helpers.Utils.FormatIban(Model.Member.Iban ?? "-")).</p>
<div style="margin-top: 1em;">
@if (Model.Text != null) {

@@ -2,7 +2,7 @@
@inherits TemplatePage<Elwig.Documents.DeliveryAncmtList>
@model Elwig.Documents.DeliveryAncmtList
@{ Layout = "Document"; }
<link rel="stylesheet" href="file:///@Raw(Model.DataPath)\resources\DeliveryAncmtList.css" />
<link rel="stylesheet" href="file:///@Raw(Model.DocumentsPath)\DeliveryAncmtList.css" />
<main>
<h1>Anmeldeliste</h1>
<h2>@Model.Filter</h2>
@@ -24,7 +24,7 @@
<th rowspan="2" style="text-align: left;">Ort</th>
<th rowspan="2" style="text-align: left;">Sorte</th>
<th rowspan="2">Anmldg.</th>
<th>Gewicht</th>
<th>Menge</th>
</tr>
<tr>
<th class="unit">[kg]</th>

@@ -3,7 +3,7 @@
@inherits TemplatePage<Elwig.Documents.DeliveryConfirmation>
@model Elwig.Documents.DeliveryConfirmation
@{ Layout = "BusinessDocument"; }
<link rel="stylesheet" href="file:///@Raw(Model.DataPath)\resources\DeliveryConfirmation.css"/>
<link rel="stylesheet" href="file:///@Raw(Model.DocumentsPath)\DeliveryConfirmation.css" />
<main>
<h1>@Model.Title</h1>
<table class="delivery-confirmation">
@@ -30,7 +30,7 @@
<th rowspan="2" style="text-align: left;">Qualitätsstufe</th>
<th colspan="2">Gradation</th>
<th colspan="2">Flächenbindung</th>
<th>Gewicht</th>
<th>Menge</th>
<th rowspan="3" style="padding: 0;">
<svg width="10" height="40" xmlns="http://www.w3.org/2000/svg">
<text x="-40" y="4" transform="rotate(270)" font-size="8pt" font-style="italic" font-family="Times New Roman"

@@ -2,7 +2,7 @@
@inherits TemplatePage<Elwig.Documents.DeliveryDepreciationList>
@model Elwig.Documents.DeliveryDepreciationList
@{ Layout = "Document"; }
<link rel="stylesheet" href="file:///@Raw(Model.DataPath)\resources\DeliveryDepreciationList.css" />
<link rel="stylesheet" href="file:///@Raw(Model.DocumentsPath)\DeliveryDepreciationList.css" />
<main>
<h1>Abwertungsliste</h1>
<h2>@Model.Filter</h2>
@@ -27,7 +27,7 @@
<th rowspan="2" style="text-align: left;">Sorte</th>
<th rowspan="2" style="text-align: left;">Attr./Bewirt.</th>
<th colspan="2">Gradation</th>
<th>Gewicht</th>
<th>Menge</th>
</tr>
<tr>
<th class="unit">[°Oe]</th>

@@ -2,7 +2,7 @@
@inherits TemplatePage<Elwig.Documents.DeliveryJournal>
@model Elwig.Documents.DeliveryJournal
@{ Layout = "Document"; }
<link rel="stylesheet" href="file:///@Raw(Model.DataPath)\resources\DeliveryJournal.css"/>
<link rel="stylesheet" href="file:///@Raw(Model.DocumentsPath)\DeliveryJournal.css"/>
<main>
<h1>Lieferjournal</h1>
<h2>@Model.Filter</h2>
@@ -29,7 +29,7 @@
<th rowspan="2" style="text-align: left;">Mitglied</th>
<th rowspan="2" style="text-align: left;">Sorte</th>
<th colspan="2">Gradation</th>
<th>Gewicht</th>
<th>Menge</th>
</tr>
<tr>
<th class="unit">[°Oe]</th>

@@ -2,7 +2,7 @@
@inherits TemplatePage<Elwig.Documents.DeliveryNote>
@model Elwig.Documents.DeliveryNote
@{ Layout = "BusinessDocument"; }
<link rel="stylesheet" href="file:///@Raw(Model.DataPath)\resources\DeliveryNote.css" />
<link rel="stylesheet" href="file:///@Raw(Model.DocumentsPath)\DeliveryNote.css" />
<main>
<h1>@Model.Title</h1>
<table class="delivery large">
@@ -24,7 +24,7 @@
<th class="main" rowspan="2" colspan="2">Attribut</th>
<th class="main" rowspan="2">Qualitätsstufe</th>
<th colspan="2">Gradation</th>
<th>Gewicht</th>
<th>Menge</th>
</tr>
<tr>
<th class="unit">[°Oe]</th>

@@ -23,7 +23,7 @@ namespace Elwig.Documents {
public bool ShowFoldMarks = App.Config.Debug;
public bool DoublePaged = false;
public string DataPath;
public string DocumentsPath;
public int CurrentNextSeason;
public string? DocumentId;
public string Title;
@@ -34,7 +34,7 @@ namespace Elwig.Documents {
public Document(string title) {
var c = App.Client;
DataPath = App.DataPath;
DocumentsPath = App.DocumentsPath;
CurrentNextSeason = Utils.CurrentNextSeason;
Title = title;
Author = c.NameFull;

@@ -7,9 +7,9 @@
<title>@Model.Title</title>
<meta name="author" value="@Model.Author"/>
<meta charset="UTF-8"/>
<link rel="stylesheet" href="file:///@Raw(Model.DataPath)\resources\Document.css"/>
<link rel="stylesheet" href="file:///@Raw(Model.DataPath)\resources\Document.Page.css"/>
<link rel="stylesheet" href="file:///@Raw(Model.DataPath)\resources\Document.Table.css"/>
<link rel="stylesheet" href="file:///@Raw(Model.DocumentsPath)\Document.css" />
<link rel="stylesheet" href="file:///@Raw(Model.DocumentsPath)\Document.Page.css" />
<link rel="stylesheet" href="file:///@Raw(Model.DocumentsPath)\Document.Table.css" />
@if (Model.DoublePaged) {
<style>
@@page :left {

@@ -3,7 +3,7 @@
@inherits TemplatePage<Elwig.Documents.MemberDataSheet>
@model Elwig.Documents.MemberDataSheet
@{ Layout = "BusinessDocument"; }
<link rel="stylesheet" href="file:///@Raw(Model.DataPath)\resources\MemberDataSheet.css" />
<link rel="stylesheet" href="file:///@Raw(Model.DocumentsPath)\MemberDataSheet.css" />
<main>
<h1>@Model.Title</h1>
<table class="member border">

@@ -2,7 +2,7 @@
@inherits TemplatePage<Elwig.Documents.MemberList>
@model Elwig.Documents.MemberList
@{ Layout = "Document"; }
<link rel="stylesheet" href="file:///@Raw(Model.DataPath)\resources\MemberList.css"/>
<link rel="stylesheet" href="file:///@Raw(Model.DocumentsPath)\MemberList.css" />
<main>
<h1>Mitgliederliste</h1>
<h2>@Model.Filter</h2>

@@ -3,7 +3,7 @@
@inherits TemplatePage<Elwig.Documents.PaymentVariantSummary>
@model Elwig.Documents.PaymentVariantSummary
@{ Layout = "Document"; }
<link rel="stylesheet" href="file:///@Raw(Model.DataPath)\resources\PaymentVariantSummary.css" />
<link rel="stylesheet" href="file:///@Raw(Model.DocumentsPath)\PaymentVariantSummary.css" />
<main>
<h1>Auszahlungsvariante Lese @Model.Variant.Year</h1>
<h2>@Model.Variant.Name</h2>
@@ -111,8 +111,8 @@
<td class="number"><span class="fleft">@Model.CurrencySymbol</span>@($"{Math.Abs(payed):N2}")</td>
@{
var weiRows = Model.Data.Rows.Where(r => r.QualityLevel == "Wein");
var minWei = weiRows.Min(r => r.Ungeb.Price);
var maxWei = weiRows.Max(r => r.Ungeb.Price);
var minWei = weiRows.Min(r => r.Ungeb.MinPrice);
var maxWei = weiRows.Max(r => r.Ungeb.MaxPrice);
}
<th class="lborder tborder">Preis (abgewertet):</th>
<td colspan="2" class="center tborder">@(minWei != maxWei ? $"{minWei:N4}{maxWei:N4}" : $"{minWei:N4}") @Model.CurrencySymbol/kg</td>
@@ -123,8 +123,8 @@
<td class="number tborder"><span class="fleft">@Model.CurrencySymbol</span>@($"{netSum:N2}")</td>
@{
var quwRows = Model.Data.Rows.Where(r => r.QualityLevel != "Wein");
var minPrice = quwRows.Min(r => r.Ungeb.Price);
var maxPrice = quwRows.Max(r => r.Ungeb.Price);
var minPrice = quwRows.Min(r => r.Ungeb.MinPrice);
var maxPrice = quwRows.Max(r => r.Ungeb.MaxPrice);
}
<th class="lborder">Preis (ungeb., nicht abgew.):</th>
<td colspan="2" class="center">@(minPrice != maxPrice ? $"{minPrice:N4}{maxPrice:N4}" : $"{minPrice:N4}") @Model.CurrencySymbol/kg</td>
@@ -135,8 +135,8 @@
<td class="number"><span class="fleft">@Model.CurrencySymbol</span>@($"{Math.Abs(vat):N2}")</td>
@{
var gebRows = Model.Data.Rows
.Where(r => r.Geb.Price != null && r.Ungeb.Price != null)
.Select(r => r.Geb.Price - r.Ungeb.Price);
.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();
}
@@ -219,19 +219,22 @@
</table>
<table class="payment-variant-data">
<colgroup>
<col style="width: 30mm;"/>
<col style="width: 20mm;"/>
<col style="width: 25mm;"/>
<col style="width: 20mm;"/>
<col style="width: 25mm;"/>
<col style="width: 20mm;"/>
<col style="width: 25mm;"/>
<col style="width: 19mm;"/>
<col style="width: 18mm;"/>
<col style="width: 15mm;"/>
<col style="width: 18mm;"/>
<col style="width: 15mm;"/>
<col style="width: 18mm;"/>
<col style="width: 15mm;"/>
<col style="width: 22mm;"/>
</colgroup>
<thead>
<tr>
<th rowspan="2" style="text-align: left;">Qualitätsstufe</th>
<th>Gradation</th>
<th colspan="2">ungebunden</th>
<th colspan="2">attributlos gebunden</th>
<th colspan="2">gebunden</th>
<th>Gesamt</th>
</tr>
@@ -241,6 +244,8 @@
<th>[@(Model.CurrencySymbol)/kg]</th>
<th>[kg]</th>
<th>[@(Model.CurrencySymbol)/kg]</th>
<th>[kg]</th>
<th>[@(Model.CurrencySymbol)/kg]</th>
<th>[@(Model.CurrencySymbol)]</th>
</tr>
</thead>
@@ -258,6 +263,8 @@
<th colspan="2">@hdr</th>
<td class="number">@($"{rows.Sum(r => r.Ungeb.Weight):N0}")</td>
<td></td>
<td class="number">@($"{rows.Sum(r => r.LowGeb.Weight):N0}")</td>
<td></td>
<td class="number">@($"{rows.Sum(r => r.Geb.Weight):N0}")</td>
<td></td>
<td class="number">@($"{rows.Sum(r => r.Amount):N2}")</td>
@@ -267,9 +274,11 @@
<td>@(row.QualityLevel)</td>
<td class="center">@($"{row.Oe:N0}")</td>
<td class="number">@(row.Ungeb.Weight != 0 ? $"{row.Ungeb.Weight:N0}" : "-")</td>
<td class="number">@(row.Ungeb.Price != null ? $"{row.Ungeb.Price:N4}" : "-")</td>
<td class="number">@(row.Ungeb.MaxPrice != null ? $"{row.Ungeb.MaxPrice:N4}" : "-")</td>
<td class="number">@(row.LowGeb.Weight != 0 ? $"{row.LowGeb.Weight:N0}" : "-")</td>
<td class="number">@(row.LowGeb.MaxPrice != null ? $"{row.LowGeb.MaxPrice:N4}" : "-")</td>
<td class="number">@(row.Geb.Weight != 0 ? $"{row.Geb.Weight:N0}" : "-")</td>
<td class="number">@(row.Geb.Price != null ? $"{row.Geb.Price:N4}" : "-")</td>
<td class="number">@(row.Geb.MaxPrice != null ? $"{row.Geb.MaxPrice:N4}" : "-")</td>
<td class="number">@($"{row.Amount:N2}")</td>
</tr>
lastHdr = hdr;

@@ -3,7 +3,7 @@
@inherits TemplatePage<Elwig.Documents.WineQualityStatistics>
@model Elwig.Documents.WineQualityStatistics
@{ Layout = "Document"; }
<link rel="stylesheet" href="file:///@Raw(Model.DataPath)\resources\WineQualityStatistics.css"/>
<link rel="stylesheet" href="file:///@Raw(Model.DocumentsPath)\WineQualityStatistics.css" />
<main>
<h1>Qualitätsstatistik</h1>
<h2>@Model.Filter</h2>

@@ -7,7 +7,7 @@
<UseWPF>true</UseWPF>
<PreserveCompilationContext>true</PreserveCompilationContext>
<ApplicationIcon>Resources\Images\Elwig.ico</ApplicationIcon>
<Version>0.13.8</Version>
<Version>0.13.9</Version>
<SatelliteResourceLanguages>de-AT</SatelliteResourceLanguages>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<ApplicationManifest>app.manifest</ApplicationManifest>
@@ -20,10 +20,6 @@
<EmbeddedResource Include="Resources\Sql\*" />
</ItemGroup>
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
<Exec Command="call fetch-resources.bat" />
</Target>
<ItemGroup>
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
<PackageReference Include="LinqKit" Version="1.3.8" />

@@ -9,7 +9,7 @@ namespace Elwig.Helpers {
public static class AppDbUpdater {
// Don't forget to update value in Tests/fetch-resources.bat!
public static readonly int RequiredSchemaVersion = 31;
public static readonly int RequiredSchemaVersion = 32;
private static int VersionOffset = 0;

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Media;
namespace Elwig.Helpers.Billing {
public class GraphEntry {
@@ -40,6 +41,7 @@ namespace Elwig.Helpers.Billing {
public string VaributeStringSimple => (Abgewertet ? "Abgew.: " : "") + (Vaributes.Count != 0 ? (Vaributes.Count >= 25 ? "Restliche Sorten" : string.Join(", ", Vaributes.Select(c => c.Listing))) : "-");
public string VaributeString => Vaributes.Count != 0 ? string.Join("\n", Vaributes.Select(c => c.FullName)) : "-";
public string VaributeStringChange => (Abgewertet ? "A." : "") + string.Join(",", Vaributes.Select(c => c.Listing));
public Brush? Color => Vaributes.Select(v => v.Variety?.Color).Distinct().SingleOrDefault();
private readonly int Precision;
public GraphEntry(int id, int precision, BillingData.CurveMode mode) {

@@ -1,14 +1,15 @@
using System.IO.Compression;
using System.IO;
using System.Threading.Tasks;
using Elwig.Models.Entities;
using System.Collections.Generic;
using System;
using System.Text.Json.Nodes;
using System.Linq;
using System.Windows;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Threading.Tasks;
using System.Windows;
namespace Elwig.Helpers.Export {
public static class ElwigData {
@@ -63,7 +64,8 @@ namespace Elwig.Helpers.Export {
List<WbRd> Riede,
List<Delivery> Deliveries,
List<DeliveryPart> DeliveryParts,
List<DeliveryPartModifier> Modifiers)>();
List<DeliveryPartModifier> Modifiers,
Dictionary<string, List<(int Id1, int Id2, DateTime CreatedAt, DateTime ModifiedAt)>> Timestamps)>();
var metaData = new List<(string FileName, string ZwstId, string Device,
int? MemberNum, string? MemberFilters,
@@ -94,7 +96,11 @@ namespace Elwig.Helpers.Export {
areaComCount, areaComFilters != null ? string.Join(" / ", areaComFilters) : null,
deliveryCount, deliveryFilters != null ? string.Join(" / ", deliveryFilters) : null));
data.Add(new([], [], [], [], [], [], [], new([], [])));
data.Add(new([], [], [], [], [], [], [], new([], [], new() {
["member"] = [],
["area_commitment"] = [],
["delivery"] = [],
})));
var r = data[^1];
var membersJson = zip.GetEntry("members.json");
@@ -103,11 +109,13 @@ namespace Elwig.Helpers.Export {
string? line;
while ((line = await reader.ReadLineAsync()) != null) {
var obj = JsonNode.Parse(line)!.AsObject();
var (m, b, telNrs, emailAddrs) = obj.ToMember(kgs);
var (m, b, telNrs, emailAddrs, timestamps) = obj.ToMember(kgs);
r.Members.Add(m);
if (b != null) r.BillingAddresses.Add(b);
r.TelephoneNumbers.AddRange(telNrs);
r.EmailAddresses.AddRange(emailAddrs);
if (timestamps.HasValue)
r.Timestamps["member"].Add((m.MgNr, 0, timestamps.Value.CreatedAt, timestamps.Value.ModifiedAt));
}
}
@@ -117,12 +125,14 @@ namespace Elwig.Helpers.Export {
string? line;
while ((line = await reader.ReadLineAsync()) != null) {
var obj = JsonNode.Parse(line)!.AsObject();
var (areaCom, wbrd) = obj.ToAreaCom(kgs, currentWbRde);
var (areaCom, wbrd, timestamps) = obj.ToAreaCom(kgs, currentWbRde);
r.AreaCommitments.Add(areaCom);
if (wbrd != null) {
currentWbRde[wbrd.KgNr].Add(wbrd);
r.Riede.Add(wbrd);
}
if (timestamps.HasValue)
r.Timestamps["area_commitment"].Add((areaCom.FbNr, 0, timestamps.Value.CreatedAt, timestamps.Value.ModifiedAt));
}
}
@@ -132,10 +142,12 @@ namespace Elwig.Helpers.Export {
string? line;
while ((line = await reader.ReadLineAsync()) != null) {
var obj = JsonNode.Parse(line)!.AsObject();
var (d, parts, mods) = obj.ToDelivery(currentLsNrs, currentDids);
var (d, parts, mods, timestamps) = obj.ToDelivery(currentLsNrs, currentDids);
r.Deliveries.Add(d);
r.DeliveryParts.AddRange(parts);
r.Modifiers.AddRange(mods);
if (timestamps.HasValue)
r.Timestamps["delivery"].Add((d.Year, d.DId, timestamps.Value.CreatedAt, timestamps.Value.ModifiedAt));
}
}
}
@@ -144,7 +156,7 @@ namespace Elwig.Helpers.Export {
var importedAreaComs = new List<(string FileName, string ZwstId, string Device, int Imported, int NotImported, string Filters)>();
var importedDeliveries = new List<(string FileName, string ZwstId, string Device, int New, int Overwritten, int NotImported, string Filters)>();
foreach (var ((members, billingAddresses, telephoneNumbers, emailAddresses, areaCommitments, riede, deliveries, deliveryParts, modifiers), meta) in data.Zip(metaData)) {
foreach (var ((members, billingAddresses, telephoneNumbers, emailAddresses, areaCommitments, riede, deliveries, deliveryParts, modifiers, timestamps), meta) in data.Zip(metaData)) {
var branch = branches[meta.ZwstId];
var device = meta.Device;
@@ -272,6 +284,26 @@ namespace Elwig.Helpers.Export {
}
await ctx.SaveChangesAsync();
var primaryKeys = new Dictionary<string, string>() {
["member"] = "mgnr, 0",
["area_commitment"] = "fbnr, 0",
["delivery"] = "year, did",
};
var updateStmts = timestamps
.SelectMany(e => e.Value.Select(m => $"UPDATE {e.Key} " +
$"SET ctime = {((DateTimeOffset)m.CreatedAt.ToUniversalTime()).ToUnixTimeSeconds()}, " +
$"mtime = {((DateTimeOffset)m.ModifiedAt.ToUniversalTime()).ToUnixTimeSeconds()} " +
$"WHERE ({primaryKeys[e.Key]}) = ({m.Id1}, {m.Id2});"));
using var cnx = AppDbContext.Connect();
await AppDbContext.ExecuteBatch(cnx, $"""
BEGIN;
UPDATE client_parameter SET value = '0' WHERE param = 'ENABLE_TIME_TRIGGERS';
{string.Join("\n", updateStmts)}
UPDATE client_parameter SET value = '1' WHERE param = 'ENABLE_TIME_TRIGGERS';
COMMIT;
""");
await AddImportedFiles(Path.GetFileName(meta.FileName));
}
App.HintContextChange();
@@ -460,15 +492,19 @@ namespace Elwig.Helpers.Export {
return obj;
}).ToArray()),
["comment"] = m.Comment,
["created_at"] = $"{m.CreatedAt:yyyy-MM-ddTHH:mm:ssK}",
["modified_at"] = $"{m.ModifiedAt:yyyy-MM-ddTHH:mm:ssK}",
};
}
public static (Member, BillingAddr?, List<MemberTelNr>, List<MemberEmailAddr>) ToMember(this JsonNode json, Dictionary<int, AT_Kg> kgs) {
public static (Member, BillingAddr?, List<MemberTelNr>, List<MemberEmailAddr>, (DateTime CreatedAt, DateTime ModifiedAt)?) ToMember(this JsonNode json, Dictionary<int, AT_Kg> kgs) {
var mgnr = json["mgnr"]!.AsValue().GetValue<int>();
var kgnr = json["default_kgnr"]?.AsValue().GetValue<int>();
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>();
return (new Member {
MgNr = mgnr,
PredecessorMgNr = json["predecessor_mgnr"]?.AsValue().GetValue<int>(),
@@ -502,6 +538,7 @@ namespace Elwig.Helpers.Export {
ContactViaPost = json["contact_postal"]?.AsValue().GetValue<bool>() ?? false,
ContactViaEmail = json["contact_email"]?.AsValue().GetValue<bool>() ?? false,
Comment = json["comment"]?.AsValue().GetValue<string>(),
ImportedAt = DateTime.Now,
}, json["billing_address"] is JsonObject a ? new BillingAddr {
MgNr = mgnr,
FullName = a["name"]!.AsValue().GetValue<string>(),
@@ -519,7 +556,10 @@ namespace Elwig.Helpers.Export {
Nr = i + 1,
Address = a["address"]!.AsValue().GetValue<string>(),
Comment = a["comment"]?.AsValue().GetValue<string>(),
}).ToList());
}).ToList(),
createdAt == null || modifiedAt == null ? null :
(DateTime.ParseExact(createdAt, "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None),
DateTime.ParseExact(modifiedAt, "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None)));
}
public static JsonObject ToJson(this AreaCom c) {
@@ -535,10 +575,12 @@ namespace Elwig.Helpers.Export {
["year_from"] = c.YearFrom,
["year_to"] = c.YearTo,
["comment"] = c.Comment,
["created_at"] = $"{c.CreatedAt:yyyy-MM-ddTHH:mm:ssK}",
["modified_at"] = $"{c.ModifiedAt:yyyy-MM-ddTHH:mm:ssK}",
};
}
public static (AreaCom, WbRd?) ToAreaCom(this JsonNode json, Dictionary<int, AT_Kg> kgs, Dictionary<int, List<WbRd>> riede) {
public static (AreaCom, WbRd?, (DateTime CreatedAt, DateTime ModifiedAt)?) ToAreaCom(this JsonNode json, Dictionary<int, AT_Kg> kgs, Dictionary<int, List<WbRd>> riede) {
var kgnr = json["kgnr"]!.AsValue().GetValue<int>();
var ried = json["ried"]?.AsValue().GetValue<string>();
WbRd? rd = null;
@@ -556,6 +598,8 @@ namespace Elwig.Helpers.Export {
rde.Add(rd);
}
}
var createdAt = json["created_at"]?.AsValue().GetValue<string>();
var modifiedAt = json["modified_at"]?.AsValue().GetValue<string>();
return (new AreaCom {
FbNr = json["fbnr"]!.AsValue().GetValue<int>(),
MgNr = json["mgnr"]!.AsValue().GetValue<int>(),
@@ -568,7 +612,11 @@ namespace Elwig.Helpers.Export {
YearFrom = json["year_from"]?.AsValue().GetValue<int>(),
YearTo = json["year_to"]?.AsValue().GetValue<int>(),
Comment = json["comment"]?.AsValue().GetValue<string>(),
}, newRd ? rd : null);
ImportedAt = DateTime.Now,
}, newRd ? rd : null,
createdAt == null || modifiedAt == null ? null :
(DateTime.ParseExact(createdAt, "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None),
DateTime.ParseExact(modifiedAt, "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None)));
}
public static JsonObject ToJson(this Delivery d) {
@@ -596,6 +644,8 @@ namespace Elwig.Helpers.Export {
["manual_weighing"] = p.IsManualWeighing,
["modids"] = new JsonArray(p.Modifiers.Select(m => (JsonNode)m.ModId).ToArray()),
["comment"] = p.Comment,
["created_at"] = $"{p.CreatedAt:yyyy-MM-ddTHH:mm:ssK}",
["modified_at"] = $"{p.ModifiedAt:yyyy-MM-ddTHH:mm:ssK}",
};
if (p.IsSplCheck) obj["spl_check"] = p.IsSplCheck;
if (p.IsHandPicked != null) obj["hand_picked"] = p.IsHandPicked;
@@ -609,10 +659,12 @@ namespace Elwig.Helpers.Export {
return obj;
}).ToArray()),
["comment"] = d.Comment,
["created_at"] = $"{d.CreatedAt:yyyy-MM-ddTHH:mm:ssK}",
["modified_at"] = $"{d.ModifiedAt:yyyy-MM-ddTHH:mm:ssK}",
};
}
public static (Delivery, List<DeliveryPart>, List<DeliveryPartModifier>) ToDelivery(this JsonNode json, Dictionary<string, int> currentLsNrs, Dictionary<int, int> currentDids) {
public static (Delivery, List<DeliveryPart>, List<DeliveryPartModifier>, (DateTime CreatedAt, DateTime ModifiedAt)?) ToDelivery(this JsonNode json, Dictionary<string, int> currentLsNrs, Dictionary<int, int> currentDids) {
var year = json["year"]!.AsValue().GetValue<int>();
var lsnr = json["lsnr"]!.AsValue().GetValue<string>();
var did = currentLsNrs.GetValueOrDefault(lsnr, -1);
@@ -621,6 +673,8 @@ namespace Elwig.Helpers.Export {
did = ++currentDids[year];
}
currentLsNrs[lsnr] = did;
var createdAt = json["created_at"]?.AsValue().GetValue<string>();
var modifiedAt = json["modified_at"]?.AsValue().GetValue<string>();
return (new Delivery {
Year = year,
DId = did,
@@ -631,6 +685,7 @@ namespace Elwig.Helpers.Export {
LsNr = lsnr,
MgNr = json["mgnr"]!.AsValue().GetValue<int>(),
Comment = json["comment"]?.AsValue().GetValue<string>(),
ImportedAt = DateTime.Now,
}, json["parts"]!.AsArray().Select(p => p!.AsObject()).Select(p => new DeliveryPart {
Year = year,
DId = did,
@@ -661,7 +716,10 @@ namespace Elwig.Helpers.Export {
DId = did,
DPNr = p["dpnr"]!.AsValue().GetValue<int>(),
ModId = m!.AsValue().GetValue<string>(),
})).ToList());
})).ToList(),
createdAt == null || modifiedAt == null ? null :
(DateTime.ParseExact(createdAt, "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None),
DateTime.ParseExact(modifiedAt, "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None)));
}
}
}

@@ -317,7 +317,7 @@ namespace Elwig.Helpers.Export {
c = $"<{ct} office:value-type=\"string\" calcext:value-type=\"string\"{add}><text:p>{SecurityElement.Escape(data.ToString())}</text:p></{ct}>";
}
return $" {c}\r\n" + (colSpan > 1 ? $" <table:covered-table-cell table:number-rows-repeated=\"{colSpan - 1}\"/>\r\n" : "");
return $" {c}\r\n" + (colSpan > 1 ? $" <table:covered-table-cell table:number-columns-repeated=\"{colSpan - 1}\"/>\r\n" : "");
}
}
}

@@ -10,7 +10,7 @@ namespace Elwig.Helpers.Printing {
public static async Task Init(Action? evtHandler = null) {
var e = new RazorLightEngineBuilder()
.UseFileSystemProject(App.DataPath + "resources")
.UseFileSystemProject(App.DocumentsPath)
.UseMemoryCachingProvider()
.Build();

@@ -14,7 +14,7 @@ using System.Drawing.Printing;
namespace Elwig.Helpers.Printing {
public static class Pdf {
private static readonly string WinziPrint = new string[] { App.ExePath }
private static readonly string WinziPrint = new string[] { App.InstallPath }
.Union(Environment.GetEnvironmentVariable("PATH")?.Split(';') ?? [])
.Select(x => Path.Combine(x, "WinziPrint.exe"))
.Where(File.Exists)

@@ -499,34 +499,39 @@ namespace Elwig.Helpers {
if (App.Config.Smtp == null)
return false;
SmtpClient? client = null;
try {
Mouse.OverrideCursor = Cursors.AppStarting;
client = await GetSmtpClient();
Mouse.OverrideCursor = Cursors.Wait;
using var msg = new MimeMessage();
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;
var body = new Multipart("mixed") {
new TextPart("plain") { Text = text }
};
foreach (var doc in docs) {
var name = NormalizeFileName(doc.Title);
body.Add(doc.AsEmailAttachment($"{name}.pdf"));
var success = await Task.Run(async () => {
SmtpClient? client = null;
try {
client = await GetSmtpClient();
using var msg = new MimeMessage();
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;
var body = new Multipart("mixed") {
new TextPart("plain") { Text = text }
};
foreach (var doc in docs) {
var name = NormalizeFileName(doc.Title);
body.Add(doc.AsEmailAttachment($"{name}.pdf"));
}
msg.Body = body;
await client!.SendAsync(msg);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
return false;
} finally {
if (client != null)
await client.DisconnectAsync(true);
client?.Dispose();
}
msg.Body = body;
await client!.SendAsync(msg);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
return false;
} finally {
if (client != null)
await client.DisconnectAsync(true);
client?.Dispose();
Mouse.OverrideCursor = null;
}
return true;
return true;
});
Mouse.OverrideCursor = null;
return success;
}
public static async Task ExportDocument(Document doc, ExportMode mode, string? filename = null, (Member, string, string)? emailData = null) {

@@ -27,14 +27,14 @@ namespace Elwig.Models.Dtos {
MgNr = mgnr;
}
public static async Task<IDictionary<int, CreditNoteDeliveryData>> ForPaymentVariant(DbSet<CreditNoteDeliveryRowSingle> table, DbSet<Season> seasons, int year, int avnr) {
var variant = (await seasons.FindAsync(year))?.PaymentVariants.Where(v => v.AvNr == avnr).SingleOrDefault();
public static async Task<IDictionary<int, CreditNoteDeliveryData>> ForPaymentVariant(DbSet<CreditNoteDeliveryRowSingle> table, DbSet<PaymentVar> paymentVariants, int year, int avnr) {
var variant = await paymentVariants.FindAsync(year, avnr);
BillingData? varData = null;
try { varData = variant != null ? BillingData.FromJson(variant.Data) : null; } catch { }
return (await FromDbSet(table, year, avnr))
.GroupBy(
r => new { r.Year, r.AvNr, r.MgNr, r.TgNr, r.DId, r.DPNr },
(k, g) => new CreditNoteDeliveryRow(g, seasons, varData?.NetWeightModifier ?? 0.0, varData?.GrossWeightModifier ?? 0.0))
(k, g) => new CreditNoteDeliveryRow(g, variant, varData))
.GroupBy(
r => new { r.Year, r.AvNr, r.MgNr, r.TgNr },
(k, g) => new CreditNoteDeliveryData(g, k.Year, k.TgNr, mgnr: k.MgNr))
@@ -86,13 +86,13 @@ namespace Elwig.Models.Dtos {
public decimal? Amount;
public double WeighingModifier;
public CreditNoteDeliveryRow(IEnumerable<CreditNoteDeliveryRowSingle> rows, DbSet<Season> seasons, double netWeightModifier, double grossWeightModifier) {
public CreditNoteDeliveryRow(IEnumerable<CreditNoteDeliveryRowSingle> rows, PaymentVar paymentVariant, BillingData? varData) {
var f = rows.First();
Year = f.Year;
TgNr = f.TgNr;
AvNr = f.AvNr;
MgNr = f.MgNr;
var season = seasons.Find(Year);
var season = paymentVariant.Season;
LsNr = f.LsNr;
DPNr = f.DPNr;
@@ -115,7 +115,7 @@ namespace Elwig.Models.Dtos {
b.Price != null ? season?.DecFromDb((long)b.Price) : null,
b.Amount != null ? season?.DecFromDb((long)b.Amount) : null))
.ToArray();
WeighingModifier = f.NetWeight ? netWeightModifier : grossWeightModifier;
WeighingModifier = (varData == null || !varData.ConsiderDelieryModifiers) ? 0 : f.NetWeight ? varData.NetWeightModifier : varData.GrossWeightModifier;
Amount = f.TotalAmount != null ? season?.DecFromDb((long)f.TotalAmount) : null;
var netAmount = f.NetAmount != null ? season?.DecFromDb((long)f.NetAmount) : null;
var amt = netAmount * (decimal)(1.0 + WeighingModifier);

@@ -17,9 +17,9 @@ namespace Elwig.Models.Dtos {
("Name2", "Vorname", null, 40),
("DefaultKg", "Ort", null, 40),
("SortId", "Sorte", null, 10),
("Weight", "Gewicht", "kg", 20),
("CreatedTimestamp", "Angemeldet", null, 35),
("ModifiedTimestamp", "Geändert", null, 35),
("Weight", "Menge", "kg", 20),
("CreatedAt", "Angemeldet", null, 35),
("ModifiedAt", "Geändert", null, 35),
("Status", "Status", null, 20),
];
@@ -47,8 +47,8 @@ namespace Elwig.Models.Dtos {
public string? DefaultKg;
public string SortId;
public string Variety;
public DateTime CreatedTimestamp;
public DateTime? ModifiedTimestamp;
public DateTime CreatedAt;
public DateTime? ModifiedAt;
public int Weight;
public string? Status;
@@ -65,10 +65,10 @@ namespace Elwig.Models.Dtos {
DefaultKg = m.DefaultKg?.Name;
SortId = a.SortId;
Variety = a.Variety.Name;
CreatedTimestamp = a.CreatedTimestamp;
ModifiedTimestamp = a.ModifiedTimestamp == a.CreatedTimestamp ? null : a.ModifiedTimestamp;
CreatedAt = a.CreatedAt;
ModifiedAt = a.ModifiedAt == a.CreatedAt ? null : a.ModifiedAt;
Weight = a.Weight;
Status = s.AncmtTo == null ? null : a.CreatedTimestamp >= s.AncmtTo ? "verspät." : "ok";
Status = s.AncmtTo == null ? null : a.CreatedAt >= s.AncmtTo ? "verspät." : "ok";
}
}
}

@@ -16,7 +16,7 @@ namespace Elwig.Models.Dtos {
("QualityLevel", "Qualitätsstufe", null, 25),
("Gradation", "Gradation", "°Oe|°KMW", 32),
("Buckets", "Flächenbindung", "|kg", 36),
("Weight", "Gewicht", "kg", 16),
("Weight", "Menge", "kg", 16),
];
private readonly int MgNr;

@@ -24,7 +24,7 @@ namespace Elwig.Models.Dtos {
("CultId", "Bewirt.", null, 15),
("QualId", "Qualität", null, 15),
("Gradation", "Gradation", "°Oe|°KMW", 40),
("Weight", "Gewicht", "kg", 20),
("Weight", "Menge", "kg", 20),
("IsNetWeight", "Gerebelt", null, 20),
("HkId", "Herkunft", null, 20),
("Modifiers", "Zu-/Abschläge", null, 40),

@@ -18,8 +18,9 @@ namespace Elwig.Models.Dtos {
("Cultivation", "Bewirt.", null, 20),
("QualityLevel", "Qualitätsstufe", null, 30),
("Oe", "Gradation", "°Oe", 20),
("Ungeb", "ungebunden", "kg|€/kg", 40),
("Geb", "gebunden", "kg|€/kg", 40),
("Ungeb", "ungebunden", "kg|€/kg|€/kg", 60),
("LowGeb", "attributlos gebunden", "kg|€/kg|€/kg", 60),
("Geb", "gebunden", "kg|€/kg|€/kg", 60),
("Amount", "Gesamt", "€", 25),
];
@@ -30,8 +31,9 @@ namespace Elwig.Models.Dtos {
string? Cultivation,
string QualityLevel,
double Oe,
(int Weight, decimal? Price) Ungeb,
(int Weight, decimal? Price) Geb,
(int Weight, decimal? MinPrice, decimal? MaxPrice) Ungeb,
(int Weight, decimal? MinPrice, decimal? MaxPrice) LowGeb,
(int Weight, decimal? MinPrice, decimal? MaxPrice) Geb,
decimal Amount
);
@@ -42,8 +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.WeightUngeb, r.PriceUngeb != null ? Utils.DecFromDb(r.PriceUngeb.Value, v.Season.Precision) : null),
(r.WeightGeb, r.PriceGeb != null ? Utils.DecFromDb(r.PriceGeb.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());
}
@@ -57,19 +60,23 @@ namespace Elwig.Models.Dtos {
q.name AS quality_level,
ROUND(kmw * (4.54 + 0.022 * kmw)) AS oe,
SUM(IIF(w.discr = '_', w.value, 0)) AS weight_ungeb,
MAX(IIF(w.discr = '_', b.price, NULL)) AS price_ungeb,
SUM(IIF(w.discr != '_', w.value, 0)) AS weight_geb,
MAX(IIF(w.discr != '_', b.price, NULL)) AS price_geb,
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)
LEFT JOIN delivery_part p ON (p.year, p.did, p.dpnr) = (b.year, b.did, b.dpnr)
LEFT JOIN delivery d ON (d.year, d.did) = (p.year, p.did)
LEFT JOIN wine_variety v ON v.sortid = p.sortid
LEFT JOIN wine_attribute a ON a.attrid = p.attrid
LEFT JOIN wine_cultivation c ON c.cultid = p.cultid
LEFT JOIN wine_quality_level q ON q.qualid = p.qualid
WHERE d.year = {year} AND b.avnr = {avnr}
WHERE p.year = {year} AND b.avnr = {avnr}
GROUP BY variety, attribute, cultivation, q.min_kmw, oe
ORDER BY variety, attribute, cultivation, q.min_kmw, oe
""").ToListAsync();
@@ -92,12 +99,22 @@ namespace Elwig.Models.Dtos {
public double Oe { get; set; }
[Column("weight_ungeb")]
public int WeightUngeb { get; set; }
[Column("price_ungeb")]
public long? PriceUngeb { 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("price_geb")]
public long? PriceGeb { 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; }
}

@@ -14,7 +14,7 @@ namespace Elwig.Models.Dtos {
("CultId", "Bewirt.", null, 15),
("QualId", "Qual.", null, 15),
("Geb", "gebunden", null, 20),
("Weight", "Gewicht", "kg", 20),
("Weight", "Menge", "kg", 20),
];
public WeightBreakdownData(IEnumerable<WeightBreakdownRow> rows, int year, string name) :

@@ -17,7 +17,7 @@ namespace Elwig.Models.Dtos {
("Members", "Mitgl.", "#", 15),
("Deliveries", "Lfrg.", "#", 15),
("Parts", "Teill.", "#", 15),
("Weight", "Gewicht", "kg", 20),
("Weight", "Menge", "kg", 20),
("Gradation", "Gradation", "°Oe|°KMW", 30),
];

@@ -41,14 +41,36 @@ namespace Elwig.Models.Entities {
public string? Comment { get; set; }
[Column("ctime"), DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public long CTime { get; private set; }
public long CTime { get; set; }
[NotMapped]
public DateTime CreatedTimestamp => DateTimeOffset.FromUnixTimeSeconds(CTime).LocalDateTime;
public DateTime CreatedAt {
get => DateTimeOffset.FromUnixTimeSeconds(CTime).LocalDateTime;
set => CTime = ((DateTimeOffset)value.ToUniversalTime()).ToUnixTimeSeconds();
}
[Column("mtime"), DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public long MTime { get; private set; }
public long MTime { get; set; }
[NotMapped]
public DateTime ModifiedTimestamp => DateTimeOffset.FromUnixTimeSeconds(MTime).LocalDateTime;
public DateTime ModifiedAt {
get => DateTimeOffset.FromUnixTimeSeconds(MTime).LocalDateTime;
set => MTime = ((DateTimeOffset)value.ToUniversalTime()).ToUnixTimeSeconds();
}
[Column("xtime")]
public long? XTime { get; set; }
[NotMapped]
public DateTime? ExportedAt {
get => XTime == null ? null : DateTimeOffset.FromUnixTimeSeconds(XTime.Value).LocalDateTime;
set => XTime = value == null ? null : ((DateTimeOffset)value.Value.ToUniversalTime()).ToUnixTimeSeconds();
}
[Column("itime")]
public long? ITime { get; set; }
[NotMapped]
public DateTime? ImportedAt {
get => ITime == null ? null : DateTimeOffset.FromUnixTimeSeconds(ITime.Value).LocalDateTime;
set => ITime = value == null ? null : ((DateTimeOffset)value.Value.ToUniversalTime()).ToUnixTimeSeconds();
}
[ForeignKey("MgNr")]
public virtual Member Member { get; private set; } = null!;

@@ -84,14 +84,36 @@ namespace Elwig.Models.Entities {
}
[Column("ctime"), DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public long CTime { get; private set; }
public long CTime { get; set; }
[NotMapped]
public DateTime CreatedTimestamp => DateTimeOffset.FromUnixTimeSeconds(CTime).LocalDateTime;
public DateTime CreatedAt {
get => DateTimeOffset.FromUnixTimeSeconds(CTime).LocalDateTime;
set => CTime = ((DateTimeOffset)value.ToUniversalTime()).ToUnixTimeSeconds();
}
[Column("mtime"), DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public long MTime { get; private set; }
public long MTime { get; set; }
[NotMapped]
public DateTime ModifiedTimestamp => DateTimeOffset.FromUnixTimeSeconds(MTime).LocalDateTime;
public DateTime ModifiedAt {
get => DateTimeOffset.FromUnixTimeSeconds(MTime).LocalDateTime;
set => MTime = ((DateTimeOffset)value.ToUniversalTime()).ToUnixTimeSeconds();
}
[Column("xtime")]
public long? XTime { get; set; }
[NotMapped]
public DateTime? ExportedAt {
get => XTime == null ? null : DateTimeOffset.FromUnixTimeSeconds(XTime.Value).LocalDateTime;
set => XTime = value == null ? null : ((DateTimeOffset)value.Value.ToUniversalTime()).ToUnixTimeSeconds();
}
[Column("itime")]
public long? ITime { get; set; }
[NotMapped]
public DateTime? ImportedAt {
get => ITime == null ? null : DateTimeOffset.FromUnixTimeSeconds(ITime.Value).LocalDateTime;
set => ITime = value == null ? null : ((DateTimeOffset)value.Value.ToUniversalTime()).ToUnixTimeSeconds();
}
[ForeignKey("Year, AvNr, MgNr")]
public virtual PaymentMember Payment { get; private set; } = null!;

@@ -4,6 +4,7 @@ using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Windows.Media;
using IndexAttribute = Microsoft.EntityFrameworkCore.IndexAttribute;
namespace Elwig.Models.Entities {
@@ -62,14 +63,36 @@ namespace Elwig.Models.Entities {
public string? Comment { get; set; }
[Column("ctime"), DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public long CTime { get; private set; }
public long CTime { get; set; }
[NotMapped]
public DateTime CreatedTimestamp => DateTimeOffset.FromUnixTimeSeconds(CTime).LocalDateTime;
public DateTime CreatedAt {
get => DateTimeOffset.FromUnixTimeSeconds(CTime).LocalDateTime;
set => CTime = ((DateTimeOffset)value.ToUniversalTime()).ToUnixTimeSeconds();
}
[Column("mtime"), DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public long MTime { get; private set; }
public long MTime { get; set; }
[NotMapped]
public DateTime ModifiedTimestamp => DateTimeOffset.FromUnixTimeSeconds(MTime).LocalDateTime;
public DateTime ModifiedAt {
get => DateTimeOffset.FromUnixTimeSeconds(MTime).LocalDateTime;
set => MTime = ((DateTimeOffset)value.ToUniversalTime()).ToUnixTimeSeconds();
}
[Column("xtime")]
public long? XTime { get; set; }
[NotMapped]
public DateTime? ExportedAt {
get => XTime == null ? null : DateTimeOffset.FromUnixTimeSeconds(XTime.Value).LocalDateTime;
set => XTime = value == null ? null : ((DateTimeOffset)value.Value.ToUniversalTime()).ToUnixTimeSeconds();
}
[Column("itime")]
public long? ITime { get; set; }
[NotMapped]
public DateTime? ImportedAt {
get => ITime == null ? null : DateTimeOffset.FromUnixTimeSeconds(ITime.Value).LocalDateTime;
set => ITime = value == null ? null : ((DateTimeOffset)value.Value.ToUniversalTime()).ToUnixTimeSeconds();
}
[ForeignKey("Year")]
public virtual Season Season { get; private set; } = null!;
@@ -96,6 +119,9 @@ namespace Elwig.Models.Entities {
public string SortIdString => string.Join(", ", SortIds);
public string FilteredSortIdString => string.Join(", ", FilteredSortIds);
public Brush? Color => Parts.Select(p => p.Variety.Color).Distinct().SingleOrDefault();
public Brush? FilteredColor => FilteredParts.Select(p => p.Variety.Color).Distinct().SingleOrDefault();
public IEnumerable<string> Modifiers => Parts
.SelectMany(p => p.Modifiers)
.Select(m => m.Name)

@@ -27,14 +27,36 @@ namespace Elwig.Models.Entities {
public required string Type { get; set; }
[Column("ctime"), DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public long CTime { get; private set; }
public long CTime { get; set; }
[NotMapped]
public DateTime CreatedTimestamp => DateTimeOffset.FromUnixTimeSeconds(CTime).LocalDateTime;
public DateTime CreatedAt {
get => DateTimeOffset.FromUnixTimeSeconds(CTime).LocalDateTime;
set => CTime = ((DateTimeOffset)value.ToUniversalTime()).ToUnixTimeSeconds();
}
[Column("mtime"), DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public long MTime { get; private set; }
public long MTime { get; set; }
[NotMapped]
public DateTime ModifiedTimestamp => DateTimeOffset.FromUnixTimeSeconds(MTime).LocalDateTime;
public DateTime ModifiedAt {
get => DateTimeOffset.FromUnixTimeSeconds(MTime).LocalDateTime;
set => MTime = ((DateTimeOffset)value.ToUniversalTime()).ToUnixTimeSeconds();
}
[Column("xtime")]
public long? XTime { get; set; }
[NotMapped]
public DateTime? ExportedAt {
get => XTime == null ? null : DateTimeOffset.FromUnixTimeSeconds(XTime.Value).LocalDateTime;
set => XTime = value == null ? null : ((DateTimeOffset)value.Value.ToUniversalTime()).ToUnixTimeSeconds();
}
[Column("itime")]
public long? ITime { get; set; }
[NotMapped]
public DateTime? ImportedAt {
get => ITime == null ? null : DateTimeOffset.FromUnixTimeSeconds(ITime.Value).LocalDateTime;
set => ITime = value == null ? null : ((DateTimeOffset)value.Value.ToUniversalTime()).ToUnixTimeSeconds();
}
[ForeignKey("Year, DsNr")]
public virtual DeliverySchedule Schedule { get; private set; } = null!;

@@ -129,14 +129,36 @@ namespace Elwig.Models.Entities {
public string? Comment { get; set; }
[Column("ctime"), DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public long CTime { get; private set; }
public long CTime { get; set; }
[NotMapped]
public DateTime CreatedTimestamp => DateTimeOffset.FromUnixTimeSeconds(CTime).LocalDateTime;
public DateTime CreatedAt {
get => DateTimeOffset.FromUnixTimeSeconds(CTime).LocalDateTime;
set => CTime = ((DateTimeOffset)value.ToUniversalTime()).ToUnixTimeSeconds();
}
[Column("mtime"), DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public long MTime { get; private set; }
public long MTime { get; set; }
[NotMapped]
public DateTime ModifiedTimestamp => DateTimeOffset.FromUnixTimeSeconds(MTime).LocalDateTime;
public DateTime ModifiedAt {
get => DateTimeOffset.FromUnixTimeSeconds(MTime).LocalDateTime;
set => MTime = ((DateTimeOffset)value.ToUniversalTime()).ToUnixTimeSeconds();
}
[Column("xtime")]
public long? XTime { get; set; }
[NotMapped]
public DateTime? ExportedAt {
get => XTime == null ? null : DateTimeOffset.FromUnixTimeSeconds(XTime.Value).LocalDateTime;
set => XTime = value == null ? null : ((DateTimeOffset)value.Value.ToUniversalTime()).ToUnixTimeSeconds();
}
[Column("itime")]
public long? ITime { get; set; }
[NotMapped]
public DateTime? ImportedAt {
get => ITime == null ? null : DateTimeOffset.FromUnixTimeSeconds(ITime.Value).LocalDateTime;
set => ITime = value == null ? null : ((DateTimeOffset)value.Value.ToUniversalTime()).ToUnixTimeSeconds();
}
[InverseProperty(nameof(DeliveryPartModifier.Part))]
public virtual ICollection<DeliveryPartModifier> PartModifiers { get; private set; } = null!;

@@ -145,14 +145,36 @@ namespace Elwig.Models.Entities {
public AT_Kg? DefaultKg => DefaultWbKg?.AtKg;
[Column("ctime"), DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public long CTime { get; private set; }
public long CTime { get; set; }
[NotMapped]
public DateTime CreatedTimestamp => DateTimeOffset.FromUnixTimeSeconds(CTime).LocalDateTime;
public DateTime CreatedAt {
get => DateTimeOffset.FromUnixTimeSeconds(CTime).LocalDateTime;
set => CTime = ((DateTimeOffset)value.ToUniversalTime()).ToUnixTimeSeconds();
}
[Column("mtime"), DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public long MTime { get; private set; }
public long MTime { get; set; }
[NotMapped]
public DateTime ModifiedTimestamp => DateTimeOffset.FromUnixTimeSeconds(MTime).LocalDateTime;
public DateTime ModifiedAt {
get => DateTimeOffset.FromUnixTimeSeconds(MTime).LocalDateTime;
set => MTime = ((DateTimeOffset)value.ToUniversalTime()).ToUnixTimeSeconds();
}
[Column("xtime")]
public long? XTime { get; set; }
[NotMapped]
public DateTime? ExportedAt {
get => XTime == null ? null : DateTimeOffset.FromUnixTimeSeconds(XTime.Value).LocalDateTime;
set => XTime = value == null ? null : ((DateTimeOffset)value.Value.ToUniversalTime()).ToUnixTimeSeconds();
}
[Column("itime")]
public long? ITime { get; set; }
[NotMapped]
public DateTime? ImportedAt {
get => ITime == null ? null : DateTimeOffset.FromUnixTimeSeconds(ITime.Value).LocalDateTime;
set => ITime = value == null ? null : ((DateTimeOffset)value.Value.ToUniversalTime()).ToUnixTimeSeconds();
}
[ForeignKey("ZwstId")]
public virtual Branch? Branch { get; private set; }

@@ -46,14 +46,36 @@ namespace Elwig.Models.Entities {
public required string Data { get; set; }
[Column("ctime"), DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public long CTime { get; private set; }
public long CTime { get; set; }
[NotMapped]
public DateTime CreatedTimestamp => DateTimeOffset.FromUnixTimeSeconds(CTime).LocalDateTime;
public DateTime CreatedAt {
get => DateTimeOffset.FromUnixTimeSeconds(CTime).LocalDateTime;
set => CTime = ((DateTimeOffset)value.ToUniversalTime()).ToUnixTimeSeconds();
}
[Column("mtime"), DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public long MTime { get; private set; }
public long MTime { get; set; }
[NotMapped]
public DateTime ModifiedTimestamp => DateTimeOffset.FromUnixTimeSeconds(MTime).LocalDateTime;
public DateTime ModifiedAt {
get => DateTimeOffset.FromUnixTimeSeconds(MTime).LocalDateTime;
set => MTime = ((DateTimeOffset)value.ToUniversalTime()).ToUnixTimeSeconds();
}
[Column("xtime")]
public long? XTime { get; set; }
[NotMapped]
public DateTime? ExportedAt {
get => XTime == null ? null : DateTimeOffset.FromUnixTimeSeconds(XTime.Value).LocalDateTime;
set => XTime = value == null ? null : ((DateTimeOffset)value.Value.ToUniversalTime()).ToUnixTimeSeconds();
}
[Column("itime")]
public long? ITime { get; set; }
[NotMapped]
public DateTime? ImportedAt {
get => ITime == null ? null : DateTimeOffset.FromUnixTimeSeconds(ITime.Value).LocalDateTime;
set => ITime = value == null ? null : ((DateTimeOffset)value.Value.ToUniversalTime()).ToUnixTimeSeconds();
}
[ForeignKey("Year")]
public virtual Season Season { get; private set; } = null!;

@@ -1,5 +1,6 @@
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations.Schema;
using System.Windows.Media;
namespace Elwig.Models.Entities {
[Table("wine_variety"), PrimaryKey("SortId")]
@@ -20,6 +21,7 @@ namespace Elwig.Models.Entities {
public bool IsRed => Type == "R";
public bool IsWhite => Type == "W";
public Brush? Color => IsWhite ? Brushes.DarkGreen : IsRed ? Brushes.DarkRed : null;
public WineVar() { }

@@ -0,0 +1,33 @@
-- schema version 31 to 32
INSERT INTO client_parameter (param, value) VALUES ('ENABLE_TIME_TRIGGERS', '1');
ALTER TABLE member ADD COLUMN xtime INTEGER DEFAULT NULL;
ALTER TABLE member ADD COLUMN itime INTEGER DEFAULT NULL;
ALTER TABLE area_commitment ADD COLUMN xtime INTEGER DEFAULT NULL;
ALTER TABLE area_commitment ADD COLUMN itime INTEGER DEFAULT NULL;
ALTER TABLE delivery_announcement ADD COLUMN xtime INTEGER DEFAULT NULL;
ALTER TABLE delivery_announcement ADD COLUMN itime INTEGER DEFAULT NULL;
ALTER TABLE delivery ADD COLUMN xtime INTEGER DEFAULT NULL;
ALTER TABLE delivery ADD COLUMN itime INTEGER DEFAULT NULL;
ALTER TABLE delivery_part ADD COLUMN xtime INTEGER DEFAULT NULL;
ALTER TABLE delivery_part ADD COLUMN itime INTEGER DEFAULT NULL;
ALTER TABLE payment_variant ADD COLUMN xtime INTEGER DEFAULT NULL;
ALTER TABLE payment_variant ADD COLUMN itime INTEGER DEFAULT NULL;
ALTER TABLE credit ADD COLUMN xtime INTEGER DEFAULT NULL;
ALTER TABLE credit ADD COLUMN itime INTEGER DEFAULT NULL;
PRAGMA writable_schema = ON;
UPDATE sqlite_schema SET sql = REPLACE(REPLACE(sql,
' WHEN',
' WHEN (SELECT value FROM client_parameter WHERE param = ''ENABLE_TIME_TRIGGERS'') = 1 AND'),
'FOR EACH ROW' || char(10) ||
'BEGIN',
'FOR EACH ROW' || char(10) ||
' WHEN (SELECT value FROM client_parameter WHERE param = ''ENABLE_TIME_TRIGGERS'') = 1' || char(10) ||
'BEGIN')
WHERE type = 'trigger' AND name LIKE '%time%';
PRAGMA writable_schema = OFF;
PRAGMA schema_version = 3101;

@@ -106,12 +106,13 @@ namespace Elwig.Services {
}
public static async Task<int> UpdateAreaCommitment(this AreaComAdminViewModel vm, int? oldFbNr) {
int newFbNr = (int)vm.FbNr!;
int newFbNr = vm.FbNr!.Value;
using (var ctx = new AppDbContext()) {
return await Task.Run(async () => {
using var ctx = new AppDbContext();
var a = new AreaCom {
FbNr = oldFbNr ?? newFbNr,
MgNr = (int)vm.MgNr!,
MgNr = vm.MgNr!.Value,
YearFrom = vm.YearFrom,
YearTo = vm.YearTo,
VtrgId = vm.AreaComType!.VtrgId,
@@ -119,8 +120,8 @@ namespace Elwig.Services {
Comment = string.IsNullOrEmpty(vm.Comment) ? null : vm.Comment,
KgNr = vm.Kg!.KgNr,
RdNr = vm.Rd?.RdNr,
GstNr = vm.GstNr!.Trim(),
Area = (int)vm.Area!,
GstNr = vm.GstNr?.Trim() ?? "-",
Area = vm.Area!.Value,
};
if (vm.Rd?.RdNr == 0) {
@@ -140,11 +141,9 @@ namespace Elwig.Services {
if (newFbNr != a.FbNr) {
await ctx.Database.ExecuteSqlAsync($"UPDATE area_commitment SET fbnr = {newFbNr} WHERE fbnr = {oldFbNr}");
}
}
App.HintContextChange();
return newFbNr;
return newFbNr;
});
}
private static void AddToolTipCell(Grid grid, string text, int row, int col, int colSpan = 1, bool bold = false, bool alignRight = false, bool alignCenter = false) {
@@ -253,5 +252,14 @@ namespace Elwig.Services {
}
return grid;
}
public static async Task DeleteAreaCom(int fbnr) {
await Task.Run(async () => {
using var ctx = new AppDbContext();
var l = (await ctx.AreaCommitments.FindAsync(fbnr))!;
ctx.Remove(l);
await ctx.SaveChangesAsync();
});
}
}
}

@@ -37,8 +37,8 @@ namespace Elwig.Services {
vm.DeliverySchedule = (DeliverySchedule?)ControlUtils.GetItemFromSourceWithPk(vm.DeliveryScheduleSource, a.Year, a.DsNr);
vm.SortId = a.SortId;
vm.Weight = a.Weight;
vm.StatusAncmtCreated = $"{a.CreatedTimestamp:dd.MM.yyyy, HH:mm} ({a.Type})";
vm.StatusAncmtModified = a.ModifiedTimestamp != a.CreatedTimestamp ? $"{a.ModifiedTimestamp:dd.MM.yyyy, HH:mm}" : "-";
vm.StatusAncmtCreated = $"{a.CreatedAt:dd.MM.yyyy, HH:mm} ({a.Type})";
vm.StatusAncmtModified = a.ModifiedAt != a.CreatedAt ? $"{a.ModifiedAt:dd.MM.yyyy, HH:mm}" : "-";
}
public static async Task<(List<string>, IQueryable<DeliveryAncmt>, List<string>)> GetFilters(this DeliveryAncmtAdminViewModel vm, AppDbContext ctx) {
@@ -211,7 +211,8 @@ namespace Elwig.Services {
int newMgNr = vm.MgNr!.Value;
string newSortId = vm.SortId!;
using (var ctx = new AppDbContext()) {
return await Task.Run(async () => {
using var ctx = new AppDbContext();
var a = new DeliveryAncmt {
Year = oldYear ?? year,
DsNr = oldDsNr ?? dsnr,
@@ -232,11 +233,9 @@ namespace Elwig.Services {
if (oldDsNr != null && (oldYear != year || oldDsNr != dsnr || oldMgNr != newMgNr || oldSortId != newSortId)) {
await ctx.Database.ExecuteSqlAsync($"UPDATE delivery_announcement SET year = {year}, dsnr = {dsnr}, mgnr = {newMgNr}, sortid = {newSortId} WHERE (year, dsnr, mgnr, sortid) = ({a.Year}, {a.DsNr}, {a.MgNr}, {a.SortId})");
}
}
App.HintContextChange();
return (year, dsnr, newMgNr, newSortId);
return (year, dsnr, newMgNr, newSortId);
});
}
public static async Task GenerateDeliveryAncmtList(this DeliveryAncmtAdminViewModel vm, ExportSubject subject, ExportMode mode) {
@@ -269,25 +268,29 @@ namespace Elwig.Services {
Title = $"{DeliveryAncmtList.Name} speichern unter - Elwig"
};
if (d.ShowDialog() == true) {
Mouse.OverrideCursor = Cursors.AppStarting;
try {
var data = await DeliveryAncmtListData.FromQuery(query, filterNames);
using var ods = new OdsFile(d.FileName);
await ods.AddTable(data);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
var data = await DeliveryAncmtListData.FromQuery(query, filterNames);
using var ods = new OdsFile(d.FileName);
await ods.AddTable(data);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
}
} else {
Mouse.OverrideCursor = Cursors.AppStarting;
try {
var data = await DeliveryAncmtListData.FromQuery(query, filterNames);
using var doc = new DeliveryAncmtList(string.Join(" / ", filterNames), data);
await Utils.ExportDocument(doc, mode);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
var data = await DeliveryAncmtListData.FromQuery(query, filterNames);
using var doc = new DeliveryAncmtList(string.Join(" / ", filterNames), data);
await Utils.ExportDocument(doc, mode);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
}
}
@@ -326,7 +329,7 @@ namespace Elwig.Services {
var weight = await deliveryAncmts.SumAsync(p => p.Weight);
text = $"{weight:N0} kg";
AddToolTipRow(grid, 0, "Gewicht", null, weight, null, weight);
AddToolTipRow(grid, 0, "Menge", null, weight, null, weight);
if (await deliveryAncmts.AnyAsync()) {
var attrGroups = await deliveryAncmts

@@ -152,7 +152,8 @@ namespace Elwig.Services {
public static async Task UpdateDeliverySchedule(this DeliveryScheduleAdminViewModel vm, int? oldYear, int? oldDsNr) {
int year = vm.Date!.Value.Year;
using (var ctx = new AppDbContext()) {
await Task.Run(async () => {
using var ctx = new AppDbContext();
var s = new DeliverySchedule {
Year = oldYear ?? year,
DsNr = oldDsNr ?? await ctx.NextDsNr(year),
@@ -181,9 +182,7 @@ namespace Elwig.Services {
.ToList(), vm.MainVarieties.Select(v => (v, 1)).Union(vm.OtherVarieties.Select(v => (v, 2))).ToList());
await ctx.SaveChangesAsync();
}
App.HintContextChange();
});
}
}
}

@@ -430,9 +430,10 @@ namespace Elwig.Services {
}
public static async Task<DeliveryPart> UpdateDeliveryPart(this DeliveryAdminViewModel vm, int? oldYear, int? oldDid, int? oldDpnr, bool dateHasChanged, bool timeHasChanged, bool timeIsDefault) {
DeliveryPart p;
return await Task.Run(async () => {
DeliveryPart p;
using (var ctx = new AppDbContext()) {
using var ctx = new AppDbContext();
int year = oldYear ?? Utils.CurrentYear;
int did = oldDid ?? await ctx.NextDId(year);
int dpnr = oldDpnr ?? await ctx.NextDPNr(year, did);
@@ -524,17 +525,16 @@ namespace Elwig.Services {
}
await ctx.SaveChangesAsync();
}
App.HintContextChange();
return p;
return p;
});
}
public static async Task<Delivery> SplitDeliveryToMember(int year, int did, int[] weights, int mgnr) {
Delivery n;
return await Task.Run(async () => {
Delivery n;
using (var ctx = new AppDbContext()) {
using var ctx = new AppDbContext();
bool anyLeft = false;
var d = (await ctx.Deliveries.FindAsync(year, did))!;
var lnr = await ctx.NextLNr(d.Date, d.ZwstId);
@@ -577,17 +577,15 @@ namespace Elwig.Services {
await ctx.SaveChangesAsync();
if (!anyLeft)
await ctx.Database.ExecuteSqlAsync($"DELETE FROM delivery WHERE (year, did) = ({d.Year}, {d.DId})");
}
App.HintContextChange();
return n;
return n;
});
}
public static async Task<Delivery> SplitDeliveryToLsNr(int year, int did, int[] weights, string lsnr) {
Delivery n;
using (var ctx = new AppDbContext()) {
return await Task.Run(async () => {
Delivery n;
using var ctx = new AppDbContext();
var anyLeft = false;
n = (await ctx.Deliveries.FirstAsync(d => d.LsNr == lsnr))!;
var d = (await ctx.Deliveries.FindAsync(year, did))!;
@@ -616,15 +614,14 @@ namespace Elwig.Services {
await ctx.SaveChangesAsync();
if (!anyLeft && n.LsNr != d.LsNr)
await ctx.Database.ExecuteSqlAsync($"DELETE FROM delivery WHERE (year, did) = ({d.Year}, {d.DId})");
}
App.HintContextChange();
return n;
return n;
});
}
public static async Task DepreciateDelivery(int year, int did, int[] weights) {
using (var ctx = new AppDbContext()) {
await Task.Run(async () => {
using var ctx = new AppDbContext();
var d = (await ctx.Deliveries.FindAsync(year, did))!;
var dpnr = await ctx.NextDPNr(year, did);
foreach (var (p, w) in d.Parts.ToList().Zip(weights)) {
@@ -648,21 +645,21 @@ namespace Elwig.Services {
}
}
await ctx.SaveChangesAsync();
}
App.HintContextChange();
});
}
public static async Task GenerateDeliveryNote(int year, int did, ExportMode mode) {
Mouse.OverrideCursor = Cursors.AppStarting;
try {
using var ctx = new AppDbContext();
var d = (await ctx.Deliveries.FindAsync(year, did))!;
using var doc = new DeliveryNote(d, ctx);
await Utils.ExportDocument(doc, mode, d.LsNr, (d.Member, $"{DeliveryNote.Name} Nr. {d.LsNr}", $"Im Anhang finden Sie den {DeliveryNote.Name} Nr. {d.LsNr}"));
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
using var ctx = new AppDbContext();
var d = (await ctx.Deliveries.FindAsync(year, did))!;
using var doc = new DeliveryNote(d, ctx);
await Utils.ExportDocument(doc, mode, d.LsNr, (d.Member, $"{DeliveryNote.Name} Nr. {d.LsNr}", $"Im Anhang finden Sie den {DeliveryNote.Name} Nr. {d.LsNr}"));
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
}
@@ -707,14 +704,16 @@ namespace Elwig.Services {
Title = $"{DeliveryJournal.Name} speichern unter - Elwig"
};
if (d.ShowDialog() == true) {
Mouse.OverrideCursor = Cursors.AppStarting;
try {
var data = await DeliveryJournalData.FromQuery(query, filterNames);
using var ods = new OdsFile(d.FileName);
await ods.AddTable(data);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
var data = await DeliveryJournalData.FromQuery(query, filterNames);
using var ods = new OdsFile(d.FileName);
await ods.AddTable(data);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
}
} else if (mode == ExportMode.Export) {
@@ -725,58 +724,64 @@ namespace Elwig.Services {
Title = $"{DeliveryJournal.Name} speichern unter - Elwig"
};
if (d.ShowDialog() == true) {
Mouse.OverrideCursor = Cursors.AppStarting;
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
await ElwigData.Export(d.FileName, await query
.Select(p => p.Delivery)
.Distinct()
.Include(d => d.Parts)
.ThenInclude(p => p.PartModifiers)
.AsSplitQuery()
.ToListAsync(), filterNames);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
}
} else if (mode == ExportMode.Upload && App.Config.SyncUrl != null) {
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
await ElwigData.Export(d.FileName, await query
var filename = $"{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{App.ZwstId}.elwig.zip";
var path = Path.Combine(App.TempPath, filename);
var list = await query
.Select(p => p.Delivery)
.Distinct()
.Include(d => d.Parts)
.ThenInclude(p => p.PartModifiers)
.AsSplitQuery()
.ToListAsync(), filterNames);
.ToListAsync();
if (list.Count == 0) {
MessageBox.Show("Es wurden keine Lieferungen zum Hochladen ausgewählt!", "Lieferungen hochladen",
MessageBoxButton.OK, MessageBoxImage.Error);
} else {
await ElwigData.Export(path, list, filterNames);
await Utils.UploadExportData(path, App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
MessageBox.Show($"Hochladen von {list.Count:N0} Lieferungen erfolgreich!", "Lieferungen hochgeladen",
MessageBoxButton.OK, MessageBoxImage.Information);
}
} catch (HttpRequestException exc) {
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Lieferungen hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
} catch (TaskCanceledException exc) {
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = null;
}
} else if (mode == ExportMode.Upload && App.Config.SyncUrl != null) {
Mouse.OverrideCursor = Cursors.AppStarting;
try {
var filename = $"{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{App.ZwstId}.elwig.zip";
var path = Path.Combine(App.TempPath, filename);
var list = await query
.Select(p => p.Delivery)
.Distinct()
.Include(d => d.Parts)
.ThenInclude(p => p.PartModifiers)
.AsSplitQuery()
.ToListAsync();
if (list.Count == 0) {
MessageBox.Show("Es wurden keine Lieferungen zum Hochladen ausgewählt!", "Lieferungen hochladen",
MessageBoxButton.OK, MessageBoxImage.Error);
} else {
await ElwigData.Export(path, list, filterNames);
await Utils.UploadExportData(path, App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
MessageBox.Show($"Hochladen von {list.Count:N0} Lieferungen erfolgreich!", "Lieferungen hochgeladen",
MessageBoxButton.OK, MessageBoxImage.Information);
}
} catch (HttpRequestException exc) {
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Lieferungen hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
} catch (TaskCanceledException exc) {
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
} else {
Mouse.OverrideCursor = Cursors.AppStarting;
try {
var data = await DeliveryJournalData.FromQuery(query, filterNames);
using var doc = new DeliveryJournal(string.Join(" / ", filterNames), data);
await Utils.ExportDocument(doc, mode);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
var data = await DeliveryJournalData.FromQuery(query, filterNames);
using var doc = new DeliveryJournal(string.Join(" / ", filterNames), data);
await Utils.ExportDocument(doc, mode);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
}
}
@@ -798,14 +803,16 @@ namespace Elwig.Services {
throw new ArgumentException("Invalid value for ExportSubject");
}
Mouse.OverrideCursor = Cursors.AppStarting;
try {
var data = await WineQualityStatisticsData.FromQuery(query, App.Client.OrderingMemberList);
using var doc = new WineQualityStatistics(string.Join(" / ", filterNames), data);
await Utils.ExportDocument(doc, mode);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
var data = await WineQualityStatisticsData.FromQuery(query, App.Client.OrderingMemberList);
using var doc = new WineQualityStatistics(string.Join(" / ", filterNames), data);
await Utils.ExportDocument(doc, mode);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
}
@@ -829,14 +836,16 @@ namespace Elwig.Services {
Title = $"Lieferstatistik pro Ort speichern unter - Elwig"
};
if (d.ShowDialog() == true) {
Mouse.OverrideCursor = Cursors.AppStarting;
try {
using var ods = new OdsFile(d.FileName);
var tbl = await WineLocalityStatisticsData.FromQuery(query, filterNames);
await ods.AddTable(tbl);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
using var ods = new OdsFile(d.FileName);
var tbl = await WineLocalityStatisticsData.FromQuery(query, filterNames);
await ods.AddTable(tbl);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
}
}
@@ -875,33 +884,37 @@ namespace Elwig.Services {
Title = $"{DeliveryDepreciationList.Name} speichern unter - Elwig"
};
if (d.ShowDialog() == true) {
Mouse.OverrideCursor = Cursors.AppStarting;
try {
using var ods = new OdsFile(d.FileName);
var tblTotal = await DeliveryJournalData.FromQuery(query, filterNames);
tblTotal.FullName = DeliveryDepreciationList.Name;
tblTotal.Name = "Gesamt";
await ods.AddTable(tblTotal);
foreach (var branch in await ctx.Branches.OrderBy(b => b.Name).ToListAsync()) {
var tbl = await DeliveryJournalData.FromQuery(query.Where(p => p.Delivery.ZwstId == branch.ZwstId), filterNames);
tbl.FullName = DeliveryDepreciationList.Name;
tbl.Name = branch.Name;
await ods.AddTable(tbl);
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
using var ods = new OdsFile(d.FileName);
var tblTotal = await DeliveryJournalData.FromQuery(query, filterNames);
tblTotal.FullName = DeliveryDepreciationList.Name;
tblTotal.Name = "Gesamt";
await ods.AddTable(tblTotal);
foreach (var branch in await ctx.Branches.OrderBy(b => b.Name).ToListAsync()) {
var tbl = await DeliveryJournalData.FromQuery(query.Where(p => p.Delivery.ZwstId == branch.ZwstId), filterNames);
tbl.FullName = DeliveryDepreciationList.Name;
tbl.Name = branch.Name;
await ods.AddTable(tbl);
}
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
}
} else {
Mouse.OverrideCursor = Cursors.AppStarting;
try {
var data = await DeliveryJournalData.FromQuery(query, filterNames);
using var doc = new DeliveryDepreciationList(string.Join(" / ", filterNames), data);
await Utils.ExportDocument(doc, mode);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
var data = await DeliveryJournalData.FromQuery(query, filterNames);
using var doc = new DeliveryDepreciationList(string.Join(" / ", filterNames), data);
await Utils.ExportDocument(doc, mode);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
}
}
@@ -946,7 +959,7 @@ namespace Elwig.Services {
var weight = await deliveryParts.SumAsync(p => p.Weight);
wText = $"{weight:N0} kg";
wGrid.Add(("Gewicht", null, weight, null, weight));
wGrid.Add(("Menge", null, weight, null, weight));
if (await deliveryParts.AnyAsync()) {
var kmwMin = await deliveryParts.MinAsync(p => p.Kmw);
@@ -1047,7 +1060,7 @@ namespace Elwig.Services {
wGrid.ColumnDefinitions.Add(new() { Width = new(50) });
int rowNum = 0;
foreach (var row in weightData) {
if (rowNum == 1 || (rowNum != 0 && row.Item1 != null)) rowNum++;
if (rowNum != 0 && row.Item2 == null) rowNum++;
AddWeightToolTipRow(wGrid, rowNum++, row.Item1, row.Item2, row.Item3, row.Item4, row.Item5);
}
@@ -1062,7 +1075,7 @@ namespace Elwig.Services {
AddToolTipCell(gGrid, "Max.", 0, 4, 1, false, false, true);
rowNum = 1;
foreach (var row in gradationData) {
if (rowNum == 2 || (rowNum != 1 && row.Item1 != null)) rowNum++;
if (rowNum != 1 && row.Item2 == null) rowNum++;
AddGradationToolTipRow(gGrid, rowNum++, row.Item1, row.Item2, row.Item3, row.Item4, row.Item5);
}
@@ -1070,11 +1083,11 @@ namespace Elwig.Services {
}
public static async Task DeleteDelivery(string lsnr) {
using (var ctx = new AppDbContext()) {
await Task.Run(async () => {
using var ctx = new AppDbContext();
await ctx.Deliveries.Where(d => d.LsNr == lsnr).ExecuteDeleteAsync();
await ctx.SaveChangesAsync();
}
App.HintContextChange();
});
}
}
}

@@ -1,20 +1,20 @@
using Elwig.Helpers;
using Elwig.Models.Entities;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System;
using Microsoft.EntityFrameworkCore;
using Elwig.Documents;
using System.Windows.Input;
using System.Windows;
using Elwig.Helpers;
using Elwig.Helpers.Billing;
using Elwig.Models.Dtos;
using Elwig.Helpers.Export;
using Microsoft.Win32;
using Elwig.Models.Dtos;
using Elwig.Models.Entities;
using Elwig.ViewModels;
using Microsoft.EntityFrameworkCore;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
namespace Elwig.Services {
public static class MemberService {
@@ -49,6 +49,11 @@ namespace Elwig.Services {
vm.StatusAreaCommitmentInfo = $"{Utils.CurrentLastSeason}";
vm.StatusAreaCommitmentToolTip = null;
vm.Age = "-";
vm.CreatedAt = "-";
vm.ModifiedAt = "-";
vm.ModifiedAtShort = "-";
vm.ExportedAt = "-";
vm.ImportedAt = "-";
}
public static void FillInputs(this MemberAdminViewModel vm, Member m) {
@@ -137,6 +142,12 @@ namespace Elwig.Services {
vm.ContactViaPost = m.ContactViaPost;
vm.ContactViaEmail = m.ContactViaEmail;
vm.CreatedAt = $"{m.CreatedAt:dd.MM.yyyy, HH:mm:ss}";
vm.ModifiedAt = $"{m.ModifiedAt:dd.MM.yyyy, HH:mm:ss}";
vm.ModifiedAtShort = $"{m.ModifiedAt:dd.MM.yyyy, HH:mm}";
vm.ExportedAt = m.ExportedAt == null ? "-" : $"{m.ExportedAt:dd.MM.yyyy, HH:mm:ss}";
vm.ImportedAt = m.ImportedAt == null ? "-" : $"{m.ImportedAt:dd.MM.yyyy, HH:mm:ss}";
vm.StatusDeliveriesLastSeasonInfo = $"{Utils.CurrentLastSeason - 1}";
vm.StatusDeliveriesLastSeason = "...";
vm.StatusDeliveriesLastSeasonToolTip = null;
@@ -357,8 +368,8 @@ namespace Elwig.Services {
if (filterMgNr.Count > 0) memberQuery = memberQuery.Where(m => filterMgNr.Contains(m.MgNr));
if (filterKgNr.Count > 0) memberQuery = memberQuery.Where(m => m.DefaultKgNr != null && filterKgNr.Contains((int)m.DefaultKgNr));
if (filterZwst.Count > 0) memberQuery = memberQuery.Where(m => m.ZwstId != null && filterZwst.Contains(m.ZwstId));
if (filterAreaCom.Count > 0) memberQuery = memberQuery.Where(m => m.AreaCommitments.AsQueryable().Where(Utils.ActiveAreaCommitments()).Any(c => filterAreaCom.Contains(c.VtrgId)));
if (filterNotAreaCom.Count > 0) memberQuery = memberQuery.Where(m => !m.AreaCommitments.AsQueryable().Where(Utils.ActiveAreaCommitments()).All(c => filterNotAreaCom.Contains(c.VtrgId)));
if (filterAreaCom.Count > 0) memberQuery = memberQuery.Where(m => m.AreaCommitments.AsQueryable().Where(Utils.ActiveAreaCommitments(Utils.CurrentLastSeason)).Any(c => filterAreaCom.Contains(c.VtrgId)));
if (filterNotAreaCom.Count > 0) memberQuery = memberQuery.Where(m => !m.AreaCommitments.AsQueryable().Where(Utils.ActiveAreaCommitments(Utils.CurrentLastSeason)).All(c => filterNotAreaCom.Contains(c.VtrgId)));
if (filterLfbisNr.Count > 0) memberQuery = memberQuery.Where(m => m.LfbisNr != null && filterLfbisNr.Contains(m.LfbisNr));
if (filterUstIdNr.Count > 0) memberQuery = memberQuery.Where(m => m.UstIdNr != null && filterUstIdNr.Contains(m.UstIdNr));
}
@@ -367,51 +378,57 @@ namespace Elwig.Services {
}
public static async Task GenerateMemberDataSheet(Member m, ExportMode mode) {
Mouse.OverrideCursor = Cursors.AppStarting;
try {
using var ctx = new AppDbContext();
using var doc = new MemberDataSheet(m, ctx);
await Utils.ExportDocument(doc, mode, emailData: (m, MemberDataSheet.Name, "Im Anhang finden Sie das aktuelle Stammdatenblatt"));
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
using var ctx = new AppDbContext();
using var doc = new MemberDataSheet(m, ctx);
await Utils.ExportDocument(doc, mode, emailData: (m, MemberDataSheet.Name, "Im Anhang finden Sie das aktuelle Stammdatenblatt"));
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
}
public static async Task GenerateDeliveryConfirmation(Member m, int year, ExportMode mode) {
Mouse.OverrideCursor = Cursors.AppStarting;
try {
var b = new Billing(year);
await b.FinishSeason();
await b.CalculateBuckets();
App.HintContextChange();
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
var b = new Billing(year);
await b.FinishSeason();
await b.CalculateBuckets();
App.HintContextChange();
using var ctx = new AppDbContext();
var data = await DeliveryConfirmationDeliveryData.ForMember(ctx.DeliveryParts, year, m);
using var doc = new DeliveryConfirmation(ctx, year, m, data);
await Utils.ExportDocument(doc, mode, emailData: (m, $"{DeliveryConfirmation.Name} {year}", $"Im Anhang finden Sie die Anlieferungsbestätigung {year}"));
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
using var ctx = new AppDbContext();
var data = await DeliveryConfirmationDeliveryData.ForMember(ctx.DeliveryParts, year, m);
using var doc = new DeliveryConfirmation(ctx, year, m, data);
await Utils.ExportDocument(doc, mode, emailData: (m, $"{DeliveryConfirmation.Name} {year}", $"Im Anhang finden Sie die Anlieferungsbestätigung {year}"));
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
}
public static async Task GenerateCreditNote(Member m, int year, int avnr, ExportMode mode) {
Mouse.OverrideCursor = Cursors.AppStarting;
try {
using var ctx = new AppDbContext();
var v = (await ctx.PaymentVariants.FindAsync(year, avnr))!;
var data = await CreditNoteDeliveryData.ForPaymentVariant(ctx.CreditNoteDeliveryRows, ctx.Seasons, year, avnr);
var p = (await ctx.MemberPayments.FindAsync(year, avnr, m.MgNr))!;
var b = BillingData.FromJson((await ctx.PaymentVariants.FindAsync(year, avnr))!.Data);
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
using var ctx = new AppDbContext();
var v = (await ctx.PaymentVariants.FindAsync(year, avnr))!;
var data = await CreditNoteDeliveryData.ForPaymentVariant(ctx.CreditNoteDeliveryRows, ctx.PaymentVariants, year, avnr);
var p = (await ctx.MemberPayments.FindAsync(year, avnr, m.MgNr))!;
var b = BillingData.FromJson((await ctx.PaymentVariants.FindAsync(year, avnr))!.Data);
using var doc = new CreditNote(ctx, p, data[m.MgNr],
b.ConsiderContractPenalties, b.ConsiderTotalPenalty, b.ConsiderAutoBusinessShares, b.ConsiderCustomModifiers,
await ctx.GetMemberUnderDelivery(year, m.MgNr));
await Utils.ExportDocument(doc, mode, emailData: (m, $"{CreditNote.Name} {v.Name}", $"Im Anhang finden Sie die Traubengutschrift {v.Name}"));
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
using var doc = new CreditNote(ctx, p, data[m.MgNr],
b.ConsiderContractPenalties, b.ConsiderTotalPenalty, b.ConsiderAutoBusinessShares, b.ConsiderCustomModifiers,
await ctx.GetMemberUnderDelivery(year, m.MgNr));
await Utils.ExportDocument(doc, mode, emailData: (m, $"{CreditNote.Name} {v.Name}", $"Im Anhang finden Sie die Traubengutschrift {v.Name}"));
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
}
@@ -464,14 +481,16 @@ namespace Elwig.Services {
Title = $"{MemberList.Name} speichern unter - Elwig"
};
if (d.ShowDialog() == true) {
Mouse.OverrideCursor = Cursors.AppStarting;
try {
var data = await MemberListData.FromQuery(query, filterNames, filterNames.Where(f => f.StartsWith("Flächenbindung")).Select(f => f.Split(' ')[^1]));
using var ods = new OdsFile(d.FileName);
await ods.AddTable(data);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
var data = await MemberListData.FromQuery(query, filterNames, filterNames.Where(f => f.StartsWith("Flächenbindung")).Select(f => f.Split(' ')[^1]));
using var ods = new OdsFile(d.FileName);
await ods.AddTable(data);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
}
} else if (mode == ExportMode.Export) {
@@ -482,8 +501,33 @@ namespace Elwig.Services {
Title = $"{MemberList.Name} speichern unter - Elwig"
};
if (d.ShowDialog() == true) {
Mouse.OverrideCursor = Cursors.AppStarting;
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
var members = await query
.OrderBy(m => m.MgNr)
.Include(m => m.BillingAddress)
.Include(m => m.TelephoneNumbers)
.Include(m => m.EmailAddresses)
.AsSplitQuery()
.ToListAsync();
var areaComs = await query
.SelectMany(m => m.AreaCommitments)
.Include(c => c.Rd)
.ToListAsync();
await ElwigData.Export(d.FileName, members, areaComs, filterNames);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
}
} else if (mode == ExportMode.Upload && App.Config.SyncUrl != null) {
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
var filename = $"{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{App.ZwstId}.elwig.zip";
var path = Path.Combine(App.TempPath, filename);
var members = await query
.OrderBy(m => m.MgNr)
.Include(m => m.BillingAddress)
@@ -495,99 +539,80 @@ namespace Elwig.Services {
.SelectMany(m => m.AreaCommitments)
.Include(c => c.Rd)
.ToListAsync();
await ElwigData.Export(d.FileName, members, areaComs, filterNames);
if (members.Count == 0) {
MessageBox.Show("Es wurden keine Mitglieder zum Hochladen ausgewählt!", "Mitglieder hochladen",
MessageBoxButton.OK, MessageBoxImage.Error);
} else {
await ElwigData.Export(path, members, areaComs, filterNames);
await Utils.UploadExportData(path, App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
MessageBox.Show($"Hochladen von {members.Count:N0} Mitgliedern erfolgreich!", "Mitglieder hochgeladen",
MessageBoxButton.OK, MessageBoxImage.Information);
}
} catch (HttpRequestException exc) {
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Mitglieder hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
} catch (TaskCanceledException exc) {
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Mitglieder hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = null;
}
} else if (mode == ExportMode.Upload && App.Config.SyncUrl != null) {
Mouse.OverrideCursor = Cursors.AppStarting;
try {
var filename = $"{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{App.ZwstId}.elwig.zip";
var path = Path.Combine(App.TempPath, filename);
var members = await query
.OrderBy(m => m.MgNr)
.Include(m => m.BillingAddress)
.Include(m => m.TelephoneNumbers)
.Include(m => m.EmailAddresses)
.AsSplitQuery()
.ToListAsync();
var areaComs = await query
.SelectMany(m => m.AreaCommitments)
.Include(c => c.Rd)
.ToListAsync();
if (members.Count == 0) {
MessageBox.Show("Es wurden keine Mitglieder zum Hochladen ausgewählt!", "Mitglieder hochladen",
MessageBoxButton.OK, MessageBoxImage.Error);
} else {
await ElwigData.Export(path, members, areaComs, filterNames);
await Utils.UploadExportData(path, App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
MessageBox.Show($"Hochladen von {members.Count:N0} Mitgliedern erfolgreich!", "Mitglieder hochgeladen",
MessageBoxButton.OK, MessageBoxImage.Information);
}
} catch (HttpRequestException exc) {
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Mitglieder hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
} catch (TaskCanceledException exc) {
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Mitglieder hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
} else {
Mouse.OverrideCursor = Cursors.AppStarting;
try {
var data = await MemberListData.FromQuery(query, filterNames, filterNames.Where(f => f.StartsWith("Flächenbindung")).Select(f => f.Split(' ')[^1]));
using var doc = new MemberList(string.Join(" / ", filterNames), data);
await Utils.ExportDocument(doc, mode);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
var data = await MemberListData.FromQuery(query, filterNames, filterNames.Where(f => f.StartsWith("Flächenbindung")).Select(f => f.Split(' ')[^1]));
using var doc = new MemberList(string.Join(" / ", filterNames), data);
await Utils.ExportDocument(doc, mode);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
}
}
public static async Task<int> UpdateMember(this MemberAdminViewModel vm, int? oldMgNr) {
var newMgNr = (int)vm.MgNr!;
var m = new Member {
MgNr = oldMgNr ?? newMgNr,
PredecessorMgNr = vm.PredecessorMgNr,
IsJuridicalPerson = vm.IsJuridicalPerson,
Prefix = vm.IsJuridicalPerson || string.IsNullOrWhiteSpace(vm.Prefix) ? null : vm.Prefix,
GivenName = vm.IsJuridicalPerson || string.IsNullOrWhiteSpace(vm.GivenName) ? null : vm.GivenName,
Name = vm.Name!,
Suffix = vm.IsJuridicalPerson || string.IsNullOrWhiteSpace(vm.Suffix) ? null : vm.Suffix,
ForTheAttentionOf = !vm.IsJuridicalPerson || string.IsNullOrWhiteSpace(vm.ForTheAttentionOf) ? null : vm.ForTheAttentionOf,
Birthday = string.IsNullOrEmpty(vm.Birthday) ? null : string.Join("-", vm.Birthday!.Split(".").Reverse()),
IsDeceased = vm.IsDeceased,
CountryNum = 40, // Austria AT AUT
PostalDestId = vm.Ort!.Id,
Address = vm.Address!,
using (var ctx = new AppDbContext()) {
var m = new Member {
MgNr = oldMgNr ?? newMgNr,
PredecessorMgNr = vm.PredecessorMgNr,
IsJuridicalPerson = vm.IsJuridicalPerson,
Prefix = vm.IsJuridicalPerson || string.IsNullOrWhiteSpace(vm.Prefix) ? null : vm.Prefix,
GivenName = vm.IsJuridicalPerson || string.IsNullOrWhiteSpace(vm.GivenName) ? null : vm.GivenName,
Name = vm.Name!,
Suffix = vm.IsJuridicalPerson || string.IsNullOrWhiteSpace(vm.Suffix) ? null : vm.Suffix,
ForTheAttentionOf = !vm.IsJuridicalPerson || string.IsNullOrWhiteSpace(vm.ForTheAttentionOf) ? null : vm.ForTheAttentionOf,
Birthday = string.IsNullOrEmpty(vm.Birthday) ? null : string.Join("-", vm.Birthday!.Split(".").Reverse()),
IsDeceased = vm.IsDeceased,
CountryNum = 40, // Austria AT AUT
PostalDestId = vm.Ort!.Id,
Address = vm.Address!,
Iban = string.IsNullOrEmpty(vm.Iban) ? null : vm.Iban?.Replace(" ", ""),
Bic = string.IsNullOrEmpty(vm.Bic) ? null : vm.Bic,
Iban = string.IsNullOrEmpty(vm.Iban) ? null : vm.Iban?.Replace(" ", ""),
Bic = string.IsNullOrEmpty(vm.Bic) ? null : vm.Bic,
UstIdNr = string.IsNullOrEmpty(vm.UstIdNr) ? null : vm.UstIdNr,
LfbisNr = string.IsNullOrEmpty(vm.LfbisNr) ? null : vm.LfbisNr,
IsBuchführend = vm.IsBuchführend,
IsOrganic = vm.IsOrganic,
UstIdNr = string.IsNullOrEmpty(vm.UstIdNr) ? null : vm.UstIdNr,
LfbisNr = string.IsNullOrEmpty(vm.LfbisNr) ? null : vm.LfbisNr,
IsBuchführend = vm.IsBuchführend,
IsOrganic = vm.IsOrganic,
EntryDateString = string.IsNullOrEmpty(vm.EntryDate) ? null : string.Join("-", vm.EntryDate.Split(".").Reverse()),
ExitDateString = string.IsNullOrEmpty(vm.ExitDate) ? null : string.Join("-", vm.ExitDate.Split(".").Reverse()),
BusinessShares = (int)vm.BusinessShares!,
AccountingNr = string.IsNullOrEmpty(vm.AccountingNr) ? null : vm.AccountingNr,
IsActive = vm.IsActive,
IsVollLieferant = vm.IsVollLieferant,
IsFunktionär = vm.IsFunktionär,
ZwstId = vm.Branch?.ZwstId,
DefaultKgNr = vm.DefaultKg?.KgNr,
Comment = string.IsNullOrEmpty(vm.Comment) ? null : vm.Comment,
ContactViaPost = vm.ContactViaPost,
ContactViaEmail = vm.ContactViaEmail,
};
EntryDateString = string.IsNullOrEmpty(vm.EntryDate) ? null : string.Join("-", vm.EntryDate.Split(".").Reverse()),
ExitDateString = string.IsNullOrEmpty(vm.ExitDate) ? null : string.Join("-", vm.ExitDate.Split(".").Reverse()),
BusinessShares = (int)vm.BusinessShares!,
AccountingNr = string.IsNullOrEmpty(vm.AccountingNr) ? null : vm.AccountingNr,
IsActive = vm.IsActive,
IsVollLieferant = vm.IsVollLieferant,
IsFunktionär = vm.IsFunktionär,
ZwstId = vm.Branch?.ZwstId,
DefaultKgNr = vm.DefaultKg?.KgNr,
Comment = string.IsNullOrEmpty(vm.Comment) ? null : vm.Comment,
ContactViaPost = vm.ContactViaPost,
ContactViaEmail = vm.ContactViaEmail,
};
return await Task.Run(async () => {
using var ctx = new AppDbContext();
if (oldMgNr != null) {
ctx.Update(m);
} else {
@@ -644,7 +669,7 @@ namespace Elwig.Services {
KgNr = c.KgNr,
GstNr = c.GstNr,
RdNr = c.RdNr,
YearFrom = vm.MaintainAreaComYearTo ? c.YearFrom : year,
YearFrom = vm.MaintainAreaComYearFrom ? c.YearFrom : year,
YearTo = c.YearTo,
}));
@@ -670,15 +695,14 @@ namespace Elwig.Services {
if (newMgNr != m.MgNr) {
await ctx.Database.ExecuteSqlAsync($"UPDATE member SET mgnr = {newMgNr} WHERE mgnr = {oldMgNr}");
}
}
App.HintContextChange();
return newMgNr;
return newMgNr;
});
}
public static async Task DeleteMember(int mgnr, bool deletePaymentData, bool deleteDeliveries, bool deleteAreaComs) {
using (var ctx = new AppDbContext()) {
await Task.Run(async () => {
using var ctx = new AppDbContext();
var l = (await ctx.Members.FindAsync(mgnr))!;
if (deletePaymentData) {
ctx.RemoveRange(l.Credits);
@@ -691,8 +715,7 @@ namespace Elwig.Services {
}
ctx.Remove(l);
await ctx.SaveChangesAsync();
}
App.HintContextChange();
});
}
}
}

@@ -0,0 +1,387 @@
using Elwig.Documents;
using Elwig.Helpers;
using Elwig.Helpers.Billing;
using Elwig.Helpers.Export;
using Elwig.Models.Dtos;
using Elwig.Models.Entities;
using Elwig.ViewModels;
using Microsoft.EntityFrameworkCore;
using Microsoft.Win32;
using System;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
namespace Elwig.Services {
public static class PaymentVariantService {
private static readonly JsonSerializerOptions JsonOpt = new() { WriteIndented = true };
public static void ClearInputs(this PaymentVariantsViewModel vm) {
vm.IsPaymentVariantSelected = false;
vm.EditText = "Bearbeiten";
vm.SaveIsEnabled = false;
vm.DeleteIsEnabled = false;
vm.CalculateIsEnabled = false;
vm.CommitIsEnabled = false;
vm.CommitVisibility = Visibility.Visible;
vm.RevertIsEnabled = false;
vm.RevertVisibility = Visibility.Hidden;
vm.Arrow = "\xF0AF";
vm.ExportIsEnabled = false;
vm.IsReadOnly = true;
vm.DataIsReadOnly = true;
vm.BillingData = null;
vm.Name = "";
vm.Comment = "";
vm.Date = null;
vm.TransferDate = null;
vm.WeightModifier = null;
vm.ConsiderModifiers = false;
vm.ConsiderPenalties = false;
vm.ConsiderPenalty = false;
vm.ConsiderAuto = false;
vm.ConsiderCustom = false;
vm.IsEnabled = false;
vm.Data = "";
vm.StatusModifierSum = "-";
vm.StatusTotalSum = "-";
vm.StatusVatSum = "-";
vm.StatusDeductionSum = "-";
vm.StatusPaymentSum = "-";
}
public static void FillInputs(this PaymentVariantsViewModel vm, PaymentVar v) {
var locked = !v.TestVariant;
vm.IsPaymentVariantSelected = true;
vm.SaveIsEnabled = !locked;
vm.DeleteIsEnabled = !locked;
vm.CalculateIsEnabled = !locked;
vm.CommitIsEnabled = !locked && !vm.SeasonLocked;
vm.CommitVisibility = !locked ? Visibility.Visible : Visibility.Hidden;
vm.RevertIsEnabled = locked && !vm.SeasonLocked;
vm.RevertVisibility = locked ? Visibility.Visible : Visibility.Hidden;
vm.Arrow = locked ? "\xF0B0" : "\xF0AF";
vm.EditText = locked ? "Ansehen" : "Bearbeiten";
vm.ExportIsEnabled = locked;
vm.IsReadOnly = false;
vm.DataIsReadOnly = locked;
vm.Name = v.Name;
vm.Comment = v.Comment ?? "";
vm.Date = v.Date;
vm.TransferDate = v.TransferDate;
try {
vm.BillingData = BillingData.FromJson(v.Data);
vm.ConsiderModifiers = vm.BillingData.ConsiderDelieryModifiers;
vm.ConsiderPenalties = vm.BillingData.ConsiderContractPenalties;
vm.ConsiderPenalty = vm.BillingData.ConsiderTotalPenalty;
vm.ConsiderAuto = vm.BillingData.ConsiderAutoBusinessShares;
vm.ConsiderCustom = vm.BillingData.ConsiderCustomModifiers;
if (vm.BillingData.NetWeightModifier != 0) {
vm.WeightModifier = Math.Round(vm.BillingData.NetWeightModifier * 100.0, 8);
} else if (vm.BillingData.GrossWeightModifier != 0) {
vm.WeightModifier = Math.Round(vm.BillingData.GrossWeightModifier * 100.0, 8);
} else {
vm.WeightModifier = null;
}
vm.Data = JsonSerializer.Serialize(vm.BillingData.Data, JsonOpt);
} catch {
vm.BillingData = null;
vm.ConsiderModifiers = false;
vm.ConsiderPenalties = false;
vm.ConsiderPenalty = false;
vm.ConsiderAuto = false;
vm.ConsiderCustom = false;
vm.WeightModifier = null;
vm.Data = v.Data;
}
vm.IsEnabled = !locked;
vm.StatusModifierSum = "...";
vm.StatusTotalSum = "...";
vm.StatusVatSum = "...";
vm.StatusDeductionSum = "...";
vm.StatusPaymentSum = "...";
Utils.RunBackground("Variantendaten laden", async () => {
await vm.UpdateSums(v);
});
}
private static async Task UpdateSums(this PaymentVariantsViewModel vm, PaymentVar v) {
if (App.MainDispatcher == null)
return;
var modText = "-";
var totalText = "-";
var vatText = "-";
var deductionText = "-";
var paymentText = "-";
using var ctx = new AppDbContext();
var sym = v.Season.Currency.Symbol ?? v.Season.Currency.Code;
var modSum = await ctx.PaymentDeliveryParts
.Where(p => p.Year == v.Year && p.AvNr == v.AvNr)
.SumAsync(p => p.AmountValue - p.NetAmountValue);
modText = $"{v.Season.DecFromDb(modSum):N2} {sym}";
var totalSum = await ctx.MemberPayments
.Where(p => p.Year == v.Year && p.AvNr == v.AvNr)
.SumAsync(p => p.AmountValue);
totalText = $"{v.Season.DecFromDb(totalSum):N2} {sym}";
await App.MainDispatcher.BeginInvoke(() => {
if (vm.SelectedPaymentVariant != v)
return;
vm.StatusModifierSum = modText;
vm.StatusTotalSum = totalText;
});
var credits = ctx.Credits.Where(c => c.Year == v.Year && c.AvNr == v.AvNr);
if (!credits.Any()) {
long lastTotalSum = 0;
decimal vatSum = 0;
var currentPayments = await ctx.MemberPayments
.Where(p => p.Year == v.Year && p.AvNr == v.AvNr)
.ToDictionaryAsync(p => p.MgNr);
var lastV = await ctx.PaymentVariants
.Where(l => l.Year == v.Year && !l.TestVariant)
.OrderByDescending(l => l.TransferDateString ?? l.DateString)
.ThenByDescending(l => l.AvNr)
.FirstOrDefaultAsync();
if (lastV != null) {
var lastPayments = await ctx.MemberPayments
.Where(p => p.Year == v.Year && p.AvNr == lastV.AvNr)
.ToDictionaryAsync(p => p.MgNr);
lastTotalSum = lastPayments.Sum(e => e.Value.AmountValue);
foreach (int mgnr in currentPayments.Keys) {
var c = currentPayments[mgnr];
var l = lastPayments[mgnr];
vatSum += (c.Amount - l.Amount) * (decimal)(c.Member.IsBuchführend ? v.Season.VatNormal : v.Season.VatFlatrate);
}
} else {
vatSum = currentPayments.Sum(e => e.Value.Amount * (decimal)(e.Value.Member.IsBuchführend ? v.Season.VatNormal : v.Season.VatFlatrate));
}
vatText = $"~{vatSum:N2} {sym}";
deductionText = $"- {sym}";
paymentText = $"~{v.Season.DecFromDb(totalSum - lastTotalSum) + vatSum:N2} {sym}";
} else {
// all values in the credit table are stored with precision 2!
totalText = $"{Utils.DecFromDb(await credits.SumAsync(c => c.NetAmountValue), 2):N2} {sym}";
vatText = $"{Utils.DecFromDb(await credits.SumAsync(c => c.VatAmountValue), 2):N2} {sym}";
deductionText = $"{-Utils.DecFromDb(await credits.SumAsync(c => c.ModifiersValue ?? 0), 2):N2} {sym}";
paymentText = $"{Utils.DecFromDb(await credits.SumAsync(c => c.AmountValue), 2):N2} {sym}";
}
await App.MainDispatcher.BeginInvoke(() => {
if (vm.SelectedPaymentVariant != v)
return;
vm.StatusModifierSum = modText;
vm.StatusTotalSum = totalText;
vm.StatusVatSum = vatText;
vm.StatusDeductionSum = deductionText;
vm.StatusPaymentSum = paymentText;
});
}
public static async Task GenerateSummary(PaymentVar v, ExportMode mode) {
if (mode == ExportMode.SaveList) {
var d = new SaveFileDialog() {
FileName = $"Variantendaten-{v.Name.Trim().Replace(' ', '-')}.ods",
DefaultExt = "ods",
Filter = "OpenDocument Format Spreadsheet (*.ods)|*.ods",
Title = $"Variantendaten {v.Name} speichern unter - Elwig"
};
if (d.ShowDialog() == false)
return;
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
using var ctx = new AppDbContext();
var data = await PaymentVariantSummaryData.ForPaymentVariant(v, ctx.PaymentVariantSummaryRows);
using var ods = new OdsFile(d.FileName);
await ods.AddTable(data);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
} else {
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
using var ctx = new AppDbContext();
var data = await PaymentVariantSummaryData.ForPaymentVariant(v, ctx.PaymentVariantSummaryRows);
using var doc = new PaymentVariantSummary((await ctx.PaymentVariants.FindAsync(v.Year, v.AvNr))!, data);
await Utils.ExportDocument(doc, mode);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
}
}
public static async Task GenerateEbics(int year, int avnr) {
using var ctx = new AppDbContext();
var v = (await ctx.PaymentVariants.FindAsync(year, avnr))!;
var withoutIban = v.Credits.Count(c => c.Member.Iban == null);
if (withoutIban > 0) {
var r = MessageBox.Show($"Achtung: Für {withoutIban:N0} Mitglieder ist kein IBAN hinterlegt.\n\nDiese werden NICHT exportiert.",
"Mitglieder ohne IBAN", MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
if (r != MessageBoxResult.OK) return;
}
var withNegAmount = v.Credits.Count(c => c.Amount <= 0);
if (withNegAmount > 0) {
var r = MessageBox.Show($"Achtung: Es gibt {withNegAmount:N0} Traubengutschriften mit negativem Betrag.\n\nDiese werden NICHT exportiert.",
"Traubengutschriften mit negativem Betrag", MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.OK);
if (r != MessageBoxResult.OK) return;
}
var d = new SaveFileDialog() {
FileName = $"{App.Client.NameToken}-Überweisungsdaten-{v.Year}-{v.Name.Trim().Replace(' ', '-')}.{Ebics.FileExtension}",
DefaultExt = Ebics.FileExtension,
Filter = "EBICS-Datei (*.xml)|*.xml",
Title = $"Überweisungsdaten speichern unter - Elwig",
};
if (d.ShowDialog() == true) {
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
using var e = new Ebics(v, d.FileName, App.Client.ExportEbicsVersion, (Ebics.AddressMode)App.Client.ExportEbicsAddress);
await e.ExportAsync(Transaction.FromPaymentVariant(v));
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
}
}
public static async Task GenerateAccountingList(int year, int avnr, string name) {
var d = new SaveFileDialog() {
FileName = $"{App.Client.NameToken}-Buchungsliste-{year}-{name.Trim().Replace(' ', '-')}.ods",
DefaultExt = "ods",
Filter = "OpenDocument Format Spreadsheet (*.ods)|*.ods",
Title = $"Buchungsliste speichern unter - Elwig"
};
if (d.ShowDialog() == true) {
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
using var ctx = new AppDbContext();
var tbl = await CreditNoteData.ForPaymentVariant(ctx, year, avnr);
using var ods = new OdsFile(d.FileName);
await ods.AddTable(tbl);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
}
}
public static async Task<PaymentVar> CreatePaymentVariant(int year) {
return await Task.Run(async () => {
using var ctx = new AppDbContext();
var v = new PaymentVar {
Year = year,
AvNr = await ctx.NextAvNr(year),
Name = "Neue Auszahlungsvariante",
TestVariant = true,
DateString = $"{DateTime.Today:yyyy-MM-dd}",
Data = "{\"mode\": \"elwig\", \"version\": 1, \"payment\": {}, \"curves\": []}",
};
ctx.Add(v);
await ctx.SaveChangesAsync();
return v;
});
}
public static async Task<PaymentVar> Duplicate(this PaymentVar orig) {
return await Task.Run(async () => {
using var ctx = new AppDbContext();
var n = new PaymentVar {
Year = orig.Year,
AvNr = await ctx.NextAvNr(orig.Year),
Name = $"{orig.Name} (Kopie)",
TestVariant = true,
DateString = $"{DateTime.Today:yyyy-MM-dd}",
Data = orig.Data,
};
ctx.Add(n);
await ctx.SaveChangesAsync();
return n;
});
}
public static async Task<(int, int)> UpdatePaymentVariant(this PaymentVariantsViewModel vm, int? oldYear, int? oldAvNr) {
var year = oldYear ?? Utils.CurrentYear;
int avnr = 0;
await Task.Run(async () => {
var d = App.Config.Debug ? BillingData.FromJson(vm.Data ?? "{}") : vm.BillingData!;
d.ConsiderDelieryModifiers = vm.ConsiderModifiers;
d.ConsiderContractPenalties = vm.ConsiderPenalties;
d.ConsiderTotalPenalty = vm.ConsiderPenalty;
d.ConsiderAutoBusinessShares = vm.ConsiderAuto;
d.ConsiderCustomModifiers = vm.ConsiderCustom;
var modVal = vm.WeightModifier ?? 0;
d.NetWeightModifier = modVal > 0 ? modVal / 100.0 : 0;
d.GrossWeightModifier = modVal < 0 ? modVal / 100.0 : 0;
using var ctx = new AppDbContext();
var v = new PaymentVar {
Year = year,
AvNr = oldAvNr ?? await ctx.NextAvNr(year),
Name = vm.Name!,
DateString = $"{vm.Date!.Value:yyyy-MM-dd}",
TransferDate = vm.TransferDate,
TestVariant = vm.SelectedPaymentVariant?.TestVariant ?? true,
CalcTimeUnix = vm.SelectedPaymentVariant?.CalcTimeUnix,
Comment = string.IsNullOrEmpty(vm.Comment) ? null : vm.Comment,
Data = JsonSerializer.Serialize(d.Data),
};
avnr = v.AvNr;
ctx.Update(v);
await ctx.SaveChangesAsync();
});
vm.WeightModifierChanged = false;
return (year, avnr);
}
public static async Task DeletePaymentVariant(int year, int avnr) {
await Task.Run(async () => {
using var ctx = new AppDbContext();
var v = (await ctx.PaymentVariants.FindAsync(year, avnr))!;
ctx.Remove(v);
await ctx.SaveChangesAsync();
});
}
public static async Task Calculate(int year, int avnr) {
await Task.Run(async () => {
var b = new BillingVariant(year, avnr);
await b.Calculate();
});
}
public static async Task Commit(int year, int avnr) {
await Task.Run(async () => {
var b = new BillingVariant(year, avnr);
await b.Commit();
});
}
public static async Task Revert(int year, int avnr) {
await Task.Run(async () => {
var b = new BillingVariant(year, avnr);
await b.Revert();
});
}
}
}

@@ -15,7 +15,7 @@ namespace Elwig.ViewModels {
[ObservableProperty]
private string? _searchQuery = "";
public List<string> TextFilter {
get => [.. SearchQuery?.ToLower().Split(' ').ToList().FindAll(e => e.Length > 0)];
get => [.. SearchQuery?.ToLower().Split(' ').ToList().FindAll(e => e.Length > 0) ?? []];
set => SearchQuery = string.Join(' ', value.Where(e => e.Length > 0));
}

@@ -18,7 +18,7 @@ namespace Elwig.ViewModels {
[ObservableProperty]
private string? _searchQuery = "";
public List<string> TextFilter => [.. SearchQuery?.ToLower().Split(' ').ToList().FindAll(e => e.Length > 0)];
public List<string> TextFilter => [.. SearchQuery?.ToLower().Split(' ').ToList().FindAll(e => e.Length > 0) ?? []];
[ObservableProperty]
private string? _lastScaleError;

@@ -10,7 +10,7 @@ namespace Elwig.ViewModels {
[ObservableProperty]
private string? _searchQuery = "";
public List<string> TextFilter => [.. SearchQuery?.ToLower().Split(' ').ToList().FindAll(e => e.Length > 0)];
public List<string> TextFilter => [.. SearchQuery?.ToLower().Split(' ').ToList().FindAll(e => e.Length > 0) ?? []];
[ObservableProperty]
private bool _filterOnlyUpcoming;

@@ -11,7 +11,7 @@ namespace Elwig.ViewModels {
[ObservableProperty]
private string? _searchQuery = "";
public List<string> TextFilter => [.. SearchQuery?.ToLower().Split(' ').ToList().FindAll(e => e.Length > 0)];
public List<string> TextFilter => [.. SearchQuery?.ToLower().Split(' ').ToList().FindAll(e => e.Length > 0) ?? []];
[ObservableProperty]
private bool _filterOnlyUpcoming;

@@ -11,14 +11,14 @@ namespace Elwig.ViewModels {
public partial class MemberAdminViewModel : ObservableObject {
public int? TransferPredecessorAreaComs = null;
public bool MaintainAreaComYearTo = false;
public bool MaintainAreaComYearFrom = false;
public int? CancelAreaComs = null;
public ObservableCollection<KeyValuePair<string, string>> PhoneNrTypes { get; set; } = new(Utils.PhoneNrTypes);
[ObservableProperty]
private string? _searchQuery = "";
public List<string> TextFilter => [.. SearchQuery?.ToLower().Split(' ').ToList().FindAll(e => e.Length > 0)];
public List<string> TextFilter => [.. SearchQuery?.ToLower().Split(' ').ToList().FindAll(e => e.Length > 0) ?? []];
[ObservableProperty]
private bool _showOnlyActiveMembers;
@@ -153,6 +153,17 @@ namespace Elwig.ViewModels {
[ObservableProperty]
private bool _contactViaEmail;
[ObservableProperty]
private string _createdAt = "-";
[ObservableProperty]
private string _modifiedAt = "-";
[ObservableProperty]
private string _modifiedAtShort = "-";
[ObservableProperty]
private string _exportedAt = "-";
[ObservableProperty]
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 {

@@ -0,0 +1,95 @@
using CommunityToolkit.Mvvm.ComponentModel;
using Elwig.Helpers.Billing;
using Elwig.Models.Entities;
using System;
using System.Collections.Generic;
using System.Windows;
namespace Elwig.ViewModels {
public partial class PaymentVariantsViewModel : ObservableObject {
[ObservableProperty]
private PaymentVar? _selectedPaymentVariant;
[ObservableProperty]
private IEnumerable<PaymentVar> _paymentVariants = [];
public BillingData? BillingData;
public bool SeasonLocked;
public bool WeightModifierChanged;
[ObservableProperty]
private string _name = "";
[ObservableProperty]
private string _comment = "";
[ObservableProperty]
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]
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]
private string _weightModifierString = "";
public double? WeightModifier {
get => double.TryParse(WeightModifierString, out var d) ? d : null;
set => WeightModifierString = $"{value}";
}
[ObservableProperty]
private string _data = "";
[ObservableProperty]
private bool _considerModifiers;
[ObservableProperty]
private bool _considerPenalties;
[ObservableProperty]
private bool _considerPenalty;
[ObservableProperty]
private bool _considerAuto;
[ObservableProperty]
private bool _considerCustom;
[ObservableProperty]
private bool _isPaymentVariantSelected;
[ObservableProperty]
private bool _isReadOnly = true;
[ObservableProperty]
private bool _dataIsReadOnly = true;
[ObservableProperty]
private bool _isEnabled = false;
[ObservableProperty]
private bool _saveIsEnabled = false;
[ObservableProperty]
private bool _deleteIsEnabled = false;
[ObservableProperty]
private bool _calculateIsEnabled = false;
[ObservableProperty]
private bool _exportIsEnabled = false;
[ObservableProperty]
private bool _commitIsEnabled = false;
[ObservableProperty]
private Visibility _commitVisibility = Visibility.Visible;
[ObservableProperty]
private bool _revertIsEnabled = false;
[ObservableProperty]
private Visibility _revertVisibility = Visibility.Hidden;
[ObservableProperty]
private string _arrow = "\xF0AF";
[ObservableProperty]
private string _editText = "Bearbeiten";
[ObservableProperty]
private string _statusModifierSum = "-";
[ObservableProperty]
private string _statusTotalSum = "-";
[ObservableProperty]
private string _statusVatSum = "-";
[ObservableProperty]
private string _statusDeductionSum = "-";
[ObservableProperty]
private string _statusPaymentSum = "-";
}
}

@@ -7,7 +7,7 @@
xmlns:local="clr-namespace:Elwig.Windows"
xmlns:ctrl="clr-namespace:Elwig.Controls"
xmlns:vm="clr-namespace:Elwig.ViewModels"
Title="{Binding Title}" Height="550" MinHeight="450" Width="920" MinWidth="860"
Title="{Binding Title}" Height="600" MinHeight="450" Width="1000" MinWidth="860"
Loaded="Window_Loaded">
<Window.DataContext>
<vm:AreaComAdminViewModel/>
@@ -57,7 +57,7 @@
<RowDefinition Height="24"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*" MinWidth="555"/>
<ColumnDefinition Width="3*" MinWidth="500"/>
<ColumnDefinition Width="5"/>
<ColumnDefinition Width="*" MinWidth="280"/>
</Grid.ColumnDefinitions>
@@ -102,25 +102,35 @@
CanUserDeleteRows="False" CanUserResizeRows="False" CanUserAddRows="False" SelectionChanged="AreaCommitmentList_SelectionChanged" Grid.Column="0" Grid.Row="1"
Margin="5,0,5,0" FontSize="14" Grid.ColumnSpan="3" Background="#e2e2e2">
<DataGrid.Columns>
<DataGridTextColumn Header="FbNr." Binding="{Binding FbNr}" Width="50"/>
<DataGridTextColumn Header="Katastralgemeinde" Binding="{Binding Kg.AtKg.Name}" Width="150"/>
<DataGridTextColumn Header="Ried" Binding="{Binding Rd.Name}" Width="130"/>
<DataGridTextColumn Header="Parzelle" Binding="{Binding GstNr}" Width="120"/>
<DataGridTextColumn Header="Fläche" Binding="{Binding Area, StringFormat='{}{0:N0} m²'}" Width="80">
<DataGridTextColumn Header="FbNr." Binding="{Binding FbNr, StringFormat='{}{0} '}" Width="50">
<DataGridTextColumn.CellStyle>
<Style>
<Setter Property="TextBlock.TextAlignment" Value="Right"/>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Sorte" Binding="{Binding AreaComType.WineVar.SortId}" Width="70">
<DataGridTextColumn Header="Katastralgemeinde" Binding="{Binding Kg.AtKg.Name}" Width="130"/>
<DataGridTextColumn Header="Sorte" Binding="{Binding AreaComType.WineVar.SortId}" Width="50">
<DataGridTextColumn.CellStyle>
<Style>
<Setter Property="TextBlock.Foreground" Value="{Binding AreaComType.WineVar.Color}"/>
<Setter Property="TextBlock.TextAlignment" Value="Center"/>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Attribut" Binding="{Binding AreaComType.WineAttr.Name}" Width="120"/>
<DataGridTextColumn Header="Fläche" Binding="{Binding Area, StringFormat='{}{0:N0} m² '}" Width="80">
<DataGridTextColumn.CellStyle>
<Style>
<Setter Property="TextBlock.TextAlignment" Value="Right"/>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Attribut" Binding="{Binding AreaComType.WineAttr.Name}" Width="100"/>
<DataGridTextColumn Header="Ried" Binding="{Binding Rd.Name}" Width="130"/>
<DataGridTextColumn Header="Parzelle" Binding="{Binding GstNr}" Width="130"/>
<DataGridTextColumn Header="Bewirt." Binding="{Binding WineCult.Name}" Width="60"/>
<DataGridTextColumn Header="Von" Binding="{Binding YearFrom}" Width="48"/>
<DataGridTextColumn Header="Bis" Binding="{Binding YearTo}" Width="48"/>
</DataGrid.Columns>
</DataGrid>
@@ -143,19 +153,19 @@
</Button.ToolTip>
</Button>
<Button x:Name="AreaCommitmentSaveButton" Content="Speichern" Click="AreaCommitmentSaveButton_Click" IsEnabled="False" Visibility="Hidden"
<Button x:Name="SaveButton" Content="Speichern" Click="SaveButton_Click" IsEnabled="False" Visibility="Hidden"
HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="5,5,2.5,10" Grid.Column="0" Grid.Row="2">
<Button.ToolTip>
<TextBlock FontWeight="Bold">Strg+S</TextBlock>
</Button.ToolTip>
</Button>
<Button x:Name="AreaCommitmentResetButton" Content="Zurücksetzen" Click="AreaCommitmentResetButton_Click" IsEnabled="False" Visibility="Hidden"
<Button x:Name="ResetButton" Content="Zurücksetzen" Click="ResetButton_Click" IsEnabled="False" Visibility="Hidden"
HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="2.5,5,2.5,10" Grid.Column="1" Grid.Row="2">
<Button.ToolTip>
<TextBlock FontWeight="Bold">Strg+Z</TextBlock>
</Button.ToolTip>
</Button>
<Button x:Name="AreaCommitmentCancelButton" Content="Abbrechen" Click="AreaCommitmentCancelButton_Click" IsEnabled="False" Visibility="Hidden" IsCancel="True"
<Button x:Name="CancelButton" Content="Abbrechen" Click="CancelButton_Click" IsEnabled="False" Visibility="Hidden" IsCancel="True"
HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="2.5,5,5,10" Grid.Column="2" Grid.Row="2">
<Button.ToolTip>
<TextBlock FontWeight="Bold">Esc</TextBlock>
@@ -175,28 +185,27 @@
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="48"/>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="FbNr.:" Margin="10,10,0,0" Grid.Column="0"/>
<Label Content="MgNr.:" Margin="10,10,0,0" Grid.Column="0"/>
<TextBox x:Name="MgNrInput" Text="{Binding MgNrString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsEnabled="False"
Margin="0,10,0,0" Width="48" HorizontalAlignment="Left" Grid.Column="1" TextAlignment="Right"/>
<Label Content="FbNr.:" Margin="10,10,0,0" Grid.Column="2"/>
<TextBox x:Name="FbNrInput" Text="{Binding FbNrString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,10,10,0" Grid.Column="1" TextAlignment="Right"
Margin="0,10,10,0" Width="56" HorizontalAlignment="Left" Grid.Column="3" TextAlignment="Right"
TextChanged="FbNrInput_TextChanged" LostFocus="FbNrInput_LostFocus"/>
<Label Content="MgNr.:" Margin="10,40,0,0" Grid.Column="0"/>
<TextBox x:Name="MgNrInput" Text="{Binding MgNrString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsEnabled="False"
Margin="0,40,10,0" Grid.Column="1" TextAlignment="Right"/>
<Label Content="Von:" Margin="10,10,0,0" Grid.Column="2"/>
<Label Content="Zeitraum:" Margin="10,40,0,0" Grid.Column="0"/>
<TextBox x:Name="YearFromInput" Text="{Binding YearFromString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,10,10,0" Grid.Column="3" TextAlignment="Right"
Margin="0,40,10,0" Width="40" HorizontalAlignment="Left" Grid.Column="1" Grid.ColumnSpan="2" TextAlignment="Right"
TextChanged="IntegerInput_TextChanged"/>
<Label Content="Bis:" Margin="10,40,0,0" Grid.Column="2"/>
<Label Content="" Grid.Column="1" Grid.ColumnSpan="3" Margin="45,40,0,0"/>
<TextBox x:Name="YearToInput" Text="{Binding YearToString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,40,10,0" Grid.Column="3" TextAlignment="Right"
Margin="60,40,10,0" Width="40" HorizontalAlignment="Left" Grid.Column="1" Grid.ColumnSpan="3" TextAlignment="Right"
TextChanged="IntegerInput_TextChanged"/>
<Label Content="Vertragsart:" Margin="10,70,0,0" Grid.Column="0" Grid.ColumnSpan="2"/>

@@ -1,13 +1,14 @@
using Microsoft.EntityFrameworkCore;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using Elwig.Dialogs;
using Elwig.Helpers;
using Elwig.Models.Entities;
using System;
using System.Threading.Tasks;
using Elwig.ViewModels;
using Elwig.Services;
using Elwig.ViewModels;
using Microsoft.EntityFrameworkCore;
using System;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace Elwig.Windows {
@@ -25,8 +26,8 @@ namespace Elwig.Windows {
ViewModel.Title = $"Flächenbindungen - {ViewModel.FilterMember.AdministrativeName} - Elwig";
ExemptInputs = [
MgNrInput, AreaCommitmentList, NewAreaCommitmentButton,
EditAreaCommitmentButton, DeleteAreaCommitmentButton, AreaCommitmentSaveButton,
AreaCommitmentResetButton, AreaCommitmentCancelButton, SearchInput, ActiveAreaCommitmentInput
EditAreaCommitmentButton, DeleteAreaCommitmentButton, SaveButton,
ResetButton, CancelButton, SearchInput, ActiveAreaCommitmentInput
];
RequiredInputs = [
FbNrInput, YearFromInput, KgInput, RdInput,
@@ -163,8 +164,8 @@ namespace Elwig.Windows {
IsCreating = true;
AreaCommitmentList.IsEnabled = false;
AreaCommitmentList.SelectedItem = null;
HideAreaCommitmentNewEditDeleteButtons();
ShowAreaCommitmentSaveResetCancelButtons();
HideNewEditDeleteButtons();
ShowSaveResetCancelButtons();
UnlockInputs();
await InitInputs();
LockSearchInputs();
@@ -184,8 +185,8 @@ namespace Elwig.Windows {
IsEditing = true;
AreaCommitmentList.IsEnabled = false;
HideAreaCommitmentNewEditDeleteButtons();
ShowAreaCommitmentSaveResetCancelButtons();
HideNewEditDeleteButtons();
ShowSaveResetCancelButtons();
UnlockInputs();
LockSearchInputs();
}
@@ -199,70 +200,107 @@ namespace Elwig.Windows {
private async void DeleteAreaCommitmentButton_Click(object? sender, RoutedEventArgs? evt) {
if (AreaCommitmentList.SelectedItem is not AreaCom a)
return;
var r = MessageBox.Show(
$"Soll die Flächenbindung {a.GstNr} ({a.Area} m²) wirklich unwiderruflich gelöscht werden?",
"Flächenbindung löschen", MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
if (r == MessageBoxResult.OK) {
Mouse.OverrideCursor = Cursors.AppStarting;
try {
using (var ctx = new AppDbContext()) {
ctx.Remove(a);
await ctx.SaveChangesAsync();
}
App.HintContextChange();
} catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Flächenbindung löschen", MessageBoxButton.OK, MessageBoxImage.Error);
var d = new AreaComModifyDialog(a.YearFrom, a.YearTo, a.Area, true);
if (d.ShowDialog() != true)
return;
Mouse.OverrideCursor = Cursors.Wait;
try {
if (d.YearTo is int yearTo) {
ViewModel.YearTo = yearTo;
await ViewModel.UpdateAreaCommitment((AreaCommitmentList.SelectedItem as AreaCom)?.FbNr);
} else {
await AreaComService.DeleteAreaCom(a.FbNr);
}
Mouse.OverrideCursor = null;
App.HintContextChange();
} catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Flächenbindung löschen", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = null;
}
protected override void ShortcutSave() {
if (!AreaCommitmentSaveButton.IsEnabled || AreaCommitmentSaveButton.Visibility != Visibility.Visible)
if (!SaveButton.IsEnabled || SaveButton.Visibility != Visibility.Visible)
return;
AreaCommitmentSaveButton_Click(null, null);
SaveButton_Click(null, null);
}
private async void AreaCommitmentSaveButton_Click(object? sender, RoutedEventArgs? evt) {
AreaCommitmentSaveButton.IsEnabled = false;
Mouse.OverrideCursor = Cursors.AppStarting;
private async void SaveButton_Click(object? sender, RoutedEventArgs? evt) {
SaveButton.IsEnabled = false;
int? yearTo = null;
if (InputHasChanged(AreaInput) || InputHasChanged(AreaComTypeInput)) {
var a = (AreaCommitmentList.SelectedItem as AreaCom)!;
var d = new AreaComModifyDialog(a.YearFrom, a.YearTo, a.Area, false);
if (d.ShowDialog() != true)
return;
yearTo = d.YearTo;
}
int fbnr;
Mouse.OverrideCursor = Cursors.Wait;
try {
AreaCom? temp = null;
if (yearTo != null && (!ViewModel.YearTo.HasValue || yearTo < ViewModel.YearTo)) {
temp = new AreaCom {
FbNr = ViewModel.FbNr!.Value,
MgNr = ViewModel.MgNr!.Value,
YearFrom = ViewModel.YearFrom,
YearTo = ViewModel.YearTo,
VtrgId = ViewModel.AreaComType!.VtrgId,
CultId = ViewModel.WineCult?.CultId,
Comment = ViewModel.Comment,
KgNr = ViewModel.Kg!.KgNr,
RdNr = ViewModel.Rd?.RdNr,
GstNr = ViewModel.GstNr?.Trim() ?? "-",
Area = ViewModel.Area!.Value,
};
RefreshInputs();
ViewModel.YearTo = yearTo;
}
fbnr = await ViewModel.UpdateAreaCommitment((AreaCommitmentList.SelectedItem as AreaCom)?.FbNr);
if (temp is AreaCom t) {
await ViewModel.InitInputs();
t.FbNr = ViewModel.FbNr!.Value;
t.YearFrom = yearTo + 1;
ViewModel.FillInputs(t);
fbnr = await ViewModel.UpdateAreaCommitment(null);
}
App.HintContextChange();
} catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Flächenbindung aktualisieren", MessageBoxButton.OK, MessageBoxImage.Error);
AreaCommitmentSaveButton.IsEnabled = true;
return;
} finally {
SaveButton.IsEnabled = true;
Mouse.OverrideCursor = null;
return;
}
IsEditing = false;
IsCreating = false;
AreaCommitmentList.IsEnabled = true;
HideAreaCommitmentSaveResetCancelButtons();
ShowAreaCommitmentNewEditDeleteButtons();
HideSaveResetCancelButtons();
ShowNewEditDeleteButtons();
LockInputs();
UnlockSearchInputs();
FinishInputFilling();
await RefreshList();
RefreshInputs();
Mouse.OverrideCursor = null;
ViewModel.SearchQuery = "";
ControlUtils.SelectItem(AreaCommitmentList, AreaCommitmentList.ItemsSource.Cast<AreaCom>().Where(a => a.FbNr == fbnr).FirstOrDefault());
}
protected override void ShortcutReset() {
if (!AreaCommitmentResetButton.IsEnabled || AreaCommitmentResetButton.Visibility != Visibility.Visible)
if (!ResetButton.IsEnabled || ResetButton.Visibility != Visibility.Visible)
return;
AreaCommitmentResetButton_Click(null, null);
ResetButton_Click(null, null);
}
private async void AreaCommitmentResetButton_Click(object? sender, RoutedEventArgs? evt) {
private async void ResetButton_Click(object? sender, RoutedEventArgs? evt) {
if (IsEditing) {
RefreshInputs();
} else if (IsCreating) {
@@ -271,12 +309,12 @@ namespace Elwig.Windows {
UpdateButtons();
}
private void AreaCommitmentCancelButton_Click(object sender, RoutedEventArgs evt) {
private void CancelButton_Click(object sender, RoutedEventArgs evt) {
IsEditing = false;
IsCreating = false;
AreaCommitmentList.IsEnabled = true;
HideAreaCommitmentSaveResetCancelButtons();
ShowAreaCommitmentNewEditDeleteButtons();
HideSaveResetCancelButtons();
ShowNewEditDeleteButtons();
RefreshInputs();
ClearInputStates();
LockInputs();
@@ -286,49 +324,49 @@ namespace Elwig.Windows {
override protected void UpdateButtons() {
if (!IsEditing && !IsCreating) return;
bool ch = HasChanged, v = IsValid;
AreaCommitmentResetButton.IsEnabled = (ch);
AreaCommitmentSaveButton.IsEnabled = (ch && v);
ResetButton.IsEnabled = (ch);
SaveButton.IsEnabled = (ch && v);
}
private void DisableAreaCommitmentNewEditDeleteButtons() {
private void DisableNewEditDeleteButtons() {
NewAreaCommitmentButton.IsEnabled = false;
EditAreaCommitmentButton.IsEnabled = false;
DeleteAreaCommitmentButton.IsEnabled = false;
}
private void EnableAreaCommitmentNewEditDeleteButtons() {
private void EnableNewEditDeleteButtons() {
NewAreaCommitmentButton.IsEnabled = true;
EditAreaCommitmentButton.IsEnabled = AreaCommitmentList.SelectedItem != null;
DeleteAreaCommitmentButton.IsEnabled = AreaCommitmentList.SelectedItem != null;
}
private void ShowAreaCommitmentSaveResetCancelButtons() {
AreaCommitmentSaveButton.IsEnabled = false;
AreaCommitmentResetButton.IsEnabled = false;
AreaCommitmentCancelButton.IsEnabled = true;
AreaCommitmentSaveButton.Visibility = Visibility.Visible;
AreaCommitmentResetButton.Visibility = Visibility.Visible;
AreaCommitmentCancelButton.Visibility = Visibility.Visible;
private void ShowSaveResetCancelButtons() {
SaveButton.IsEnabled = false;
ResetButton.IsEnabled = false;
CancelButton.IsEnabled = true;
SaveButton.Visibility = Visibility.Visible;
ResetButton.Visibility = Visibility.Visible;
CancelButton.Visibility = Visibility.Visible;
}
private void HideAreaCommitmentSaveResetCancelButtons() {
AreaCommitmentSaveButton.IsEnabled = false;
AreaCommitmentResetButton.IsEnabled = false;
AreaCommitmentCancelButton.IsEnabled = false;
AreaCommitmentSaveButton.Visibility = Visibility.Hidden;
AreaCommitmentResetButton.Visibility = Visibility.Hidden;
AreaCommitmentCancelButton.Visibility = Visibility.Hidden;
private void HideSaveResetCancelButtons() {
SaveButton.IsEnabled = false;
ResetButton.IsEnabled = false;
CancelButton.IsEnabled = false;
SaveButton.Visibility = Visibility.Hidden;
ResetButton.Visibility = Visibility.Hidden;
CancelButton.Visibility = Visibility.Hidden;
}
private void ShowAreaCommitmentNewEditDeleteButtons() {
EnableAreaCommitmentNewEditDeleteButtons();
private void ShowNewEditDeleteButtons() {
EnableNewEditDeleteButtons();
NewAreaCommitmentButton.Visibility = Visibility.Visible;
EditAreaCommitmentButton.Visibility = Visibility.Visible;
DeleteAreaCommitmentButton.Visibility = Visibility.Visible;
}
private void HideAreaCommitmentNewEditDeleteButtons() {
DisableAreaCommitmentNewEditDeleteButtons();
private void HideNewEditDeleteButtons() {
DisableNewEditDeleteButtons();
NewAreaCommitmentButton.Visibility = Visibility.Hidden;
EditAreaCommitmentButton.Visibility = Visibility.Hidden;
DeleteAreaCommitmentButton.Visibility = Visibility.Hidden;
@@ -345,6 +383,8 @@ namespace Elwig.Windows {
}
private void AreaCommitmentList_SelectionChanged(object sender, SelectionChangedEventArgs evt) {
if (AreaCommitmentList.SelectedItem != null)
AreaCommitmentList.ScrollIntoView(AreaCommitmentList.SelectedItem);
RefreshInputs();
}

@@ -157,7 +157,7 @@ namespace Elwig.Windows {
}
var d = new NewSeasonDialog(s, currencies);
if (d.ShowDialog() == true) {
Mouse.OverrideCursor = Cursors.AppStarting;
Mouse.OverrideCursor = Cursors.Wait;
try {
using var ctx = new AppDbContext();
ctx.Add(new Season {
@@ -209,7 +209,7 @@ namespace Elwig.Windows {
$"Soll die Saison {s.Year} wirklich unwiderruflich gelöscht werden?",
"Saison löschen", MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
if (r == MessageBoxResult.OK) {
Mouse.OverrideCursor = Cursors.AppStarting;
Mouse.OverrideCursor = Cursors.Wait;
try {
using var ctx = new AppDbContext();
ctx.Remove(s);

@@ -318,8 +318,7 @@ namespace Elwig.Windows {
private async void SaveButton_Click(object? sender, RoutedEventArgs? evt) {
SaveButton.IsEnabled = false;
Mouse.OverrideCursor = Cursors.AppStarting;
Mouse.OverrideCursor = Cursors.Wait;
try {
await Save();
} catch (Exception exc) {
@@ -327,9 +326,8 @@ namespace Elwig.Windows {
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Stammdaten aktualisieren", MessageBoxButton.OK, MessageBoxImage.Error);
SaveButton.IsEnabled = true;
return;
} finally {
Mouse.OverrideCursor = null;
return;
}
IsEditing = false;
@@ -349,6 +347,7 @@ namespace Elwig.Windows {
}
App.HintContextChange();
Mouse.OverrideCursor = null;
}
private void FillInputs(ClientParameters p, Season? s) {

@@ -75,8 +75,8 @@
<ctrl:CheckComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Variety.Name}" Width="150"/>
<TextBlock Text="{Binding Variety.Type}" Width="30"/>
<TextBlock Text="{Binding Variety.Name}" Foreground="{Binding Variety.Color}" Width="150"/>
<TextBlock Text="{Binding Variety.Type}" Foreground="{Binding Variety.Color}" Width="30"/>
<TextBlock Text="{Binding Attribute.Name}" Width="80"/>
<TextBlock Text="{Binding Cultivation.Name}" Width="80"/>
<TextBlock Text="{Binding AssignedGraphId}" Width="30"/>
@@ -94,14 +94,14 @@
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Id}" Width="30"/>
<TextBlock Text="{Binding VaributeStringSimple}" ToolTip="{Binding VaributeString}"/>
<TextBlock Text="{Binding Id}" Foreground="{Binding Color}" Width="30"/>
<TextBlock Text="{Binding VaributeStringSimple}" Foreground="{Binding Color}" ToolTip="{Binding VaributeString}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button x:Name="SaveButton" Content="Speichern" IsEnabled="False"
<Button x:Name="SaveButton" Content="Speichern &amp; Berechnen" IsEnabled="False"
HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="10,5,35,10" Grid.Column="0" Grid.Row="2"
Click="SaveButton_Click"/>

@@ -639,10 +639,11 @@ namespace Elwig.Windows {
private async void SaveButton_Click(object sender, RoutedEventArgs e) {
SaveButton.IsEnabled = false;
Mouse.OverrideCursor = Cursors.AppStarting;
Mouse.OverrideCursor = Cursors.Wait;
try {
using (var ctx = new AppDbContext()) {
await Task.Run(async () => {
using var ctx = new AppDbContext();
var origData = BillingData.FromJson(PaymentVar.Data);
var data = BillingData.FromGraphEntries(GraphEntries, origData, Utils.GetVaributes(ctx, Year),
AllVaributesAssigned, AllVaributesAssignedAbgew);
@@ -650,21 +651,31 @@ namespace Elwig.Windows {
PaymentVar.Data = data.ToJsonString();
ctx.Update(PaymentVar);
await ctx.SaveChangesAsync();
}
LockContext = false;
App.HintContextChange();
});
} catch (Exception exc) {
Mouse.OverrideCursor = null;
var str = "Der Eintrag konnte nicht in der Datenbank gespeichert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Auszahlungsvariante speichern", MessageBoxButton.OK, MessageBoxImage.Error);
SaveButton.IsEnabled = true;
return;
} finally {
Mouse.OverrideCursor = null;
}
try {
await Task.Run(async () => {
var b = new BillingVariant(PaymentVar.Year, PaymentVar.AvNr);
await b.Calculate();
});
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Berechnungsfehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
LockContext = false;
App.HintContextChange();
LockContext = true;
SetHasChanged(false);
Mouse.OverrideCursor = null;
}
private void EnableTextBox(TextBox u) {

@@ -217,7 +217,7 @@
<Bold>Zweigstelle</Bold>: z.B. musterort, ...<LineBreak/>
<Bold>Attribut</Bold>: z.B. kabinett, !kabinett (alle außer kabinett), ...<LineBreak/>
<Bold>Bewirtschaftung</Bold>: z.B. bio, !kip (alle außer KIP), ...<LineBreak/>
<Bold>Gewicht</Bold>: z.B. &lt;500kg, &gt;6000kg, ... (gilt für Gewicht der gesamten Lieferung)<LineBreak/>
<Bold>Gewicht</Bold>: z.B. &lt;500kg, &gt;6000kg, ... (gilt für Menge der gesamten Lieferung)<LineBreak/>
<Bold>Datum</Bold>: z.B. 1.9., 15.9.-10.10., -15.10.2020, ...<LineBreak/>
<Bold>Uhrzeit</Bold>: z.B. 06:00-08:00, 18:00-, ...<LineBreak/>
<Bold>Handwiegung</Bold>: handw[iegung], !Handw[iegung] (alle ohne Handwiegung)<LineBreak/>
@@ -268,11 +268,12 @@
<DataGridTextColumn Header="Sorte" Binding="{Binding FilteredSortIdString}" Width="50">
<DataGridTextColumn.CellStyle>
<Style>
<Setter Property="TextBlock.Foreground" Value="{Binding FilteredColor}"/>
<Setter Property="TextBlock.TextAlignment" Value="Center"/>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Gewicht" Binding="{Binding FilteredWeight, StringFormat='{}{0:N0} kg '}" Width="75">
<DataGridTextColumn Header="Menge" Binding="{Binding FilteredWeight, StringFormat='{}{0:N0} kg '}" Width="75">
<DataGridTextColumn.CellStyle>
<Style>
<Setter Property="TextBlock.TextAlignment" Value="Right"/>
@@ -438,7 +439,7 @@
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding DPNr}" Width="13" TextAlignment="Right" Margin="0,0,7,0"/>
<TextBlock Text="{Binding SortId}" Width="30"/>
<TextBlock Text="{Binding SortId}" Foreground="{Binding Variety.Color}" TextAlignment="Center" Width="30"/>
<TextBlock Text="{Binding Kmw, StringFormat='{}{0:N1}°'}" Width="40" TextAlignment="Right" Padding="0,0,10,0"/>
<TextBlock Text="{Binding QualId}" Width="30"/>
<TextBlock Text="{Binding Weight, StringFormat='{}{0:N0} kg'}" Width="60" TextAlignment="Right" Padding="0,0,10,0"/>
@@ -460,7 +461,7 @@
</Grid.ColumnDefinitions>
<Label Content="Sorte:" Margin="10,10,0,0" Grid.Column="0"/>
<TextBox x:Name="SortIdInput" Text="{Binding SortId, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
<TextBox x:Name="SortIdInput" Text="{Binding SortId, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Foreground="{Binding WineVar.Color}"
Width="36" Grid.Row="1" Grid.Column="1" Margin="0,10,0,0" HorizontalAlignment="Left"
TextChanged="SortIdInput_TextChanged" LostFocus="SortIdInput_LostFocus" KeyUp="Input_KeyUp"/>
<ComboBox x:Name="WineVarietyInput" SelectedItem="{Binding WineVar, Mode=TwoWay}" ItemsSource="{Binding WineVarSource, Mode=TwoWay}"
@@ -516,7 +517,7 @@
</Grid>
</GroupBox>
<GroupBox Header="Gewicht" Grid.Column="1" Grid.Row="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"/>
@@ -669,7 +670,7 @@
<Separator Grid.Column="5"/>
<StatusBarItem Grid.Column="6">
<TextBlock ToolTip="{Binding StatusWeightToolTip}">
Gewicht: <Run Text="{Binding StatusWeight}"/>
Menge: <Run Text="{Binding StatusWeight}"/>
</TextBlock>
</StatusBarItem>
<Separator Grid.Column="7"/>

@@ -719,7 +719,7 @@ namespace Elwig.Windows {
private async void NewDeliveryPartButton_Click(object sender, RoutedEventArgs evt) {
FinishButton.IsEnabled = false;
NewDeliveryPartButton.IsEnabled = false;
Mouse.OverrideCursor = Cursors.AppStarting;
Mouse.OverrideCursor = Cursors.Wait;
DeliveryPartList.IsEnabled = false;
DeliveryPart? p;
@@ -732,6 +732,7 @@ namespace Elwig.Windows {
InputHasChanged(TimeInput),
!InputIsNotDefault(TimeInput)
);
App.HintContextChange();
} catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
@@ -757,7 +758,7 @@ namespace Elwig.Windows {
private async void FinishButton_Click(object sender, RoutedEventArgs evt) {
FinishButton.IsEnabled = false;
NewDeliveryPartButton.IsEnabled = false;
Mouse.OverrideCursor = Cursors.AppStarting;
Mouse.OverrideCursor = Cursors.Wait;
DeliveryPartList.IsEnabled = false;
DeliveryPart? p;
@@ -770,6 +771,7 @@ namespace Elwig.Windows {
InputHasChanged(TimeInput),
!InputIsNotDefault(TimeInput)
);
App.HintContextChange();
} catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
@@ -888,7 +890,7 @@ namespace Elwig.Windows {
if (res == null)
return;
Mouse.OverrideCursor = Cursors.AppStarting;
Mouse.OverrideCursor = Cursors.Wait;
try {
var id = res.Value.Item1;
var weights = res.Value.Item2;
@@ -905,6 +907,7 @@ namespace Elwig.Windows {
var n = await DeliveryService.SplitDeliveryToLsNr(d.Year, d.DId, weights, id);
ControlUtils.SelectItemWithPk(DeliveryList, n.Year, n.DId);
}
App.HintContextChange();
} catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
@@ -959,9 +962,10 @@ namespace Elwig.Windows {
$"Soll die Lieferung {d.LsNr} ({d.Member.AdministrativeName}, MgNr. {d.Member.MgNr}) wirklich unwiderruflich gelöscht werden?",
"Lieferung löschen", MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
if (r == MessageBoxResult.OK) {
Mouse.OverrideCursor = Cursors.AppStarting;
Mouse.OverrideCursor = Cursors.Wait;
try {
await DeliveryService.DeleteDelivery(d.LsNr);
App.HintContextChange();
} catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
@@ -979,7 +983,7 @@ namespace Elwig.Windows {
private async void SaveButton_Click(object? sender, RoutedEventArgs? evt) {
SaveButton.IsEnabled = false;
Mouse.OverrideCursor = Cursors.AppStarting;
Mouse.OverrideCursor = Cursors.Wait;
DeliveryPart? p;
try {
@@ -991,14 +995,14 @@ namespace Elwig.Windows {
InputHasChanged(TimeInput),
!InputIsNotDefault(TimeInput)
);
App.HintContextChange();
} catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Lieferung aktualisieren", MessageBoxButton.OK, MessageBoxImage.Error);
SaveButton.IsEnabled = true;
return;
} finally {
Mouse.OverrideCursor = null;
return;
}
IsEditing = false;
@@ -1015,6 +1019,7 @@ namespace Elwig.Windows {
await RefreshDeliveryParts();
RefreshInputs();
Mouse.OverrideCursor = null;
DepreciateButton.IsEnabled = true;
}

@@ -125,7 +125,7 @@
<Bold>Zweigstelle</Bold>: z.B. musterort, ...<LineBreak/>
<Bold>Attribut</Bold>: z.B. kabinett, !kabinett (alle außer kabinett), ...<LineBreak/>
<Bold>Bewirtschaftung</Bold>: z.B. bio, !kip (alle außer KIP), ...<LineBreak/>
<Bold>Gewicht</Bold>: z.B. &lt;500kg, &gt;6000kg, ...<LineBreak/>
<Bold>Menge</Bold>: z.B. &lt;500kg, &gt;6000kg, ...<LineBreak/>
<Bold>Datum</Bold>: z.B. 1.9., 15.9.-10.10., -15.10.2020, ...
</TextBlock>
</TextBox.ToolTip>
@@ -187,18 +187,19 @@
<DataGridTextColumn Header="Sorte" Binding="{Binding SortId}" Width="50">
<DataGridTextColumn.CellStyle>
<Style>
<Setter Property="TextBlock.Foreground" Value="{Binding Variety.Color}"/>
<Setter Property="TextBlock.TextAlignment" Value="Center"/>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Gewicht" Binding="{Binding Weight, StringFormat='{}{0:N0} kg'}" Width="75">
<DataGridTextColumn Header="Menge" Binding="{Binding Weight, StringFormat='{}{0:N0} kg'}" Width="75">
<DataGridTextColumn.CellStyle>
<Style>
<Setter Property="TextBlock.TextAlignment" Value="Right"/>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Angemeldet" Binding="{Binding CreatedTimestamp, StringFormat='{}{0:HH:mm, dd.MM.}'}" Width="100">
<DataGridTextColumn Header="Angemeldet" Binding="{Binding CreatedAt, StringFormat='{}{0:HH:mm, dd.MM.}'}" Width="100">
<DataGridTextColumn.CellStyle>
<Style>
<Setter Property="TextBlock.TextAlignment" Value="Center"/>
@@ -316,7 +317,7 @@
</ComboBox>
<Label Content="Sorte:" Margin="10,40,0,0" Grid.Column="0"/>
<TextBox x:Name="SortIdInput" Text="{Binding SortId, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
<TextBox x:Name="SortIdInput" Text="{Binding SortId, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Foreground="{Binding WineVariety.Color}"
Width="36" Grid.Row="1" Grid.Column="1" Margin="0,40,0,0" HorizontalAlignment="Left"
TextChanged="SortIdInput_TextChanged" LostFocus="SortIdInput_LostFocus" KeyUp="Input_KeyUp"/>
<ComboBox x:Name="WineVarietyInput" SelectedItem="{Binding WineVariety, Mode=TwoWay}" ItemsSource="{Binding WineVarietySource, Mode=TwoWay}"
@@ -328,7 +329,7 @@
</ComboBox.ItemTemplateSelector>
</ComboBox>
<Label Content="Gewicht:" Margin="10,70,0,0" Grid.Column="0"/>
<Label Content="Menge:" Margin="10,70,0,0" Grid.Column="0"/>
<ctrl:UnitTextBox x:Name="WeightInput" Unit="kg" Text="{Binding WeightString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Grid.Column="1" Margin="0,70,10,10" Width="61" HorizontalAlignment="Left"
TextChanged="WeightInput_TextChanged" KeyUp="Input_KeyUp"/>
@@ -364,7 +365,7 @@
<Separator Grid.Column="1"/>
<StatusBarItem Grid.Column="2">
<TextBlock ToolTip="{Binding StatusWeightToolTip}">
Gewicht: <Run Text="{Binding StatusWeight}"/>
Menge: <Run Text="{Binding StatusWeight}"/>
</TextBlock>
</StatusBarItem>
<Separator Grid.Column="3"/>

@@ -103,6 +103,7 @@ namespace Elwig.Windows {
var deliveryAncmts = await deliveryAncmtQuery
.Include(a => a.Member.BillingAddress)
.Include(a => a.Schedule)
.Include(a => a.Variety)
.AsSplitQuery()
.ToListAsync();
@@ -317,12 +318,13 @@ namespace Elwig.Windows {
$"Soll die Anmeldung wirklich unwiderruflich gelöscht werden?",
"Anmeldung löschen", MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
if (r == MessageBoxResult.OK) {
Mouse.OverrideCursor = Cursors.AppStarting;
Mouse.OverrideCursor = Cursors.Wait;
try {
using (var ctx = new AppDbContext()) {
await Task.Run(async () => {
using var ctx = new AppDbContext();
ctx.Remove(a);
await ctx.SaveChangesAsync();
}
});
App.HintContextChange();
} catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
@@ -340,7 +342,7 @@ namespace Elwig.Windows {
}
private async void SaveButton_Click(object? sender, RoutedEventArgs? evt) {
Mouse.OverrideCursor = Cursors.AppStarting;
Mouse.OverrideCursor = Cursors.Wait;
SaveButton.IsEnabled = false;
int year = -1, dsnr = -1, mgnr = -1;
@@ -348,6 +350,7 @@ namespace Elwig.Windows {
try {
var s = ViewModel.SelectedDeliveryAncmt;
(year, dsnr, mgnr, sortid) = await ViewModel.UpdateDeliveryAncmt(s?.Year, s?.DsNr, s?.MgNr, s?.SortId, s?.Type);
App.HintContextChange();
} catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;

@@ -127,7 +127,7 @@
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Beschreibung" Binding="{Binding Description}" Width="200"/>
<DataGridTextColumn Header="Max. Gew." Binding="{Binding MaxWeight, StringFormat='{}{0:N0} kg'}" Width="80">
<DataGridTextColumn Header="Max. Mg." Binding="{Binding MaxWeight, StringFormat='{}{0:N0} kg'}" Width="80">
<DataGridTextColumn.CellStyle>
<Style>
<Setter Property="TextBlock.TextAlignment" Value="Right"/>
@@ -211,7 +211,7 @@
Margin="0,40,10,10" Grid.Column="1" Grid.ColumnSpan="2"
TextChanged="TextBox_TextChanged"/>
<Label Content="Max. Gewicht:" Margin="10,70,0,10"/>
<Label Content="Max. Menge:" Margin="10,70,0,10"/>
<ctrl:UnitTextBox x:Name="MaxWeightInput" Unit="kg" Text="{Binding MaxWeightString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,70,10,10" Grid.Column="1" Grid.ColumnSpan="2" Width="68" HorizontalAlignment="Left"
TextChanged="MaxWeightInput_TextChanged"/>

@@ -177,12 +177,13 @@ namespace Elwig.Windows {
$"Soll der Leseplan \"{s.Description}\" vom {s.Date:dd.MM.yyyy} wirklich unwiderruflich gelöscht werden?",
"Leseplan löschen", MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
if (r == MessageBoxResult.OK) {
Mouse.OverrideCursor = Cursors.AppStarting;
Mouse.OverrideCursor = Cursors.Wait;
try {
using (var ctx = new AppDbContext()) {
await Task.Run(async () => {
using var ctx = new AppDbContext();
ctx.Remove(s);
await ctx.SaveChangesAsync();
}
});
App.HintContextChange();
} catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
@@ -200,11 +201,12 @@ namespace Elwig.Windows {
}
private async void SaveButton_Click(object? sender, RoutedEventArgs? evt) {
Mouse.OverrideCursor = Cursors.AppStarting;
Mouse.OverrideCursor = Cursors.Wait;
SaveButton.IsEnabled = false;
try {
await ViewModel.UpdateDeliverySchedule(ViewModel.SelectedDeliverySchedule?.Year, ViewModel.SelectedDeliverySchedule?.DsNr);
App.HintContextChange();
} catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;

@@ -3,7 +3,8 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Elwig.Windows"
Title="Ausgangs-Protokoll - Rundschreiben - Elwig" Height="600" Width="1000">
Title="Ausgangs-Protokoll - Rundschreiben - Elwig" Height="600" Width="1000"
Loaded="Window_Loaded">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*"/>

@@ -2,6 +2,7 @@ using Elwig.Helpers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
namespace Elwig.Windows {
@@ -18,8 +19,16 @@ namespace Elwig.Windows {
FilterInput.TextChanged -= FilterInput_TextChanged;
}
private async void Window_Loaded(object sender, RoutedEventArgs evt) {
await Load();
}
private async void TimeSpanInput_SelectionChanged(object sender, RoutedEventArgs evt) {
if (!IsLoaded) return;
await Load();
}
private async Task Load() {
DateTime? fromDate = DateTime.Now;
if (TimeSpanInput.SelectedIndex == 0) {
fromDate = fromDate.Value.AddDays(-7);

@@ -602,7 +602,7 @@ namespace Elwig.Windows {
PreviewButton.IsEnabled = false;
PrintButton.IsEnabled = false;
EmailButton.IsEnabled = false;
Mouse.OverrideCursor = Cursors.AppStarting;
Mouse.OverrideCursor = Cursors.Wait;
GenerateButton.IsEnabled = false;
DisposeDocs();
@@ -671,7 +671,7 @@ namespace Elwig.Windows {
var avnr = details.Item2;
try {
cnData[(year, avnr)] = (
await CreditNoteDeliveryData.ForPaymentVariant(ctx.CreditNoteDeliveryRows, ctx.Seasons, year, avnr),
await CreditNoteDeliveryData.ForPaymentVariant(ctx.CreditNoteDeliveryRows, ctx.PaymentVariants, year, avnr),
await ctx.MemberPayments.Where(p => p.Year == year && p.AvNr == avnr).ToDictionaryAsync(c => c.MgNr),
BillingData.FromJson((await ctx.PaymentVariants.FindAsync(year, avnr))!.Data)
);
@@ -828,25 +828,27 @@ namespace Elwig.Windows {
EmailButton.IsEnabled = EmailDocuments != null && App.Config.Smtp != null;
}
private void PreviewButton_Click(object sender, RoutedEventArgs evt) {
private async void PreviewButton_Click(object sender, RoutedEventArgs evt) {
var d = new OpenFolderDialog() {
Title = "Ordner auswählen - Elwig",
};
if (d.ShowDialog() == true) {
Mouse.OverrideCursor = Cursors.AppStarting;
PrintDocument?.SaveTo($"{d.FolderName}/Print.pdf");
if (EmailDocuments != null) {
foreach (var (m, docs) in EmailDocuments) {
var folder = $"{d.FolderName}/E-Mail/{m.AdministrativeName.Trim()}";
Directory.CreateDirectory(folder);
foreach (var item in docs.Select((d, i) => new { Index = i, Doc = d })) {
var doc = item.Doc;
var name = Utils.NormalizeFileName(doc.Title);
doc.SaveTo($"{folder}/{item.Index + 1:00}.{name}.pdf");
}
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(() => {
PrintDocument?.SaveTo($"{d.FolderName}/Print.pdf");
if (EmailDocuments != null) {
foreach (var (m, docs) in EmailDocuments) {
var folder = $"{d.FolderName}/E-Mail/{m.AdministrativeName.Trim()}";
Directory.CreateDirectory(folder);
foreach (var item in docs.Select((d, i) => new { Index = i, Doc = d })) {
var doc = item.Doc;
var name = Utils.NormalizeFileName(doc.Title);
doc.SaveTo($"{folder}/{item.Index + 1:00}.{name}.pdf");
}
}
}
}
});
Mouse.OverrideCursor = null;
Process.Start("explorer.exe", d.FolderName);
}
@@ -862,20 +864,22 @@ namespace Elwig.Windows {
var res = MessageBox.Show($"Sollen {PrintDocument.Pages} Blätter ({PrintDocument.TotalPages} Seiten) gedruckt werden?",
"Rundschreiben drucken", MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No);
if (res == MessageBoxResult.Yes) {
Mouse.OverrideCursor = Cursors.AppStarting;
if (App.Config.Debug) {
PrintDocument.Show();
} else {
await PrintDocument.Print();
await Utils.AddSentMails(
PrintMemberDocuments.Select(d => (
"postal", d.Key.MgNr, d.Key.AdministrativeName,
new string[] { d.Value.Select(d => (d as BusinessDocument)?.Address).FirstOrDefault(a => a != null) ?? d.Key.FullAddress },
d.Value.Select(d => d.Title).FirstOrDefault("Briefkopf"),
d.Value.Select(d => d.Title).ToArray()
))
);
}
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
if (App.Config.Debug) {
PrintDocument.Show();
} else {
await PrintDocument.Print();
await Utils.AddSentMails(
PrintMemberDocuments.Select(d => (
"postal", d.Key.MgNr, d.Key.AdministrativeName,
new string[] { d.Value.Select(d => (d as BusinessDocument)?.Address).FirstOrDefault(a => a != null) ?? d.Key.FullAddress },
d.Value.Select(d => d.Title).FirstOrDefault("Briefkopf"),
d.Value.Select(d => d.Title).ToArray()
))
);
}
});
Mouse.OverrideCursor = null;
}
@@ -893,8 +897,8 @@ namespace Elwig.Windows {
SmtpClient? client = null;
try {
Mouse.OverrideCursor = Cursors.AppStarting;
client = await Utils.GetSmtpClient();
Mouse.OverrideCursor = Cursors.Wait;
client = await Task.Run(Utils.GetSmtpClient);
Mouse.OverrideCursor = null;
var res = MessageBox.Show($"Sollen {EmailDocuments.Count:N0} E-Mails verschickt werden?",
@@ -903,31 +907,33 @@ namespace Elwig.Windows {
return;
}
Mouse.OverrideCursor = Cursors.AppStarting;
Mouse.OverrideCursor = Cursors.Wait;
var subject = EmailSubjectInput.Text;
var text = EmailBodyInput.Text;
await Utils.AddSentMailBody(subject, text, EmailDocuments.Count);
foreach (var (m, docs) in EmailDocuments) {
using var msg = new MimeMessage();
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;
var body = new Multipart("mixed") {
new TextPart("plain") { Text = text }
};
foreach (var doc in docs) {
var name = Utils.NormalizeFileName(doc.Title);
body.Add(doc.AsEmailAttachment($"{name}.pdf"));
await Task.Run(async () => {
await Utils.AddSentMailBody(subject, text, EmailDocuments.Count);
foreach (var (m, docs) in EmailDocuments) {
using var msg = new MimeMessage();
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;
var body = new Multipart("mixed") {
new TextPart("plain") { Text = text }
};
foreach (var doc in docs) {
var name = Utils.NormalizeFileName(doc.Title);
body.Add(doc.AsEmailAttachment($"{name}.pdf"));
}
msg.Body = body;
await client!.SendAsync(msg);
await Utils.AddSentMails([(
"email", m.MgNr, m.AdministrativeName,
m.EmailAddresses.OrderBy(a => a.Nr).Select(a => a.Address).ToArray(),
subject,
docs.Select(d => d.Title).ToArray()
)]);
}
msg.Body = body;
await client!.SendAsync(msg);
await Utils.AddSentMails([(
"email", m.MgNr, m.AdministrativeName,
m.EmailAddresses.OrderBy(a => a.Nr).Select(a => a.Address).ToArray(),
subject,
docs.Select(d => d.Title).ToArray()
)]);
}
});
MessageBox.Show("Erfolgreich alle E-Mails verschickt!", "Rundschreiben verschicken", MessageBoxButton.OK, MessageBoxImage.Information);
} catch (Exception exc) {

@@ -207,7 +207,7 @@
<Button x:Name="BreakdownButton"
Click="BreakdownButton_Click"
Margin="195,90,0,10" Width="190" Padding="3,5,5,5"
ToolTip="Aufschlüsselung des Gewichts nach Zweigstelle, Mitglied, Sorte, Attribut/Bewirt., Qualitätsstufe, gebunden/ungebunden">
ToolTip="Aufschlüsselung der Menge nach Zweigstelle, Mitglied, Sorte, Attribut/Bewirt., Qualitätsstufe, gebunden/ungebunden">
<Grid>
<TextBlock FontFamily="Segoe MDL2 Assets" FontSize="16" Text="&#xE9F9;"
TextAlignment="Left" HorizontalAlignment="Left" Padding="6.5,0.5,0,0"/>
@@ -252,7 +252,7 @@
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="1" TextAlignment="Right"><Bold>Mitglieder</Bold></TextBlock>
<TextBlock Grid.Row="0" Grid.Column="2" TextAlignment="Right"><Bold>Gewicht</Bold></TextBlock>
<TextBlock Grid.Row="0" Grid.Column="2" TextAlignment="Right"><Bold>Menge</Bold></TextBlock>
<TextBlock Grid.Row="0" Grid.Column="3" TextAlignment="Right"><Bold>Fläche</Bold></TextBlock>
<TextBlock Grid.Row="1" Grid.Column="0">Gesamt:</TextBlock>

@@ -62,7 +62,7 @@ namespace Elwig.Windows {
}
private async void Menu_Help_Smtp_Click(object sender, RoutedEventArgs evt) {
Mouse.OverrideCursor = Cursors.AppStarting;
Mouse.OverrideCursor = Cursors.Wait;
try {
using var client = await Utils.GetSmtpClient();
await client!.DisconnectAsync(true);
@@ -133,8 +133,10 @@ namespace Elwig.Windows {
Multiselect = true,
};
if (d.ShowDialog() == true) {
Mouse.OverrideCursor = Cursors.AppStarting;
await ElwigData.Import(d.FileNames, ElwigData.ImportMode.Interactively);
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
await ElwigData.Import(d.FileNames, ElwigData.ImportMode.Interactively);
});
}
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
@@ -145,77 +147,81 @@ namespace Elwig.Windows {
private async void DownloadButton_Click(object sender, RoutedEventArgs evt) {
if (App.Config.SyncUrl == null)
return;
Mouse.OverrideCursor = Cursors.AppStarting;
try {
var data = await Utils.GetExportMetaData(App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
var files = data
.Select(f => new {
Name = f!["name"]!.AsValue().GetValue<string>(),
Timestamp = f!["timestamp"] != null && DateTime.TryParseExact(f!["timestamp"]!.AsValue().GetValue<string>(), "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None, out var dt) ? dt : (DateTime?)null,
ZwstId = f!["meta"]?["zwstid"]?.AsValue().GetValue<string>() ?? f!["zwstid"]?.AsValue().GetValue<string>(),
Device = f!["meta"]?["device"]!.AsValue().GetValue<string>(),
Url = f!["url"]!.AsValue().GetValue<string>(),
Size = f!["size"]!.AsValue().GetValue<long>(),
})
.Where(f => f.Timestamp >= new DateTime(Utils.CurrentLastSeason, 7, 1))
.ToList();
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
var data = await Utils.GetExportMetaData(App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
var files = data
.Select(f => new {
Name = f!["name"]!.AsValue().GetValue<string>(),
Timestamp = f!["timestamp"] != null && DateTime.TryParseExact(f!["timestamp"]!.AsValue().GetValue<string>(), "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None, out var dt) ? dt : (DateTime?)null,
ZwstId = f!["meta"]?["zwstid"]?.AsValue().GetValue<string>() ?? f!["zwstid"]?.AsValue().GetValue<string>(),
Device = f!["meta"]?["device"]!.AsValue().GetValue<string>(),
Url = f!["url"]!.AsValue().GetValue<string>(),
Size = f!["size"]!.AsValue().GetValue<long>(),
})
.Where(f => f.Timestamp >= new DateTime(Utils.CurrentLastSeason, 7, 1))
.ToList();
var imported = await ElwigData.GetImportedFiles();
var import = files
.Where(f => f.Device != Environment.MachineName && !imported.Contains(f.Name))
.ToList();
var paths = new List<string>();
using (var client = Utils.GetHttpClient(App.Config.SyncUsername, App.Config.SyncPassword)) {
foreach (var f in import) {
var filename = Path.Combine(App.TempPath, f.Name);
using var stream = new FileStream(filename, FileMode.Create);
await client.DownloadAsync(f.Url, stream);
paths.Add(filename);
var imported = await ElwigData.GetImportedFiles();
var import = files
.Where(f => f.Device != Environment.MachineName && !imported.Contains(f.Name))
.ToList();
var paths = new List<string>();
using (var client = Utils.GetHttpClient(App.Config.SyncUsername, App.Config.SyncPassword)) {
foreach (var f in import) {
var filename = Path.Combine(App.TempPath, f.Name);
using var stream = new FileStream(filename, FileMode.Create);
await client.DownloadAsync(f.Url, stream);
paths.Add(filename);
}
}
await ElwigData.Import(paths, ElwigData.ImportMode.FromBranches);
} catch (HttpRequestException exc) {
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
} catch (TaskCanceledException exc) {
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
await ElwigData.Import(paths, ElwigData.ImportMode.FromBranches);
} catch (HttpRequestException exc) {
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
} catch (TaskCanceledException exc) {
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
}
private async void UploadButton_Click(object sender, RoutedEventArgs evt) {
if (App.Config.SyncUrl == null)
return;
Mouse.OverrideCursor = Cursors.AppStarting;
try {
var path = Path.Combine(App.TempPath, $"{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{App.ZwstId}.elwig.zip");
using var ctx = new AppDbContext();
var deliveries = await ctx.Deliveries
.Where(d => d.Year == Utils.CurrentLastSeason && d.ZwstId == App.ZwstId)
.Include(d => d.Parts)
.ThenInclude(p => p.PartModifiers)
.OrderBy(d => d.DateString)
.ThenBy(d => d.TimeString)
.ThenBy(d => d.LsNr)
.AsSplitQuery()
.ToListAsync();
if (deliveries.Count == 0) {
MessageBox.Show("Es gibt keine Lieferungen, die hochgeladen werden können!", "Lieferungen hochladen",
MessageBoxButton.OK, MessageBoxImage.Error);
} else {
await ElwigData.Export(path, deliveries, [$"{Utils.CurrentLastSeason}", $"Zweigstelle {App.BranchName}"]);
await Utils.UploadExportData(path, App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
MessageBox.Show($"Hochladen von {deliveries.Count:N0} Lieferungen erfolgreich!", "Lieferungen hochladen",
MessageBoxButton.OK, MessageBoxImage.Information);
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
var path = Path.Combine(App.TempPath, $"{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{App.ZwstId}.elwig.zip");
using var ctx = new AppDbContext();
var deliveries = await ctx.Deliveries
.Where(d => d.Year == Utils.CurrentLastSeason && d.ZwstId == App.ZwstId)
.Include(d => d.Parts)
.ThenInclude(p => p.PartModifiers)
.OrderBy(d => d.DateString)
.ThenBy(d => d.TimeString)
.ThenBy(d => d.LsNr)
.AsSplitQuery()
.ToListAsync();
if (deliveries.Count == 0) {
MessageBox.Show("Es gibt keine Lieferungen, die hochgeladen werden können!", "Lieferungen hochladen",
MessageBoxButton.OK, MessageBoxImage.Error);
} else {
await ElwigData.Export(path, deliveries, [$"{Utils.CurrentLastSeason}", $"Zweigstelle {App.BranchName}"]);
await Utils.UploadExportData(path, App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
MessageBox.Show($"Hochladen von {deliveries.Count:N0} Lieferungen erfolgreich!", "Lieferungen hochladen",
MessageBoxButton.OK, MessageBoxImage.Information);
}
} catch (HttpRequestException exc) {
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Lieferungen hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
} catch (TaskCanceledException exc) {
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Lieferungen hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Lieferungen hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
}
} catch (HttpRequestException exc) {
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Lieferungen hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
} catch (TaskCanceledException exc) {
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Lieferungen hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
}
@@ -270,24 +276,31 @@ namespace Elwig.Windows {
AreaCommitmentsButton.IsEnabled = valid;
BreakdownMemberVarietyButton.IsEnabled = valid;
SeasonStatMembersTotal.Text = "-";
SeasonStatMembersGeb.Text = "-";
SeasonStatWeightTotal.Text = "-";
SeasonStatWeightGeb.Text = "-";
SeasonStatWeightUngeb.Text = "-";
SeasonStatArea.Text = "-";
if (valid) {
var areaComs = Utils.ActiveAreaCommitments(ctx.AreaCommitments, year!.Value);
var weightTotal = await ctx.DeliveryParts.Where(p => p.Year == year).SumAsync(p => p.Weight);
var gebWeight = await ctx.DeliveryPartBuckets.Where(b => b.Year == year && b.Discr != "_").SumAsync(b => b.Value);
SeasonStatMembersTotal.Text = $"{await ctx.Deliveries.Where(d => d.Year == year).Select(d => d.Member).Distinct().CountAsync():N0}";
SeasonStatMembersGeb.Text = $"{await areaComs.Select(c => c.Member).Distinct().CountAsync():N0}";
SeasonStatWeightTotal.Text = $"{weightTotal:N0} kg";
SeasonStatWeightGeb.Text = $"{gebWeight:N0} kg";
SeasonStatWeightUngeb.Text = $"{weightTotal - gebWeight:N0} kg";
SeasonStatArea.Text = $"{await areaComs.SumAsync(c => c.Area):N0} m²";
} else {
SeasonStatMembersTotal.Text = "-";
SeasonStatMembersGeb.Text = "-";
SeasonStatWeightTotal.Text = "-";
SeasonStatWeightGeb.Text = "-";
SeasonStatWeightUngeb.Text = "-";
SeasonStatArea.Text = "-";
}
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 membersGeb = await areaComs.Select(c => c.Member).Distinct().CountAsync();
var weightTotal = await ctx.DeliveryParts.Where(p => p.Year == year).SumAsync(p => p.Weight);
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}";
SeasonStatMembersGeb.Text = $"{membersGeb:N0}";
SeasonStatWeightTotal.Text = $"{weightTotal:N0} kg";
SeasonStatWeightGeb.Text = $"{gebWeight:N0} kg";
SeasonStatWeightUngeb.Text = $"{weightTotal - gebWeight:N0} kg";
SeasonStatArea.Text = $"{area:N0} m²";
});
});
};
}
private void DeliveryConfirmationButton_Click(object sender, RoutedEventArgs evt) {
@@ -315,22 +328,24 @@ namespace Elwig.Windows {
if (d.ShowDialog() == false)
return;
Mouse.OverrideCursor = Cursors.AppStarting;
try {
var b = new Billing(year);
await b.FinishSeason();
await b.CalculateBuckets();
App.HintContextChange();
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
var b = new Billing(year);
await b.FinishSeason();
await b.CalculateBuckets();
App.HintContextChange();
using var ctx = new AppDbContext();
var tbl1 = await OverUnderDeliveryData.ForSeason(ctx.OverUnderDeliveryRows, year);
var tbl2 = await AreaComUnderDeliveryData.ForSeason(ctx.AreaComUnderDeliveryRows, year);
using var ods = new OdsFile(d.FileName);
await ods.AddTable(tbl1);
await ods.AddTable(tbl2);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
using var ctx = new AppDbContext();
var tbl1 = await OverUnderDeliveryData.ForSeason(ctx.OverUnderDeliveryRows, year);
var tbl2 = await AreaComUnderDeliveryData.ForSeason(ctx.AreaComUnderDeliveryRows, year);
using var ods = new OdsFile(d.FileName);
await ods.AddTable(tbl1);
await ods.AddTable(tbl2);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
}
@@ -346,24 +361,26 @@ namespace Elwig.Windows {
if (d.ShowDialog() == false)
return;
Mouse.OverrideCursor = Cursors.AppStarting;
try {
var b = new Billing(year);
await b.FinishSeason();
await b.CalculateBuckets();
App.HintContextChange();
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
var b = new Billing(year);
await b.FinishSeason();
await b.CalculateBuckets();
App.HintContextChange();
using var ctx = new AppDbContext();
using var ods = new OdsFile(d.FileName);
var tblTotal = await WeightBreakdownData.ForSeason(ctx.WeightBreakDownRows, year);
await ods.AddTable(tblTotal);
foreach (var branch in await ctx.Branches.OrderBy(b => b.Name).ToListAsync()) {
var tbl = await WeightBreakdownData.ForSeason(ctx.WeightBreakDownRows, year, branch);
await ods.AddTable(tbl);
using var ctx = new AppDbContext();
using var ods = new OdsFile(d.FileName);
var tblTotal = await WeightBreakdownData.ForSeason(ctx.WeightBreakDownRows, year);
await ods.AddTable(tblTotal);
foreach (var branch in await ctx.Branches.OrderBy(b => b.Name).ToListAsync()) {
var tbl = await WeightBreakdownData.ForSeason(ctx.WeightBreakDownRows, year, branch);
await ods.AddTable(tbl);
}
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
}
@@ -379,20 +396,22 @@ namespace Elwig.Windows {
if (d.ShowDialog() == false)
return;
Mouse.OverrideCursor = Cursors.AppStarting;
try {
var b = new Billing(year);
await b.FinishSeason();
await b.CalculateBuckets();
App.HintContextChange();
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
var b = new Billing(year);
await b.FinishSeason();
await b.CalculateBuckets();
App.HintContextChange();
using var ctx = new AppDbContext();
var tbl = await MemberAreaComsData.ForSeason(ctx.MemberAreaComsRows, year);
using var ods = new OdsFile(d.FileName);
await ods.AddTable(tbl);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
using var ctx = new AppDbContext();
var tbl = await MemberAreaComsData.ForSeason(ctx.MemberAreaComsRows, year);
using var ods = new OdsFile(d.FileName);
await ods.AddTable(tbl);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
}
@@ -408,20 +427,22 @@ namespace Elwig.Windows {
if (d.ShowDialog() == false)
return;
Mouse.OverrideCursor = Cursors.AppStarting;
try {
var b = new Billing(year);
await b.FinishSeason();
await b.CalculateBuckets();
App.HintContextChange();
Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => {
try {
var b = new Billing(year);
await b.FinishSeason();
await b.CalculateBuckets();
App.HintContextChange();
using var ctx = new AppDbContext();
var tbl = await MemberDeliveryPerVarietyData.ForSeason(ctx.MemberDeliveryPerVariantRows, year);
using var ods = new OdsFile(d.FileName);
await ods.AddTable(tbl);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
using var ctx = new AppDbContext();
var tbl = await MemberDeliveryPerVarietyData.ForSeason(ctx.MemberDeliveryPerVariantRows, year);
using var ods = new OdsFile(d.FileName);
await ods.AddTable(tbl);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
Mouse.OverrideCursor = null;
}
}

@@ -653,13 +653,40 @@
TextChanged="TextBox_TextChanged"
VerticalAlignment="Stretch" Height="auto" AcceptsReturn="True" TextWrapping="Wrap" VerticalScrollBarVisibility="Visible"/>
<Label Content="Kontaktart:" Margin="10,10,0,10" Grid.Column="0" VerticalAlignment="Bottom"/>
<Label Content="Kontaktart:" Margin="10,10,0,40" Grid.Column="0" VerticalAlignment="Bottom"/>
<CheckBox x:Name="ContactPostalInput" Content="Post" IsChecked="{Binding ContactViaPost, Mode=TwoWay}" IsEnabled="False"
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"
HorizontalAlignment="Left" Margin="0,0,0,15" VerticalAlignment="Bottom" Grid.Column="1" Grid.ColumnSpan="2"/>
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,15" VerticalAlignment="Bottom" Grid.Column="1" Grid.ColumnSpan="2"/>
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" TextWrapping="NoWrap" VerticalAlignment="Bottom">
<TextBlock.ToolTip>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="110"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Erstellt:"/>
<TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding CreatedAt}"/>
<TextBlock Grid.Row="1" Grid.Column="0" Text="Zuletzt geändert:"/>
<TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding ModifiedAt}"/>
<TextBlock Grid.Row="2" Grid.Column="0" Text="Zuletzt von diesem Gerät exportiert:"/>
<TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding ExportedAt}"/>
<TextBlock Grid.Row="3" Grid.Column="0" Text="Zuletzt auf dieses Gerät importiert:"/>
<TextBlock Grid.Row="3" Grid.Column="1" Text="{Binding ImportedAt}"/>
</Grid>
</TextBlock.ToolTip>
</TextBlock>
<Button x:Name="DeliveryButton" Content="Lieferungen" IsEnabled="{Binding IsMemberSelected}"
Click="DeliveryButton_Click"

@@ -389,9 +389,10 @@ namespace Elwig.Windows {
}
var d = new DeleteMemberDialog(m.MgNr, m.AdministrativeName, areaComs, deliveries, credits);
if (d.ShowDialog() == true) {
Mouse.OverrideCursor = Cursors.AppStarting;
Mouse.OverrideCursor = Cursors.Wait;
try {
await MemberService.DeleteMember(m.MgNr, d.DeletePaymentData, d.DeleteDeliveries, d.DeleteAreaComs);
App.HintContextChange();
} catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
@@ -408,20 +409,20 @@ namespace Elwig.Windows {
}
private async void SaveButton_Click(object? sender, RoutedEventArgs? evt) {
Mouse.OverrideCursor = Cursors.AppStarting;
Mouse.OverrideCursor = Cursors.Wait;
SaveButton.IsEnabled = false;
int mgnr;
try {
mgnr = await ViewModel.UpdateMember(ViewModel.SelectedMember?.MgNr);
App.HintContextChange();
} catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Mitglied aktualisieren", MessageBoxButton.OK, MessageBoxImage.Error);
SaveButton.IsEnabled = true;
return;
} finally {
Mouse.OverrideCursor = null;
return;
}
IsEditing = false;
@@ -436,6 +437,7 @@ namespace Elwig.Windows {
await RefreshList();
RefreshInputs();
ViewModel.SearchQuery = "";
Mouse.OverrideCursor = null;
if (mgnr is int m)
FocusMember(m);
}
@@ -491,15 +493,17 @@ namespace Elwig.Windows {
private async void Menu_Contact_Letterhead_Click(object sender, RoutedEventArgs evt) {
if (ViewModel.SelectedMember is not Member m) return;
Mouse.OverrideCursor = Cursors.AppStarting;
Mouse.OverrideCursor = Cursors.Wait;
try {
using var doc = new Letterhead(m);
await doc.Generate();
if (!App.Config.Debug) {
await doc.Print();
} else {
doc.Show();
}
await Task.Run(async () => {
using var doc = new Letterhead(m);
await doc.Generate();
if (!App.Config.Debug) {
await doc.Print();
} else {
doc.Show();
}
});
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
@@ -780,11 +784,11 @@ namespace Elwig.Windows {
$"{ViewModel.Prefix}{(!string.IsNullOrEmpty(ViewModel.Prefix) ? " " : "")}" +
$"{ViewModel.GivenName}{(!string.IsNullOrEmpty(ViewModel.GivenName) ? " " : "")}" +
$"{ViewModel.Suffix}{(!string.IsNullOrEmpty(ViewModel.Suffix) ? " " : "")}";
var d = new AreaComDialog(oldMember.AdministrativeName, newName, areaComs.Count, areaComs.Sum(c => c.Area));
var d = new AreaComTransferDialog(oldMember.AdministrativeName, newName, areaComs.Count, areaComs.Sum(c => c.Area));
if (d.ShowDialog() != true)
return;
ViewModel.TransferPredecessorAreaComs = d.SuccessorSeason;
ViewModel.MaintainAreaComYearTo = d.MaintainYearTo;
ViewModel.MaintainAreaComYearFrom = d.MaintainYearFrom;
if (IsEditing)
SetOriginalValue(PredecessorMgNrInput, -1); // hack to allow user to save
UpdateButtons();
@@ -843,7 +847,7 @@ namespace Elwig.Windows {
.Where(c => c.MgNr == mgnr && (c.YearTo == null || c.YearTo >= Utils.FollowingSeason))
.ToListAsync();
if (areaComs.Count > 0) {
var d = new AreaComDialog(m.AdministrativeName, areaComs.Count, areaComs.Sum(c => c.Area));
var d = new AreaComTransferDialog(m.AdministrativeName, areaComs.Count, areaComs.Sum(c => c.Area));
if (d.ShowDialog() == true) {
ViewModel.CancelAreaComs = d.CancelSeason;
}

@@ -156,7 +156,7 @@ namespace Elwig.Windows {
}
private async void AutoAdjustBsButton_Click(object sender, RoutedEventArgs evt) {
Mouse.OverrideCursor = Cursors.AppStarting;
Mouse.OverrideCursor = Cursors.Wait;
try {
int? kg = AllowanceKgInput.Text == "" ? null : int.Parse(AllowanceKgInput.Text);
double? bs = AllowanceBsInput.Text == "" ? null : double.Parse(AllowanceBsInput.Text);
@@ -169,10 +169,12 @@ namespace Elwig.Windows {
App.Client.AutoAdjustBs.AllowanceKgPerBs = kgPerBs;
App.Client.AutoAdjustBs.AllowancePercent = percent;
App.Client.AutoAdjustBs.MinBs = minBs;
await App.Client.UpdateValues();
var b = new Billing(Year);
await b.AutoAdjustBusinessShares(new DateOnly(Year, 11, 30), kg ?? default, bs ?? default, kgPerBs ?? default, percent / 100.0 ?? default, minBs ?? default);
await Task.Run(async () => {
await App.Client.UpdateValues();
var b = new Billing(Year);
await b.AutoAdjustBusinessShares(new DateOnly(Year, 11, 30), kg ?? default, bs ?? default, kgPerBs ?? default, percent / 100.0 ?? default, minBs ?? default);
});
App.HintContextChange();
} catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
@@ -183,10 +185,12 @@ namespace Elwig.Windows {
}
private async void UnAdjustBsButton_Click(object sender, RoutedEventArgs evt) {
Mouse.OverrideCursor = Cursors.AppStarting;
Mouse.OverrideCursor = Cursors.Wait;
try {
var b = new Billing(Year);
await b.UnAdjustBusinessShares();
await Task.Run(async () => {
var b = new Billing(Year);
await b.UnAdjustBusinessShares();
});
App.HintContextChange();
} catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
@@ -281,35 +285,37 @@ namespace Elwig.Windows {
private async void CustomButton_Click(object sender, RoutedEventArgs evt) {
if (MemberInput.SelectedItem is not Member m) return;
Mouse.OverrideCursor = Cursors.AppStarting;
Mouse.OverrideCursor = Cursors.Wait;
try {
using var ctx = new AppDbContext();
if (CustomPayments?.TryGetValue(m.MgNr, out var p) == true) {
ctx.Remove(p);
}
if (sender == SaveCustomButton) {
var modAbs = decimal.TryParse(CustomModAbsInput.Text, out var n1) ? (decimal?)n1 : null;
var modRel = decimal.TryParse(CustomModRelInput.Text, out var n2) ? (decimal?)n2 / 100 : null;
var amount = decimal.TryParse(CustomAmountInput.Text, out var n3) ? (decimal?)n3 : null;
var modText = CustomModCommentInput.Text.Trim();
var text = CustomCommentInput.Text.Trim();
ctx.Add(new PaymentCustom {
MgNr = m.MgNr,
Year = Year,
ModAbs = modAbs,
ModRel = modRel,
ModComment = modText == "" ? null : modText,
Amount = amount,
Comment = text == "" ? null : text,
});
}
await ctx.SaveChangesAsync();
var modAbs = decimal.TryParse(CustomModAbsInput.Text, out var n1) ? (decimal?)n1 : null;
var modRel = decimal.TryParse(CustomModRelInput.Text, out var n2) ? (decimal?)n2 / 100 : null;
var amount = decimal.TryParse(CustomAmountInput.Text, out var n3) ? (decimal?)n3 : null;
var modText = CustomModCommentInput.Text.Trim();
var text = CustomCommentInput.Text.Trim();
await Task.Run(async () => {
using var ctx = new AppDbContext();
if (CustomPayments?.TryGetValue(m.MgNr, out var p) == true) {
ctx.Remove(p);
}
if (sender == SaveCustomButton) {
ctx.Add(new PaymentCustom {
MgNr = m.MgNr,
Year = Year,
ModAbs = modAbs,
ModRel = modRel,
ModComment = modText == "" ? null : modText,
Amount = amount,
Comment = text == "" ? null : text,
});
}
await ctx.SaveChangesAsync();
});
App.HintContextChange();
} catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Benutzerdefinierten Zu-/Abschlag speichern", MessageBoxButton.OK, MessageBoxImage.Error);
}
App.HintContextChange();
Mouse.OverrideCursor = null;
}
}

@@ -5,8 +5,12 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Elwig.Windows"
xmlns:vm="clr-namespace:Elwig.ViewModels"
xmlns:ctrl="clr-namespace:Elwig.Controls"
Title="Auszahlungsvarianten - Elwig" Height="480" Width="850" MinHeight="400" MinWidth="830">
Title="Auszahlungsvarianten - Elwig" Height="480" Width="850" MinHeight="400" MinWidth="850">
<Window.DataContext>
<vm:PaymentVariantsViewModel/>
</Window.DataContext>
<Window.Resources>
<Style TargetType="Label">
<Setter Property="HorizontalAlignment" Value="Left"/>
@@ -55,25 +59,25 @@
<Menu Grid.ColumnSpan="2" BorderThickness="0,0,0,1" BorderBrush="LightGray" Background="White">
<MenuItem Header="Variantendaten">
<MenuItem x:Name="Menu_SummaryShow" Header="...anzeigen (PDF)" IsEnabled="False"
<MenuItem x:Name="Menu_SummaryShow" Header="...anzeigen (PDF)" IsEnabled="{Binding IsPaymentVariantSelected}"
Click="Menu_SummaryShow_Click" InputGestureText="Strg+P">
<MenuItem.Icon>
<TextBlock FontFamily="Segoe MDL2 Assets" FontSize="16" Text="&#xE8FF;"/>
</MenuItem.Icon>
</MenuItem>
<MenuItem x:Name="Menu_SummarySave" Header="...speichern... (PDF)" IsEnabled="False"
<MenuItem x:Name="Menu_SummarySave" Header="...speichern... (PDF)" IsEnabled="{Binding IsPaymentVariantSelected}"
Click="Menu_SummarySave_Click">
<MenuItem.Icon>
<TextBlock FontFamily="Segoe MDL2 Assets" FontSize="16" Text="&#xEA90;"/>
</MenuItem.Icon>
</MenuItem>
<MenuItem x:Name="Menu_SummaryExport" Header="...speichern... (Excel)" IsEnabled="False"
<MenuItem x:Name="Menu_SummaryExport" Header="...speichern... (Excel)" IsEnabled="{Binding IsPaymentVariantSelected}"
Click="Menu_SummaryExport_Click">
<MenuItem.Icon>
<TextBlock FontFamily="Segoe MDL2 Assets" FontSize="16" Text="&#xE9F9;"/>
</MenuItem.Icon>
</MenuItem>
<MenuItem x:Name="Menu_SummaryPrint" Header="...drucken" IsEnabled="False"
<MenuItem x:Name="Menu_SummaryPrint" Header="...drucken" IsEnabled="{Binding IsPaymentVariantSelected}"
Click="Menu_SummaryPrint_Click" InputGestureText="Strg+Shift+P">
<MenuItem.Icon>
<TextBlock FontFamily="Segoe MDL2 Assets" FontSize="16" Text="&#xE749;"/>
@@ -81,7 +85,7 @@
</MenuItem>
</MenuItem>
<MenuItem Header="Buchungsliste">
<MenuItem x:Name="Menu_ExportSave" Header="...speichern... (Excel)" IsEnabled="False"
<MenuItem x:Name="Menu_ExportSave" Header="...speichern... (Excel)" IsEnabled="{Binding ExportIsEnabled}"
Click="Menu_ExportSave_Click" InputGestureText="Strg+L">
<MenuItem.Icon>
<TextBlock FontFamily="Segoe MDL2 Assets" FontSize="16" Text="&#xE9F9;"/>
@@ -89,7 +93,7 @@
</MenuItem>
</MenuItem>
<MenuItem Header="Überweisungsdaten">
<MenuItem x:Name="Menu_EbicsSave" Header="...exportieren... (EBICS)" IsEnabled="False"
<MenuItem x:Name="Menu_EbicsSave" Header="...exportieren... (EBICS)" IsEnabled="{Binding ExportIsEnabled}"
Click="Menu_EbicsSave_Click" InputGestureText="Strg+Ü">
<MenuItem.Icon>
<TextBlock FontFamily="Segoe MDL2 Assets" FontSize="16" Text="&#xE792;"/>
@@ -99,7 +103,9 @@
</Menu>
<Grid Grid.Row="1">
<ListBox x:Name="PaymentVariantList" Margin="10,10,35,10" Grid.RowSpan="2" SelectionChanged="PaymentVariantList_SelectionChanged">
<ListBox x:Name="PaymentVariantList" Margin="10,10,35,10" Grid.RowSpan="2"
SelectionChanged="PaymentVariantList_SelectionChanged"
ItemsSource="{Binding PaymentVariants, Mode=TwoWay}" SelectedItem="{Binding SelectedPaymentVariant, Mode=TwoWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
@@ -109,17 +115,21 @@
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button x:Name="AddButton" Content="&#xF8AA;" FontFamily="Segoe MDL2 Assets" FontSize="11" Padding="0,1.5,0,0" ToolTip="Neue Auszahlungsvariante hinzufügen"
<Button x:Name="AddButton"
Content="&#xF8AA;" FontFamily="Segoe MDL2 Assets" FontSize="11" Padding="0,1.5,0,0" ToolTip="Neue Auszahlungsvariante hinzufügen"
VerticalAlignment="Center" HorizontalAlignment="Right" Width="25" Height="25" Margin="5,0,5,60" Grid.RowSpan="2"
Click="AddButton_Click"/>
<Button x:Name="CopyButton" Content="&#xE8C8;" FontFamily="Segoe MDL2 Assets" FontSize="12" Padding="0,0,0,0" IsEnabled="False" ToolTip="Ausgewählte Auszahlungsvariante duplizieren"
<Button x:Name="CopyButton" IsEnabled="{Binding IsPaymentVariantSelected}"
Content="&#xE8C8;" FontFamily="Segoe MDL2 Assets" FontSize="12" Padding="0,0,0,0" ToolTip="Ausgewählte Auszahlungsvariante duplizieren"
VerticalAlignment="Center" HorizontalAlignment="Right" Width="25" Height="25" Margin="5,0,5,0" Grid.RowSpan="2"
Click="CopyButton_Click"/>
<Button x:Name="DeleteButton" Content="&#xF8AB;" FontFamily="Segoe MDL2 Assets" FontSize="11" Padding="0,1.5,0,0" IsEnabled="False" ToolTip="Ausgewählte Auszahlungsvariante löschen"
<Button x:Name="DeleteButton" IsEnabled="{Binding DeleteIsEnabled}"
Content="&#xF8AB;" FontFamily="Segoe MDL2 Assets" FontSize="11" Padding="0,1.5,0,0" ToolTip="Ausgewählte Auszahlungsvariante löschen"
VerticalAlignment="Center" HorizontalAlignment="Right" Width="25" Height="25" Margin="5,60,5,0" Grid.RowSpan="2"
Click="DeleteButton_Click"/>
<TextBox x:Name="DataInput" Margin="10,200,35,10"
<TextBox x:Name="DataInput" Text="{Binding Data, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsReadOnly="{Binding DataIsReadOnly}"
Margin="10,200,35,10"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Height="auto"
AcceptsReturn="True" VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Auto"
FontFamily="Cascadia Code Light" FontSize="13"
@@ -133,23 +143,28 @@
</Grid.ColumnDefinitions>
<Label Content="Name:" Margin="10,10,0,0" Grid.Column="0"/>
<TextBox x:Name="NameInput" Width="200" Grid.Column="1" HorizontalAlignment="Left" Margin="0,10,0,0"
<TextBox x:Name="NameInput" Text="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsReadOnly="{Binding IsReadOnly}"
Width="200" Grid.Column="1" HorizontalAlignment="Left" Margin="0,10,0,0"
TextChanged="NameInput_TextChanged"/>
<Label Content="Beschreibung:" Margin="10,40,0,0" Grid.Column="0"/>
<TextBox x:Name="CommentInput" Grid.Column="1" HorizontalAlignment="Stretch" Margin="0,40,10,0"
<TextBox x:Name="CommentInput" Text="{Binding Comment, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsReadOnly="{Binding IsReadOnly}"
Grid.Column="1" HorizontalAlignment="Stretch" Margin="0,40,10,0"
TextChanged="CommentInput_TextChanged"/>
<Label Content="Datum:" Margin="10,70,0,0" Grid.Column="0"/>
<TextBox x:Name="DateInput" Grid.Column="1" Width="77" HorizontalAlignment="Left" Margin="0,70,10,0"
<TextBox x:Name="DateInput" Text="{Binding DateString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsReadOnly="{Binding IsReadOnly}"
Grid.Column="1" Width="77" HorizontalAlignment="Left" Margin="0,70,10,0"
TextChanged="DateInput_TextChanged"/>
<Label Content="Überwiesen am:" Margin="10,100,0,0" Grid.Column="0"/>
<TextBox x:Name="TransferDateInput" Grid.Column="1" Width="77" HorizontalAlignment="Left" Margin="0,100,10,0"
<TextBox x:Name="TransferDateInput" Text="{Binding TransferDateString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsReadOnly="{Binding IsReadOnly}"
Grid.Column="1" Width="77" HorizontalAlignment="Left" Margin="0,100,10,0"
TextChanged="TransferDateInput_TextChanged"/>
<Label Content="Rebelzuschlag:" Margin="10,130,0,0" Grid.Column="0"/>
<ctrl:UnitTextBox x:Name="WeightModifierInput" Grid.Column="1" Width="60" Margin="0,130,10,0" Unit="%"
<ctrl:UnitTextBox x:Name="WeightModifierInput" Text="{Binding WeightModifierString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsReadOnly="{Binding IsReadOnly}"
Grid.Column="1" Width="60" Margin="0,130,10,0" Unit="%"
HorizontalAlignment="Left" VerticalAlignment="Top"
TextChanged="WeightModifierInput_TextChanged" LostFocus="WeightModifierInput_LostFocus"/>
@@ -160,19 +175,24 @@
</TextBlock>
<Label Content="Berücksichtigen:" Margin="90,70,10,10" Grid.Column="1"/>
<CheckBox x:Name="ConsiderModifiersInput" Content="Zu-/Abschläge bei Lieferungen"
<CheckBox x:Name="ConsiderModifiersInput" IsChecked="{Binding ConsiderModifiers, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsEnabled="{Binding IsEnabled}"
Content="Zu-/Abschläge bei Lieferungen (inkl. Rebelzuschl.)"
Margin="110,95,10,10" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Top"
Checked="ConsiderModifiersInput_Changed" Unchecked="ConsiderModifiersInput_Changed"/>
<CheckBox x:Name="ConsiderPenaltiesInput" Content="Pönalen bei Unterlieferungen (FB)"
<CheckBox x:Name="ConsiderPenaltiesInput" IsChecked="{Binding ConsiderPenalties, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsEnabled="{Binding IsEnabled}"
Content="Pönalen bei Unterlieferungen (FB)"
Margin="110,115,10,10" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Top"
Checked="ConsiderPenaltiesInput_Changed" Unchecked="ConsiderPenaltiesInput_Changed"/>
<CheckBox x:Name="ConsiderPenaltyInput" Content="Strafen bei Unterlieferungen (GA)"
<CheckBox x:Name="ConsiderPenaltyInput" IsChecked="{Binding ConsiderPenalty, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsEnabled="{Binding IsEnabled}"
Content="Strafen bei Unterlieferungen (GA)"
Margin="110,135,10,10" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Top"
Checked="ConsiderPenaltyInput_Changed" Unchecked="ConsiderPenaltyInput_Changed"/>
<CheckBox x:Name="ConsiderAutoInput" Content="Automatische Nachzeichnungen der GA"
<CheckBox x:Name="ConsiderAutoInput" IsChecked="{Binding ConsiderAuto, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsEnabled="{Binding IsEnabled}"
Content="Automatische Nachzeichnungen der GA"
Margin="110,155,10,10" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Top"
Checked="ConsiderAutoInput_Changed" Unchecked="ConsiderAutoInput_Changed"/>
<CheckBox x:Name="ConsiderCustomInput" Content="Benutzerdefinierte Zu-/Abschläge pro Mitglied"
<CheckBox x:Name="ConsiderCustomInput" IsChecked="{Binding ConsiderCustom, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsEnabled="{Binding IsEnabled}"
Content="Benutzerdefinierte Zu-/Abschläge pro Mitglied"
Margin="110,175,10,10" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Top"
Checked="ConsiderCustomInput_Changed" Unchecked="ConsiderCustomInput_Changed"/>
<Label Content="&#xF0AE;" FontFamily="Segoe MDL2 Assets" FontSize="16" Grid.Row="0" Grid.Column="1" Margin="108,195,10,10"/>
@@ -206,7 +226,8 @@
</Style>
</Grid.Resources>
<Button x:Name="EditButton" Content="Bearbeiten" Grid.Column="0" Grid.Row="2"
<Button x:Name="EditButton" IsEnabled="{Binding IsPaymentVariantSelected}"
Content="{Binding EditText}" Grid.Column="0" Grid.Row="2"
Click="EditButton_Click"/>
<Label Content="&#xF0AF;" FontFamily="Segoe MDL2 Assets" FontSize="16" Grid.Row="2" Grid.Column="1"/>
<Button x:Name="ModifierButton" Content="Zu-/Abschläge" Grid.Column="0" Grid.Row="4"
@@ -219,12 +240,13 @@
</TransformGroup>
</Label.RenderTransform>
</Label>
<Button x:Name="CalculateButton" Content="Berechnen" Grid.Column="2" Grid.Row="2"
<Button x:Name="CalculateButton" IsEnabled="{Binding CalculateIsEnabled}"
Content="Berechnen" Grid.Column="2" Grid.Row="2"
Click="CalculateButton_Click"/>
<Label Content="&#xF0AF;" FontFamily="Segoe MDL2 Assets" FontSize="16" Grid.Row="2" Grid.Column="3" x:Name="Arrow3"/>
<Label Content="{Binding Arrow}" FontFamily="Segoe MDL2 Assets" FontSize="16" Grid.Row="2" Grid.Column="3"/>
<Button x:Name="PaymentAdjustmentButton" Content="Anpassen" Grid.Column="2" Grid.Row="4"
Click="PaymentAdjustmentButton_Click"/>
<Label Content="&#xF0AF;" FontFamily="Segoe MDL2 Assets" FontSize="16" Grid.Row="4" Grid.Column="3" x:Name="Arrow4" RenderTransformOrigin="0.5,0.5" >
<Label Content="{Binding Arrow}" FontFamily="Segoe MDL2 Assets" FontSize="16" Grid.Row="4" Grid.Column="3" RenderTransformOrigin="0.5,0.5" >
<Label.RenderTransform>
<TransformGroup>
<RotateTransform Angle="-45"/>
@@ -232,16 +254,19 @@
</TransformGroup>
</Label.RenderTransform>
</Label>
<Button x:Name="CommitButton" Content="Festsetzen" Grid.Column="4" Grid.Row="2"
<Button x:Name="CommitButton" IsEnabled="{Binding CommitIsEnabled}" Visibility="{Binding CommitVisibility}"
Content="Festsetzen" Grid.Column="4" Grid.Row="2"
Click="CommitButton_Click"/>
<Button x:Name="RevertButton" Content="Freigeben" Grid.Column="4" Grid.Row="2"
<Button x:Name="RevertButton" IsEnabled="{Binding RevertIsEnabled}" Visibility="{Binding RevertVisibility}"
Content="Freigeben" Grid.Column="4" Grid.Row="2"
Click="RevertButton_Click"/>
<Button x:Name="SaveButton" Content="Speichern" Grid.Column="4" Grid.Row="0"
<Button x:Name="SaveButton" IsEnabled="{Binding SaveIsEnabled}"
Content="Speichern" Grid.Column="4" Grid.Row="0"
Click="SaveButton_Click"/>
</Grid>
<Button x:Name="MailButton"
FontSize="14" Width="180" Margin="10,10,10,10" Height="30" IsEnabled="False"
<Button x:Name="MailButton" IsEnabled="{Binding IsPaymentVariantSelected}"
FontSize="14" Width="180" Margin="10,10,10,10" Height="30"
Click="MailButton_Click"
VerticalAlignment="Bottom" HorizontalAlignment="Right" HorizontalContentAlignment="Stretch" Grid.Column="1">
<Grid>
@@ -273,35 +298,35 @@
<StatusBarItem Grid.Column="0" HorizontalContentAlignment="Stretch">
<DockPanel>
<TextBlock Text="Zu-/Abschl.:"/>
<TextBlock x:Name="ModifierSum" Text="-" TextAlignment="Right"/>
<TextBlock Text="{Binding StatusModifierSum}" TextAlignment="Right"/>
</DockPanel>
</StatusBarItem>
<Separator Grid.Column="1"/>
<StatusBarItem Grid.Column="2" HorizontalContentAlignment="Stretch">
<DockPanel>
<TextBlock Text="Gesamt:"/>
<TextBlock x:Name="TotalSum" Text="-" TextAlignment="Right"/>
<TextBlock Text="{Binding StatusTotalSum}" TextAlignment="Right"/>
</DockPanel>
</StatusBarItem>
<Separator Grid.Column="3"/>
<StatusBarItem Grid.Column="4" HorizontalContentAlignment="Stretch">
<DockPanel>
<TextBlock Text="MwSt.:"/>
<TextBlock x:Name="VatSum" Text="-" TextAlignment="Right"/>
<TextBlock Text="{Binding StatusVatSum}" TextAlignment="Right"/>
</DockPanel>
</StatusBarItem>
<Separator Grid.Column="5"/>
<StatusBarItem Grid.Column="6" HorizontalContentAlignment="Stretch">
<DockPanel>
<TextBlock Text="Abzüge:"/>
<TextBlock x:Name="DeductionSum" Text="-" TextAlignment="Right"/>
<TextBlock Text="{Binding StatusDeductionSum}" TextAlignment="Right"/>
</DockPanel>
</StatusBarItem>
<Separator Grid.Column="7"/>
<StatusBarItem Grid.Column="8" HorizontalContentAlignment="Stretch">
<DockPanel>
<TextBlock Text="Auszahl.:"/>
<TextBlock x:Name="PaymentSum" Text="-" TextAlignment="Right"/>
<TextBlock Text="{Binding StatusPaymentSum}" TextAlignment="Right"/>
</DockPanel>
</StatusBarItem>
</StatusBar>

@@ -1,29 +1,27 @@
using Elwig.Helpers;
using Elwig.Helpers.Billing;
using Elwig.Helpers.Export;
using Elwig.Models.Dtos;
using Elwig.Models.Entities;
using Elwig.Services;
using Elwig.ViewModels;
using Microsoft.EntityFrameworkCore;
using Microsoft.Win32;
using System;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Elwig.Helpers.Billing;
using Elwig.Helpers.Export;
using Microsoft.Win32;
using System.Text.Json;
using Elwig.Documents;
namespace Elwig.Windows {
public partial class PaymentVariantsWindow : ContextWindow {
public readonly int Year;
public readonly bool SeasonLocked;
private bool DataValid, DataChanged, NameChanged, CommentChanged, DateValid, DateChanged, TransferDateValid, TransferDateChanged;
private BillingData? BillingData;
private bool WeightModifierChanged = false;
public PaymentVariantsViewModel ViewModel => (PaymentVariantsViewModel)DataContext;
private static readonly JsonSerializerOptions JsonOpt = new() { WriteIndented = true };
public readonly int Year;
private bool DataValid, DataChanged, NameChanged, CommentChanged, DateValid, DateChanged, TransferDateValid, TransferDateChanged;
private readonly RoutedCommand CtrlL = new("CtrlL", typeof(MemberAdminWindow), [new KeyGesture(Key.L, ModifierKeys.Control)]);
private readonly RoutedCommand CtrlP = new("CtrlP", typeof(MemberAdminWindow), [new KeyGesture(Key.P, ModifierKeys.Control)]);
@@ -38,7 +36,7 @@ namespace Elwig.Windows {
CommandBindings.Add(new CommandBinding(CtrlShiftP, Menu_SummaryPrint_Click));
Year = year;
using (var ctx = new AppDbContext()) {
SeasonLocked = ctx.Seasons.Find(Year + 1) != null;
ViewModel.SeasonLocked = ctx.Seasons.Find(Year + 1) != null;
}
Title = $"Auszahlungsvarianten - Lese {Year} - Elwig";
if (!App.Config.Debug) {
@@ -57,257 +55,95 @@ namespace Elwig.Windows {
.OrderBy(v => v.AvNr)
.Include(v => v.Season.Currency)
.ToListAsync());
await Update();
Update();
}
private async Task Update() {
private void Update() {
if (PaymentVariantList.SelectedItem is PaymentVar v) {
var locked = !v.TestVariant;
DeleteButton.IsEnabled = !locked;
CalculateButton.IsEnabled = !locked;
CommitButton.IsEnabled = !locked && !SeasonLocked;
CommitButton.Visibility = !locked ? Visibility.Visible : Visibility.Hidden;
RevertButton.IsEnabled = locked && !SeasonLocked;
RevertButton.Visibility = locked ? Visibility.Visible : Visibility.Hidden;
Arrow3.Content = locked ? "\xF0B0" : "\xF0AF";
Arrow4.Content = locked ? "\xF0B0" : "\xF0AF";
CopyButton.IsEnabled = true;
EditButton.Content = locked ? "Ansehen" : "Bearbeiten";
EditButton.IsEnabled = true;
SaveButton.IsEnabled = !locked;
MailButton.IsEnabled = true;
Menu_ExportSave.IsEnabled = locked;
Menu_EbicsSave.IsEnabled = locked;
Menu_SummaryExport.IsEnabled = true;
Menu_SummaryShow.IsEnabled = true;
Menu_SummarySave.IsEnabled = true;
Menu_SummaryPrint.IsEnabled = true;
NameInput.Text = v.Name;
NameInput.IsReadOnly = false;
CommentInput.Text = v.Comment;
CommentInput.IsReadOnly = false;
DateInput.Text = $"{v.Date:dd.MM.yyyy}";
DateInput.IsReadOnly = false;
TransferDateInput.Text = $"{v.TransferDate:dd.MM.yyyy}";
TransferDateInput.IsReadOnly = false;
try {
BillingData = BillingData.FromJson(v.Data);
ConsiderModifiersInput.IsChecked = BillingData.ConsiderDelieryModifiers;
ConsiderPenaltiesInput.IsChecked = BillingData.ConsiderContractPenalties;
ConsiderPenaltyInput.IsChecked = BillingData.ConsiderTotalPenalty;
ConsiderAutoInput.IsChecked = BillingData.ConsiderAutoBusinessShares;
ConsiderCustomInput.IsChecked = BillingData.ConsiderCustomModifiers;
if (BillingData.NetWeightModifier != 0) {
WeightModifierInput.Text = $"{Math.Round(BillingData.NetWeightModifier * 100.0, 8)}";
} else if (BillingData.GrossWeightModifier != 0) {
WeightModifierInput.Text = $"{Math.Round(BillingData.GrossWeightModifier * 100.0, 8)}";
} else {
WeightModifierInput.Text = "";
}
DataInput.Text = JsonSerializer.Serialize(BillingData.Data, JsonOpt);
} catch {
BillingData = null;
ConsiderModifiersInput.IsChecked = false;
ConsiderPenaltiesInput.IsChecked = false;
ConsiderPenaltyInput.IsChecked = false;
ConsiderAutoInput.IsChecked = false;
ConsiderCustomInput.IsChecked = false;
WeightModifierInput.Text = "";
DataInput.Text = v.Data;
}
WeightModifierInput.IsReadOnly = false;
ConsiderModifiersInput.IsEnabled = !locked;
ConsiderPenaltiesInput.IsEnabled = !locked;
ConsiderPenaltyInput.IsEnabled = !locked;
ConsiderAutoInput.IsEnabled = !locked;
ConsiderCustomInput.IsEnabled = !locked;
DataInput.IsReadOnly = locked;
ViewModel.FillInputs(v);
} else {
EditButton.Content = "Bearbeiten";
EditButton.IsEnabled = false;
SaveButton.IsEnabled = false;
CopyButton.IsEnabled = false;
CalculateButton.IsEnabled = false;
CommitButton.IsEnabled = false;
CommitButton.Visibility = Visibility.Visible;
RevertButton.IsEnabled = false;
RevertButton.Visibility = Visibility.Hidden;
Arrow3.Content = "\xF0AF";
Arrow4.Content = "\xF0AF";
DeleteButton.IsEnabled = false;
MailButton.IsEnabled = false;
Menu_ExportSave.IsEnabled = false;
Menu_EbicsSave.IsEnabled = false;
Menu_SummaryExport.IsEnabled = false;
Menu_SummaryShow.IsEnabled = false;
Menu_SummarySave.IsEnabled = false;
Menu_SummaryPrint.IsEnabled = false;
BillingData = null;
NameInput.Text = "";
NameInput.IsReadOnly = true;
CommentInput.Text = "";
CommentInput.IsReadOnly = true;
DateInput.Text = "";
DateInput.IsReadOnly = true;
TransferDateInput.Text = "";
TransferDateInput.IsReadOnly = true;
WeightModifierInput.Text = "";
WeightModifierInput.IsReadOnly = true;
ConsiderModifiersInput.IsChecked = false;
ConsiderModifiersInput.IsEnabled = false;
ConsiderPenaltiesInput.IsChecked = false;
ConsiderPenaltiesInput.IsEnabled = false;
ConsiderPenaltyInput.IsChecked = false;
ConsiderPenaltyInput.IsEnabled = false;
ConsiderAutoInput.IsChecked = false;
ConsiderAutoInput.IsEnabled = false;
ConsiderCustomInput.IsChecked = false;
ConsiderCustomInput.IsEnabled = false;
DataInput.Text = "";
DataInput.IsReadOnly = true;
ViewModel.ClearInputs();
}
await UpdateSums();
UpdateSaveButton();
UpdateButtons();
}
private void UpdateSaveButton() {
SaveButton.IsEnabled = PaymentVariantList.SelectedItem != null &&
private void UpdateButtons() {
ViewModel.SaveIsEnabled = PaymentVariantList.SelectedItem != null &&
((DataChanged && DataValid) || NameChanged || CommentChanged ||
(DateChanged && DateValid) ||
(TransferDateChanged && TransferDateValid) ||
(ConsiderModifiersInput.IsChecked != BillingData?.ConsiderDelieryModifiers) ||
(ConsiderPenaltiesInput.IsChecked != BillingData?.ConsiderContractPenalties) ||
(ConsiderPenaltyInput.IsChecked != BillingData?.ConsiderTotalPenalty) ||
(ConsiderAutoInput.IsChecked != BillingData?.ConsiderAutoBusinessShares) ||
(ConsiderCustomInput.IsChecked != BillingData?.ConsiderCustomModifiers) ||
WeightModifierChanged);
CalculateButton.IsEnabled = !SaveButton.IsEnabled && PaymentVariantList.SelectedItem is PaymentVar { TestVariant: true };
CommitButton.IsEnabled = CalculateButton.IsEnabled;
(ViewModel.ConsiderModifiers != ViewModel.BillingData?.ConsiderDelieryModifiers) ||
(ViewModel.ConsiderPenalties != ViewModel.BillingData?.ConsiderContractPenalties) ||
(ViewModel.ConsiderPenalty != ViewModel.BillingData?.ConsiderTotalPenalty) ||
(ViewModel.ConsiderAuto != ViewModel.BillingData?.ConsiderAutoBusinessShares) ||
(ViewModel.ConsiderCustom != ViewModel.BillingData?.ConsiderCustomModifiers) ||
ViewModel.WeightModifierChanged);
ViewModel.CalculateIsEnabled = !ViewModel.SaveIsEnabled && PaymentVariantList.SelectedItem is PaymentVar { TestVariant: true };
ViewModel.CommitIsEnabled = ViewModel.CalculateIsEnabled;
}
private async Task UpdateSums() {
if (PaymentVariantList.SelectedItem is PaymentVar v) {
using var ctx = new AppDbContext();
var sym = v.Season.Currency.Symbol ?? v.Season.Currency.Code;
var modSum = await ctx.PaymentDeliveryParts
.Where(p => p.Year == v.Year && p.AvNr == v.AvNr)
.SumAsync(p => p.AmountValue - p.NetAmountValue);
ModifierSum.Text = $"{v.Season.DecFromDb(modSum):N2} {sym}";
var totalSum = await ctx.MemberPayments
.Where(p => p.Year == v.Year && p.AvNr == v.AvNr)
.SumAsync(p => p.AmountValue);
TotalSum.Text = $"{v.Season.DecFromDb(totalSum):N2} {sym}";
var credits = ctx.Credits.Where(c => c.Year == v.Year && c.AvNr == v.AvNr);
if (!credits.Any()) {
VatSum.Text = $"- {sym}";
DeductionSum.Text = $"- {sym}";
PaymentSum.Text = $"- {sym}";
} else {
// all values in the credit table are stored with precision 2!
TotalSum.Text = $"{Utils.DecFromDb(await credits.SumAsync(c => c.NetAmountValue), 2):N2} {sym}";
VatSum.Text = $"{Utils.DecFromDb(await credits.SumAsync(c => c.VatAmountValue), 2):N2} {sym}";
DeductionSum.Text = $"{-Utils.DecFromDb(await credits.SumAsync(c => c.ModifiersValue ?? 0), 2):N2} {sym}";
PaymentSum.Text = $"{Utils.DecFromDb(await credits.SumAsync(c => c.AmountValue), 2):N2} {sym}";
}
} else {
ModifierSum.Text = "-";
TotalSum.Text = "-";
VatSum.Text = "-";
DeductionSum.Text = "-";
PaymentSum.Text = "-";
}
}
private async void PaymentVariantList_SelectionChanged(object sender, SelectionChangedEventArgs evt) {
await Update();
private void PaymentVariantList_SelectionChanged(object sender, SelectionChangedEventArgs evt) {
Update();
}
private async void AddButton_Click(object sender, RoutedEventArgs evt) {
Mouse.OverrideCursor = Cursors.Wait;
try {
PaymentVar? v;
using (var ctx = new AppDbContext()) {
v = new PaymentVar {
Year = Year,
AvNr = await ctx.NextAvNr(Year),
Name = "Neue Auszahlungsvariante",
TestVariant = true,
DateString = $"{DateTime.Today:yyyy-MM-dd}",
Data = "{\"mode\": \"elwig\", \"version\": 1, \"payment\": {}, \"curves\": []}",
};
ctx.Add(v);
await ctx.SaveChangesAsync();
}
var v = await PaymentVariantService.CreatePaymentVariant(Year);
App.HintContextChange();
ControlUtils.SelectItem(PaymentVariantList, v);
} catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Auszahlungsvariante erstellen", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = null;
}
private async void CopyButton_Click(object sender, RoutedEventArgs evt) {
if (PaymentVariantList.SelectedItem is not PaymentVar orig) return;
if (PaymentVariantList.SelectedItem is not PaymentVar orig)
return;
Mouse.OverrideCursor = Cursors.Wait;
try {
PaymentVar? n;
using (var ctx = new AppDbContext()) {
n = new PaymentVar {
Year = orig.Year,
AvNr = await ctx.NextAvNr(Year),
Name = $"{orig.Name} (Kopie)",
TestVariant = true,
DateString = $"{DateTime.Today:yyyy-MM-dd}",
Data = orig.Data,
};
ctx.Add(n);
await ctx.SaveChangesAsync();
}
PaymentVar n = await orig.Duplicate();
App.HintContextChange();
ControlUtils.SelectItem(PaymentVariantList, n);
} catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Auszahlungsvariante kopieren", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = null;
}
private async void DeleteButton_Click(object sender, RoutedEventArgs evt) {
if (PaymentVariantList.SelectedItem is not PaymentVar v || !v.TestVariant) return;
if (PaymentVariantList.SelectedItem is not PaymentVar v || !v.TestVariant)
return;
Mouse.OverrideCursor = Cursors.Wait;
try {
using (var ctx = new AppDbContext()) {
ctx.Remove(v);
await ctx.SaveChangesAsync();
}
await PaymentVariantService.DeletePaymentVariant(v.Year, v.AvNr);
App.HintContextChange();
} catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Auszahlungsvariante löschen", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = null;
}
private async void CalculateButton_Click(object sender, RoutedEventArgs evt) {
if (PaymentVariantList.SelectedItem is not PaymentVar v)
return;
CalculateButton.IsEnabled = false;
Mouse.OverrideCursor = Cursors.AppStarting;
ViewModel.CalculateIsEnabled = false;
Mouse.OverrideCursor = Cursors.Wait;
try {
var b = new BillingVariant(v.Year, v.AvNr);
await b.Calculate();
await PaymentVariantService.Calculate(v.Year, v.AvNr);
App.HintContextChange();
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Berechnungsfehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
App.HintContextChange();
Mouse.OverrideCursor = null;
CalculateButton.IsEnabled = true;
ViewModel.CalculateIsEnabled = true;
}
private void EditButton_Click(object sender, RoutedEventArgs evt) {
@@ -336,71 +172,40 @@ namespace Elwig.Windows {
private async void Menu_SummaryExport_Click(object sender, RoutedEventArgs evt) {
if (PaymentVariantList.SelectedItem is not PaymentVar v)
return;
var d = new SaveFileDialog() {
FileName = $"Variantendaten-{v.Name.Trim().Replace(' ', '-')}.ods",
DefaultExt = "ods",
Filter = "OpenDocument Format Spreadsheet (*.ods)|*.ods",
Title = $"Variantendaten {v.Name} speichern unter - Elwig"
};
if (d.ShowDialog() == false)
return;
Mouse.OverrideCursor = Cursors.AppStarting;
try {
using var ctx = new AppDbContext();
var data = await PaymentVariantSummaryData.ForPaymentVariant(v, ctx.PaymentVariantSummaryRows);
using var ods = new OdsFile(d.FileName);
await ods.AddTable(data);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = null;
await PaymentVariantService.GenerateSummary(v, ExportMode.SaveList);
}
private async void Menu_SummaryShow_Click(object sender, RoutedEventArgs evt) {
if (PaymentVariantList.SelectedItem is not PaymentVar v)
return;
await GenerateSummary(v, ExportMode.Show);
await PaymentVariantService.GenerateSummary(v, ExportMode.Show);
}
private async void Menu_SummarySave_Click(object sender, RoutedEventArgs evt) {
if (PaymentVariantList.SelectedItem is not PaymentVar v)
return;
await GenerateSummary(v, ExportMode.SavePdf);
await PaymentVariantService.GenerateSummary(v, ExportMode.SavePdf);
}
private async void Menu_SummaryPrint_Click(object sender, RoutedEventArgs evt) {
if (PaymentVariantList.SelectedItem is not PaymentVar v)
return;
await GenerateSummary(v, ExportMode.Print);
}
private static async Task GenerateSummary(PaymentVar v, ExportMode mode) {
Mouse.OverrideCursor = Cursors.AppStarting;
try {
using var ctx = new AppDbContext();
var data = await PaymentVariantSummaryData.ForPaymentVariant(v, ctx.PaymentVariantSummaryRows);
using var doc = new PaymentVariantSummary((await ctx.PaymentVariants.FindAsync(v.Year, v.AvNr))!, data);
await Utils.ExportDocument(doc, mode);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = null;
await PaymentVariantService.GenerateSummary(v, ExportMode.Print);
}
private async void CommitButton_Click(object sender, RoutedEventArgs evt) {
if (PaymentVariantList.SelectedItem is not PaymentVar v)
return;
CommitButton.IsEnabled = false;
Mouse.OverrideCursor = Cursors.AppStarting;
ViewModel.CommitIsEnabled = false;
Mouse.OverrideCursor = Cursors.Wait;
try {
var b = new BillingVariant(v.Year, v.AvNr);
await b.Commit();
await PaymentVariantService.Commit(v.Year, v.AvNr);
App.HintContextChange();
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = null;
RevertButton.IsEnabled = true;
App.HintContextChange();
ViewModel.RevertIsEnabled = true;
}
private async void RevertButton_Click(object sender, RoutedEventArgs evt) {
@@ -412,13 +217,16 @@ namespace Elwig.Windows {
"Traubengutschriften löschen", MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No);
if (res != MessageBoxResult.Yes)
return;
RevertButton.IsEnabled = false;
Mouse.OverrideCursor = Cursors.AppStarting;
var b = new BillingVariant(v.Year, v.AvNr);
await b.Revert();
App.HintContextChange();
ViewModel.RevertIsEnabled = false;
Mouse.OverrideCursor = Cursors.Wait;
try {
await PaymentVariantService.Revert(v.Year, v.AvNr);
App.HintContextChange();
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = null;
CommitButton.IsEnabled = true;
ViewModel.CommitIsEnabled = true;
}
private async void Menu_EbicsSave_Click(object sender, RoutedEventArgs evt) {
@@ -428,107 +236,39 @@ namespace Elwig.Windows {
MessageBox.Show("Überweisungsdatum muss gesetzt sein!", "Exportieren nicht möglich", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
using var ctx = new AppDbContext();
v = (await ctx.PaymentVariants.FindAsync(v.Year, v.AvNr))!;
var withoutIban = v.Credits.Count(c => c.Member.Iban == null);
if (withoutIban > 0) {
var r = MessageBox.Show($"Achtung: Für {withoutIban:N0} Mitglieder ist kein IBAN hinterlegt.\n\nDiese werden NICHT exportiert.",
"Mitglieder ohne IBAN", MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
if (r != MessageBoxResult.OK) return;
}
var withNegAmount = v.Credits.Count(c => c.Amount <= 0);
if (withNegAmount > 0) {
var r = MessageBox.Show($"Achtung: Es gibt {withNegAmount:N0} Traubengutschriften mit negativem Betrag.\n\nDiese werden NICHT exportiert.",
"Traubengutschriften mit negativem Betrag", MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.OK);
if (r != MessageBoxResult.OK) return;
}
var d = new SaveFileDialog() {
FileName = $"{App.Client.NameToken}-Überweisungsdaten-{v.Year}-{v.Name.Trim().Replace(' ', '-')}.{Ebics.FileExtension}",
DefaultExt = Ebics.FileExtension,
Filter = "EBICS-Datei (*.xml)|*.xml",
Title = $"Überweisungsdaten speichern unter - Elwig",
};
if (d.ShowDialog() == true) {
Menu_EbicsSave.IsEnabled = false;
Mouse.OverrideCursor = Cursors.AppStarting;
try {
using var e = new Ebics(v, d.FileName, App.Client.ExportEbicsVersion, (Ebics.AddressMode)App.Client.ExportEbicsAddress);
await e.ExportAsync(Transaction.FromPaymentVariant(v));
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = null;
Menu_EbicsSave.IsEnabled = true;
}
await PaymentVariantService.GenerateEbics(v.Year, v.AvNr);
}
private async void Menu_ExportSave_Click(object sender, RoutedEventArgs evt) {
if (PaymentVariantList.SelectedItem is not PaymentVar v) {
if (PaymentVariantList.SelectedItem is not PaymentVar v)
return;
}
var d = new SaveFileDialog() {
FileName = $"{App.Client.NameToken}-Buchungsliste-{v.Year}-{v.Name.Trim().Replace(' ', '-')}.ods",
DefaultExt = "ods",
Filter = "OpenDocument Format Spreadsheet (*.ods)|*.ods",
Title = $"Buchungsliste speichern unter - Elwig"
};
if (d.ShowDialog() == true) {
Menu_ExportSave.IsEnabled = false;
Mouse.OverrideCursor = Cursors.AppStarting;
try {
using var ctx = new AppDbContext();
var tbl = await CreditNoteData.ForPaymentVariant(ctx, v.Year, v.AvNr);
using var ods = new OdsFile(d.FileName);
await ods.AddTable(tbl);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = null;
Menu_ExportSave.IsEnabled = true;
}
await PaymentVariantService.GenerateAccountingList(v.Year, v.AvNr, v.Name);
}
private async void SaveButton_Click(object sender, RoutedEventArgs evt) {
if (PaymentVariantList.SelectedItem is not PaymentVar v || BillingData == null) return;
if (PaymentVariantList.SelectedItem is not PaymentVar v || ViewModel.BillingData == null)
return;
Mouse.OverrideCursor = Cursors.Wait;
try {
v.Name = NameInput.Text;
v.Comment = (CommentInput.Text != "") ? CommentInput.Text : null;
v.DateString = string.Join("-", DateInput.Text.Split(".").Reverse());
v.TransferDateString = (TransferDateInput.Text != "") ? string.Join("-", TransferDateInput.Text.Split(".").Reverse()) : null;
var d = App.Config.Debug ? BillingData.FromJson(DataInput.Text) : BillingData;
d.ConsiderDelieryModifiers = ConsiderModifiersInput.IsChecked ?? false;
d.ConsiderContractPenalties = ConsiderPenaltiesInput.IsChecked ?? false;
d.ConsiderTotalPenalty = ConsiderPenaltyInput.IsChecked ?? false;
d.ConsiderAutoBusinessShares = ConsiderAutoInput.IsChecked ?? false;
d.ConsiderCustomModifiers = ConsiderCustomInput.IsChecked ?? false;
var modVal = WeightModifierInput.Text.Length > 0 ? double.Parse(WeightModifierInput.Text) : 0;
d.NetWeightModifier = modVal > 0 ? modVal / 100.0 : 0;
d.GrossWeightModifier = modVal < 0 ? modVal / 100.0 : 0;
WeightModifierChanged = false;
v.Data = JsonSerializer.Serialize(d.Data);
using (var ctx = new AppDbContext()) {
ctx.Update(v);
await ctx.SaveChangesAsync();
}
await ViewModel.UpdatePaymentVariant(v.Year, v.AvNr);
App.HintContextChange();
CommentInput_TextChanged(null, null);
ConsiderModifiersInput_Changed(null, null);
ConsiderPenaltiesInput_Changed(null, null);
ConsiderPenaltyInput_Changed(null, null);
ConsiderAutoInput_Changed(null, null);
ConsiderCustomInput_Changed(null, null);
WeightModifierInput_TextChanged(null, null);
} catch (Exception exc) {
await HintContextChange();
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Auszahlungsvariante aktualisieren", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = null;
await HintContextChange();
CommentInput_TextChanged(null, null);
DateInput_TextChanged(null, null);
TransferDateInput_TextChanged(null, null);
ConsiderModifiersInput_Changed(null, null);
ConsiderPenaltiesInput_Changed(null, null);
ConsiderPenaltyInput_Changed(null, null);
ConsiderAutoInput_Changed(null, null);
ConsiderCustomInput_Changed(null, null);
WeightModifierInput_TextChanged(null, null);
}
private void ModifierButton_Click(object sender, RoutedEventArgs evt) {
@@ -547,7 +287,7 @@ namespace Elwig.Windows {
ControlUtils.ClearInputState(NameInput);
NameChanged = false;
}
UpdateSaveButton();
UpdateButtons();
}
private void CommentInput_TextChanged(object? sender, TextChangedEventArgs? evt) {
@@ -562,10 +302,10 @@ namespace Elwig.Windows {
ControlUtils.ClearInputState(CommentInput);
CommentChanged = false;
}
UpdateSaveButton();
UpdateButtons();
}
private void DateInput_TextChanged(object sender, TextChangedEventArgs evt) {
private void DateInput_TextChanged(object? sender, TextChangedEventArgs? evt) {
if (PaymentVariantList.SelectedItem is not PaymentVar v) {
ControlUtils.ClearInputState(DateInput);
return;
@@ -583,10 +323,10 @@ namespace Elwig.Windows {
DateValid = true;
DateChanged = false;
}
UpdateSaveButton();
UpdateButtons();
}
private void TransferDateInput_TextChanged(object sender, TextChangedEventArgs evt) {
private void TransferDateInput_TextChanged(object? sender, TextChangedEventArgs? evt) {
if (PaymentVariantList.SelectedItem is not PaymentVar v) {
ControlUtils.ClearInputState(TransferDateInput);
return;
@@ -604,7 +344,7 @@ namespace Elwig.Windows {
TransferDateValid = true;
TransferDateChanged = false;
}
UpdateSaveButton();
UpdateButtons();
}
private void DataInput_TextChanged(object sender, TextChangedEventArgs evt) {
@@ -630,89 +370,89 @@ namespace Elwig.Windows {
ControlUtils.SetInputInvalid(DataInput);
DataValid = false;
}
UpdateSaveButton();
UpdateButtons();
}
private void ConsiderModifiersInput_Changed(object? sender, RoutedEventArgs? evt) {
if (BillingData == null) {
if (ViewModel.BillingData == null) {
ControlUtils.ClearInputState(ConsiderModifiersInput);
return;
}
if (BillingData.ConsiderDelieryModifiers != ConsiderModifiersInput.IsChecked) {
if (ViewModel.BillingData.ConsiderDelieryModifiers != ConsiderModifiersInput.IsChecked) {
ControlUtils.SetInputChanged(ConsiderModifiersInput);
} else {
ControlUtils.ClearInputState(ConsiderModifiersInput);
}
UpdateSaveButton();
UpdateButtons();
}
private void ConsiderPenaltiesInput_Changed(object? sender, RoutedEventArgs? evt) {
if (BillingData == null) {
if (ViewModel.BillingData == null) {
ControlUtils.ClearInputState(ConsiderPenaltiesInput);
return;
}
if (BillingData.ConsiderContractPenalties != ConsiderPenaltiesInput.IsChecked) {
if (ViewModel.BillingData.ConsiderContractPenalties != ConsiderPenaltiesInput.IsChecked) {
ControlUtils.SetInputChanged(ConsiderPenaltiesInput);
} else {
ControlUtils.ClearInputState(ConsiderPenaltiesInput);
}
UpdateSaveButton();
UpdateButtons();
}
private void ConsiderPenaltyInput_Changed(object? sender, RoutedEventArgs? evt) {
if (BillingData == null) {
if (ViewModel.BillingData == null) {
ControlUtils.ClearInputState(ConsiderPenaltyInput);
return;
}
if (BillingData.ConsiderTotalPenalty != ConsiderPenaltyInput.IsChecked) {
if (ViewModel.BillingData.ConsiderTotalPenalty != ConsiderPenaltyInput.IsChecked) {
ControlUtils.SetInputChanged(ConsiderPenaltyInput);
} else {
ControlUtils.ClearInputState(ConsiderPenaltyInput);
}
UpdateSaveButton();
UpdateButtons();
}
private void ConsiderAutoInput_Changed(object? sender, RoutedEventArgs? evt) {
if (BillingData == null) {
if (ViewModel.BillingData == null) {
ControlUtils.ClearInputState(ConsiderAutoInput);
return;
}
if (BillingData.ConsiderAutoBusinessShares != ConsiderAutoInput.IsChecked) {
if (ViewModel.BillingData.ConsiderAutoBusinessShares != ConsiderAutoInput.IsChecked) {
ControlUtils.SetInputChanged(ConsiderAutoInput);
} else {
ControlUtils.ClearInputState(ConsiderAutoInput);
}
UpdateSaveButton();
UpdateButtons();
}
private void ConsiderCustomInput_Changed(object? sender, RoutedEventArgs? evt) {
if (BillingData == null) {
if (ViewModel.BillingData == null) {
ControlUtils.ClearInputState(ConsiderCustomInput);
return;
}
if (BillingData.ConsiderCustomModifiers != ConsiderCustomInput.IsChecked) {
if (ViewModel.BillingData.ConsiderCustomModifiers != ConsiderCustomInput.IsChecked) {
ControlUtils.SetInputChanged(ConsiderCustomInput);
} else {
ControlUtils.ClearInputState(ConsiderCustomInput);
}
UpdateSaveButton();
UpdateButtons();
}
private void WeightModifierInput_TextChanged(object? sender, TextChangedEventArgs? evt) {
var res = Validator.CheckDecimal(WeightModifierInput, false, 3, 2, true);
if (BillingData == null) {
if (ViewModel.BillingData == null) {
ControlUtils.ClearInputState(WeightModifierInput);
return;
}
var val = WeightModifierInput.Text.Length > 0 && res.IsValid ? double.Parse(WeightModifierInput.Text) : 0;
WeightModifierChanged = (val != Math.Round(BillingData.NetWeightModifier * 100.0, 8) && val != Math.Round(BillingData.GrossWeightModifier * 100.0, 8)) ||
(val == 0 && (BillingData.NetWeightModifier != 0 || BillingData.GrossWeightModifier != 0));
if (WeightModifierChanged) {
ViewModel.WeightModifierChanged = (val != Math.Round(ViewModel.BillingData.NetWeightModifier * 100.0, 8) && val != Math.Round(ViewModel.BillingData.GrossWeightModifier * 100.0, 8)) ||
(val == 0 && (ViewModel.BillingData.NetWeightModifier != 0 || ViewModel.BillingData.GrossWeightModifier != 0));
if (ViewModel.WeightModifierChanged) {
ControlUtils.SetInputChanged(WeightModifierInput);
} else {
ControlUtils.ClearInputState(WeightModifierInput);
}
UpdateSaveButton();
UpdateButtons();
}
private void WeightModifierInput_LostFocus(object sender, RoutedEventArgs evt) {

@@ -1,5 +0,0 @@
::mkdir "C:\Program Files\Elwig"
mkdir "C:\ProgramData\Elwig\resources"
copy /b /y Documents\*.css "C:\ProgramData\Elwig\resources"
copy /b /y Documents\*.cshtml "C:\ProgramData\Elwig\resources"
::copy /b /y ..\Installer\Files\*.exe "C:\Program Files\Elwig\"

@@ -1,23 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
<Fragment>
<!-- C:\Program Files (x86)\Elwig oder C:\Program Files\Elwig -->
<!-- C:\Program Files (x86)\Elwig oder C:\Program Files\Elwig -->
<StandardDirectory Id="ProgramFiles64Folder">
<Directory Id="InstallFolder" Name="!(bind.Property.ProductName)" />
<Directory Id="InstallFolder" Name="!(bind.Property.ProductName)">
<Directory Id="InstallFolderResources" Name="resources">
<Directory Id="InstallFolderDocuments" Name="Documents" />
</Directory>
</Directory>
</StandardDirectory>
<!-- C:\ProgramData\Elwig -->
<StandardDirectory Id="CommonAppDataFolder">
<Directory Id="ConfigFolder" Name="!(bind.Property.ProductName)">
<Directory Id="ConfigFolderResources" Name="resources" />
</Directory>
</StandardDirectory>
<!-- C:\ProgramData\Microsoft\Windows\Start Menu\Programs -->
<StandardDirectory Id="ProgramMenuFolder">
<Directory Id="StartMenuProgramsFolder" Name="!(bind.Property.ProductName)" />
</StandardDirectory>
<!-- C:\Users{USERNAME}\Desktop -->
<StandardDirectory Id="DesktopFolder" />
<!-- C:\ProgramData\Elwig -->
<StandardDirectory Id="CommonAppDataFolder">
<Directory Id="ConfigFolder" Name="!(bind.Property.ProductName)" />
</StandardDirectory>
<!-- C:\ProgramData\Microsoft\Windows\Start Menu\Programs -->
<StandardDirectory Id="ProgramMenuFolder">
<Directory Id="StartMenuProgramsFolder" Name="!(bind.Property.ProductName)" />
</StandardDirectory>
<!-- C:\Users\{USERNAME}\Desktop -->
<StandardDirectory Id="DesktopFolder" />
</Fragment>
</Wix>

@@ -1,14 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
<Fragment>
<ComponentGroup Id="HeatComponents">
<Files Directory="InstallFolder" Include="..\Elwig\bin\Publish\**">
<Exclude Files="..\Elwig\bin\Publish\**.exe" />
<Exclude Files="..\Elwig\bin\Publish\**.pdb" />
</Files>
<Files Directory="ConfigFolderResources" Include="..\Elwig\Documents\**">
<Exclude Files="..\Elwig\Documents\**.cs" />
</Files>
</ComponentGroup>
<ComponentGroup Id="HeatComponents">
<Files Directory="InstallFolder" Include="..\Elwig\bin\Publish\**">
<Exclude Files="..\Elwig\bin\Publish\**.exe" />
<Exclude Files="..\Elwig\bin\Publish\**.pdb" />
</Files>
<Files Directory="InstallFolderDocuments" Include="..\Elwig\Documents\**">
<Exclude Files="..\Elwig\Documents\**.cs" />
</Files>
</ComponentGroup>
</Fragment>
</Wix>

@@ -1,28 +0,0 @@
using Elwig.Documents;
using Elwig.Helpers;
using Elwig.Models.Dtos;
namespace Tests.DocumentTests {
[TestFixture]
public class PaymentVariantSummaryTest {
[Test]
public async Task Test_01_PaymentVariant2020() {
using var ctx = new AppDbContext();
var v = (await ctx.PaymentVariants.FindAsync(2020, 1))!;
var data = await PaymentVariantSummaryData.ForPaymentVariant(v, ctx.PaymentVariantSummaryRows);
using var doc = new PaymentVariantSummary(v, data);
var text = await Utils.GeneratePdfText(doc);
Assert.Multiple(() => {
Assert.That(text, Contains.Substring("Auszahlungsvariante"));
Assert.That(text, Contains.Substring(v.Name));
Assert.That(text, Contains.Substring("""
Gradation ungebunden gebunden Gesamt
[°Oe] [kg] [/kg] [kg] [/kg] []
Grüner Veltliner 3 219 0 1 609,50
Qualitätswein 73 3 219 0,5000 - - 1 609,50
"""));
});
}
}
}

@@ -1,6 +1,6 @@
using OpenQA.Selenium;
using OpenQA.Selenium.Appium.Windows;
using Tests.WeighingTests;
using Tests.UnitTests.WeighingTests;
namespace Tests.E2ETests {
[TestFixture, Order(2)]

@@ -3,7 +3,7 @@ using Elwig.Helpers;
using Elwig.Models.Dtos;
using Microsoft.EntityFrameworkCore;
namespace Tests.DocumentTests {
namespace Tests.UnitTests.DocumentTests {
[TestFixture]
public class CreditNoteTest {
@@ -12,7 +12,7 @@ namespace Tests.DocumentTests {
using var ctx = new AppDbContext();
var m = await ctx.Members.FindAsync(101);
var p = await ctx.MemberPayments.Where(p => p.Year == 2020 && p.AvNr == 1).SingleAsync();
var data = await CreditNoteDeliveryData.ForPaymentVariant(ctx.CreditNoteDeliveryRows, ctx.Seasons, 2020, 1);
var data = await CreditNoteDeliveryData.ForPaymentVariant(ctx.CreditNoteDeliveryRows, ctx.PaymentVariants, 2020, 1);
using var doc = new CreditNote(ctx, p, data[m!.MgNr], false, false, false, false,
ctx.GetMemberUnderDelivery(2020, m!.MgNr).GetAwaiter().GetResult());
var text = await Utils.GeneratePdfText(doc);

@@ -2,7 +2,7 @@ using Elwig.Documents;
using Elwig.Helpers;
using Elwig.Models.Dtos;
namespace Tests.DocumentTests {
namespace Tests.UnitTests.DocumentTests {
[TestFixture]
public class DeliveryAncmtListTest {

@@ -2,7 +2,7 @@ using Elwig.Documents;
using Elwig.Helpers;
using Elwig.Models.Dtos;
namespace Tests.DocumentTests {
namespace Tests.UnitTests.DocumentTests {
[TestFixture]
public class DeliveryConfirmationTest {

@@ -2,7 +2,7 @@ using Elwig.Documents;
using Elwig.Helpers;
using Elwig.Models.Dtos;
namespace Tests.DocumentTests {
namespace Tests.UnitTests.DocumentTests {
[TestFixture]
public class DeliveryDepreciationListTest {

@@ -2,7 +2,7 @@ using Elwig.Documents;
using Elwig.Helpers;
using Elwig.Models.Dtos;
namespace Tests.DocumentTests {
namespace Tests.UnitTests.DocumentTests {
[TestFixture]
public class DeliveryJournalTest {

@@ -1,7 +1,7 @@
using Elwig.Documents;
using Elwig.Helpers;
namespace Tests.DocumentTests {
namespace Tests.UnitTests.DocumentTests {
[TestFixture]
public class DeliveryNoteTest {

@@ -1,7 +1,7 @@
using Elwig.Documents;
using Elwig.Helpers;
namespace Tests.DocumentTests {
namespace Tests.UnitTests.DocumentTests {
[TestFixture]
public class LetterheadTest {

@@ -1,7 +1,7 @@
using Elwig.Documents;
using Elwig.Helpers;
namespace Tests.DocumentTests {
namespace Tests.UnitTests.DocumentTests {
[TestFixture]
public class MemberDataSheetTest {

@@ -2,7 +2,7 @@ using Elwig.Documents;
using Elwig.Helpers;
using Elwig.Models.Dtos;
namespace Tests.DocumentTests {
namespace Tests.UnitTests.DocumentTests {
[TestFixture]
public class MemberListTest {

@@ -0,0 +1,29 @@
using Elwig.Documents;
using Elwig.Helpers;
using Elwig.Models.Dtos;
namespace Tests.UnitTests.DocumentTests {
[TestFixture]
public class PaymentVariantSummaryTest {
[Test]
public async Task Test_01_PaymentVariant2020() {
using var ctx = new AppDbContext();
var v = (await ctx.PaymentVariants.FindAsync(2020, 1))!;
var data = await PaymentVariantSummaryData.ForPaymentVariant(v, ctx.PaymentVariantSummaryRows);
using var doc = new PaymentVariantSummary(v, data);
var text = await Utils.GeneratePdfText(doc, true);
var table = Utils.ExtractTable(text);
Assert.Multiple(() => {
Assert.That(text, Contains.Substring("Auszahlungsvariante"));
Assert.That(text, Contains.Substring(v.Name));
Assert.That(table.Skip(17).ToArray(), Is.EqualTo(new string[][] {
[ "Gradation", "ungebunden", "attributlos gebunden", "gebunden", "Gesamt" ],
[ "[°Oe]", "[kg]", "[/kg]", "[kg]", "[/kg]", "[kg]", "[/kg]", "[]" ],
["Grüner Veltliner", "3 219", "0", "0", "1 609,50"],
["Qualitätswein", "73", "3 219", "0,5000", "-", "-", "-", "-", "1 609,50"]
}));
});
}
}
}

@@ -3,7 +3,7 @@ using System.Reflection;
using Microsoft.Data.Sqlite;
using Elwig.Helpers.Printing;
namespace Tests.DocumentTests {
namespace Tests.UnitTests.DocumentTests {
[SetUpFixture]
public class Setup {

@@ -2,7 +2,7 @@ using Elwig.Documents;
using NReco.PdfRenderer;
using System.Text.RegularExpressions;
namespace Tests.DocumentTests {
namespace Tests.UnitTests.DocumentTests {
public static class Utils {
private static readonly string FileName = Path.Combine(Path.GetTempPath(), "test_document.pdf");

@@ -2,7 +2,7 @@ using Elwig.Documents;
using Elwig.Helpers;
using Elwig.Models.Dtos;
namespace Tests.DocumentTests {
namespace Tests.UnitTests.DocumentTests {
[TestFixture]
public class WineQualityStatisticsTest {

@@ -2,7 +2,7 @@ using Elwig.Helpers;
using Elwig.Helpers.Billing;
using System.Text.Json;
namespace Tests.HelperTests {
namespace Tests.UnitTests.HelperTests {
[TestFixture]
public class BillingDataTest {

@@ -3,7 +3,7 @@ using Elwig.Helpers.Billing;
using Microsoft.Data.Sqlite;
using System.Reflection;
namespace Tests.HelperTests {
namespace Tests.UnitTests.HelperTests {
[TestFixture]
public class BillingTest {

@@ -5,7 +5,7 @@ using Elwig.Models.Entities;
using System.Reflection;
using System.Xml;
namespace Tests.HelperTests {
namespace Tests.UnitTests.HelperTests {
// see https://www.iso20022.org/iso-20022-message-definitions
// and https://www.iso20022.org/catalogue-messages/iso-20022-messages-archive?search=pain
[TestFixture]

@@ -1,6 +1,6 @@
using Elwig.Helpers;
namespace Tests.HelperTests {
namespace Tests.UnitTests.HelperTests {
[TestFixture]
public class UtilsTest {

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