Compare commits
102 Commits
Author | SHA1 | Date | |
---|---|---|---|
70129695ae | |||
51b9799b56 | |||
c1903b1f36 | |||
66eb177fbf | |||
87467bbe75 | |||
abf465f821 | |||
792c18365e | |||
5c46a00752 | |||
9d9f929843 | |||
b76c5ea874 | |||
86e69e9ff8 | |||
050e4f5b6f | |||
01f055ee17 | |||
da9df5cbeb | |||
cc0aa6046f | |||
5cb7d2cbb0 | |||
6c1e50ad02 | |||
46551fb142 | |||
b404839ad1 | |||
ab926421b0 | |||
bbd8b67afd | |||
70f8276808 | |||
4483eb6a69 | |||
6fc38b9db0 | |||
5a4ff26f31 | |||
012352c562 | |||
81f286f504 | |||
324a63cf9a | |||
ca0497e396 | |||
08f551a394 | |||
3460b9378c | |||
a06921d4ec | |||
f2c2d3270b | |||
6927d44b82 | |||
cc0843f183 | |||
5039c1252a | |||
6e4f3b799d | |||
4c9a151f77 | |||
03cacf604b | |||
c12d111c57 | |||
302870fb58 | |||
f756220d75 | |||
293c8967be | |||
601ac548fe | |||
4e477c38e0 | |||
46fc0db6ba | |||
a531e948c1 | |||
cc4ec6c5db | |||
ff375e3caf | |||
5b952c4eb1 | |||
48c441b787 | |||
be246d6f06 | |||
2b10e52ab0 | |||
e3fd705f52 | |||
81e18ac553 | |||
f95f0f0ef3 | |||
8eba40a8c1 | |||
69aa75a50a | |||
13340c0979 | |||
4bd378e048 | |||
602c237fa0 | |||
5e6d0ebf17 | |||
b064643010 | |||
3526234432 | |||
b03f81d4f2 | |||
f123bb44c5 | |||
30536819e7 | |||
384f7c9ec0 | |||
d102a1cb7a | |||
6906584ef0 | |||
c0c0b4a26a | |||
0ce8e488f9 | |||
eb4562dceb | |||
35e5a1dfff | |||
179c8bd4f7 | |||
fd17d294b9 | |||
2a4e8d69d0 | |||
8bf8362480 | |||
c4d68d11bc | |||
21fe5bc094 | |||
e7bfc69842 | |||
f53371ab19 | |||
5f8688f0cd | |||
fa00eaaefc | |||
443e111594 | |||
c6905bbb42 | |||
c360e6b6a7 | |||
9062d55b20 | |||
a9f38a3ccb | |||
cbc0d0ebff | |||
27b5d653e6 | |||
869f652afc | |||
80e91ad776 | |||
bce709efe4 | |||
12eb53cb44 | |||
657910ff48 | |||
5c3cf41d3d | |||
b8851fb241 | |||
66898714bb | |||
1047bc6e8f | |||
1419c834ac | |||
eddea88e77 |
.gitea/workflows
Elwig
App.xamlApp.xaml.cs
Controls
CheckComboBox.csCheckComboBox.xamlIntegerUpDown.csIntegerUpDown.xamlUnitTextBox.csUnitTextBox.xamlUnitTextBox.xaml.csVisibilityConverter.csWidthToMarginConverter.csWineOriginTemplateSelector.csWineQualityLevelTemplateSelector.csWineVarietyTemplateSelector.cs
Dialogs
AbwertenDialog.xamlAreaComDialog.xamlAreaComDialog.xaml.csDeleteMemberDialog.xamlDeleteMemberDialog.xaml.csDeliveryExtractionDialog.xamlLinearPriceIncreaseDialog.xamlManualWeighingDialog.xamlNewSeasonDialog.xamlNewSeasonDialog.xaml.csUpdateDialog.xaml
Documents
BusinessDocument.csCreditNote.csCreditNote.cshtmlDeliveryConfirmation.csDocument.Table.cssDocument.csDocument.cssMemberDataSheet.cshtmlPaymentVariantSummary.csPaymentVariantSummary.cshtmlPaymentVariantSummary.cssWineQualityStatistics.csWineQualityStatistics.cshtmlWineQualityStatistics.css
Elwig.csprojHelpers
AppDbContext.csAppDbUpdater.cs
Billing
ClientParameters.csConfig.csControlUtils.csExport
ExportMode.csExtensions.csHttpClientExtensions.csPrinting
StreamExtensions.csUtils.csWeighing
Models
Dtos
CreditNoteData.csOverUnderDeliveryData.csPaymentVariantSummaryData.csWeightBreakdownData.csWineQualityStatisticsData.cs
Entities
IAddress.csResources
Themes
Windows
AdministrationWindow.csAreaComAdminWindow.xamlAreaComAdminWindow.xaml.csBaseDataWindow.xamlBaseDataWindow.xaml.AreaCom.csBaseDataWindow.xaml.Mod.csBaseDataWindow.xaml.Season.csBaseDataWindow.xaml.WineAttr.csBaseDataWindow.xaml.WineCult.csBaseDataWindow.xaml.csChartWindow.xamlChartWindow.xaml.csDeliveryAdminWindow.xamlDeliveryAdminWindow.xaml.csMailWindow.xamlMailWindow.xaml.csMainWindow.xamlMainWindow.xaml.csMemberAdminWindow.xaml.csPaymentAdjustmentWindow.xamlPaymentAdjustmentWindow.xaml.csPaymentVariantsWindow.xamlPaymentVariantsWindow.xaml.csSeasonFinishWindow.xamlSeasonFinishWindow.xaml.csTestWindow.xamlTestWindow.xaml.cs
fetch-resources.batInstaller
BuildFilesTransform.xsltDocumentTransform.xslt
Files
Folders.wxsHeatComponents.wxsInstaller.wixprojPackage.wxsSetup
Tests
DocumentTests
CreditNoteTest.csDeliveryConfirmationTest.csDeliveryJournalTest.csDeliveryNoteTest.csLetterheadTest.csMemberDataSheetTest.csMemberListTest.csPaymentVariantSummaryTest.csUtils.csWineQualityStatisticsTest.cs
HelperTests
Resources
Tests.csprojWeighingTests
MockScale.csScaleTestBadenL320.csScaleTestGrInzersdorfL246.csScaleTestHaugsdorf.csScaleTestMatzenIT3000A.csScaleTestSitzendorf.csScaleTestWolkersdorfIT6000E.cs
fetch-resources.bat@ -48,7 +48,7 @@ jobs:
|
||||
run: |
|
||||
$content = [System.IO.File]::ReadAllBytes("Setup/bin/x64/Release/Elwig-${{ env.APP_VERSION }}.exe")
|
||||
Invoke-WebRequest `
|
||||
-Uri "https://www.necronda.net/elwig/files/Elwig-${{ env.APP_VERSION }}.exe" `
|
||||
-Uri "https://elwig.at/files/Elwig-${{ env.APP_VERSION }}.exe" `
|
||||
-Method PUT `
|
||||
-Body $content `
|
||||
-Headers @{ Authorization = "${{ secrets.API_AUTHORIZATION }}" } `
|
||||
|
@ -3,11 +3,10 @@
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:ctrl="clr-namespace:Elwig.Controls"
|
||||
StartupUri="Windows\MainWindow.xaml"
|
||||
Exit="Application_Exit">
|
||||
<Application.Resources>
|
||||
<ctrl:BoolToStringConverter x:Key="BoolToStarConverter" FalseValue="" TrueValue="*"/>
|
||||
<ctrl:WidthToPaddingConverter x:Key="WidthToPaddingConverter"/>
|
||||
<ctrl:WidthToMarginConverter x:Key="WidthToMarginConverter"/>
|
||||
|
||||
<DataTemplate x:Key="PostalDestTemplate">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
@ -29,25 +28,17 @@
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
|
||||
<ControlTemplate x:Key="WineVarietyTemplateSimple">
|
||||
<DataTemplate x:Key="WineVarietyTemplateCollapsed">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding Name}"/>
|
||||
</StackPanel>
|
||||
</ControlTemplate>
|
||||
<ControlTemplate x:Key="WineVarietyTemplateExtended">
|
||||
</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 CommentFormat}" FontSize="10" VerticalAlignment="Bottom" Margin="0,0,0,2"/>
|
||||
</StackPanel>
|
||||
</ControlTemplate>
|
||||
<DataTemplate x:Key="WineVarietyTemplate">
|
||||
<Control x:Name="Control" Focusable="False" Template="{StaticResource WineVarietyTemplateExtended}"/>
|
||||
<DataTemplate.Triggers>
|
||||
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ComboBoxItem}}, Path=IsSelected}" Value="{x:Null}">
|
||||
<Setter TargetName="Control" Property="Template" Value="{StaticResource WineVarietyTemplateSimple}"/>
|
||||
</DataTrigger>
|
||||
</DataTemplate.Triggers>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="ModifierTemplate">
|
||||
@ -63,25 +54,17 @@
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
|
||||
<ControlTemplate x:Key="WineQualityLevelTemplateSimple">
|
||||
<DataTemplate x:Key="WineQualityLevelTemplateCollapsed">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding Name}"/>
|
||||
</StackPanel>
|
||||
</ControlTemplate>
|
||||
<ControlTemplate x:Key="WineQualityLevelTemplateExtended">
|
||||
</DataTemplate>
|
||||
<DataTemplate x:Key="WineQualityLevelTemplateExpanded">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding IsPredicate, Converter={StaticResource BoolToStarConverter}}" MinWidth="6"/>
|
||||
<TextBlock Text="{Binding Name}" MinWidth="100" Margin="0,0,10,0"/>
|
||||
<TextBlock Text="{Binding MinKmwStr}"/>
|
||||
</StackPanel>
|
||||
</ControlTemplate>
|
||||
<DataTemplate x:Key="WineQualityLevelTemplate">
|
||||
<Control x:Name="Control" Focusable="False" Template="{StaticResource WineQualityLevelTemplateExtended}"/>
|
||||
<DataTemplate.Triggers>
|
||||
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ComboBoxItem}}, Path=IsSelected}" Value="{x:Null}">
|
||||
<Setter TargetName="Control" Property="Template" Value="{StaticResource WineQualityLevelTemplateSimple}"/>
|
||||
</DataTrigger>
|
||||
</DataTemplate.Triggers>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="WineOriginTemplate">
|
||||
@ -90,24 +73,16 @@
|
||||
<TextBlock Text="{Binding Name}"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
<ControlTemplate x:Key="WineOriginTemplateSimple">
|
||||
<DataTemplate x:Key="WineOriginTemplateCollapsed">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding Name}"/>
|
||||
</StackPanel>
|
||||
</ControlTemplate>
|
||||
<ControlTemplate x:Key="WineOriginTemplateExtended">
|
||||
</DataTemplate>
|
||||
<DataTemplate x:Key="WineOriginTemplateExpanded">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding HkIdLevel}" MinWidth="70" Margin="0,0,10,0"/>
|
||||
<TextBlock Text="{Binding Name}"/>
|
||||
</StackPanel>
|
||||
</ControlTemplate>
|
||||
<DataTemplate x:Key="WineOriginComboTemplate">
|
||||
<Control x:Name="Control" Focusable="False" Template="{StaticResource WineOriginTemplateExtended}"/>
|
||||
<DataTemplate.Triggers>
|
||||
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ComboBoxItem}}, Path=IsSelected}" Value="{x:Null}">
|
||||
<Setter TargetName="Control" Property="Template" Value="{StaticResource WineOriginTemplateSimple}"/>
|
||||
</DataTrigger>
|
||||
</DataTemplate.Triggers>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="GemTemplate">
|
||||
|
@ -17,6 +17,7 @@ using Elwig.Dialogs;
|
||||
using System.Threading.Tasks;
|
||||
using Elwig.Helpers.Billing;
|
||||
using Elwig.Models.Entities;
|
||||
using System.Text;
|
||||
|
||||
namespace Elwig {
|
||||
public partial class App : Application {
|
||||
@ -65,7 +66,7 @@ namespace Elwig {
|
||||
private readonly DispatcherTimer ContextTimer = new() { Interval = TimeSpan.FromSeconds(2) };
|
||||
|
||||
public App() : base() {
|
||||
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
|
||||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||
Directory.CreateDirectory(TempPath);
|
||||
Directory.CreateDirectory(DataPath);
|
||||
MainDispatcher = Dispatcher;
|
||||
@ -158,7 +159,9 @@ namespace Elwig {
|
||||
list.Add(Scale.FromConfig(s));
|
||||
} catch (Exception e) {
|
||||
list.Add(new InvalidScale(s.Id));
|
||||
MessageBox.Show($"Unable to create scale {s.Id}:\n\n{e.Message}", "Scale Error", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
if (Config.Debug || s.Required)
|
||||
MessageBox.Show($"Unable to create scale {s.Id}:\n\n{e.Message}", "Scale Error",
|
||||
MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
Scales = list;
|
||||
@ -178,6 +181,9 @@ namespace Elwig {
|
||||
}
|
||||
|
||||
base.OnStartup(evt);
|
||||
|
||||
var window = new MainWindow();
|
||||
window.Show();
|
||||
}
|
||||
|
||||
private async void Application_Exit(object sender, ExitEventArgs evt) {
|
||||
@ -212,11 +218,11 @@ namespace Elwig {
|
||||
if (w is UpdateDialog) return;
|
||||
}
|
||||
if (Utils.HasInternetConnectivity()) {
|
||||
Utils.RunBackground("Auto Updater", CheckForUpdates);
|
||||
Utils.RunBackground("Auto Updater", async () => await CheckForUpdates());
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task CheckForUpdates() {
|
||||
public static async Task CheckForUpdates(bool showSuccess = false) {
|
||||
if (Config.UpdateUrl == null) return;
|
||||
var latest = await Utils.GetLatestInstallerUrl(Config.UpdateUrl);
|
||||
if (latest != null && new Version(latest.Value.Version) > new Version(Version)) {
|
||||
@ -227,6 +233,9 @@ namespace Elwig {
|
||||
Current.Shutdown();
|
||||
}
|
||||
});
|
||||
} else if (showSuccess) {
|
||||
MessageBox.Show("Elwig ist auf dem aktuellsten Stand!", "Nach Updates suchen",
|
||||
MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
}
|
||||
|
||||
@ -273,10 +282,6 @@ namespace Elwig {
|
||||
return w;
|
||||
}
|
||||
|
||||
public static SeasonFinishWindow FocusSeasonFinish() {
|
||||
return FocusWindow<SeasonFinishWindow>(() => new());
|
||||
}
|
||||
|
||||
public static OriginHierarchyWindow FocusOriginHierarchy() {
|
||||
return FocusWindow<OriginHierarchyWindow>(() => new());
|
||||
}
|
||||
@ -291,6 +296,10 @@ namespace Elwig {
|
||||
return FocusWindow<PaymentVariantsWindow>(() => new(year), w => w.Year == year);
|
||||
}
|
||||
|
||||
public static PaymentAdjustmentWindow FocusPaymentAdjustment(int year) {
|
||||
return FocusWindow<PaymentAdjustmentWindow>(() => new(year), w => w.Year == year);
|
||||
}
|
||||
|
||||
public static ChartWindow FocusChartWindow(int year, int avnr) {
|
||||
return FocusWindow<ChartWindow>(() => new(year, avnr), w => w.Year == year && w.AvNr == avnr);
|
||||
}
|
||||
|
106
Elwig/Controls/CheckComboBox.cs
Normal file
106
Elwig/Controls/CheckComboBox.cs
Normal file
@ -0,0 +1,106 @@
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Elwig.Controls {
|
||||
public class CheckComboBox : ListBox {
|
||||
|
||||
public static readonly DependencyProperty DelimiterProperty = DependencyProperty.Register("Delimiter", typeof(string), typeof(CheckComboBox), new FrameworkPropertyMetadata(", "));
|
||||
public string Delimiter {
|
||||
get => (string)GetValue(DelimiterProperty);
|
||||
set => SetValue(DelimiterProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty AllItemsSelectedContentProperty = DependencyProperty.Register("AllItemsSelectedContent", typeof(string), typeof(CheckComboBox), new FrameworkPropertyMetadata("All"));
|
||||
public string AllItemsSelectedContent {
|
||||
get => (string)GetValue(AllItemsSelectedContentProperty);
|
||||
set => SetValue(AllItemsSelectedContentProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsSelectAllActiveProperty = DependencyProperty.Register("IsSelectAllActive", typeof(bool), typeof(CheckComboBox), new FrameworkPropertyMetadata(false));
|
||||
public bool IsSelectAllActive {
|
||||
get => (bool)GetValue(IsSelectAllActiveProperty);
|
||||
set => SetValue(IsSelectAllActiveProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SelectAllContentProperty = DependencyProperty.Register("SelectAllContent", typeof(string), typeof(CheckComboBox), new FrameworkPropertyMetadata("All"));
|
||||
public string SelectAllContent {
|
||||
get => (string)GetValue(SelectAllContentProperty);
|
||||
set => SetValue(SelectAllContentProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty AllItemsSelectedProperty = DependencyProperty.Register("AllItemsSelected", typeof(bool?), typeof(CheckComboBox), new FrameworkPropertyMetadata(false));
|
||||
public bool? AllItemsSelected {
|
||||
get => (bool?)GetValue(AllItemsSelectedProperty);
|
||||
set => SetValue(AllItemsSelectedProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsDropDownOpenProperty = DependencyProperty.Register("IsDropDownOpen", typeof(bool), typeof(CheckComboBox), new FrameworkPropertyMetadata(false));
|
||||
public bool IsDropDownOpen {
|
||||
get => (bool)GetValue(IsDropDownOpenProperty);
|
||||
set => SetValue(IsDropDownOpenProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty MaxDropDownHeightProperty = DependencyProperty.Register("MaxDropDownHeight", typeof(double), typeof(CheckComboBox), new FrameworkPropertyMetadata(ComboBox.MaxDropDownHeightProperty.DefaultMetadata.DefaultValue));
|
||||
public double MaxDropDownHeight {
|
||||
get => (double)GetValue(MaxDropDownHeightProperty);
|
||||
set => SetValue(MaxDropDownHeightProperty, value);
|
||||
}
|
||||
|
||||
static CheckComboBox() {
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(CheckComboBox), new FrameworkPropertyMetadata(typeof(CheckComboBox)));
|
||||
}
|
||||
|
||||
private TextBlock TextBox;
|
||||
|
||||
public CheckComboBox() {
|
||||
SelectionMode = SelectionMode.Multiple;
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate() {
|
||||
TextBox = (GetTemplateChild("TextBox") as TextBlock)!;
|
||||
var button = GetTemplateChild("Button") as Button;
|
||||
button!.Click += Button_MouseDown;
|
||||
var item = GetTemplateChild("SelectAllItem") as ListBoxItem;
|
||||
item!.PreviewMouseDown += SelectAllItem_MouseDown;
|
||||
SelectionChanged += OnSelectionChanged;
|
||||
IsEnabledChanged += OnIsEnabledChanged;
|
||||
base.OnApplyTemplate();
|
||||
}
|
||||
|
||||
private void Button_MouseDown(object sender, RoutedEventArgs evt) {
|
||||
IsDropDownOpen = !IsDropDownOpen;
|
||||
}
|
||||
|
||||
private void SelectAllItem_MouseDown(object sender, RoutedEventArgs evt) {
|
||||
if (AllItemsSelected == false) {
|
||||
SelectAll();
|
||||
} else {
|
||||
UnselectAll();
|
||||
}
|
||||
evt.Handled = true;
|
||||
}
|
||||
|
||||
private void OnSelectionChanged(object sender, SelectionChangedEventArgs evt) {
|
||||
var dmp = DisplayMemberPath != null && DisplayMemberPath != "" ? DisplayMemberPath : null;
|
||||
if (SelectedItems.Count == ItemsSource.Cast<object>().Count() && AllItemsSelectedContent != null) {
|
||||
TextBox.Text = AllItemsSelectedContent;
|
||||
AllItemsSelected = true;
|
||||
} else if (SelectedItems.Count == 0) {
|
||||
TextBox.Text = "";
|
||||
AllItemsSelected = false;
|
||||
} else {
|
||||
TextBox.Text = string.Join(Delimiter,
|
||||
dmp == null ? SelectedItems.Cast<object>() :
|
||||
SelectedItems.Cast<object>()
|
||||
.Select(i => i.GetType().GetProperty(dmp)?.GetValue(i))
|
||||
);
|
||||
AllItemsSelected = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnIsEnabledChanged(object sender, DependencyPropertyChangedEventArgs evt) {
|
||||
if (!IsEnabled) IsDropDownOpen = false;
|
||||
}
|
||||
}
|
||||
}
|
118
Elwig/Controls/CheckComboBox.xaml
Normal file
118
Elwig/Controls/CheckComboBox.xaml
Normal file
@ -0,0 +1,118 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:ctrl="clr-namespace:Elwig.Controls">
|
||||
<ctrl:VisibilityConverter x:Key="VisibilityConverter"/>
|
||||
<Style TargetType="ctrl:CheckComboBox" BasedOn="{StaticResource {x:Type ListBox}}">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="ctrl:CheckComboBox">
|
||||
<Grid Style="{x:Null}">
|
||||
<Button x:Name="Button" ClickMode="Press" BorderThickness="1"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
IsEnabled="{Binding IsEnabled, RelativeSource={RelativeSource TemplatedParent}}">
|
||||
<Button.Style>
|
||||
<Style TargetType="{x:Type Button}">
|
||||
<Setter Property="Background" Value="White"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type Button}">
|
||||
<Border Background="{TemplateBinding Background}" SnapsToDevicePixels="True"
|
||||
BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="1">
|
||||
<ContentPresenter HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</Button.Style>
|
||||
<Path x:Name="IconDropdown" Data="M 0,0 L 3,3 L 6,0" Stroke="#FF606060" StrokeThickness="1" Margin="0,0,5,0"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Center"/>
|
||||
</Button>
|
||||
<TextBlock x:Name="TextBox" Style="{x:Null}" Margin="6,0,18,0" IsHitTestVisible="False"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Center"/>
|
||||
<Popup x:Name="Popup" Placement="Bottom" Focusable="True"
|
||||
IsOpen="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
|
||||
PopupAnimation="Slide" AllowsTransparency="True">
|
||||
<Popup.Style>
|
||||
<Style TargetType="{x:Type Popup}">
|
||||
<Setter Property="StaysOpen" Value="False"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsMouseOver, ElementName=Button}" Value="True">
|
||||
<Setter Property="StaysOpen" Value="True"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding IsMouseOver, ElementName=Border}" Value="True">
|
||||
<Setter Property="StaysOpen" Value="True"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Popup.Style>
|
||||
<Border x:Name="Border" Style="{x:Null}" BorderThickness="1" BorderBrush="Gray" Background="White" SnapsToDevicePixels="True"
|
||||
MinWidth="{TemplateBinding ActualWidth}"
|
||||
MaxHeight="{TemplateBinding MaxDropDownHeight}">
|
||||
<DockPanel>
|
||||
<ListBoxItem x:Name="SelectAllItem" Padding="2,1,2,1" DockPanel.Dock="Top"
|
||||
Visibility="{TemplateBinding IsSelectAllActive, Converter={StaticResource VisibilityConverter}}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<CheckBox VerticalAlignment="Center" Margin="0,0,5,0" IsThreeState="True"
|
||||
IsChecked="{Binding AllItemsSelected, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"/>
|
||||
<TextBlock Text="{TemplateBinding SelectAllContent}" VerticalAlignment="Center" Margin="0" SnapsToDevicePixels="True"/>
|
||||
</StackPanel>
|
||||
</ListBoxItem>
|
||||
<ScrollViewer Style="{x:Null}">
|
||||
<StackPanel Style="{x:Null}" IsItemsHost="True" SnapsToDevicePixels="True"
|
||||
KeyboardNavigation.DirectionalNavigation="Contained"/>
|
||||
</ScrollViewer>
|
||||
</DockPanel>
|
||||
</Border>
|
||||
</Popup>
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter TargetName="IconDropdown" Property="Stroke" Value="#FFA0A0A0"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="IconDropdown" Property="Stroke" Value="Black"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="ItemContainerStyle">
|
||||
<Setter.Value>
|
||||
<Style TargetType="ListBoxItem">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="ListBoxItem">
|
||||
<Border BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
Background="{TemplateBinding Background}"
|
||||
Padding="2,1,2,1">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<CheckBox VerticalAlignment="Center" Margin="0,0,5,0"
|
||||
IsChecked="{Binding IsSelected, Mode=TwoWay, RelativeSource={RelativeSource AncestorType=ListBoxItem}}"/>
|
||||
<ContentPresenter VerticalAlignment="Center" Margin="0" SnapsToDevicePixels="True"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="BorderBrush" Value="#FF70C0E7"/>
|
||||
<Setter Property="Background" Value="#FFE5F3FB"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Foreground" Value="Gray"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="BorderBrush" Value="#FF7EB4EA"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
106
Elwig/Controls/IntegerUpDown.cs
Normal file
106
Elwig/Controls/IntegerUpDown.cs
Normal file
@ -0,0 +1,106 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace Elwig.Controls {
|
||||
public class IntegerUpDown : TextBox {
|
||||
|
||||
public static readonly DependencyProperty MinimumProperty = DependencyProperty.Register("Miminum", typeof(int?), typeof(IntegerUpDown), new FrameworkPropertyMetadata(null));
|
||||
public int? Minimum {
|
||||
get => (int?)GetValue(MinimumProperty);
|
||||
set => SetValue(MinimumProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty MaximumProperty = DependencyProperty.Register("Maximum", typeof(int?), typeof(IntegerUpDown), new FrameworkPropertyMetadata(null));
|
||||
public int? Maximum {
|
||||
get => (int?)GetValue(MaximumProperty);
|
||||
set => SetValue(MaximumProperty, value);
|
||||
}
|
||||
|
||||
public int? Value {
|
||||
get => int.TryParse(Text, out var res) ? res : null;
|
||||
set => Text = $"{value}";
|
||||
}
|
||||
|
||||
static IntegerUpDown() {
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(IntegerUpDown), new FrameworkPropertyMetadata(typeof(IntegerUpDown)));
|
||||
}
|
||||
|
||||
public IntegerUpDown() {
|
||||
TextChanged += IntegerUpDown_TextChanged;
|
||||
LostFocus += IntegerUpDown_LostFocus;
|
||||
KeyUp += IntegerUpDown_KeyUp;
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate() {
|
||||
var incButton = GetTemplateChild("IncrementButton") as RepeatButton;
|
||||
var decButton = GetTemplateChild("DecrementButton") as RepeatButton;
|
||||
incButton!.Click += IncrementButton_Click;
|
||||
decButton!.Click += DecrementButton_Click;
|
||||
base.OnApplyTemplate();
|
||||
}
|
||||
|
||||
private void IntegerUpDown_TextChanged(object sender, TextChangedEventArgs evt) {
|
||||
var idx = CaretIndex;
|
||||
Text = new string(Text.Where(char.IsAsciiDigit).Take(4).ToArray());
|
||||
CaretIndex = idx;
|
||||
evt.Handled = !(Value >= Minimum && Value <= Maximum);
|
||||
if (idx >= 4) {
|
||||
if (Value < Minimum) {
|
||||
Value = Minimum;
|
||||
} else if (Value > Maximum) {
|
||||
Value = Maximum;
|
||||
}
|
||||
CaretIndex = 4;
|
||||
}
|
||||
}
|
||||
|
||||
private void IntegerUpDown_LostFocus(object sender, RoutedEventArgs evt) {
|
||||
if (Value < Minimum) {
|
||||
Value = Minimum;
|
||||
} else if (Value > Maximum) {
|
||||
Value = Maximum;
|
||||
}
|
||||
}
|
||||
|
||||
private void IncrementButton_Click(object sender, RoutedEventArgs evt) {
|
||||
Value = Math.Min((Value ?? 0) + 1, Maximum ?? int.MaxValue);
|
||||
}
|
||||
|
||||
private void DecrementButton_Click(object sender, RoutedEventArgs evt) {
|
||||
Value = Math.Max((Value ?? 0) - 1, Minimum ?? int.MinValue);
|
||||
}
|
||||
|
||||
private void IntegerUpDown_KeyUp(object sender, KeyEventArgs evt) {
|
||||
switch (evt.Key) {
|
||||
case Key.Up:
|
||||
case Key.Add:
|
||||
case Key.OemPlus:
|
||||
Value = Math.Min((Value ?? 0) + 1, Maximum ?? int.MaxValue);
|
||||
evt.Handled = true;
|
||||
CaretIndex = 4;
|
||||
break;
|
||||
case Key.Down:
|
||||
case Key.Subtract:
|
||||
case Key.OemMinus:
|
||||
Value = Math.Max((Value ?? 0) - 1, Minimum ?? int.MinValue);
|
||||
evt.Handled = true;
|
||||
CaretIndex = 4;
|
||||
break;
|
||||
case Key.PageUp:
|
||||
Value = Math.Min((Value ?? 0) + 10, Maximum ?? int.MaxValue);
|
||||
evt.Handled = true;
|
||||
CaretIndex = 4;
|
||||
break;
|
||||
case Key.PageDown:
|
||||
Value = Math.Max((Value ?? 0) - 10, Minimum ?? int.MinValue);
|
||||
evt.Handled = true;
|
||||
CaretIndex = 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
52
Elwig/Controls/IntegerUpDown.xaml
Normal file
52
Elwig/Controls/IntegerUpDown.xaml
Normal file
@ -0,0 +1,52 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:ctrl="clr-namespace:Elwig.Controls">
|
||||
<Style TargetType="ctrl:IntegerUpDown" BasedOn="{StaticResource {x:Type TextBox}}">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="ctrl:IntegerUpDown">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="18"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Border x:Name="Border" BorderThickness="1,1,0,1"
|
||||
BorderBrush="{Binding Path=BorderBrush, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
|
||||
SnapsToDevicePixels="True" Grid.RowSpan="2">
|
||||
<ScrollViewer x:Name="PART_ContentHost" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
|
||||
<RepeatButton x:Name="IncrementButton" Padding="0" Height="Auto" Width="Auto" BorderThickness="1,1,1,1"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Row="0" Grid.Column="1">
|
||||
<Path x:Name="IconIncrement" Data="M 0,4 L 4,0 L 8,4 Z" Fill="#FF444444"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</RepeatButton>
|
||||
<RepeatButton x:Name="DecrementButton" Padding="0" Height="Auto" Width="Auto" BorderThickness="1,0,1,1"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Row="1" Grid.Column="1">
|
||||
<Path x:Name="IconDecrement" Data="M 0,0 L 4,4 L 8,0 Z" Fill="#FF444444"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</RepeatButton>
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter TargetName="Border" Property="BorderBrush" Value="LightGray"/>
|
||||
<Setter TargetName="IconIncrement" Property="Fill" Value="#FF888888"/>
|
||||
<Setter TargetName="IconDecrement" Property="Fill" Value="#FF888888"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="TextAlignment" Value="Right"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Foreground" Value="Gray"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
17
Elwig/Controls/UnitTextBox.cs
Normal file
17
Elwig/Controls/UnitTextBox.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Elwig.Controls {
|
||||
public class UnitTextBox : TextBox {
|
||||
|
||||
public static readonly DependencyProperty UnitProperty = DependencyProperty.Register("Unit", typeof(string), typeof(UnitTextBox), new FrameworkPropertyMetadata(""));
|
||||
public string Unit {
|
||||
get => (string)GetValue(UnitProperty);
|
||||
set => SetValue(UnitProperty, value);
|
||||
}
|
||||
|
||||
static UnitTextBox() {
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(UnitTextBox), new FrameworkPropertyMetadata(typeof(UnitTextBox)));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +1,41 @@
|
||||
<UserControl x:Class="Elwig.Controls.UnitTextBox"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Grid VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Height="25">
|
||||
<TextBox x:Name="TextBox" TextAlignment="Right" FontSize="14" VerticalAlignment="Stretch"
|
||||
Padding="{Binding ElementName=UnitBlock, Path=ActualWidth, Converter={StaticResource WidthToPaddingConverter}}"
|
||||
Text="{Binding Path=Text}" TextChanged="TextBox_TextChanged"/>
|
||||
<TextBlock x:Name="UnitBlock" Text="{Binding Path=Unit}" Margin="0,0,4,4" FontSize="10"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Bottom"/>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:ctrl="clr-namespace:Elwig.Controls">
|
||||
<Style TargetType="ctrl:UnitTextBox" BasedOn="{StaticResource {x:Type TextBox}}">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="ctrl:UnitTextBox">
|
||||
<Border x:Name="Border"
|
||||
BorderThickness="{Binding Path=BorderThickness, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
|
||||
BorderBrush="{Binding Path=BorderBrush, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
|
||||
SnapsToDevicePixels="True">
|
||||
<Grid>
|
||||
<ScrollViewer x:Name="PART_ContentHost" VerticalAlignment="Bottom">
|
||||
<ScrollViewer.Margin>
|
||||
<Binding ElementName="UnitBlock" Path="ActualWidth">
|
||||
<Binding.Converter>
|
||||
<ctrl:WidthToMarginConverter/>
|
||||
</Binding.Converter>
|
||||
</Binding>
|
||||
</ScrollViewer.Margin>
|
||||
</ScrollViewer>
|
||||
<TextBlock x:Name="UnitBlock" Text="{Binding Path=Unit, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
|
||||
FontSize="10" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="3"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter TargetName="Border" Property="BorderBrush" Value="LightGray"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="TextAlignment" Value="Right"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Foreground" Value="Gray"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
|
@ -1,37 +0,0 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Elwig.Controls {
|
||||
public partial class UnitTextBox : UserControl {
|
||||
|
||||
public event TextChangedEventHandler? TextChanged;
|
||||
|
||||
public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(UnitTextBox));
|
||||
public string Text {
|
||||
get => (string)GetValue(TextProperty);
|
||||
set => SetValue(TextProperty, value ?? "");
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty UnitProperty = DependencyProperty.Register("Unit", typeof(string), typeof(UnitTextBox));
|
||||
public string Unit {
|
||||
get => (string)GetValue(UnitProperty);
|
||||
set => SetValue(UnitProperty, value ?? "");
|
||||
}
|
||||
|
||||
public UnitTextBox() {
|
||||
Text = "";
|
||||
Unit = "";
|
||||
InitializeComponent();
|
||||
DataContext = this;
|
||||
}
|
||||
|
||||
private void TextBox_TextChanged(object sender, TextChangedEventArgs evt) {
|
||||
Text = TextBox.Text;
|
||||
TextChanged?.Invoke(sender, evt);
|
||||
}
|
||||
|
||||
public new void Focus() {
|
||||
TextBox.Focus();
|
||||
}
|
||||
}
|
||||
}
|
16
Elwig/Controls/VisibilityConverter.cs
Normal file
16
Elwig/Controls/VisibilityConverter.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Elwig.Controls {
|
||||
public class VisibilityConverter : IValueConverter {
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
|
||||
return (bool)value ? Visibility.Visible : Visibility.Collapsed;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
|
||||
return (Visibility)value == Visibility.Visible;
|
||||
}
|
||||
}
|
||||
}
|
@ -4,13 +4,13 @@ using System.Windows.Data;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Elwig.Controls {
|
||||
public class WidthToPaddingConverter : IValueConverter {
|
||||
public class WidthToMarginConverter : IValueConverter {
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
|
||||
return new Thickness(2, 2, 4 + (double)value, 2);
|
||||
return new Thickness(0, 0, 2 + (double)value, 0);
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
|
||||
return ((Thickness)value).Right - 4;
|
||||
return ((Thickness)value).Right - 2;
|
||||
}
|
||||
}
|
||||
}
|
15
Elwig/Controls/WineOriginTemplateSelector.cs
Normal file
15
Elwig/Controls/WineOriginTemplateSelector.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using System.Windows.Controls;
|
||||
using System.Windows;
|
||||
|
||||
namespace Elwig.Controls {
|
||||
public class WineOriginTemplateSelector : DataTemplateSelector {
|
||||
public override DataTemplate SelectTemplate(object item, DependencyObject container) {
|
||||
ContentPresenter presenter = (ContentPresenter)container;
|
||||
if (presenter.TemplatedParent is ComboBox) {
|
||||
return (DataTemplate)presenter.FindResource("WineOriginTemplateCollapsed");
|
||||
} else {
|
||||
return (DataTemplate)presenter.FindResource("WineOriginTemplateExpanded");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
15
Elwig/Controls/WineQualityLevelTemplateSelector.cs
Normal file
15
Elwig/Controls/WineQualityLevelTemplateSelector.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using System.Windows.Controls;
|
||||
using System.Windows;
|
||||
|
||||
namespace Elwig.Controls {
|
||||
public class WineQualityLevelTemplateSelector : DataTemplateSelector {
|
||||
public override DataTemplate SelectTemplate(object item, DependencyObject container) {
|
||||
ContentPresenter presenter = (ContentPresenter)container;
|
||||
if (presenter.TemplatedParent is ComboBox) {
|
||||
return (DataTemplate)presenter.FindResource("WineQualityLevelTemplateCollapsed");
|
||||
} else {
|
||||
return (DataTemplate)presenter.FindResource("WineQualityLevelTemplateExpanded");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
15
Elwig/Controls/WineVarietyTemplateSelector.cs
Normal file
15
Elwig/Controls/WineVarietyTemplateSelector.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using System.Windows.Controls;
|
||||
using System.Windows;
|
||||
|
||||
namespace Elwig.Controls {
|
||||
public class WineVarietyTemplateSelector : DataTemplateSelector {
|
||||
public override DataTemplate SelectTemplate(object item, DependencyObject container) {
|
||||
ContentPresenter presenter = (ContentPresenter)container;
|
||||
if (presenter.TemplatedParent is ComboBox) {
|
||||
return (DataTemplate)presenter.FindResource("WineVarietyTemplateCollapsed");
|
||||
} else {
|
||||
return (DataTemplate)presenter.FindResource("WineVarietyTemplateExpanded");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -4,10 +4,7 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:Elwig.Dialogs"
|
||||
mc:Ignorable="d"
|
||||
ResizeMode="NoResize"
|
||||
ShowInTaskbar="False"
|
||||
Topmost="True"
|
||||
ResizeMode="NoResize" ShowInTaskbar="False" Topmost="True"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
FocusManager.FocusedElement="{Binding ElementName=WeightInput}"
|
||||
Title="Teillieferung abwerten" Height="190" Width="400">
|
||||
|
74
Elwig/Dialogs/AreaComDialog.xaml
Normal file
74
Elwig/Dialogs/AreaComDialog.xaml
Normal file
@ -0,0 +1,74 @@
|
||||
<Window x:Class="Elwig.Dialogs.AreaComDialog"
|
||||
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 übertragen" Height="230" 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">
|
||||
Sollen die aktiven Flächenbindungen des angegebenen Vorgängers<LineBreak/>
|
||||
übernommen werden? (<Run Text="{Binding AreaComNum}"/> FB, <Run Text="{Binding Area}"/> m²)
|
||||
</TextBlock>
|
||||
<TextBlock x:Name="QuestionBlock2" TextAlignment="Center" Margin="0,10,0,0" Visibility="Hidden"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Top">
|
||||
Sollen die aktiven Flächenbindungen gekündigt werden? (<Run Text="{Binding AreaComNum}"/> FB, <Run Text="{Binding Area}"/> m²)
|
||||
</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"/>
|
||||
|
||||
<TextBlock x:Name="DescBlock1" Margin="0,85,0,0" TextAlignment="Center"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Top">
|
||||
Die Flächenbindungen beim <Bold>Vorgänger</Bold> sind bis inkl. Saison <Bold><Run x:Name="CancelSeason1"/></Bold> gültig,<LineBreak/>
|
||||
und werden beim <Bold>Nachfolger</Bold> ab inkl. Saison <Bold><Run x:Name="TransferSeason"/></Bold> übernommen.
|
||||
</TextBlock>
|
||||
<TextBlock x:Name="DescBlock2" Margin="0,70,0,0" TextAlignment="Center" Visibility="Hidden"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Top">
|
||||
Die Flächenbindungen sind bis inklusive Saison <Bold><Run x:Name="CancelSeason2"/></Bold> gültig.
|
||||
</TextBlock>
|
||||
|
||||
<TextBlock x:Name="InfoBlock" Margin="0,0,0,75" TextAlignment="Center"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Bottom">
|
||||
Falls die Flächenbindungen später an ein neues Mitglied<LineBreak/>
|
||||
übertragen werden sollen bitte <Italic>Nein</Italic> auswählen!
|
||||
</TextBlock>
|
||||
<TextBlock Text="Die Änderungen werden erst beim Speichern übernommen!"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="0,0,0,50"/>
|
||||
|
||||
<Button x:Name="ConfirmButton" Content="Ja" Margin="10,10,115,10" Grid.Column="1"
|
||||
Click="ConfirmButton_Click"/>
|
||||
<Button x:Name="CancelButton" Content="Nein" Margin="10,10,10,10" Grid.Column="1" IsCancel="True"/>
|
||||
</Grid>
|
||||
</Window>
|
52
Elwig/Dialogs/AreaComDialog.xaml.cs
Normal file
52
Elwig/Dialogs/AreaComDialog.xaml.cs
Normal file
@ -0,0 +1,52 @@
|
||||
using Elwig.Helpers;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Elwig.Dialogs {
|
||||
public partial class AreaComDialog : Window {
|
||||
|
||||
public int CancelSeason { get; set; }
|
||||
public int SuccessorSeason => CancelSeason + 1;
|
||||
|
||||
public string AreaComNum { get; set; }
|
||||
public string Area { get; set; }
|
||||
|
||||
public AreaComDialog(string name, int areaComNum, int area) {
|
||||
CancelSeason = Utils.FollowingSeason - 1;
|
||||
AreaComNum = $"{areaComNum:N0}";
|
||||
Area = $"{area:N0}";
|
||||
InitializeComponent();
|
||||
SeasonInput.Text = $"{CancelSeason}";
|
||||
Title = $"Aktive Flächenbindungen kündigen - {name}";
|
||||
QuestionBlock1.Visibility = Visibility.Hidden;
|
||||
QuestionBlock2.Visibility = Visibility.Visible;
|
||||
DescBlock1.Visibility = Visibility.Hidden;
|
||||
DescBlock2.Visibility = Visibility.Visible;
|
||||
Height = 240;
|
||||
SeasonInput.Margin = new(0, 40, 0, 0);
|
||||
SeasonLabel.Margin = new(0, 40, 100, 0);
|
||||
}
|
||||
|
||||
public AreaComDialog(string name, string successorName, int areaComNum, int area) {
|
||||
CancelSeason = Utils.FollowingSeason - 1;
|
||||
AreaComNum = $"{areaComNum:N0}";
|
||||
Area = $"{area:N0}";
|
||||
InitializeComponent();
|
||||
SeasonInput.Text = $"{CancelSeason}";
|
||||
Title = $"Aktive Flächenbindungen übertragen - {name} - {successorName}";
|
||||
InfoBlock.Visibility = Visibility.Hidden;
|
||||
}
|
||||
|
||||
private void SeasonInput_TextChanged(object sender, TextChangedEventArgs evt) {
|
||||
CancelSeason = (int)SeasonInput.Value!;
|
||||
CancelSeason1.Text = $"{CancelSeason}";
|
||||
CancelSeason2.Text = $"{CancelSeason}";
|
||||
TransferSeason.Text = $"{SuccessorSeason}";
|
||||
}
|
||||
|
||||
private void ConfirmButton_Click(object sender, RoutedEventArgs evt) {
|
||||
DialogResult = true;
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
63
Elwig/Dialogs/DeleteMemberDialog.xaml
Normal file
63
Elwig/Dialogs/DeleteMemberDialog.xaml
Normal file
@ -0,0 +1,63 @@
|
||||
<Window x:Class="Elwig.Dialogs.DeleteMemberDialog"
|
||||
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"
|
||||
ResizeMode="NoResize" ShowInTaskbar="False" Topmost="True"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
DataContext="{Binding RelativeSource={RelativeSource Self}}"
|
||||
Title="Mitglied löschen" Height="280" Width="400">
|
||||
<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="CheckBox">
|
||||
<Setter Property="HorizontalAlignment" Value="Left"/>
|
||||
<Setter Property="VerticalAlignment" Value="Top"/>
|
||||
</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 TextAlignment="Center" Margin="10,10,10,10" VerticalAlignment="Top">
|
||||
Bei Bestätigung wird das Mitglied samt zugehöriger Daten<LineBreak/>
|
||||
<Bold>unwiderruflich gelöscht!</Bold> Wenn möglich sollte stattdessen<LineBreak/>
|
||||
der Status des Mitglieds auf <Italic>Inaktiv</Italic> gesetzt werden!
|
||||
</TextBlock>
|
||||
|
||||
<Label Content="Name u. MgNr. wiederholen:" Margin="10,60,10,10" HorizontalAlignment="Center"/>
|
||||
<TextBox x:Name="NameInput" Margin="10,85,10,10"
|
||||
TextChanged="NameInput_TextChanged"/>
|
||||
|
||||
<Label Content="Beim Löschen müssen folgende Daten auch gelöscht werden:" Margin="10,120,10,10"/>
|
||||
<CheckBox x:Name="AreaComInput" Content="Flächenbindungen" Margin="40,145,0,0"
|
||||
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"
|
||||
IsChecked="{Binding DeleteAreaComs}"/>
|
||||
<CheckBox x:Name="DeliveryInput" Content="Lieferungen" Margin="40,165,0,0"
|
||||
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"
|
||||
IsChecked="{Binding DeleteDeliveries}"/>
|
||||
<CheckBox x:Name="PaymentInput" Content="Auszahlungsdaten" Margin="40,185,0,0"
|
||||
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"
|
||||
IsChecked="{Binding DeletePaymentData}"/>
|
||||
|
||||
<Button x:Name="ConfirmButton" Content="Bestätigen" Margin="10,10,115,10" Grid.Column="1" IsEnabled="False"
|
||||
Click="ConfirmButton_Click"/>
|
||||
<Button x:Name="CancelButton" Content="Abbrechen" Margin="10,10,10,10" Grid.Column="1" IsCancel="True"/>
|
||||
</Grid>
|
||||
</Window>
|
66
Elwig/Dialogs/DeleteMemberDialog.xaml.cs
Normal file
66
Elwig/Dialogs/DeleteMemberDialog.xaml.cs
Normal file
@ -0,0 +1,66 @@
|
||||
using Elwig.Helpers;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Elwig.Dialogs {
|
||||
public partial class DeleteMemberDialog : Window {
|
||||
|
||||
protected string[] NameParts;
|
||||
|
||||
public bool DeleteAreaComs { get; set; }
|
||||
public bool DeleteDeliveries { get; set; }
|
||||
public bool DeletePaymentData { get; set; }
|
||||
|
||||
public DeleteMemberDialog(int mgnr, string name, int numAreaComs, int numDeliveries, int numCredits) {
|
||||
NameParts = name.ToLower().Split(' ').Where(p => p.Length > 0).Append($"{mgnr}").ToArray();
|
||||
InitializeComponent();
|
||||
Title += " - " + name;
|
||||
AreaComInput.IsEnabled = numAreaComs != 0;
|
||||
AreaComInput.Content += $" ({numAreaComs:N0})";
|
||||
DeliveryInput.IsEnabled = numDeliveries != 0;
|
||||
DeliveryInput.Content += $" ({numDeliveries:N0})";
|
||||
PaymentInput.IsEnabled = numCredits != 0;
|
||||
PaymentInput.Content += $" ({numCredits:N0})";
|
||||
}
|
||||
|
||||
private void NameInput_TextChanged(object sender, TextChangedEventArgs evt) {
|
||||
Update();
|
||||
}
|
||||
|
||||
private void CheckBox_Changed(object sender, RoutedEventArgs evt) {
|
||||
Update();
|
||||
}
|
||||
|
||||
private static void UpdateCheckBox(CheckBox cb) {
|
||||
if (cb.IsEnabled && cb.IsChecked != true) {
|
||||
ControlUtils.SetInputInvalid(cb);
|
||||
} else {
|
||||
ControlUtils.ClearInputState(cb);
|
||||
}
|
||||
}
|
||||
|
||||
private void Update() {
|
||||
var t = NameInput.Text.ToLower().Split(' ');
|
||||
var nameValid = NameParts.All(t.Contains);
|
||||
UpdateCheckBox(AreaComInput);
|
||||
UpdateCheckBox(DeliveryInput);
|
||||
UpdateCheckBox(PaymentInput);
|
||||
if (!nameValid) {
|
||||
ControlUtils.SetInputInvalid(NameInput);
|
||||
} else {
|
||||
ControlUtils.ClearInputState(NameInput);
|
||||
}
|
||||
ConfirmButton.IsEnabled =
|
||||
(!AreaComInput.IsEnabled || DeleteAreaComs) &&
|
||||
(!DeliveryInput.IsEnabled || DeleteDeliveries) &&
|
||||
(!PaymentInput.IsEnabled || DeletePaymentData) &&
|
||||
nameValid;
|
||||
}
|
||||
|
||||
private void ConfirmButton_Click(object sender, RoutedEventArgs evt) {
|
||||
DialogResult = true;
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
@ -4,10 +4,7 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:Elwig.Dialogs"
|
||||
mc:Ignorable="d"
|
||||
ResizeMode="NoResize"
|
||||
ShowInTaskbar="False"
|
||||
Topmost="True"
|
||||
ResizeMode="NoResize" ShowInTaskbar="False" Topmost="True"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
FocusManager.FocusedElement="{Binding ElementName=WeightInput}"
|
||||
Title="Teillieferung extrahieren" Height="210" Width="380">
|
||||
|
@ -4,10 +4,7 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:Elwig.Dialogs"
|
||||
mc:Ignorable="d"
|
||||
ResizeMode="NoResize"
|
||||
ShowInTaskbar="False"
|
||||
Topmost="True"
|
||||
ResizeMode="NoResize" ShowInTaskbar="False" Topmost="True"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
FocusManager.FocusedElement="{Binding ElementName=PriceInput}"
|
||||
Title="Linear wachsen" Height="140" Width="270">
|
||||
|
@ -4,10 +4,7 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:Elwig.Dialogs"
|
||||
mc:Ignorable="d"
|
||||
ResizeMode="NoResize"
|
||||
ShowInTaskbar="False"
|
||||
Topmost="True"
|
||||
ResizeMode="NoResize" ShowInTaskbar="False" Topmost="True"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
FocusManager.FocusedElement="{Binding ElementName=WeightInput}"
|
||||
Title="Handwiegung" Height="170" Width="400">
|
||||
|
68
Elwig/Dialogs/NewSeasonDialog.xaml
Normal file
68
Elwig/Dialogs/NewSeasonDialog.xaml
Normal file
@ -0,0 +1,68 @@
|
||||
<Window x:Class="Elwig.Dialogs.NewSeasonDialog"
|
||||
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"
|
||||
ResizeMode="NoResize" ShowInTaskbar="False" Topmost="True"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
DataContext="{Binding RelativeSource={RelativeSource Self}}"
|
||||
Title="Saison anlegen" Height="180" Width="400">
|
||||
<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="ComboBox">
|
||||
<Setter Property="HorizontalAlignment" Value="Left"/>
|
||||
<Setter Property="VerticalAlignment" Value="Top"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="Height" Value="25"/>
|
||||
</Style>
|
||||
<Style TargetType="CheckBox">
|
||||
<Setter Property="HorizontalAlignment" Value="Left"/>
|
||||
<Setter Property="VerticalAlignment" Value="Top"/>
|
||||
</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>
|
||||
<Label Content="Währung:" Margin="10,10,10,10"/>
|
||||
<ComboBox x:Name="CurrencyInput" Width="150" Margin="130,10,10,10"
|
||||
ItemsSource="{Binding Currencies}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding Code}" Width="30"/>
|
||||
<TextBlock Text="- "/>
|
||||
<TextBlock Text="{Binding Name}"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
|
||||
<Label Content="Nachkommastellen:" Margin="10,40,10,10"/>
|
||||
<ComboBox x:Name="PrecisionInput" Width="50" Margin="130,40,10,10">
|
||||
<ComboBoxItem>2</ComboBoxItem>
|
||||
<ComboBoxItem>3</ComboBoxItem>
|
||||
<ComboBoxItem IsSelected="True">4</ComboBoxItem>
|
||||
<ComboBoxItem>5</ComboBoxItem>
|
||||
<ComboBoxItem>6</ComboBoxItem>
|
||||
<ComboBoxItem>7</ComboBoxItem>
|
||||
<ComboBoxItem>8</ComboBoxItem>
|
||||
</ComboBox>
|
||||
|
||||
<CheckBox x:Name="CopyModifiersInput" Content="Zu-/Abschläge der letzten Saison übernehmen"
|
||||
Margin="15,75,10,10" IsChecked="{Binding CopyModifiers}"/>
|
||||
|
||||
<Button x:Name="ConfirmButton" Content="Bestätigen" Margin="10,10,115,10" Grid.Column="1" IsDefault="True"
|
||||
Click="ConfirmButton_Click"/>
|
||||
<Button x:Name="CancelButton" Content="Abbrechen" Margin="10,10,10,10" Grid.Column="1" IsCancel="True"/>
|
||||
</Grid>
|
||||
</Window>
|
30
Elwig/Dialogs/NewSeasonDialog.xaml.cs
Normal file
30
Elwig/Dialogs/NewSeasonDialog.xaml.cs
Normal file
@ -0,0 +1,30 @@
|
||||
using Elwig.Helpers;
|
||||
using Elwig.Models.Entities;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows;
|
||||
|
||||
namespace Elwig.Dialogs {
|
||||
public partial class NewSeasonDialog : Window {
|
||||
|
||||
public IEnumerable<Currency> Currencies { get; set; }
|
||||
public int Year { get; set; }
|
||||
|
||||
public string CurrencyCode => (CurrencyInput.SelectedItem as Currency)!.Code;
|
||||
public byte Precision => (byte)(PrecisionInput.SelectedIndex + 2);
|
||||
public bool CopyModifiers { get; set; }
|
||||
|
||||
public NewSeasonDialog(Season? s, IEnumerable<Currency> currencies) {
|
||||
Currencies = currencies;
|
||||
CopyModifiers = s != null;
|
||||
InitializeComponent();
|
||||
CopyModifiersInput.IsEnabled = s != null;
|
||||
ControlUtils.SelectItemWithPk(CurrencyInput, s?.CurrencyCode ?? "EUR");
|
||||
PrecisionInput.SelectedIndex = (s?.Precision ?? 4) - 2;
|
||||
}
|
||||
|
||||
private void ConfirmButton_Click(object sender, RoutedEventArgs evt) {
|
||||
DialogResult = true;
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
@ -3,10 +3,7 @@
|
||||
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"
|
||||
mc:Ignorable="d"
|
||||
ResizeMode="NoResize"
|
||||
ShowInTaskbar="False"
|
||||
Topmost="True"
|
||||
ResizeMode="NoResize" ShowInTaskbar="False" Topmost="True"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
Title="Neues Update verfügbar - Elwig" Height="180" Width="400">
|
||||
<Grid>
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Elwig.Helpers;
|
||||
using Elwig.Models;
|
||||
using Elwig.Models.Entities;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
|
@ -18,7 +18,8 @@ namespace Elwig.Documents {
|
||||
public string MemberModifier;
|
||||
public IEnumerable<(string Name, int Kg, decimal Amount)>? MemberUnderDeliveries;
|
||||
public decimal MemberTotalUnderDelivery;
|
||||
public decimal MemberAutoBusinessShares;
|
||||
public int MemberAutoBusinessShares;
|
||||
public decimal MemberAutoBusinessSharesAmount;
|
||||
|
||||
public CreditNote(
|
||||
AppDbContext ctx,
|
||||
@ -66,7 +67,8 @@ namespace Elwig.Documents {
|
||||
MemberAutoBusinessShares = ctx.MemberHistory
|
||||
.Where(h => h.MgNr == p.Member.MgNr && h.Type == "auto")
|
||||
.Where(h => h.DateString.CompareTo(fromDate) >= 0 && h.DateString.CompareTo(toDate) <= 0)
|
||||
.Sum(h => h.BusinessShares) * (-season.BusinessShareValue ?? 0);
|
||||
.Sum(h => h.BusinessShares);
|
||||
MemberAutoBusinessSharesAmount = MemberAutoBusinessShares * (-season.BusinessShareValue ?? 0);
|
||||
}
|
||||
if (considerContractPenalties) {
|
||||
var varieties = ctx.WineVarieties.ToDictionary(v => v.SortId, v => v);
|
||||
|
@ -153,9 +153,9 @@
|
||||
@Raw(FormatRow("Unterlieferung (GA)", Model.MemberTotalUnderDelivery, add: true));
|
||||
penalty += Model.MemberTotalUnderDelivery;
|
||||
}
|
||||
@if (Model.MemberAutoBusinessShares != 0) {
|
||||
@Raw(FormatRow("Autom. Nachz. von GA", Model.MemberAutoBusinessShares, add: true));
|
||||
penalty += Model.MemberAutoBusinessShares;
|
||||
@if (Model.MemberAutoBusinessSharesAmount != 0) {
|
||||
@Raw(FormatRow($"Autom. Nachz. von GA ({Model.MemberAutoBusinessShares})", Model.MemberAutoBusinessSharesAmount, add: true));
|
||||
penalty += Model.MemberAutoBusinessSharesAmount;
|
||||
}
|
||||
|
||||
@if (Model.Credit == null) {
|
||||
|
@ -20,7 +20,6 @@ namespace Elwig.Documents {
|
||||
Season = ctx.Seasons.Find(year) ?? throw new ArgumentException("invalid season");
|
||||
ShowDateAndLocation = true;
|
||||
UseBillingAddress = true;
|
||||
IncludeSender = true;
|
||||
DocumentId = $"Anl.-Best. {Season.Year}/{m.MgNr}";
|
||||
Data = data;
|
||||
MemberBuckets = ctx.GetMemberBuckets(Season.Year, m.MgNr).GetAwaiter().GetResult();
|
||||
|
@ -165,6 +165,7 @@ main table th.narrow {
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
main table .tborder {border-top: var(--border-thickness) solid black;}
|
||||
main table .lborder {border-left: var(--border-thickness) solid black;}
|
||||
main table .rborder {border-right: var(--border-thickness) solid black;}
|
||||
|
||||
|
@ -88,6 +88,8 @@ namespace Elwig.Documents {
|
||||
name = "MemberList";
|
||||
} else if (this is WineQualityStatistics) {
|
||||
name = "WineQualityStatistics";
|
||||
} else if (this is PaymentVariantSummary) {
|
||||
name = "PaymentVariantSummary";
|
||||
} else {
|
||||
throw new InvalidOperationException("Invalid document object");
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
:root {
|
||||
font-family: "Times New Roman", serif;
|
||||
line-height: 1;
|
||||
--border-thickness: 0.05pt;
|
||||
--border-thickness: 0.5pt;
|
||||
}
|
||||
|
||||
* {
|
||||
|
@ -2,9 +2,7 @@
|
||||
@using Elwig.Helpers
|
||||
@inherits TemplatePage<Elwig.Documents.MemberDataSheet>
|
||||
@model Elwig.Documents.MemberDataSheet
|
||||
@{
|
||||
Layout = "BusinessDocument";
|
||||
}
|
||||
@{ Layout = "BusinessDocument"; }
|
||||
<link rel="stylesheet" href="file:///@Raw(Model.DataPath)\resources\MemberDataSheet.css" />
|
||||
<main>
|
||||
<h1>@Model.Title</h1>
|
||||
|
30
Elwig/Documents/PaymentVariantSummary.cs
Normal file
30
Elwig/Documents/PaymentVariantSummary.cs
Normal file
@ -0,0 +1,30 @@
|
||||
using Elwig.Helpers.Billing;
|
||||
using Elwig.Models.Dtos;
|
||||
using Elwig.Models.Entities;
|
||||
using System.Linq;
|
||||
|
||||
namespace Elwig.Documents {
|
||||
public class PaymentVariantSummary : Document {
|
||||
|
||||
public new static string Name => "Auszahlungsvariante";
|
||||
|
||||
public PaymentVariantSummaryData Data;
|
||||
public PaymentVar Variant;
|
||||
public BillingData BillingData;
|
||||
public string CurrencySymbol;
|
||||
public int MemberNum;
|
||||
public int DeliveryNum;
|
||||
public int DeliveryPartNum;
|
||||
|
||||
public PaymentVariantSummary(PaymentVar v, PaymentVariantSummaryData data) :
|
||||
base($"{Name} {v.Year} - {v.Name}") {
|
||||
Variant = v;
|
||||
BillingData = BillingData.FromJson(v.Data);
|
||||
Data = data;
|
||||
CurrencySymbol = v.Season.Currency.Symbol ?? v.Season.Currency.Code;
|
||||
MemberNum = v.Credits.Count;
|
||||
DeliveryNum = v.DeliveryPartPayments.DistinctBy(p => p.DeliveryPart.Delivery).Count();
|
||||
DeliveryPartNum = v.DeliveryPartPayments.Count;
|
||||
}
|
||||
}
|
||||
}
|
229
Elwig/Documents/PaymentVariantSummary.cshtml
Normal file
229
Elwig/Documents/PaymentVariantSummary.cshtml
Normal file
@ -0,0 +1,229 @@
|
||||
@using RazorLight
|
||||
@using Elwig.Helpers
|
||||
@inherits TemplatePage<Elwig.Documents.PaymentVariantSummary>
|
||||
@model Elwig.Documents.PaymentVariantSummary
|
||||
@{ Layout = "Document"; }
|
||||
<link rel="stylesheet" href="file:///@Raw(Model.DataPath)\resources\PaymentVariantSummary.css" />
|
||||
<main>
|
||||
<h1>Auszahlungsvariante Lese @Model.Variant.Year</h1>
|
||||
<h2>@Model.Variant.Name</h2>
|
||||
<table class="payment-variant border">
|
||||
<colgroup>
|
||||
<col style="width: 20.0mm;"/>
|
||||
<col style="width: 30.0mm;"/>
|
||||
<col style="width: 4.5mm;"/>
|
||||
<col style="width: 28.0mm;"/>
|
||||
<col style="width: 47.5mm;"/>
|
||||
<col style="width: 15.0mm;"/>
|
||||
<col style="width: 20.0mm;"/>
|
||||
</colgroup>
|
||||
@{
|
||||
//var sum1 = Model.Variant.DeliveryPartPayments.Sum(p => p.NetAmount);
|
||||
//var sum2 = Model.Variant.Credits.Sum(p => p.); //Model.Variant.MemberPayments.Sum(p => p.Amount);
|
||||
var modifiers = Model.Variant.DeliveryPartPayments.Sum(p => p.Amount - p.NetAmount);
|
||||
var sum2 = Model.Variant.Credits.Sum(p => p.NetAmount);
|
||||
var sum1 = sum2 - modifiers;
|
||||
var payed = -Model.Variant.Credits.Sum(p => p.PrevNetAmount ?? 0m);
|
||||
var netSum = Model.Variant.Credits.Sum(p => p.NetAmount) - Model.Variant.Credits.Sum(p => p.PrevNetAmount ?? 0m);
|
||||
var vat = Model.Variant.Credits.Sum(p => p.VatAmount);
|
||||
var grossSum = Model.Variant.Credits.Sum(p => p.GrossAmount);
|
||||
var totalMods = Model.Variant.Credits.Sum(p => p.Modifiers ?? 0m);
|
||||
var considered = -Model.Variant.Credits.Sum(p => p.PrevModifiers ?? 0m);
|
||||
var totalSum = Model.Variant.Credits.Sum(p => p.Amount);
|
||||
}
|
||||
<tbody>
|
||||
<tr class="sectionheading">
|
||||
<th colspan="4">Allgemein</th>
|
||||
<th colspan="3" class="lborder">Berücksichtigt</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Name:</th>
|
||||
<td colspan="3">@Model.Variant.Name</td>
|
||||
<th colspan="2" class="lborder">Zu-/Abschläge bei Lieferungen:</th>
|
||||
<td class="center">@(Model.BillingData.ConsiderDelieryModifiers ? "Ja" : "Nein")</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Beschr.:</th>
|
||||
<td colspan="3">@Model.Variant.Comment</td>
|
||||
<th colspan="2" class="lborder">Pönalen bei Unterlieferungen (FB):</th>
|
||||
<td class="center">@(Model.BillingData.ConsiderContractPenalties ? "Ja" : "Nein")</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th style="overflow: visible;">Nto./bto.-Zuschl:</th>
|
||||
<td colspan="3" class="center">
|
||||
@($"{Utils.GetSign(Model.BillingData.NetWeightModifier)}{Math.Abs(Model.BillingData.NetWeightModifier) * 100:N2}") % /
|
||||
@($"{Utils.GetSign(Model.BillingData.GrossWeightModifier)}{Math.Abs(Model.BillingData.GrossWeightModifier) * 100:N2}") %
|
||||
</td>
|
||||
<th colspan="2" class="lborder">Strafen bei Unterlieferungen (GA):</th>
|
||||
<td class="center">@(Model.BillingData.ConsiderTotalPenalty ? "Ja" : "Nein")</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th style="overflow: visible;">Datum/Überw.:</th>
|
||||
<td colspan="3" class="center">
|
||||
@($"{Model.Variant.Date:dd.MM.yyyy}") /
|
||||
@($"{Model.Variant.TransferDate:dd.MM.yyyy}")
|
||||
</td>
|
||||
<th colspan="2" class="lborder">Automatische Nachzeichnung der GA:</th>
|
||||
<td class="center">@(Model.BillingData.ConsiderAutoBusinessShares ? "Ja" : "Nein")</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Berechnung:</th>
|
||||
<td colspan="3" class="center">@($"{Model.Variant.CalcTime:dd.MM.yyyy, HH:mm:ss}")</td>
|
||||
<th colspan="2" class="lborder">Benutzerdef. Zu-/Abschläge pro Mitglied:</th>
|
||||
<td class="center">@(Model.BillingData.ConsiderCustomModifiers ? "Ja" : "Nein")</td>
|
||||
</tr>
|
||||
<tr class="sectionheading">
|
||||
<th colspan="4">Beträge</th>
|
||||
<th colspan="3" class="lborder">Statistik</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="2">Zwischensumme:</th>
|
||||
<td></td>
|
||||
<td class="number"><span class="fleft">@Model.CurrencySymbol</span>@($"{sum1:N2}")</td>
|
||||
<th class="lborder">Lieferanten:</th>
|
||||
<td colspan="2" class="number">@($"{Model.MemberNum:N0}")</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="2">Zu-/Abschläge (Lieferungen):</th>
|
||||
<td class="number">@Utils.GetSign(modifiers)</td>
|
||||
<td class="number"><span class="fleft">@Model.CurrencySymbol</span>@($"{Math.Abs(modifiers):N2}")</td>
|
||||
<th class="lborder">Lieferungen:</th>
|
||||
<td colspan="2" class="number">@($"{Model.DeliveryNum:N0}")</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="2">Gesamtsumme:</th>
|
||||
<td class="number tborder"></td>
|
||||
<td class="number tborder"><span class="fleft">@Model.CurrencySymbol</span>@($"{sum2:N2}")</td>
|
||||
<th class="lborder">Teillieferungen:</th>
|
||||
<td colspan="2" class="number">@($"{Model.DeliveryPartNum:N0}")</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="2">Bisher ausgezahlt:</th>
|
||||
<td class="number">@Utils.GetSign(payed)</td>
|
||||
<td class="number"><span class="fleft">@Model.CurrencySymbol</span>@($"{Math.Abs(payed):N2}")</td>
|
||||
<th class="lborder"></th>
|
||||
<td colspan="2"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="2">Nettosumme:</th>
|
||||
<td class="number tborder"></td>
|
||||
<td class="number tborder"><span class="fleft">@Model.CurrencySymbol</span>@($"{netSum: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);
|
||||
}
|
||||
<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>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="2">Mehrwertsteuer:</th>
|
||||
<td class="number">@Utils.GetSign(vat)</td>
|
||||
<td class="number"><span class="fleft">@Model.CurrencySymbol</span>@($"{Math.Abs(vat):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);
|
||||
}
|
||||
<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>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="2">Bruttosumme:</th>
|
||||
<td class="number tborder"></td>
|
||||
<td class="number tborder"><span class="fleft">@Model.CurrencySymbol</span>@($"{grossSum: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);
|
||||
var minGeb = gebRows.Min();
|
||||
var maxGeb = gebRows.Max();
|
||||
}
|
||||
<th class="lborder">Gebunden-Zuschlag:</th>
|
||||
<td colspan="2" class="center">
|
||||
@(minGeb != maxGeb ? $"{minGeb:N4}–{maxGeb:N4} {Model.CurrencySymbol}/kg" : minGeb == 0 ? "-" : $"{minGeb:N4} {Model.CurrencySymbol}/kg")
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="2">Abzüge (Strafen/Pönalen, GA, ...):</th>
|
||||
<td class="number">@Utils.GetSign(totalMods)</td>
|
||||
<td class="number"><span class="fleft">@Model.CurrencySymbol</span>@($"{Math.Abs(totalMods):N2}")</td>
|
||||
<th class="lborder tborder">Menge (ungebunden):</th>
|
||||
<td colspan="2" class="number tborder">@($"{Model.Data.Rows.Sum(r => r.Ungeb.Weight):N0}") kg</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="2">Bereits berücksichtigte Abzüge:</th>
|
||||
<td class="number">@Utils.GetSign(considered)</td>
|
||||
<td class="number"><span class="fleft">@Model.CurrencySymbol</span>@($"{Math.Abs(considered):N2}")</td>
|
||||
<th class="lborder">Menge (gebunden):</th>
|
||||
<td colspan="2" class="number">@($"{Model.Data.Rows.Sum(r => r.Geb.Weight):N0}") kg</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="2">Auszahlungsbetrag:</th>
|
||||
<td class="number tborder"></td>
|
||||
<td class="number tborder"><span class="fleft">@Model.CurrencySymbol</span>@($"{totalSum:N2}")</td>
|
||||
<th class="lborder">Gesamtmenge:</th>
|
||||
<td colspan="2" class="number tborder">@($"{Model.Data.Rows.Sum(r => r.Ungeb.Weight + r.Geb.Weight):N0}") kg</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</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;"/>
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th rowspan="2" style="text-align: left;">Qualitätsstufe</th>
|
||||
<th>Gradation</th>
|
||||
<th colspan="2">ungebunden</th>
|
||||
<th colspan="2">gebunden</th>
|
||||
<th>Gesamt</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>[@(true ? "°Oe" : "°KMW")]</th>
|
||||
<th>[kg]</th>
|
||||
<th>[@(Model.CurrencySymbol)/kg]</th>
|
||||
<th>[kg]</th>
|
||||
<th>[@(Model.CurrencySymbol)/kg]</th>
|
||||
<th>[@(Model.CurrencySymbol)]</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@{
|
||||
string? lastHdr = null;
|
||||
}
|
||||
@foreach (var row in Model.Data.Rows) {
|
||||
var hdr = $"{row.Variety}{(row.Attribute != null ? " / " : "")}{row.Attribute}{(row.Cultivation != null ? " / " : "")}{row.Cultivation}";
|
||||
if (lastHdr != hdr) {
|
||||
var rows = Model.Data.Rows
|
||||
.Where(r => r.Variety == row.Variety && r.Attribute == row.Attribute && r.Cultivation == row.Cultivation)
|
||||
.ToList();
|
||||
<tr class="subheading @(lastHdr != null ? "new" : "")">
|
||||
<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.Geb.Weight):N0}")</td>
|
||||
<td></td>
|
||||
<td class="number">@($"{rows.Sum(r => r.Amount):N2}")</td>
|
||||
</tr>
|
||||
}
|
||||
<tr>
|
||||
<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.Geb.Weight != 0 ? $"{row.Geb.Weight:N0}" : "-")</td>
|
||||
<td class="number">@(row.Geb.Price != null ? $"{row.Geb.Price:N4}" : "-")</td>
|
||||
<td class="number">@($"{row.Amount:N2}")</td>
|
||||
</tr>
|
||||
lastHdr = hdr;
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</main>
|
21
Elwig/Documents/PaymentVariantSummary.css
Normal file
21
Elwig/Documents/PaymentVariantSummary.css
Normal file
@ -0,0 +1,21 @@
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
font-size: 24pt;
|
||||
margin-top: 10mm;
|
||||
margin-bottom: 2mm;
|
||||
}
|
||||
|
||||
h2 {
|
||||
text-align: center;
|
||||
font-size: 14pt;
|
||||
margin-top: 2mm;
|
||||
}
|
||||
|
||||
table.payment-variant {
|
||||
margin-top: 10mm;
|
||||
}
|
||||
|
||||
table.payment-variant-data {
|
||||
break-before: page;
|
||||
}
|
@ -17,6 +17,7 @@ namespace Elwig.Documents {
|
||||
|
||||
public string Filter;
|
||||
public WineQualityStatisticsData Data;
|
||||
public bool UseOe => Data.UseOe;
|
||||
|
||||
public WineQualityStatistics(string filter, WineQualityStatisticsData data) : base($"{Name} {filter}") {
|
||||
Filter = filter;
|
||||
|
@ -1,4 +1,5 @@
|
||||
@using RazorLight
|
||||
@using Elwig.Helpers
|
||||
@inherits TemplatePage<Elwig.Documents.WineQualityStatistics>
|
||||
@model Elwig.Documents.WineQualityStatistics
|
||||
@{ Layout = "Document"; }
|
||||
@ -26,15 +27,15 @@
|
||||
@foreach (var qualIds in Model.QualIds) {
|
||||
<td class="container">
|
||||
<div class="row">
|
||||
<span class="units">[°Oe]</span>
|
||||
<span class="units">[@(Model.UseOe ? "°Oe" : "°KMW")]</span>
|
||||
<span class="units">[#]</span>
|
||||
<span class="units">[kg]</span>
|
||||
</div>
|
||||
@foreach (var qualId in qualIds) {
|
||||
<h4>@(Model.QualityLevels.GetValueOrDefault(qualId, qualId))</h4>
|
||||
@foreach (var (oe, num, weight) in sec.Data.GetValueOrDefault(qualId, Array.Empty<(int, int, int)>())) {
|
||||
@foreach (var (grad, avgKmw, num, weight) in sec.Data.GetValueOrDefault(qualId, Array.Empty<(double, double, int, int)>())) {
|
||||
<div class="row">
|
||||
<span class="oe">@oe</span>
|
||||
<span class="gradation">@(Model.UseOe ? $"{grad:N0}" : $"{grad:N1}")</span>
|
||||
<span class="number">@($"{num:N0}")</span>
|
||||
<span class="number">@($"{weight:N0}")</span>
|
||||
</div>
|
||||
@ -45,13 +46,13 @@
|
||||
</tr>
|
||||
<tr>
|
||||
@foreach (var qualIds in Model.QualIds) {
|
||||
var quals = qualIds.Select(q => sec.Data.GetValueOrDefault(q, Array.Empty<(int Oe, int Num, int Weight)>()));
|
||||
var quals = qualIds.Select(q => sec.Data.GetValueOrDefault(q, Array.Empty<(double Grad, double AvgKmw, int Num, int Weight)>()));
|
||||
var weight = quals.Sum(q => q.Sum(kv => kv.Weight));
|
||||
var num = quals.Sum(q => q.Sum(kv => kv.Num));
|
||||
var oe = quals.Sum(q => q.Sum(kv => (double)kv.Oe * kv.Weight)) / weight;
|
||||
var kmw = quals.Sum(q => q.Sum(kv => kv.AvgKmw * kv.Weight)) / weight;
|
||||
<td class="container bold">
|
||||
<div class="row">
|
||||
<span class="oe">@(weight == 0 ? "-" : $"{oe:N0}")</span>
|
||||
<span class="gradation">@(weight == 0 ? "-" : Model.UseOe ? $"{Utils.KmwToOe(kmw):N0}" : $"{kmw:N1}")</span>
|
||||
<span class="number">@($"{num:N0}")</span>
|
||||
<span class="number">@($"{weight:N0}")</span>
|
||||
</div>
|
||||
@ -64,11 +65,11 @@
|
||||
@{
|
||||
var totalWeight = sec.Data.Values.Sum(q => q.Sum(kv => kv.Weight));
|
||||
var totalNum = sec.Data.Values.Sum(q => q.Sum(kv => kv.Num));
|
||||
var totalOe = sec.Data.Values.Sum(q => q.Sum(kv => (double)kv.Oe * kv.Weight)) / totalWeight;
|
||||
var totalKmw = sec.Data.Values.Sum(q => q.Sum(kv => kv.AvgKmw * kv.Weight)) / totalWeight;
|
||||
}
|
||||
<td colspan="4" class="container bold footer @(sec.Type == "R" ? "red" : sec.Type == "W" ? "green" : "")">
|
||||
<div class="row" style="width: 24%; margin-left: 76%;">
|
||||
<span class="oe">@(totalWeight == 0 ? "-" : $"{totalOe:N0}")</span>
|
||||
<span class="gradation">@(totalWeight == 0 ? "-" : Model.UseOe ? $"{Utils.KmwToOe(totalKmw):N0}" : $"{totalKmw:N1}")</span>
|
||||
<span class="number">@($"{totalNum:N0}")</span>
|
||||
<span class="number">@($"{totalWeight:N0}")</span>
|
||||
</div>
|
||||
|
@ -85,7 +85,7 @@ table .footer.green {
|
||||
padding: 1mm;
|
||||
}
|
||||
|
||||
.oe {
|
||||
.gradation {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
<UseWPF>true</UseWPF>
|
||||
<PreserveCompilationContext>true</PreserveCompilationContext>
|
||||
<ApplicationIcon>Resources\Images\Elwig.ico</ApplicationIcon>
|
||||
<Version>0.7.2</Version>
|
||||
<Version>0.8.5</Version>
|
||||
<SatelliteResourceLanguages>de-AT</SatelliteResourceLanguages>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
@ -25,17 +25,16 @@
|
||||
</Target>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Extended.Wpf.Toolkit" Version="4.6.0" />
|
||||
<PackageReference Include="LinqKit" Version="1.2.5" />
|
||||
<PackageReference Include="MailKit" Version="4.4.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Razor.Language" Version="6.0.27" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="8.0.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.2" />
|
||||
<PackageReference Include="MailKit" Version="4.6.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Razor.Language" Version="6.0.31" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="8.0.6" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.6" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Ini" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.2365.46" />
|
||||
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.2535.41" />
|
||||
<PackageReference Include="NJsonSchema" Version="11.0.0" />
|
||||
<PackageReference Include="RazorLight" Version="2.3.1" />
|
||||
<PackageReference Include="ScottPlot.WPF" Version="5.0.21" />
|
||||
<PackageReference Include="ScottPlot.WPF" Version="5.0.34" />
|
||||
<PackageReference Include="System.IO.Ports" Version="8.0.0" />
|
||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="8.0.0" />
|
||||
</ItemGroup>
|
||||
|
@ -64,6 +64,8 @@ namespace Elwig.Helpers {
|
||||
public DbSet<MemberDeliveryPerVariantRowSingle> MemberDeliveryPerVariantRows { get; private set; }
|
||||
public DbSet<CreditNoteDeliveryRowSingle> CreditNoteDeliveryRows { get; private set; }
|
||||
public DbSet<CreditNoteRowSingle> CreditNoteRows { get; private set; }
|
||||
public DbSet<WeightBreakdownRow> WeightBreakDownRows { get; private set; }
|
||||
public DbSet<PaymentVariantSummaryRow> PaymentVariantSummaryRows { get; private set; }
|
||||
|
||||
private readonly StreamWriter? LogFile = null;
|
||||
public static DateTime LastWriteTime => File.GetLastWriteTime(App.Config.DatabaseFile);
|
||||
@ -239,23 +241,23 @@ namespace Elwig.Helpers {
|
||||
.LastAsync();
|
||||
}
|
||||
|
||||
public void UpdateDeliveryPartModifiers(DeliveryPart part, IEnumerable<Modifier> modifiers) {
|
||||
public void UpdateDeliveryPartModifiers(DeliveryPart part, IEnumerable<Modifier> oldModifiers, IEnumerable<Modifier> newModifiers) {
|
||||
foreach (var m in Modifiers.Where(m => m.Year == part.Year)) {
|
||||
var mod = part.PartModifiers.Where(pa => pa.ModId == m.ModId).FirstOrDefault();
|
||||
if (modifiers.Contains(m)) {
|
||||
var dpm = new DeliveryPartModifier {
|
||||
Year = part.Year,
|
||||
DId = part.DId,
|
||||
DPNr = part.DPNr,
|
||||
ModId = m.ModId,
|
||||
};
|
||||
if (mod == null) {
|
||||
Add(dpm);
|
||||
var mod = new DeliveryPartModifier {
|
||||
Year = part.Year,
|
||||
DId = part.DId,
|
||||
DPNr = part.DPNr,
|
||||
ModId = m.ModId,
|
||||
};
|
||||
var old = oldModifiers.Where(pa => pa.ModId == m.ModId).FirstOrDefault();
|
||||
if (newModifiers.Any(md => md.ModId == m.ModId)) {
|
||||
if (old == null) {
|
||||
Add(mod);
|
||||
} else {
|
||||
Update(dpm);
|
||||
Update(mod);
|
||||
}
|
||||
} else {
|
||||
if (mod != null) {
|
||||
if (old != null) {
|
||||
Remove(mod);
|
||||
}
|
||||
}
|
||||
@ -352,6 +354,27 @@ namespace Elwig.Helpers {
|
||||
_memberUnderDelivery[year] = buckets;
|
||||
}
|
||||
|
||||
public async Task<Dictionary<int, long>> GetBusinessSharePenalties(int year) {
|
||||
using var cnx = await ConnectAsync();
|
||||
var dict = new Dictionary<int, long>();
|
||||
using var cmd = cnx.CreateCommand();
|
||||
cmd.CommandText = $"""
|
||||
SELECT mgnr, ROUND((
|
||||
COALESCE(-s.penalty_amount, 0) +
|
||||
COALESCE(-s.penalty_per_bs_amount * CEIL(CAST(-u.diff AS REAL) / s.min_kg_per_bs), 0) +
|
||||
COALESCE(u.diff * s.penalty_per_kg, 0)
|
||||
) / POW(10, s.precision - 2))
|
||||
FROM v_total_under_delivery u
|
||||
JOIN season s ON s.year = u.year
|
||||
WHERE s.year = {year} AND u.diff < 0
|
||||
""";
|
||||
using var reader = await cmd.ExecuteReaderAsync();
|
||||
while (await reader.ReadAsync()) {
|
||||
dict[reader.GetInt32(0)] = reader.GetInt64(1);
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
|
||||
public async Task<Dictionary<string, AreaComBucket>> GetMemberAreaCommitmentBuckets(int year, int mgnr, SqliteConnection? cnx = null) {
|
||||
if (!_memberAreaCommitmentBuckets.ContainsKey(year))
|
||||
await FetchMemberAreaCommitmentBuckets(year, cnx);
|
||||
|
@ -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 = 18;
|
||||
public static readonly int RequiredSchemaVersion = 21;
|
||||
|
||||
private static int VersionOffset = 0;
|
||||
|
||||
|
@ -3,6 +3,7 @@ using Microsoft.Data.Sqlite;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@ -33,15 +34,45 @@ namespace Elwig.Helpers.Billing {
|
||||
""");
|
||||
}
|
||||
|
||||
public async Task AutoAdjustBusinessShare() {
|
||||
public async Task AutoAdjustBusinessShares(DateOnly date, int allowanceKg = 0, double allowanceBs = 0, int allowanceKgPerBs = 0, double allowanceRel = 0, int addMinBs = 1) {
|
||||
if (addMinBs < 1) addMinBs = 1;
|
||||
using var cnx = await AppDbContext.ConnectAsync();
|
||||
await AppDbContext.ExecuteBatch(cnx, $"""
|
||||
INSERT INTO member_history (mgnr, date, business_shares, type)
|
||||
SELECT u.mgnr, '{Utils.Today:yyyy-MM-dd}', u.diff / s.max_kg_per_bs AS bs, 'auto'
|
||||
UPDATE member
|
||||
SET business_shares = member.business_shares - h.business_shares
|
||||
FROM member_history h
|
||||
WHERE h.date = '{Year}-11-30' AND h.type = 'auto' AND h.mgnr = member.mgnr AND member.active;
|
||||
|
||||
INSERT INTO member_history (mgnr, date, type, business_shares)
|
||||
SELECT u.mgnr,
|
||||
'{date:yyyy-MM-dd}',
|
||||
'auto',
|
||||
CEIL((u.diff - {allowanceKg}.0 - {allowanceKgPerBs}.0 * u.business_shares) / s.max_kg_per_bs
|
||||
- {allowanceBs.ToString(CultureInfo.InvariantCulture)}
|
||||
- {allowanceRel.ToString(CultureInfo.InvariantCulture)} * u.business_shares) AS bs
|
||||
FROM v_total_under_delivery u
|
||||
JOIN season s ON s.year = u.year
|
||||
WHERE s.year = {Year} AND bs > 0
|
||||
ON CONFLICT DO NOTHING
|
||||
JOIN member m ON m.mgnr = u.mgnr
|
||||
WHERE s.year = {Year} AND bs >= {addMinBs} AND m.active
|
||||
ON CONFLICT DO UPDATE
|
||||
SET business_shares = excluded.business_shares;
|
||||
|
||||
UPDATE member
|
||||
SET business_shares = member.business_shares + h.business_shares
|
||||
FROM member_history h
|
||||
WHERE h.date = '{Year}-11-30' AND h.type = 'auto' AND h.mgnr = member.mgnr;
|
||||
""");
|
||||
}
|
||||
|
||||
public async Task UnAdjustBusinessShares() {
|
||||
using var cnx = await AppDbContext.ConnectAsync();
|
||||
await AppDbContext.ExecuteBatch(cnx, $"""
|
||||
UPDATE member
|
||||
SET business_shares = member.business_shares - h.business_shares
|
||||
FROM member_history h
|
||||
WHERE h.date = '{Year}-11-30' AND h.type = 'auto' AND h.mgnr = member.mgnr AND member.active;
|
||||
|
||||
DELETE FROM member_history WHERE date = '{Year}-11-30' AND type = 'auto';
|
||||
""");
|
||||
}
|
||||
|
||||
|
@ -41,6 +41,10 @@ namespace Elwig.Helpers.Billing {
|
||||
get => GetConsider("consider_auto_business_shares");
|
||||
set => SetConsider(value, "consider_auto_business_shares");
|
||||
}
|
||||
public bool ConsiderCustomModifiers {
|
||||
get => GetConsider("consider_custom_modifiers");
|
||||
set => SetConsider(value, "consider_custom_modifiers");
|
||||
}
|
||||
|
||||
public double NetWeightModifier {
|
||||
get => GetWeightModifier("net_weight_modifier", "Rebelzuschlag");
|
||||
|
@ -47,7 +47,6 @@ namespace Elwig.Helpers.Billing {
|
||||
ROUND(lp.amount / POW(10, s.precision - 2)) AS prev_amount,
|
||||
IIF(m.buchführend, s.vat_normal, s.vat_flatrate) AS vat,
|
||||
ROUND(IIF({Data.ConsiderContractPenalties}, COALESCE(u.total_penalty, 0), 0) / POW(10, 4 - 2)) +
|
||||
ROUND(IIF({Data.ConsiderTotalPenalty}, COALESCE(b.total_penalty, 0), 0) / POW(10, s.precision - 2)) +
|
||||
ROUND(IIF({Data.ConsiderAutoBusinessShares}, -COALESCE(a.total_amount, 0), 0) / POW(10, s.precision - 2))
|
||||
AS modifiers,
|
||||
lc.modifiers AS prev_modifiers
|
||||
@ -66,12 +65,30 @@ namespace Elwig.Helpers.Billing {
|
||||
LEFT JOIN payment_member p ON (p.year, p.avnr, p.mgnr) = (v.year, v.avnr, m.mgnr)
|
||||
LEFT JOIN credit lc ON (lc.year, lc.avnr, lc.mgnr) = (l.year, l.avnr, m.mgnr)
|
||||
LEFT JOIN v_penalty_area_commitments u ON (u.year, u.mgnr) = (s.year, m.mgnr)
|
||||
LEFT JOIN v_penalty_business_shares b ON (b.year, b.mgnr) = (s.year, m.mgnr)
|
||||
LEFT JOIN v_auto_business_shares a ON (a.year, a.mgnr) = (s.year, m.mgnr)
|
||||
WHERE s.year = {Year} AND v.avnr = {AvNr};
|
||||
|
||||
UPDATE payment_variant SET test_variant = FALSE WHERE (year, avnr) = ({Year}, {AvNr});
|
||||
""");
|
||||
if (Data.ConsiderTotalPenalty) {
|
||||
if (App.Client.IsWinzerkeller) {
|
||||
// TODO
|
||||
} else {
|
||||
await AppDbContext.ExecuteBatch(cnx, $"""
|
||||
UPDATE credit AS c
|
||||
SET modifiers = modifiers + ROUND((
|
||||
COALESCE(-s.penalty_amount, 0) +
|
||||
COALESCE(-s.penalty_per_bs_amount * CEIL(CAST(-u.diff AS REAL) / s.min_kg_per_bs), 0) +
|
||||
COALESCE(u.diff * s.penalty_per_kg, 0)
|
||||
) / POW(10, s.precision - 2))
|
||||
FROM v_total_under_delivery u
|
||||
JOIN season s ON s.year = u.year
|
||||
WHERE c.year = {Year} AND c.avnr = {AvNr} AND (u.year, u.mgnr) = (c.year, c.mgnr) AND
|
||||
u.diff < 0
|
||||
""");
|
||||
}
|
||||
}
|
||||
await AppDbContext.ExecuteBatch(cnx, $"""
|
||||
UPDATE payment_variant SET test_variant = FALSE WHERE (year, avnr) = ({Year}, {AvNr});
|
||||
""");
|
||||
}
|
||||
|
||||
public async Task Revert() {
|
||||
|
@ -1,6 +1,7 @@
|
||||
using Elwig.Models.Entities;
|
||||
using Microsoft.Data.Sqlite;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@ -57,6 +58,7 @@ namespace Elwig.Helpers {
|
||||
public string? Website;
|
||||
|
||||
public int ModeDeliveryNoteStats;
|
||||
public int ModeWineQualityStatistics;
|
||||
public int OrderingMemberList;
|
||||
|
||||
public string? TextDeliveryNote;
|
||||
@ -65,6 +67,11 @@ namespace Elwig.Helpers {
|
||||
public string? TextEmailSubject;
|
||||
public string? TextEmailBody;
|
||||
|
||||
public int ExportEbicsVersion;
|
||||
public int ExportEbicsAddress;
|
||||
|
||||
public (int? AllowanceKg, double? AllowanceBs, int? AllowanceKgPerBs, double? AllowancePercent, int? MinBs) AutoAdjustBs;
|
||||
|
||||
public ClientParameters(AppDbContext ctx) : this(ctx.ClientParameters.ToDictionary(e => e.Param, e => e.Value)) { }
|
||||
|
||||
public ClientParameters(Dictionary<string, string?> parameters) {
|
||||
@ -103,6 +110,13 @@ namespace Elwig.Helpers {
|
||||
case "SHORT": ModeDeliveryNoteStats = 2; break;
|
||||
case "FULL": ModeDeliveryNoteStats = 3; break;
|
||||
}
|
||||
switch (parameters.GetValueOrDefault("MODE_WINEQUALITYSTATISTICS", "OE")?.ToUpper()) {
|
||||
case "OE": ModeWineQualityStatistics = 0; break;
|
||||
case "KMW/1": ModeWineQualityStatistics = 1; break;
|
||||
case "KMW/2": ModeWineQualityStatistics = 2; break;
|
||||
case "KMW/5": ModeWineQualityStatistics = 3; break;
|
||||
case "KMW/10": ModeWineQualityStatistics = 4; break;
|
||||
}
|
||||
switch (parameters.GetValueOrDefault("ORDERING_MEMBERLIST", "")?.ToUpper()) {
|
||||
case "MGNR": OrderingMemberList = 0; break;
|
||||
case "NAME": OrderingMemberList = 1; break;
|
||||
@ -120,6 +134,22 @@ namespace Elwig.Helpers {
|
||||
if (TextEmailSubject == "") TextEmailSubject = null;
|
||||
TextEmailBody = parameters.GetValueOrDefault("TEXT_EMAIL_BODY");
|
||||
if (TextEmailBody == "") TextEmailBody = null;
|
||||
|
||||
ExportEbicsVersion = int.TryParse(parameters.GetValueOrDefault("EXPORT_EBICS_VERSION"), out var v) ? v : 9;
|
||||
switch (parameters.GetValueOrDefault("EXPORT_EBICS_ADDRESS", "FULL")?.ToUpper()) {
|
||||
case "OMIT": ExportEbicsAddress = 0; break;
|
||||
case "LINES": ExportEbicsAddress = 1; break;
|
||||
case "FULL": ExportEbicsAddress = 2; break;
|
||||
}
|
||||
|
||||
var autoAdjust = (parameters.GetValueOrDefault("AUTOADJUST_BUSINESSSHARES") ?? "").Split(';');
|
||||
AutoAdjustBs = autoAdjust.Length == 5 ? (
|
||||
int.TryParse(autoAdjust[0], out var v1) ? v1 : null,
|
||||
double.TryParse(autoAdjust[1], out var v2) ? v2 : null,
|
||||
int.TryParse(autoAdjust[2], out var v3) ? v3 : null,
|
||||
double.TryParse(autoAdjust[3], out var v4) ? v4 : null,
|
||||
int.TryParse(autoAdjust[4], out var v5) ? v5 : null
|
||||
) : (null, null, null, null, null);
|
||||
} catch {
|
||||
throw new KeyNotFoundException();
|
||||
}
|
||||
@ -133,12 +163,29 @@ namespace Elwig.Helpers {
|
||||
case 2: deliveryNoteStats = "SHORT"; break;
|
||||
case 3: deliveryNoteStats = "FULL"; break;
|
||||
}
|
||||
string modeWineQualityStatistics = "OE";
|
||||
switch (ModeWineQualityStatistics) {
|
||||
case 0: modeWineQualityStatistics = "OE"; break;
|
||||
case 1: modeWineQualityStatistics = "KMW/1"; break;
|
||||
case 2: modeWineQualityStatistics = "KMW/2"; break;
|
||||
case 3: modeWineQualityStatistics = "KMW/5"; break;
|
||||
case 4: modeWineQualityStatistics = "KMW/10"; break;
|
||||
}
|
||||
string orderingMemberList = "MGNR";
|
||||
switch (OrderingMemberList) {
|
||||
case 0: orderingMemberList = "MGNR"; break;
|
||||
case 1: orderingMemberList = "NAME"; break;
|
||||
case 2: orderingMemberList = "KG"; break;
|
||||
}
|
||||
string exportEbicsAddress = "FULL";
|
||||
switch (ExportEbicsAddress) {
|
||||
case 0: exportEbicsAddress = "OMIT"; break;
|
||||
case 1: exportEbicsAddress = "LINES"; break;
|
||||
case 2: exportEbicsAddress = "FULL"; break;
|
||||
}
|
||||
string autoAdjust = $"{AutoAdjustBs.AllowanceKg};{AutoAdjustBs.AllowanceBs?.ToString(CultureInfo.InvariantCulture)};" +
|
||||
$"{AutoAdjustBs.AllowanceKgPerBs};{AutoAdjustBs.AllowancePercent?.ToString(CultureInfo.InvariantCulture)};" +
|
||||
$"{AutoAdjustBs.MinBs}";
|
||||
return [
|
||||
("CLIENT_NAME_TOKEN", NameToken),
|
||||
("CLIENT_NAME_SHORT", NameShort),
|
||||
@ -157,13 +204,17 @@ namespace Elwig.Helpers {
|
||||
("CLIENT_BIC", Bic),
|
||||
("CLIENT_IBAN", Iban),
|
||||
("MODE_DELIVERYNOTE_STATS", deliveryNoteStats),
|
||||
("MODE_WINEQUALITYSTATISTICS", modeWineQualityStatistics),
|
||||
("ORDERING_MEMBERLIST", orderingMemberList),
|
||||
("DOCUMENT_SENDER", Sender2),
|
||||
("TEXT_DELIVERYNOTE", TextDeliveryNote),
|
||||
("TEXT_DELIVERYCONFIRMATION", TextDeliveryConfirmation),
|
||||
("TEXT_CREDITNOTE", TextCreditNote),
|
||||
("TEXT_EMAIL_SUBJECT", TextEmailSubject),
|
||||
("TEXT_EMAIL_BODY", TextEmailBody)
|
||||
("TEXT_EMAIL_BODY", TextEmailBody),
|
||||
("EXPORT_EBICS_VERSION", ExportEbicsVersion.ToString()),
|
||||
("EXPORT_EBICS_ADDRESS", exportEbicsAddress),
|
||||
("AUTOADJUST_BUSINESSSHARES", autoAdjust),
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -13,10 +13,11 @@ namespace Elwig.Helpers {
|
||||
public string? Empty;
|
||||
public string? Filling;
|
||||
public string? Limit;
|
||||
public bool Required;
|
||||
public string? Log;
|
||||
public string? _Log;
|
||||
|
||||
public ScaleConfig(string id, string? type, string? model, string? cnx, string? empty, string? filling, string? limit, string? log) {
|
||||
public ScaleConfig(string id, string? type, string? model, string? cnx, string? empty, string? filling, string? limit, bool? required, string? log) {
|
||||
Id = id;
|
||||
Type = type;
|
||||
Model = model;
|
||||
@ -24,6 +25,7 @@ namespace Elwig.Helpers {
|
||||
Empty = empty;
|
||||
Filling = filling;
|
||||
Limit = limit;
|
||||
Required = required ?? true;
|
||||
_Log = log;
|
||||
Log = log != null ? Path.Combine(App.DataPath, log) : null;
|
||||
}
|
||||
@ -41,6 +43,9 @@ namespace Elwig.Helpers {
|
||||
public string? Branch = null;
|
||||
public string? UpdateUrl = null;
|
||||
public bool UpdateAuto = false;
|
||||
public string? SyncUrl = null;
|
||||
public string SyncUsername = "";
|
||||
public string SyncPassword = "";
|
||||
|
||||
public string? SmtpHost = null;
|
||||
public int? SmtpPort = null;
|
||||
@ -71,6 +76,9 @@ namespace Elwig.Helpers {
|
||||
Debug = TrueValues.Contains(config["general:debug"]?.ToLower());
|
||||
UpdateUrl = config["update:url"];
|
||||
UpdateAuto = TrueValues.Contains(config["update:auto"]?.ToLower());
|
||||
SyncUrl = config["sync:url"];
|
||||
SyncUsername = config["sync:username"] ?? "";
|
||||
SyncPassword = config["sync:password"] ?? "";
|
||||
|
||||
SmtpHost = config["smtp:host"];
|
||||
SmtpPort = config["smtp:port"]?.All(char.IsAsciiDigit) == true && config["smtp:port"]?.Length > 0 ? int.Parse(config["smtp:port"]!) : null;
|
||||
@ -85,7 +93,9 @@ namespace Elwig.Helpers {
|
||||
foreach (var s in scales) {
|
||||
ScaleList.Add(new(
|
||||
s, config[$"scale.{s}:type"], config[$"scale.{s}:model"], config[$"scale.{s}:connection"],
|
||||
config[$"scale.{s}:empty"], config[$"scale.{s}:filling"], config[$"scale.{s}:limit"], config[$"scale.{s}:log"]
|
||||
config[$"scale.{s}:empty"], config[$"scale.{s}:filling"], config[$"scale.{s}:limit"],
|
||||
config[$"scale.{s}:required"] != null ? TrueValues.Contains(config[$"scale.{s}:required"]?.ToLower()) : null,
|
||||
config[$"scale.{s}:log"]
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -102,20 +102,6 @@ namespace Elwig.Helpers {
|
||||
selector.SelectedItem = selItem;
|
||||
}
|
||||
|
||||
public static void RenewItemsSource(Xceed.Wpf.Toolkit.Primitives.Selector selector, IEnumerable? source, Xceed.Wpf.Toolkit.Primitives.ItemSelectionChangedEventHandler? handler = null) {
|
||||
if (selector.ItemsSource == source)
|
||||
return;
|
||||
var selectedIds = selector.SelectedItems.Cast<object>().Select(i => Utils.GetEntityIdentifier(i)).ToList();
|
||||
if (handler != null && selectedIds != null) selector.ItemSelectionChanged -= handler;
|
||||
selector.ItemsSource = source;
|
||||
if (source != null) {
|
||||
selector.SelectedItems.Clear();
|
||||
foreach (var i in source.Cast<object>().Where(i => selectedIds.Contains(Utils.GetEntityIdentifier(i))))
|
||||
selector.SelectedItems.Add(i);
|
||||
}
|
||||
if (handler != null && selectedIds != null) selector.ItemSelectionChanged += handler;
|
||||
}
|
||||
|
||||
public static void RenewItemsSource(DataGrid dataGrid, IEnumerable? source, SelectionChangedEventHandler? handler = null, RenewSourceDefault def = RenewSourceDefault.None, bool keepSort = true) {
|
||||
if (dataGrid.ItemsSource == source)
|
||||
return;
|
||||
@ -148,19 +134,31 @@ namespace Elwig.Helpers {
|
||||
public static void RenewItemsSource(ListBox listBox, IEnumerable? source, SelectionChangedEventHandler? handler = null, RenewSourceDefault def = RenewSourceDefault.None) {
|
||||
if (listBox.ItemsSource == source)
|
||||
return;
|
||||
var selectedId = Utils.GetEntityIdentifier(listBox.SelectedItem);
|
||||
object? selItem = null;
|
||||
if (selectedId != 0 && source != null)
|
||||
selItem = source.Cast<object>().FirstOrDefault(i => selectedId.Equals(Utils.GetEntityIdentifier(i)));
|
||||
if (source != null && selItem == null) {
|
||||
if ((def == RenewSourceDefault.IfOnly && source.Cast<object>().Count() == 1) || def == RenewSourceDefault.First) {
|
||||
selItem = source.Cast<object>().FirstOrDefault();
|
||||
if (listBox.SelectionMode == SelectionMode.Single) {
|
||||
var selectedId = Utils.GetEntityIdentifier(listBox.SelectedItem);
|
||||
object? selItem = null;
|
||||
if (selectedId != 0 && source != null)
|
||||
selItem = source.Cast<object>().FirstOrDefault(i => selectedId.Equals(Utils.GetEntityIdentifier(i)));
|
||||
if (source != null && selItem == null) {
|
||||
if ((def == RenewSourceDefault.IfOnly && source.Cast<object>().Count() == 1) || def == RenewSourceDefault.First) {
|
||||
selItem = source.Cast<object>().FirstOrDefault();
|
||||
}
|
||||
}
|
||||
if (handler != null && selItem != null) listBox.SelectionChanged -= handler;
|
||||
listBox.ItemsSource = source;
|
||||
if (handler != null && selItem != null) listBox.SelectionChanged += handler;
|
||||
listBox.SelectedItem = selItem;
|
||||
} else {
|
||||
var selectedIds = listBox.SelectedItems.Cast<object>().Select(Utils.GetEntityIdentifier).ToList();
|
||||
if (handler != null && selectedIds != null) listBox.SelectionChanged -= handler;
|
||||
listBox.ItemsSource = source;
|
||||
if (source != null && selectedIds != null) {
|
||||
listBox.SelectedItems.Clear();
|
||||
foreach (var i in source.Cast<object>().Where(i => selectedIds.Contains(Utils.GetEntityIdentifier(i))))
|
||||
listBox.SelectedItems.Add(i);
|
||||
}
|
||||
if (handler != null && selectedIds != null) listBox.SelectionChanged += handler;
|
||||
}
|
||||
if (handler != null && selItem != null) listBox.SelectionChanged -= handler;
|
||||
listBox.ItemsSource = source;
|
||||
if (handler != null && selItem != null) listBox.SelectionChanged += handler;
|
||||
listBox.SelectedItem = selItem;
|
||||
}
|
||||
|
||||
public static object? GetItemFromSource(IEnumerable source, int? hash) {
|
||||
@ -210,15 +208,15 @@ namespace Elwig.Helpers {
|
||||
return GetItemsFromSource(source, items.Select(Utils.GetEntityIdentifier));
|
||||
}
|
||||
|
||||
public static void SelectItems(Xceed.Wpf.Toolkit.CheckComboBox ccb, IEnumerable<int?>? ids) {
|
||||
ccb.SelectedItems.Clear();
|
||||
public static void SelectItems(ListBox lb, IEnumerable<int?>? ids) {
|
||||
lb.SelectedItems.Clear();
|
||||
if (ids == null) return;
|
||||
foreach (var id in ids)
|
||||
ccb.SelectedItems.Add(GetItemFromSource(ccb.ItemsSource, id));
|
||||
lb.SelectedItems.Add(GetItemFromSource(lb.ItemsSource, id));
|
||||
}
|
||||
|
||||
public static void SelectItems(Xceed.Wpf.Toolkit.CheckComboBox ccb, IEnumerable<object>? items) {
|
||||
SelectItems(ccb, items?.Select(Utils.GetEntityIdentifier));
|
||||
public static void SelectItems(ListBox lb, IEnumerable<object>? items) {
|
||||
SelectItems(lb, items?.Select(Utils.GetEntityIdentifier));
|
||||
}
|
||||
|
||||
public static int? GetInputHashCode(Control input) {
|
||||
@ -226,8 +224,8 @@ namespace Elwig.Helpers {
|
||||
return Utils.GetEntityIdentifier(tb.Text);
|
||||
} else if (input is ComboBox sb) {
|
||||
return Utils.GetEntityIdentifier(sb.SelectedItem);
|
||||
} else if (input is Xceed.Wpf.Toolkit.CheckComboBox ccb) {
|
||||
return Utils.GetEntityIdentifier(ccb.SelectedItems);
|
||||
} else if (input is ListBox lb) {
|
||||
return Utils.GetEntityIdentifier(lb.SelectedItems);
|
||||
} else if (input is CheckBox cb) {
|
||||
return Utils.GetEntityIdentifier(cb.IsChecked);
|
||||
} else if (input is RadioButton rb) {
|
||||
|
@ -1,15 +1,17 @@
|
||||
using Elwig.Models;
|
||||
using Elwig.Models.Dtos;
|
||||
using Elwig.Models.Entities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Elwig.Helpers.Export {
|
||||
public class Ebics(PaymentVar variant, string filename, int version) : IBankingExporter {
|
||||
public class Ebics(PaymentVar variant, string filename, int version, Ebics.AddressMode mode = Ebics.AddressMode.Full) : IBankingExporter {
|
||||
|
||||
public enum AddressMode { Omit = 0, Lines = 1, Full = 2 }
|
||||
|
||||
public static string FileExtension => "xml";
|
||||
|
||||
@ -19,6 +21,7 @@ namespace Elwig.Helpers.Export {
|
||||
private readonly string Name = variant.Name;
|
||||
private readonly int AvNr = variant.AvNr;
|
||||
private readonly int Version = version;
|
||||
private readonly AddressMode ShowAddresses = mode;
|
||||
|
||||
public void Dispose() {
|
||||
GC.SuppressFinalize(this);
|
||||
@ -35,8 +38,11 @@ namespace Elwig.Helpers.Export {
|
||||
}
|
||||
|
||||
public async Task ExportAsync(IEnumerable<Transaction> transactions, IProgress<double>? progress = null) {
|
||||
if (transactions.Any(tx => tx.Amount < 0))
|
||||
if (transactions.Any(tx => tx.Amount < 0)) {
|
||||
throw new ArgumentException("Tranaction amount may not be negative");
|
||||
} else if (App.Client.Iban == null) {
|
||||
throw new ArgumentException("Client IBAN has to be set");
|
||||
}
|
||||
progress?.Report(0.0);
|
||||
var nbOfTxs = transactions.Count();
|
||||
int count = nbOfTxs + 2, i = 0;
|
||||
@ -78,11 +84,18 @@ namespace Elwig.Helpers.Export {
|
||||
<Amt><InstdAmt Ccy="{tx.Currency}">{Transaction.FormatAmount(tx.Amount)}</InstdAmt></Amt>
|
||||
<Cdtr>
|
||||
<Nm>{SecurityElement.Escape(a.Name[..Math.Min(140, a.Name.Length)])}</Nm>
|
||||
<PstlAdr>
|
||||
<StrtNm>{a1?[..Math.Min(70, a1.Length)]}</StrtNm><BldgNb>{SecurityElement.Escape(a2?[..Math.Min(16, a2.Length)])}</BldgNb>
|
||||
<PstCd>{a.PostalDest.AtPlz?.Plz}</PstCd><TwnNm>{SecurityElement.Escape(a.PostalDest.AtPlz?.Ort.Name)}</TwnNm>
|
||||
<Ctry>{a.PostalDest.Country.Alpha2}</Ctry>
|
||||
</PstlAdr>
|
||||
""");
|
||||
if (ShowAddresses != AddressMode.Omit) {
|
||||
var full = ShowAddresses == AddressMode.Full;
|
||||
await Writer.WriteLineAsync($"""
|
||||
<PstlAdr>{(full ? "" : $"\r\n <Ctry>{a.PostalDest.Country.Alpha2}</Ctry>")}
|
||||
{(full ? $"<StrtNm>{SecurityElement.Escape(a1?[..Math.Min(70, a1.Length)])}</StrtNm> <BldgNb>{SecurityElement.Escape(a2?[..Math.Min(16, a2.Length)])}</BldgNb>" :
|
||||
$"<AdrLine>{SecurityElement.Escape(a.Address[..Math.Min(70, a.Address.Length)])}</AdrLine>")}
|
||||
<{(full ? "PstCd" : "AdrLine")}>{a.PostalDest.AtPlz?.Plz}{(full ? "</PstCd> <TwnNm>" : " ")}{SecurityElement.Escape(a.PostalDest.AtPlz?.Ort.Name)}</{(full ? "TwnNm" : "AdrLine")}>
|
||||
{(full ? $" <Ctry>{a.PostalDest.Country.Alpha2}</Ctry>\r\n " : "")}</PstlAdr>
|
||||
""");
|
||||
}
|
||||
await Writer.WriteLineAsync($"""
|
||||
</Cdtr>
|
||||
<CdtrAcct><Id><IBAN>{tx.Member.Iban!}</IBAN></Id></CdtrAcct>
|
||||
<RmtInf><Ustrd>{SecurityElement.Escape(info)}</Ustrd></RmtInf>
|
||||
|
251
Elwig/Helpers/Export/ElwigData.cs
Normal file
251
Elwig/Helpers/Export/ElwigData.cs
Normal file
@ -0,0 +1,251 @@
|
||||
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;
|
||||
|
||||
namespace Elwig.Helpers.Export {
|
||||
public static class ElwigData {
|
||||
|
||||
public static readonly string ImportedTxt = Path.Combine(App.DataPath, "imported.txt");
|
||||
|
||||
public static async Task<string[]> GetImportedFiles() {
|
||||
try {
|
||||
return await File.ReadAllLinesAsync(ImportedTxt, Utils.UTF8);
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task AddImportedFiles(IEnumerable<string> filenames) {
|
||||
await File.AppendAllLinesAsync(ImportedTxt, filenames, Utils.UTF8);
|
||||
}
|
||||
|
||||
public static Task Import(string filename, bool interactive) => Import([filename], interactive);
|
||||
|
||||
public static async Task Import(IEnumerable<string> filenames, bool interactive) {
|
||||
try {
|
||||
using var ctx = new AppDbContext();
|
||||
var currentDids = await ctx.Deliveries
|
||||
.GroupBy(d => d.Year)
|
||||
.ToDictionaryAsync(g => g.Key, g => g.Max(d => d.DId));
|
||||
|
||||
var deliveries = new List<Delivery>();
|
||||
var deliveryParts = new List<DeliveryPart>();
|
||||
var modifiers = new List<DeliveryPartModifier>();
|
||||
|
||||
var metaData = new List<(string Name, int DeliveryNum, string Filters)>();
|
||||
|
||||
foreach (var filename in filenames) {
|
||||
using var zip = ZipFile.Open(filename, ZipArchiveMode.Read);
|
||||
|
||||
var version = zip.GetEntry("version");
|
||||
using (var reader = new StreamReader(version!.Open(), Utils.UTF8)) {
|
||||
if (await reader.ReadToEndAsync() != "elwig:1")
|
||||
throw new FileFormatException("Ungültige Export-Datei");
|
||||
}
|
||||
|
||||
var metaJson = zip.GetEntry("meta.json");
|
||||
var meta = await JsonNode.ParseAsync(metaJson!.Open());
|
||||
var deliveryCount = meta!["deliveries"]?["count"]!.AsValue().GetValue<int>();
|
||||
var deliveryFilters = meta!["deliveries"]?["filters"]!.AsArray().Select(f => f!.AsValue().GetValue<string>()).ToArray();
|
||||
if (deliveryCount != null && deliveryFilters != null)
|
||||
metaData.Add((Path.GetFileName(filename), (int)deliveryCount, string.Join(" / ", deliveryFilters)));
|
||||
|
||||
var membersJson = zip.GetEntry("members.json");
|
||||
if (membersJson != null) {
|
||||
using var reader = new StreamReader(membersJson.Open(), Utils.UTF8);
|
||||
string? line;
|
||||
while ((line = await reader.ReadLineAsync()) != null) {
|
||||
var obj = JsonNode.Parse(line)!.AsObject();
|
||||
// TODO import members.json
|
||||
}
|
||||
}
|
||||
|
||||
var areaComsJson = zip.GetEntry("area_commitments.json");
|
||||
if (areaComsJson != null) {
|
||||
using var reader = new StreamReader(areaComsJson.Open(), Utils.UTF8);
|
||||
string? line;
|
||||
while ((line = await reader.ReadLineAsync()) != null) {
|
||||
var obj = JsonNode.Parse(line)!.AsObject();
|
||||
// TODO import area_commitments.json
|
||||
}
|
||||
}
|
||||
|
||||
var deliveriesJson = zip.GetEntry("deliveries.json");
|
||||
if (deliveriesJson != null) {
|
||||
using var reader = new StreamReader(deliveriesJson.Open(), Utils.UTF8);
|
||||
string? line;
|
||||
while ((line = await reader.ReadLineAsync()) != null) {
|
||||
var obj = JsonNode.Parse(line)!.AsObject();
|
||||
var (d, parts, mods) = JsonToDelivery(obj, currentDids);
|
||||
deliveries.Add(d);
|
||||
deliveryParts.AddRange(parts);
|
||||
modifiers.AddRange(mods);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var lsnrs = deliveries.Select(d => d.LsNr).ToList();
|
||||
var duplicateLsNrs = await ctx.Deliveries
|
||||
.Where(d => lsnrs.Contains(d.LsNr))
|
||||
.Select(d => d.LsNr)
|
||||
.ToListAsync();
|
||||
var duplicateDIds = deliveries
|
||||
.Where(d => duplicateLsNrs.Contains(d.LsNr))
|
||||
.Select(d => (d.Year, d.DId))
|
||||
.ToList();
|
||||
bool overwriteDelivieries = false;
|
||||
if (duplicateLsNrs.Count > 0) {
|
||||
var res = MessageBox.Show($"Sollen {duplicateLsNrs.Count} Lieferungen überschreiben werden?", "Lieferungen überschreiben",
|
||||
MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No);
|
||||
overwriteDelivieries = res == MessageBoxResult.Yes;
|
||||
}
|
||||
if (overwriteDelivieries) {
|
||||
ctx.RemoveRange(ctx.Deliveries.Where(d => duplicateLsNrs.Contains(d.LsNr)));
|
||||
ctx.AddRange(deliveries);
|
||||
ctx.AddRange(deliveryParts);
|
||||
ctx.AddRange(modifiers);
|
||||
} else {
|
||||
ctx.AddRange(deliveries.Where(d => !duplicateDIds.Contains((d.Year, d.DId))));
|
||||
ctx.AddRange(deliveryParts.Where(p => !duplicateDIds.Contains((p.Year, p.DId))));
|
||||
ctx.AddRange(modifiers.Where(m => !duplicateDIds.Contains((m.Year, m.DId))));
|
||||
}
|
||||
await ctx.SaveChangesAsync();
|
||||
await AddImportedFiles(filenames.Select(f => Path.GetFileName(f)));
|
||||
await App.HintContextChange();
|
||||
|
||||
MessageBox.Show(
|
||||
$"Das importieren der Daten war erfolgreich!\n" +
|
||||
$"Folgendes wurde importiert:\n" +
|
||||
$" Lieferungen: {deliveries.Count}\n" +
|
||||
string.Join("\n", metaData.Select(d => $" {d.Name} ({d.DeliveryNum})\n {d.Filters}")) +
|
||||
"\n", "Importieren erfolgreich",
|
||||
MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
} catch (Exception exc) {
|
||||
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task ExportDeliveries(string filename, IEnumerable<Delivery> deliveries, IEnumerable<string> filters) {
|
||||
File.Delete(filename);
|
||||
using var zip = ZipFile.Open(filename, ZipArchiveMode.Create);
|
||||
|
||||
var version = zip.CreateEntry("version", CompressionLevel.NoCompression);
|
||||
using (var writer = new StreamWriter(version.Open(), Utils.UTF8)) {
|
||||
await writer.WriteAsync("elwig:1");
|
||||
}
|
||||
|
||||
var meta = zip.CreateEntry("meta.json", CompressionLevel.NoCompression);
|
||||
using (var writer = new StreamWriter(meta.Open(), Utils.UTF8)) {
|
||||
await writer.WriteAsync(
|
||||
$"{{\"timestamp\": \"{DateTime.UtcNow:yyyy-MM-ddTHH:mm:ssZ}\", " +
|
||||
$"\"zwstid\": \"{App.ZwstId}\", \"device\": \"{Environment.MachineName}\", " +
|
||||
$"\"deliveries\": {{" +
|
||||
$"\"count\": {deliveries.Count()}, " +
|
||||
$"\"parts\": {deliveries.Sum(d => d.Parts.Count)}, " +
|
||||
$"\"filters\": [{string.Join(", ", filters.Select(f => '"' + f + '"'))}]" +
|
||||
$"}}}}");
|
||||
}
|
||||
|
||||
var json = zip.CreateEntry("deliveries.json");
|
||||
using (var writer = new StreamWriter(json.Open(), Utils.UTF8)) {
|
||||
foreach (var d in deliveries) {
|
||||
await writer.WriteLineAsync(DeliveryToJson(d).ToJsonString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static JsonObject DeliveryToJson(Delivery d) {
|
||||
return new JsonObject {
|
||||
["lsnr"] = d.LsNr,
|
||||
["year"] = d.Year,
|
||||
["date"] = $"{d.Date:yyyy-MM-dd}",
|
||||
["zwstid"] = d.ZwstId,
|
||||
["lnr"] = d.LNr,
|
||||
["time"] = d.Time != null ? $"{d.Time:HH:mm:ss}" : null,
|
||||
["mgnr"] = d.MgNr,
|
||||
["parts"] = new JsonArray(d.Parts.OrderBy(p => p.DPNr).Select(p => {
|
||||
var obj = new JsonObject {
|
||||
["dpnr"] = p.DPNr,
|
||||
["sortid"] = p.SortId,
|
||||
["attrid"] = p.AttrId,
|
||||
["cultid"] = p.CultId,
|
||||
["weight"] = p.Weight,
|
||||
["kmw"] = p.Kmw,
|
||||
["qualid"] = p.QualId,
|
||||
["hkid"] = p.HkId,
|
||||
["kgnr"] = p.KgNr,
|
||||
["rdnr"] = p.RdNr,
|
||||
["net_weight"] = p.IsNetWeight,
|
||||
["manual_weighing"] = p.IsManualWeighing,
|
||||
["modids"] = new JsonArray(p.Modifiers.Select(m => (JsonNode)m.ModId).ToArray()),
|
||||
["comment"] = p.Comment,
|
||||
};
|
||||
if (p.IsSplCheck) obj["spl_check"] = p.IsSplCheck;
|
||||
if (p.IsHandPicked != null) obj["hand_picked"] = p.IsHandPicked;
|
||||
if (p.IsLesewagen != null) obj["lesewagen"] = p.IsLesewagen;
|
||||
if (p.IsGebunden != null) obj["gebunden"] = p.IsGebunden;
|
||||
if (p.Temperature != null) obj["temperature"] = p.Temperature;
|
||||
if (p.Acid != null) obj["acid"] = p.Acid;
|
||||
if (p.ScaleId != null) obj["scale_id"] = p.ScaleId;
|
||||
if (p.WeighingId != null) obj["weighing_id"] = p.WeighingId;
|
||||
if (p.WeighingReason != null) obj["weighing_reason"] = p.WeighingReason;
|
||||
return obj;
|
||||
}).ToArray()),
|
||||
["comment"] = d.Comment,
|
||||
};
|
||||
}
|
||||
|
||||
public static (Delivery, List<DeliveryPart>, List<DeliveryPartModifier>) JsonToDelivery(JsonNode json, Dictionary<int, int> currentDids) {
|
||||
var year = json["year"]!.AsValue().GetValue<int>();
|
||||
var did = ++currentDids[year];
|
||||
return (new Delivery {
|
||||
Year = year,
|
||||
DId = did,
|
||||
DateString = json["date"]!.AsValue().GetValue<string>(),
|
||||
TimeString = json["time"]?.AsValue().GetValue<string>(),
|
||||
ZwstId = json["zwstid"]!.AsValue().GetValue<string>(),
|
||||
LNr = json["lnr"]!.AsValue().GetValue<int>(),
|
||||
LsNr = json["lsnr"]!.AsValue().GetValue<string>(),
|
||||
MgNr = json["mgnr"]!.AsValue().GetValue<int>(),
|
||||
Comment = json["comment"]?.AsValue().GetValue<string>(),
|
||||
}, json["parts"]!.AsArray().Select(p => p!.AsObject()).Select(p => new DeliveryPart {
|
||||
Year = year,
|
||||
DId = did,
|
||||
DPNr = p["dpnr"]!.AsValue().GetValue<int>(),
|
||||
SortId = p["sortid"]!.AsValue().GetValue<string>(),
|
||||
AttrId = p["attrid"]?.AsValue().GetValue<string>(),
|
||||
CultId = p["cultid"]?.AsValue().GetValue<string>(),
|
||||
Weight = p["weight"]!.AsValue().GetValue<int>(),
|
||||
Kmw = p["kmw"]!.AsValue().GetValue<double>(),
|
||||
QualId = p["qualid"]!.AsValue().GetValue<string>(),
|
||||
HkId = p["hkid"]!.AsValue().GetValue<string>(),
|
||||
KgNr = p["kgnr"]?.AsValue().GetValue<int>(),
|
||||
RdNr = p["rdnr"]?.AsValue().GetValue<int>(),
|
||||
IsNetWeight = p["net_weight"]!.AsValue().GetValue<bool>(),
|
||||
IsManualWeighing = p["manual_weighing"]!.AsValue().GetValue<bool>(),
|
||||
Comment = p["comment"]?.AsValue().GetValue<string>(),
|
||||
IsSplCheck = p["spl_check"]?.AsValue().GetValue<bool>() ?? false,
|
||||
IsHandPicked = p["hand_picked"]?.AsValue().GetValue<bool>(),
|
||||
IsLesewagen = p["lesewagen"]?.AsValue().GetValue<bool>(),
|
||||
IsGebunden = p["gebunden"]?.AsValue().GetValue<bool>(),
|
||||
Temperature = p["temperature"]?.AsValue().GetValue<double>(),
|
||||
Acid = p["acid"]?.AsValue().GetValue<double>(),
|
||||
ScaleId = p["scale_id"]?.AsValue().GetValue<string>(),
|
||||
WeighingId = p["weighing_id"]?.AsValue().GetValue<string>(),
|
||||
WeighingReason = p["weighing_reason"]?.AsValue().GetValue<string>(),
|
||||
}).ToList(), json["parts"]!.AsArray().SelectMany(p => p!["modids"]!.AsArray().Select(m => new DeliveryPartModifier {
|
||||
Year = year,
|
||||
DId = did,
|
||||
DPNr = p["dpnr"]!.AsValue().GetValue<int>(),
|
||||
ModId = m!.AsValue().GetValue<string>(),
|
||||
})).ToList());
|
||||
}
|
||||
}
|
||||
}
|
@ -302,9 +302,11 @@ namespace Elwig.Helpers.Export {
|
||||
switch (units[0]) {
|
||||
case "%": n = 1; data = $"{v:N1}"; break;
|
||||
case "€": n = 2; data = $"{v:N2}"; break;
|
||||
case "€/kg": n = 4; data = $"{v:N4}"; break;
|
||||
case "°KMW": n = 1; data = $"{v:N1}"; break;
|
||||
case "°Oe": n = 0; data = $"{v:N0}"; break;
|
||||
case "m²": n = 0; data = $"{v:N0}"; break;
|
||||
case "kg": n = 0; data = $"{v:N0}"; break;
|
||||
}
|
||||
if (n >= 0) add = string.Join(' ', add.Split(' ').Select(p => p.StartsWith("table:style-name=") ? $"table:style-name=\"N{n}\"" : p));
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
namespace Elwig.Helpers {
|
||||
public enum ExportMode {
|
||||
Show, SaveList, SavePdf, Print, Email
|
||||
Show, SaveList, SavePdf, Print, Email, Export, Upload
|
||||
}
|
||||
}
|
||||
|
99
Elwig/Helpers/Extensions.cs
Normal file
99
Elwig/Helpers/Extensions.cs
Normal file
@ -0,0 +1,99 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Elwig.Helpers {
|
||||
static partial class Extensions {
|
||||
|
||||
[LibraryImport("msvcrt.dll")]
|
||||
[UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])]
|
||||
private static unsafe partial int memcmp(void* b1, void* b2, long count);
|
||||
|
||||
public static unsafe int CompareBuffers(char[] buffer1, int offset1, char[] buffer2, int offset2, int count) {
|
||||
fixed (char* b1 = buffer1, b2 = buffer2) {
|
||||
return memcmp(b1 + offset1, b2 + offset2, count);
|
||||
}
|
||||
}
|
||||
|
||||
public static string? ReadUntil(this StreamReader reader, string delimiter) {
|
||||
return ReadUntil(reader, delimiter.ToCharArray());
|
||||
}
|
||||
|
||||
public static string? ReadUntil(this StreamReader reader, char delimiter) {
|
||||
return ReadUntil(reader, new char[] { delimiter });
|
||||
}
|
||||
|
||||
public static string? ReadUntil(this StreamReader reader, char[] delimiter) {
|
||||
var buf = new char[512];
|
||||
int bufSize = 0, ret;
|
||||
while (!reader.EndOfStream && bufSize < buf.Length - 1) {
|
||||
if ((ret = reader.Read()) == -1)
|
||||
return null;
|
||||
buf[bufSize++] = (char)ret;
|
||||
|
||||
if (bufSize >= delimiter.Length && CompareBuffers(buf, bufSize - delimiter.Length, delimiter, 0, delimiter.Length) == 0)
|
||||
return new string(buf, 0, bufSize);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Task<string?> ReadUntilAsync(this StreamReader reader, string delimiter) {
|
||||
return ReadUntilAsync(reader, delimiter.ToCharArray());
|
||||
}
|
||||
|
||||
public static Task<string?> ReadUntilAsync(this StreamReader reader, char delimiter) {
|
||||
return ReadUntilAsync(reader, new char[] { delimiter });
|
||||
}
|
||||
|
||||
public static async Task<string?> ReadUntilAsync(this StreamReader reader, char[] delimiter) {
|
||||
var buf = new char[512];
|
||||
int bufSize = 0;
|
||||
var tmpBuf = new char[1];
|
||||
while (!reader.EndOfStream && bufSize < buf.Length - 1) {
|
||||
if ((await reader.ReadAsync(tmpBuf, 0, 1)) != 1)
|
||||
return null;
|
||||
buf[bufSize++] = tmpBuf[0];
|
||||
|
||||
if (bufSize >= delimiter.Length && CompareBuffers(buf, bufSize - delimiter.Length, delimiter, 0, delimiter.Length) == 0)
|
||||
return new string(buf, 0, bufSize);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static async Task CopyToAsync(this Stream source, Stream destination, int bufferSize, IProgress<long>? progress = null, CancellationToken cancellationToken = default) {
|
||||
ArgumentNullException.ThrowIfNull(source);
|
||||
if (!source.CanRead) throw new ArgumentException("Has to be readable", nameof(source));
|
||||
ArgumentNullException.ThrowIfNull(destination);
|
||||
if (!destination.CanWrite) throw new ArgumentException("Has to be writable", nameof(destination));
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(bufferSize);
|
||||
|
||||
var buffer = new byte[bufferSize];
|
||||
long totalBytesRead = 0;
|
||||
int bytesRead;
|
||||
while ((bytesRead = await source.ReadAsync(buffer, cancellationToken).ConfigureAwait(false)) != 0) {
|
||||
await destination.WriteAsync(buffer.AsMemory(0, bytesRead), cancellationToken).ConfigureAwait(false);
|
||||
totalBytesRead += bytesRead;
|
||||
progress?.Report(totalBytesRead);
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task DownloadAsync(this HttpClient client, string requestUri, Stream destination, IProgress<double>? progress = null, CancellationToken cancellationToken = default) {
|
||||
using var response = await client.GetAsync(requestUri, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
|
||||
response.EnsureSuccessStatusCode();
|
||||
var contentLength = response.Content.Headers.ContentLength;
|
||||
|
||||
using var download = await response.Content.ReadAsStreamAsync(cancellationToken);
|
||||
if (progress == null || !contentLength.HasValue) {
|
||||
await download.CopyToAsync(destination, cancellationToken);
|
||||
return;
|
||||
}
|
||||
|
||||
var relativeProgress = new Progress<long>(totalBytes => progress.Report((double)totalBytes / contentLength.Value));
|
||||
await download.CopyToAsync(destination, 81920, relativeProgress, cancellationToken);
|
||||
progress.Report(100.0);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Elwig.Helpers {
|
||||
public static class HttpClientExtensions {
|
||||
public static async Task DownloadAsync(this HttpClient client, string requestUri, Stream destination, IProgress<double>? progress = null, CancellationToken cancellationToken = default) {
|
||||
using var response = await client.GetAsync(requestUri, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
|
||||
var contentLength = response.Content.Headers.ContentLength;
|
||||
|
||||
using var download = await response.Content.ReadAsStreamAsync(cancellationToken);
|
||||
if (progress == null || !contentLength.HasValue) {
|
||||
await download.CopyToAsync(destination, cancellationToken);
|
||||
return;
|
||||
}
|
||||
|
||||
var relativeProgress = new Progress<long>(totalBytes => progress.Report((double)totalBytes / contentLength.Value));
|
||||
await download.CopyToAsync(destination, 81920, relativeProgress, cancellationToken);
|
||||
progress.Report(100.0);
|
||||
}
|
||||
}
|
||||
}
|
@ -59,7 +59,7 @@ namespace Elwig.Helpers.Printing {
|
||||
progress?.Report(0.0);
|
||||
using var client = new TcpClient("127.0.0.1", 30983);
|
||||
using var stream = client.GetStream();
|
||||
await stream.WriteAsync(Encoding.UTF8.GetBytes(
|
||||
await stream.WriteAsync(Utils.UTF8.GetBytes(
|
||||
"-e utf-8;-p;" + (doublePaged ? "-2;" : "") +
|
||||
$"{string.Join(';', htmlPath)};{pdfPath}" +
|
||||
"\r\n"));
|
||||
|
@ -1,25 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Elwig.Helpers {
|
||||
public static class StreamExtensions {
|
||||
public static async Task CopyToAsync(this Stream source, Stream destination, int bufferSize, IProgress<long>? progress = null, CancellationToken cancellationToken = default) {
|
||||
ArgumentNullException.ThrowIfNull(source);
|
||||
if (!source.CanRead) throw new ArgumentException("Has to be readable", nameof(source));
|
||||
ArgumentNullException.ThrowIfNull(destination);
|
||||
if (!destination.CanWrite) throw new ArgumentException("Has to be writable", nameof(destination));
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(bufferSize);
|
||||
|
||||
var buffer = new byte[bufferSize];
|
||||
long totalBytesRead = 0;
|
||||
int bytesRead;
|
||||
while ((bytesRead = await source.ReadAsync(buffer, cancellationToken).ConfigureAwait(false)) != 0) {
|
||||
await destination.WriteAsync(buffer.AsMemory(0, bytesRead), cancellationToken).ConfigureAwait(false);
|
||||
totalBytesRead += bytesRead;
|
||||
progress?.Report(totalBytesRead);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -81,7 +81,7 @@ namespace Elwig.Helpers {
|
||||
return PhoneNrTypes.Where(t => t.Key == type).Select(t => t.Value).FirstOrDefault(type);
|
||||
}
|
||||
|
||||
private static readonly string[] TempWildcards = ["*.html", "*.pdf", "*.exe"];
|
||||
private static readonly string[] TempWildcards = ["*.html", "*.pdf", "*.exe", "*.zip"];
|
||||
|
||||
private static readonly ushort[] Crc16ModbusTable = [
|
||||
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
|
||||
@ -409,21 +409,48 @@ namespace Elwig.Helpers {
|
||||
return InternetGetConnectedState(out var _, 0);
|
||||
}
|
||||
|
||||
public static HttpClient GetHttpClient(string? username = null, string? password = null, string? accept = null) {
|
||||
var client = new HttpClient() {
|
||||
Timeout = TimeSpan.FromSeconds(5),
|
||||
};
|
||||
client.DefaultRequestHeaders.Accept.Clear();
|
||||
if (accept != null)
|
||||
client.DefaultRequestHeaders.Accept.Add(new(accept));
|
||||
if (username != null || password != null)
|
||||
client.DefaultRequestHeaders.Authorization = new("Basic", Convert.ToBase64String(
|
||||
Utils.UTF8.GetBytes($"{username}:{password}")));
|
||||
return client;
|
||||
}
|
||||
|
||||
public static async Task<(string Version, string Url, long Size)?> GetLatestInstallerUrl(string url) {
|
||||
try {
|
||||
using var client = new HttpClient() {
|
||||
Timeout = TimeSpan.FromSeconds(5),
|
||||
};
|
||||
client.DefaultRequestHeaders.Accept.Clear();
|
||||
client.DefaultRequestHeaders.Accept.Add(new("application/json"));
|
||||
var res = JsonNode.Parse(await client.GetStringAsync(url));
|
||||
var data = res!["data"]![0]!;
|
||||
using var client = GetHttpClient(accept: "application/json");
|
||||
var resJson = JsonNode.Parse(await client.GetStringAsync(url));
|
||||
var data = resJson!["data"]![0]!;
|
||||
return ((string)data["version"]!, (string)data["url"]!, (long)data["size"]!);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task UploadExportData(string zip, string url, string username, string password) {
|
||||
if (!url.EndsWith('/')) url += "/";
|
||||
using var client = GetHttpClient(username, password, accept: "application/json");
|
||||
var content = new StreamContent(new FileStream(zip, FileMode.Open, FileAccess.Read));
|
||||
content.Headers.ContentType = new("application/zip");
|
||||
using var res = await client.PutAsync(url + Path.GetFileName(zip), content);
|
||||
res.EnsureSuccessStatusCode();
|
||||
}
|
||||
|
||||
public static async Task<JsonArray> GetExportMetaData(string url, string username, string password) {
|
||||
using var client = GetHttpClient(username, password, accept: "application/json");
|
||||
using var res = await client.GetAsync(url);
|
||||
res.EnsureSuccessStatusCode();
|
||||
var resJson = JsonNode.Parse(await res.Content.ReadAsStringAsync());
|
||||
var data = resJson!["data"]!;
|
||||
return data.AsArray();
|
||||
}
|
||||
|
||||
public static void CleanupTempFiles() {
|
||||
var dir = new DirectoryInfo(App.TempPath);
|
||||
foreach (var file in TempWildcards.SelectMany(dir.EnumerateFiles)) {
|
||||
|
@ -26,6 +26,8 @@ namespace Elwig.Helpers.Weighing {
|
||||
Model = model;
|
||||
IsReady = true;
|
||||
HasFillingClearance = false;
|
||||
Stream.WriteTimeout = -1;
|
||||
Stream.ReadTimeout = -1;
|
||||
BackgroundThread = new Thread(new ParameterizedThreadStart(BackgroundLoop));
|
||||
BackgroundThread.Start();
|
||||
}
|
||||
@ -46,7 +48,8 @@ namespace Elwig.Helpers.Weighing {
|
||||
while (IsRunning) {
|
||||
try {
|
||||
var data = await Receive();
|
||||
RaiseWeighingEvent(new WeighingEventArgs(data));
|
||||
if (data != null)
|
||||
RaiseWeighingEvent(new WeighingEventArgs(data.Value));
|
||||
} catch (Exception ex) {
|
||||
MessageBox.Show($"Beim Wiegen ist ein Fehler Aufgetreten:\n\n{ex.Message}", "Waagenfehler",
|
||||
MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
@ -54,13 +57,12 @@ namespace Elwig.Helpers.Weighing {
|
||||
}
|
||||
}
|
||||
|
||||
protected async Task<WeighingResult> Receive() {
|
||||
string? line = null;
|
||||
using (var reader = new StreamReader(Stream, Encoding.ASCII, false, -1, true)) {
|
||||
line = await reader.ReadLineAsync();
|
||||
if (LogPath != null) await File.AppendAllTextAsync(LogPath, $"{line}\r\n");
|
||||
}
|
||||
if (line == null || line.Length != 33 || line[0] != ' ' || line[9] != ' ' || line[15] != ' ' || line[20] != ' ' || line[32] != ' ') {
|
||||
protected async Task<WeighingResult?> Receive() {
|
||||
var line = await Reader.ReadUntilAsync("\r\n");
|
||||
if (LogPath != null) await File.AppendAllTextAsync(LogPath, line);
|
||||
if (line == null || line == "") {
|
||||
return null;
|
||||
} else if (line.Length != 35 || line[0] != ' ' || line[9] != ' ' || line[15] != ' ' || line[20] != ' ' || line[32] != ' ') {
|
||||
throw new IOException($"Invalid event from scale: '{line}'");
|
||||
}
|
||||
|
||||
|
122
Elwig/Helpers/Weighing/GassnerScale.cs
Normal file
122
Elwig/Helpers/Weighing/GassnerScale.cs
Normal file
@ -0,0 +1,122 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO.Ports;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Elwig.Helpers.Weighing {
|
||||
public class GassnerScale : Scale, ICommandScale {
|
||||
|
||||
public string Manufacturer => "Gassner";
|
||||
public int InternalScaleNr => 1;
|
||||
public string Model { get; private set; }
|
||||
public string ScaleId { get; private set; }
|
||||
public bool IsReady { get; private set; }
|
||||
public bool HasFillingClearance { get; private set; }
|
||||
|
||||
public GassnerScale(string id, string model, string cnx, string? empty = null, string? filling = null, int? limit = null, string? log = null) :
|
||||
base(cnx, empty, filling, limit, log) {
|
||||
ScaleId = id;
|
||||
Model = model;
|
||||
IsReady = true;
|
||||
HasFillingClearance = false;
|
||||
Stream.WriteTimeout = 250;
|
||||
Stream.ReadTimeout = 11000;
|
||||
}
|
||||
|
||||
protected Task SendCommand(char command) => SendCommand(Convert.ToByte(command));
|
||||
|
||||
protected async Task SendCommand(byte command) {
|
||||
byte[] cmd = [command];
|
||||
await Stream.WriteAsync(cmd);
|
||||
if (LogPath != null) await File.AppendAllTextAsync(LogPath, Encoding.ASCII.GetString(cmd));
|
||||
}
|
||||
|
||||
protected async Task<string> ReceiveResponse() {
|
||||
var line = await Reader.ReadUntilAsync('\x03');
|
||||
if (LogPath != null) await File.AppendAllTextAsync(LogPath, $"{line}\r\n");
|
||||
if (line == null || line.Length < 4 || !line.StartsWith('\x02')) {
|
||||
throw new IOException("Invalid response from scale");
|
||||
}
|
||||
|
||||
var status = line[1..3];
|
||||
if (status[0] == 'E' || status[1] != 'S') {
|
||||
string msg = $"Unbekannter Fehler (Fehler code {status})";
|
||||
switch (status[1]) {
|
||||
case 'M': msg = "Waage in Bewegung"; break;
|
||||
}
|
||||
throw new IOException($"Waagenfehler {status}: {msg}");
|
||||
} else if (status[0] != ' ') {
|
||||
throw new IOException($"Invalid response from scale (error code {status})");
|
||||
}
|
||||
|
||||
return line[1..^1];
|
||||
}
|
||||
|
||||
protected async Task<WeighingResult> Weigh(bool incIdentNr) {
|
||||
await SendCommand(incIdentNr ? '\x05' : '?');
|
||||
string record = await ReceiveResponse();
|
||||
if (record.Length != 45)
|
||||
throw new IOException("Invalid response from scale: Received record has invalid size");
|
||||
var line = record[2..];
|
||||
|
||||
var status = line[ 0.. 2];
|
||||
var brutto = line[ 2.. 9].Trim();
|
||||
var tara = line[ 9..16].Trim();
|
||||
var netto = line[16..23].Trim();
|
||||
var scaleNr = line[23..25].Trim();
|
||||
var identNr = line[25..31].Trim();
|
||||
var date = line[31..39];
|
||||
var time = line[39..45];
|
||||
|
||||
identNr = identNr.Length > 0 && identNr != "0" ? identNr : null;
|
||||
var parsedDate = DateOnly.ParseExact(date, "yyyyMMdd");
|
||||
return new() {
|
||||
Weight = int.Parse(netto),
|
||||
WeighingId = identNr,
|
||||
FullWeighingId = identNr,
|
||||
Date = parsedDate,
|
||||
Time = TimeOnly.ParseExact(time, "HHmmss"),
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<WeighingResult> Weigh() {
|
||||
return await Weigh(true);
|
||||
}
|
||||
|
||||
public async Task<WeighingResult> GetCurrentWeight() {
|
||||
return await Weigh(false);
|
||||
}
|
||||
|
||||
public async Task Empty() {
|
||||
SerialPort? p = ControlSerialEmpty ?? Serial;
|
||||
if (EmptyMode == Output.RTS && p != null) {
|
||||
p.RtsEnable = true;
|
||||
await Task.Delay(EmptyDelay);
|
||||
p.RtsEnable = false;
|
||||
} else if (EmptyMode == Output.DTR && p != null) {
|
||||
p.DtrEnable = true;
|
||||
await Task.Delay(EmptyDelay);
|
||||
p.DtrEnable = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected Task SetFillingClearance(bool status) {
|
||||
SerialPort? p = ControlSerialFilling ?? Serial;
|
||||
if (FillingClearanceMode == Output.RTS && p != null) {
|
||||
p.RtsEnable = status;
|
||||
} else if (FillingClearanceMode == Output.DTR && p != null) {
|
||||
p.DtrEnable = status;
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async Task GrantFillingClearance() {
|
||||
await SetFillingClearance(true);
|
||||
}
|
||||
|
||||
public async Task RevokeFillingClearance() {
|
||||
await SetFillingClearance(false);
|
||||
}
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
using System.IO;
|
||||
using System.Net.Sockets;
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace Elwig.Helpers.Weighing {
|
||||
public abstract class Scale : IDisposable {
|
||||
@ -12,6 +13,7 @@ namespace Elwig.Helpers.Weighing {
|
||||
protected SerialPort? ControlSerialEmpty = null, ControlSerialFilling = null;
|
||||
protected TcpClient? Tcp = null;
|
||||
protected Stream Stream;
|
||||
protected StreamReader Reader;
|
||||
|
||||
protected readonly Output? EmptyMode = null;
|
||||
protected readonly Output? FillingClearanceMode = null;
|
||||
@ -26,6 +28,8 @@ namespace Elwig.Helpers.Weighing {
|
||||
return new SysTecITScale(config.Id, config.Model!, config.Connection!, config.Empty, config.Filling, limit, config.Log);
|
||||
} else if (config.Type == "Avery-Async") {
|
||||
return new AveryEventScale(config.Id, config.Model!, config.Connection!, config.Empty, config.Filling, limit, config.Log);
|
||||
} else if (config.Type == "Gassner") {
|
||||
return new GassnerScale(config.Id, config.Model!, config.Connection!, config.Empty, config.Filling, limit, config.Log);
|
||||
} else {
|
||||
throw new ArgumentException($"Invalid scale type: \"{config.Type}\"");
|
||||
}
|
||||
@ -41,6 +45,7 @@ namespace Elwig.Helpers.Weighing {
|
||||
} else {
|
||||
throw new ArgumentException($"Unsupported scheme: \"{cnx.Split(':')[0]}\"");
|
||||
}
|
||||
Reader = new(Stream, Encoding.ASCII, false, 512);
|
||||
|
||||
LogPath = log;
|
||||
|
||||
@ -73,6 +78,7 @@ namespace Elwig.Helpers.Weighing {
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
Reader.Close();
|
||||
Stream.Close();
|
||||
Serial?.Close();
|
||||
ControlSerialEmpty?.Close();
|
||||
|
@ -31,12 +31,9 @@ namespace Elwig.Helpers.Weighing {
|
||||
}
|
||||
|
||||
protected async Task<string> ReceiveResponse() {
|
||||
string? line = null;
|
||||
using (var reader = new StreamReader(Stream, Encoding.ASCII, false, -1, true)) {
|
||||
line = await reader.ReadLineAsync();
|
||||
if (LogPath != null) await File.AppendAllTextAsync(LogPath, $"{line}\r\n");
|
||||
}
|
||||
if (line == null || line.Length < 4 || !line.StartsWith('<') || !line.EndsWith('>')) {
|
||||
var line = await Reader.ReadUntilAsync("\r\n");
|
||||
if (LogPath != null) await File.AppendAllTextAsync(LogPath, line);
|
||||
if (line == null || line.Length < 4 || !line.StartsWith('<') || !line.EndsWith(">\r\n")) {
|
||||
throw new IOException("Invalid response from scale");
|
||||
}
|
||||
|
||||
@ -68,7 +65,7 @@ namespace Elwig.Helpers.Weighing {
|
||||
throw new IOException($"Invalid response from scale (error code {error})");
|
||||
}
|
||||
|
||||
return line[1..^1];
|
||||
return line[1..^3];
|
||||
}
|
||||
|
||||
protected async Task<WeighingResult> Weigh(bool incIdentNr) {
|
||||
@ -82,7 +79,7 @@ namespace Elwig.Helpers.Weighing {
|
||||
var date = line[ 2..10];
|
||||
var time = line[10..15];
|
||||
var identNr = line[15..19].Trim();
|
||||
var scaleNr = line[19..20];
|
||||
var scaleNr = line[19..20].Trim();
|
||||
var brutto = line[20..28].Trim();
|
||||
var tara = line[28..36].Trim();
|
||||
var netto = line[36..44].Trim();
|
||||
|
@ -42,8 +42,9 @@ namespace Elwig.Models.Dtos {
|
||||
public static async Task<CreditNoteData> ForPaymentVariant(AppDbContext ctx, int year, int avnr) {
|
||||
var variant = await ctx.PaymentVariants.FindAsync(year, avnr);
|
||||
var name = variant!.Name;
|
||||
var bsPenalty = await ctx.GetBusinessSharePenalties(year);
|
||||
var data = BillingData.FromJson(variant!.Data);
|
||||
var rows = (await FromDbSet(ctx.CreditNoteRows, year, avnr)).Select(r => new CreditNoteRow(r, data)).ToList();
|
||||
var rows = (await FromDbSet(ctx.CreditNoteRows, year, avnr)).Select(r => new CreditNoteRow(r, data, bsPenalty)).ToList();
|
||||
return new CreditNoteData(rows, year, name);
|
||||
}
|
||||
|
||||
@ -56,7 +57,6 @@ namespace Elwig.Models.Dtos {
|
||||
p.amount - p.net_amount AS surcharge,
|
||||
c.net_amount, c.prev_net_amount, c.vat, c.vat_amount, c.gross_amount, c.modifiers, c.prev_modifiers, c.amount,
|
||||
ROUND(COALESCE(u.total_penalty, 0) / POW(10, 4 - 2)) AS fb_penalty,
|
||||
ROUND(COALESCE(b.total_penalty, 0) / POW(10, s.precision - 2)) AS bs_penalty,
|
||||
ROUND(COALESCE(a.total_amount, 0) / POW(10, s.precision - 2)) AS auto_bs
|
||||
FROM credit c
|
||||
LEFT JOIN member m ON m.mgnr = c.mgnr
|
||||
@ -65,7 +65,6 @@ namespace Elwig.Models.Dtos {
|
||||
LEFT JOIN AT_ort o ON o.okz = p.okz
|
||||
LEFT JOIN season s ON s.year = c.year
|
||||
LEFT JOIN v_penalty_area_commitments u ON (u.year, u.mgnr) = (s.year, m.mgnr)
|
||||
LEFT JOIN v_penalty_business_shares b ON (b.year, b.mgnr) = (s.year, m.mgnr)
|
||||
LEFT JOIN v_auto_business_shares a ON (a.year, a.mgnr) = (s.year, m.mgnr)
|
||||
WHERE c.year = {year} AND c.avnr = {avnr}
|
||||
ORDER BY m.mgnr
|
||||
@ -96,7 +95,7 @@ namespace Elwig.Models.Dtos {
|
||||
public decimal? Considered;
|
||||
public decimal Amount;
|
||||
|
||||
public CreditNoteRow(CreditNoteRowSingle row, BillingData data) {
|
||||
public CreditNoteRow(CreditNoteRowSingle row, BillingData data, Dictionary<int, long> bsPenalty) {
|
||||
byte prec1 = 2, prec2 = row.Precision;
|
||||
MgNr = row.MgNr;
|
||||
Name1 = row.Name1;
|
||||
@ -120,7 +119,7 @@ namespace Elwig.Models.Dtos {
|
||||
if (data.ConsiderContractPenalties)
|
||||
Penalties = (row.FbPenalty == null || row.FbPenalty == 0) ? null : Utils.DecFromDb((long)row.FbPenalty, prec1);
|
||||
if (data.ConsiderTotalPenalty)
|
||||
Penalty = (row.BsPealty == null || row.BsPealty == 0) ? null : Utils.DecFromDb((long)row.BsPealty, prec1);
|
||||
Penalty = (!bsPenalty.TryGetValue(row.MgNr, out var val) || val == 0) ? null : Utils.DecFromDb(val, prec1);
|
||||
if (data.ConsiderAutoBusinessShares)
|
||||
AutoBs = (row.AutoBs == null || row.AutoBs == 0) ? null : -Utils.DecFromDb((long)row.AutoBs, prec1);
|
||||
mod -= (Penalties ?? 0) + (Penalty ?? 0) + (AutoBs ?? 0);
|
||||
@ -175,8 +174,6 @@ namespace Elwig.Models.Dtos {
|
||||
public long Amount { get; set; }
|
||||
[Column("fb_penalty")]
|
||||
public long? FbPenalty { get; set; }
|
||||
[Column("bs_penalty")]
|
||||
public long? BsPealty { get; set; }
|
||||
[Column("auto_bs")]
|
||||
public long? AutoBs { get; set; }
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Threading.Tasks;
|
||||
@ -39,7 +38,7 @@ namespace Elwig.Models.Dtos {
|
||||
LEFT JOIN AT_ort o ON o.okz = p.okz
|
||||
LEFT JOIN season s ON s.year = {year}
|
||||
LEFT JOIN v_delivery d ON d.mgnr = m.mgnr AND d.year = s.year
|
||||
WHERE m.active = 1
|
||||
WHERE m.active = TRUE OR d.weight > 0
|
||||
GROUP BY d.year, m.mgnr
|
||||
ORDER BY 100.0 * sum / max_kg, m.mgnr;
|
||||
""").ToListAsync();
|
||||
|
104
Elwig/Models/Dtos/PaymentVariantSummaryData.cs
Normal file
104
Elwig/Models/Dtos/PaymentVariantSummaryData.cs
Normal file
@ -0,0 +1,104 @@
|
||||
using Elwig.Documents;
|
||||
using Elwig.Helpers;
|
||||
using Elwig.Models.Entities;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Data.Entity.Core.Common.CommandTrees.ExpressionBuilder;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Elwig.Models.Dtos {
|
||||
public class PaymentVariantSummaryData : DataTable<PaymentVariantSummaryData.PaymentRow> {
|
||||
|
||||
private static readonly (string, string, string?, int?)[] FieldNames = [
|
||||
("Type", "Typ", null, 10),
|
||||
("Variety", "Sorte", null, 40),
|
||||
("Attribute", "Attribut", null, 20),
|
||||
("Cultivation", "Bewirt.", null, 20),
|
||||
("QualityLevel", "Qualitätsstufe", null, 30),
|
||||
("Oe", "Gradation", "°Oe", 20),
|
||||
("Ungeb", "ungebunden", "kg|€/kg", 40),
|
||||
("Geb", "gebunden", "kg|€/kg", 40),
|
||||
("Amount", "Gesamt", "€", 25),
|
||||
];
|
||||
|
||||
public record struct PaymentRow(
|
||||
string Type,
|
||||
string Variety,
|
||||
string? Attribute,
|
||||
string? Cultivation,
|
||||
string QualityLevel,
|
||||
double Oe,
|
||||
(int Weight, decimal? Price) Ungeb,
|
||||
(int Weight, decimal? Price) Geb,
|
||||
decimal Amount
|
||||
);
|
||||
|
||||
public PaymentVariantSummaryData(PaymentVar v, IEnumerable<PaymentRow> rows) :
|
||||
base($"{PaymentVariantSummary.Name} {v.Year}", $"{PaymentVariantSummary.Name} Lese {v.Year}", v.Name, rows, FieldNames) {
|
||||
}
|
||||
|
||||
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),
|
||||
Utils.DecFromDb(r.Amount, v.Season.Precision)))
|
||||
.ToArray());
|
||||
}
|
||||
|
||||
private static async Task<IEnumerable<PaymentVariantSummaryRow>> FromDbSet(DbSet<PaymentVariantSummaryRow> table, int year, int avnr) {
|
||||
return await table.FromSqlRaw($"""
|
||||
SELECT v.type AS type,
|
||||
v.name AS variety,
|
||||
a.name AS attribute,
|
||||
c.name AS cultivation,
|
||||
q.name AS quality_level,
|
||||
ROUND(kmw * (4.54 + 0.022 * kmw)) AS oe,
|
||||
SUM(IIF(w.discr = '_', w.value, 0)) AS weight_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,
|
||||
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}
|
||||
GROUP BY variety, attribute, cultivation, q.min_kmw, oe
|
||||
ORDER BY variety, attribute, cultivation, q.min_kmw, oe
|
||||
""").ToListAsync();
|
||||
}
|
||||
}
|
||||
|
||||
[Keyless]
|
||||
public class PaymentVariantSummaryRow {
|
||||
[Column("type")]
|
||||
public required string Type { get; set; }
|
||||
[Column("variety")]
|
||||
public required string Variety { get; set; }
|
||||
[Column("attribute")]
|
||||
public string? Attribute { get; set; }
|
||||
[Column("cultivation")]
|
||||
public string? Cultivation { get; set; }
|
||||
[Column("quality_level")]
|
||||
public required string QualityLevel { get; set; }
|
||||
[Column("oe")]
|
||||
public double Oe { get; set; }
|
||||
[Column("weight_ungeb")]
|
||||
public int WeightUngeb { get; set; }
|
||||
[Column("price_ungeb")]
|
||||
public long? PriceUngeb { get; set; }
|
||||
[Column("weight_geb")]
|
||||
public int WeightGeb { get; set; }
|
||||
[Column("price_geb")]
|
||||
public long? PriceGeb { get; set; }
|
||||
[Column("amount")]
|
||||
public long Amount { get; set; }
|
||||
}
|
||||
}
|
58
Elwig/Models/Dtos/WeightBreakdownData.cs
Normal file
58
Elwig/Models/Dtos/WeightBreakdownData.cs
Normal file
@ -0,0 +1,58 @@
|
||||
using Elwig.Models.Entities;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Elwig.Models.Dtos {
|
||||
public class WeightBreakdownData : DataTable<WeightBreakdownRow> {
|
||||
|
||||
private static readonly (string, string, string?, int?)[] FieldNames = [
|
||||
("Type", "R/W", null, 10),
|
||||
("SortId", "Sorte", null, 10),
|
||||
("AttrId", "Attr.", null, 10),
|
||||
("CultId", "Bewirt.", null, 15),
|
||||
("QualId", "Qual.", null, 15),
|
||||
("Geb", "gebunden", null, 20),
|
||||
("Weight", "Gewicht", "kg", 20),
|
||||
];
|
||||
|
||||
public WeightBreakdownData(IEnumerable<WeightBreakdownRow> rows, int year, string name) :
|
||||
base(name, $"Sorten-/Qualitätsaufschlüsselung {year}", name, rows, FieldNames) {
|
||||
}
|
||||
|
||||
public static async Task<WeightBreakdownData> ForSeason(DbSet<WeightBreakdownRow> table, int year, Branch? branch = null) {
|
||||
return new(await FromDbSet(table, year, branch?.ZwstId), year, branch?.Name ?? "Gesamt");
|
||||
}
|
||||
|
||||
private static async Task<IEnumerable<WeightBreakdownRow>> FromDbSet(DbSet<WeightBreakdownRow> table, int year, string? zwstid) {
|
||||
zwstid = zwstid == null ? "NULL" : $"'{zwstid}'";
|
||||
return await table.FromSqlRaw($"""
|
||||
SELECT type, sortid, attrid, cultid, v.qualid, geb, SUM(weight) AS weight
|
||||
FROM v_stat_total v
|
||||
LEFT JOIN wine_quality_level q ON q.qualid = v.qualid
|
||||
WHERE year = {year} AND ({zwstid} IS NULL OR zwstid = {zwstid})
|
||||
GROUP BY type, sortid, attrid, cultid, v.qualid, geb
|
||||
ORDER BY type DESC, sortid, attrid, cultid, q.min_kmw, geb
|
||||
""").ToListAsync();
|
||||
}
|
||||
}
|
||||
|
||||
[Keyless]
|
||||
public class WeightBreakdownRow {
|
||||
[Column("type")]
|
||||
public required string Type { get; set; }
|
||||
[Column("sortid")]
|
||||
public required string SortId { get; set; }
|
||||
[Column("attrid")]
|
||||
public string? AttrId { get; set; }
|
||||
[Column("cultid")]
|
||||
public string? CultId { get; set; }
|
||||
[Column("qualid")]
|
||||
public required string QualId { get; set; }
|
||||
[Column("geb")]
|
||||
public required string Geb { get; set; }
|
||||
[Column("weight")]
|
||||
public int Weight { get; set; }
|
||||
}
|
||||
}
|
@ -5,24 +5,24 @@ using System.Collections.Generic;
|
||||
using System.Data.Entity.Core.Common.CommandTrees.ExpressionBuilder;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
|
||||
namespace Elwig.Models.Dtos {
|
||||
public class WineQualityStatisticsData {
|
||||
|
||||
public record struct QualityRow(string? Variety, string? Attribute, string? Cultivation, string? Type, string QualId, int Oe, int Num, int Weight);
|
||||
public record struct QualitySection(string Name, string? Type, Dictionary<string, (int Oe, int Num, int Weight)[]> Data);
|
||||
public record struct QualityRow(string? Variety, string? Attribute, string? Cultivation, string? Type, string QualId, double AvgKmw, double Grad, int Num, int Weight);
|
||||
public record struct QualitySection(string Name, string? Type, Dictionary<string, (double Grad, double AvgKmw, int Num, int Weight)[]> Data);
|
||||
|
||||
public bool UseOe = true;
|
||||
public QualitySection[] Sections;
|
||||
|
||||
public WineQualityStatisticsData(QualitySection[] sections) {
|
||||
Sections = sections;
|
||||
}
|
||||
|
||||
private static QualitySection[] GetQualitySections(IEnumerable<QualityRow> rows) {
|
||||
private static QualitySection[] GetSections(IEnumerable<QualityRow> rows) {
|
||||
var data = new List<QualitySection>();
|
||||
var currentQual = new Dictionary<int, (int Num, int Weight)>();
|
||||
var current = new Dictionary<string, (int, int, int)[]>();
|
||||
var currentQual = new Dictionary<double, (double AvgKmw, int Num, int Weight)>();
|
||||
var current = new Dictionary<string, (double, double, int, int)[]>();
|
||||
string? lastSection = null;
|
||||
string? lastType = null;
|
||||
string? lastQual = null;
|
||||
@ -31,25 +31,25 @@ namespace Elwig.Models.Dtos {
|
||||
$"{(row.Attribute != null ? " / " : "")}{row.Attribute}" +
|
||||
$"{(row.Cultivation != null ? " / " : "")}{row.Cultivation}";
|
||||
if (lastQual != null && lastQual != row.QualId) {
|
||||
current[lastQual] = currentQual.Select(kv => (kv.Key, kv.Value.Num, kv.Value.Weight)).ToArray();
|
||||
current[lastQual] = currentQual.Select(kv => (kv.Key, kv.Value.AvgKmw, kv.Value.Num, kv.Value.Weight)).ToArray();
|
||||
currentQual.Clear();
|
||||
}
|
||||
if (lastSection != null && lastSection != sec) {
|
||||
if (!current.ContainsKey(lastQual!)) {
|
||||
current[lastQual!] = currentQual.Select(kv => (kv.Key, kv.Value.Num, kv.Value.Weight)).ToArray();
|
||||
current[lastQual!] = currentQual.Select(kv => (kv.Key, kv.Value.AvgKmw, kv.Value.Num, kv.Value.Weight)).ToArray();
|
||||
currentQual.Clear();
|
||||
}
|
||||
data.Add(new(lastSection, lastType, current));
|
||||
current = [];
|
||||
currentQual.Clear();
|
||||
}
|
||||
currentQual[row.Oe] = (row.Num, row.Weight);
|
||||
currentQual[row.Grad] = (row.AvgKmw, row.Num, row.Weight);
|
||||
lastSection = sec;
|
||||
lastType = row.Type;
|
||||
lastQual = row.QualId;
|
||||
}
|
||||
if (lastQual != null) {
|
||||
current[lastQual] = currentQual.Select(kv => (kv.Key, kv.Value.Num, kv.Value.Weight)).ToArray();
|
||||
current[lastQual] = currentQual.Select(kv => (kv.Key, kv.Value.AvgKmw, kv.Value.Num, kv.Value.Weight)).ToArray();
|
||||
currentQual.Clear();
|
||||
}
|
||||
if (lastSection != null) {
|
||||
@ -60,7 +60,7 @@ namespace Elwig.Models.Dtos {
|
||||
return [.. data];
|
||||
}
|
||||
|
||||
public static async Task<WineQualityStatisticsData> FromQuery(IQueryable<DeliveryPart> query) {
|
||||
public static async Task<WineQualityStatisticsData> FromQuery(IQueryable<DeliveryPart> query, int mode = 0) {
|
||||
var rows = (await query
|
||||
.GroupBy(p => new {
|
||||
p.Variety.Type,
|
||||
@ -68,38 +68,61 @@ namespace Elwig.Models.Dtos {
|
||||
Attribute = p.Attribute!.Name,
|
||||
Cultivation = p.Cultivation!.Name,
|
||||
p.QualId,
|
||||
Oe = (int)Math.Round(p.Kmw * (4.54 + 0.022 * p.Kmw), 0),
|
||||
}, (k, g) => new { Key = k, Num = g.Count(), Weight = g.Sum(p => p.Weight) })
|
||||
Grad = mode == 0 ? Math.Round(p.Kmw * (4.54 + 0.022 * p.Kmw), 0) :
|
||||
mode == 1 ? Math.Floor(p.Kmw) :
|
||||
mode == 2 ? Math.Floor(p.Kmw * 2) / 2 :
|
||||
mode == 3 ? Math.Floor(p.Kmw * 5) / 5 :
|
||||
Math.Round(p.Kmw, 1),
|
||||
}, (k, g) => new {
|
||||
Key = k,
|
||||
Num = g.Count(),
|
||||
Weight = g.Sum(p => p.Weight),
|
||||
AvgKmw = g.Sum(p => p.Weight * p.Kmw) / g.Sum(p => p.Weight),
|
||||
})
|
||||
.OrderBy(g => g.Key.Variety)
|
||||
.ThenBy(g => g.Key.Attribute)
|
||||
.ThenBy(g => g.Key.Cultivation)
|
||||
.ThenBy(g => g.Key.QualId)
|
||||
.ThenBy(g => g.Key.Oe)
|
||||
.ThenBy(g => g.Key.Grad)
|
||||
.ToListAsync())
|
||||
.Select(r => new QualityRow(r.Key.Variety, r.Key.Attribute, r.Key.Cultivation, r.Key.Type, r.Key.QualId, r.Key.Oe, r.Num, r.Weight))
|
||||
.Select(r => new QualityRow(r.Key.Variety, r.Key.Attribute, r.Key.Cultivation, r.Key.Type, r.Key.QualId, r.AvgKmw, r.Key.Grad, r.Num, r.Weight))
|
||||
.ToList();
|
||||
|
||||
var data = GetQualitySections(rows);
|
||||
var data = GetSections(rows);
|
||||
if (data.Length <= 1)
|
||||
return new(data);
|
||||
|
||||
var typeRows = rows
|
||||
.GroupBy(s => new { s.Type, s.QualId, s.Oe }, (k, g) => new QualityRow(null, null, null, k.Type, k.QualId, k.Oe, g.Sum(g => g.Num), g.Sum(p => p.Weight)))
|
||||
.GroupBy(s => new { s.Type, s.QualId, s.Grad }, (k, g) => new QualityRow(
|
||||
null, null, null,
|
||||
k.Type, k.QualId,
|
||||
g.Sum(p => p.Weight * p.AvgKmw) / g.Sum(p => p.Weight),
|
||||
k.Grad,
|
||||
g.Sum(p => p.Num),
|
||||
g.Sum(p => p.Weight)
|
||||
))
|
||||
.OrderBy(g => g.Type)
|
||||
.ThenBy(g => g.QualId)
|
||||
.ThenBy(g => g.Oe)
|
||||
.ThenBy(g => g.Grad)
|
||||
.ToList();
|
||||
var typeData = GetQualitySections(typeRows);
|
||||
var typeData = GetSections(typeRows);
|
||||
if (typeData.Length <= 1)
|
||||
return new([.. typeData, .. data]);
|
||||
|
||||
var totalRows = rows
|
||||
.GroupBy(s => new { s.QualId, s.Oe }, (k, g) => new QualityRow(null, null, null, null, k.QualId, k.Oe, g.Sum(p => p.Num), g.Sum(p => p.Weight)))
|
||||
.GroupBy(s => new { s.QualId, s.Grad }, (k, g) => new QualityRow(
|
||||
null, null, null, null,
|
||||
k.QualId,
|
||||
g.Sum(p => p.Weight * p.AvgKmw) / g.Sum(p => p.Weight),
|
||||
k.Grad,
|
||||
g.Sum(p => p.Num),
|
||||
g.Sum(p => p.Weight)
|
||||
))
|
||||
.OrderBy(g => g.QualId)
|
||||
.ThenBy(g => g.Oe)
|
||||
.ThenBy(g => g.Grad)
|
||||
.ToList();
|
||||
var totalData = GetQualitySections(totalRows);
|
||||
return new([.. totalData, .. typeData, .. data]);
|
||||
var totalData = GetSections(totalRows);
|
||||
return new([.. totalData, .. typeData, .. data]) { UseOe = mode == 0 };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
using Elwig.Helpers;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
|
@ -166,6 +166,9 @@ namespace Elwig.Models.Entities {
|
||||
[InverseProperty(nameof(Delivery.Member))]
|
||||
public virtual ICollection<Delivery> Deliveries { get; private set; } = null!;
|
||||
|
||||
[InverseProperty(nameof(Credit.Member))]
|
||||
public virtual ICollection<Credit> Credits { get; private set; } = null!;
|
||||
|
||||
[InverseProperty(nameof(MemberTelNr.Member))]
|
||||
public virtual ICollection<MemberTelNr> TelephoneNumbers { get; private set; } = null!;
|
||||
|
||||
|
@ -3,7 +3,7 @@ using System;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Elwig.Models.Entities {
|
||||
[Table("member_history"), PrimaryKey("MgNr", "DateString")]
|
||||
[Table("member_history"), PrimaryKey("MgNr", "DateString", "Type")]
|
||||
public class MemberHistory {
|
||||
[Column("mgnr")]
|
||||
public int MgNr { get; set; }
|
||||
@ -16,12 +16,12 @@ namespace Elwig.Models.Entities {
|
||||
set => value.ToString("yyyy-MM-dd");
|
||||
}
|
||||
|
||||
[Column("business_shares")]
|
||||
public int BusinessShares { get; set; }
|
||||
|
||||
[Column("type")]
|
||||
public required string Type { get; set; }
|
||||
|
||||
[Column("business_shares")]
|
||||
public int BusinessShares { get; set; }
|
||||
|
||||
[Column("comment")]
|
||||
public string? Comment { get; set; }
|
||||
|
||||
|
@ -17,7 +17,6 @@ namespace Elwig.Models.Entities {
|
||||
|
||||
[Column("date")]
|
||||
public required string DateString { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public DateOnly Date {
|
||||
get => DateOnly.ParseExact(DateString, "yyyy-MM-dd");
|
||||
@ -26,7 +25,6 @@ namespace Elwig.Models.Entities {
|
||||
|
||||
[Column("transfer_date")]
|
||||
public string? TransferDateString { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public DateOnly? TransferDate {
|
||||
get => TransferDateString != null ? DateOnly.ParseExact(TransferDateString, "yyyy-MM-dd") : null;
|
||||
@ -37,7 +35,9 @@ namespace Elwig.Models.Entities {
|
||||
public bool TestVariant { get; set; }
|
||||
|
||||
[Column("calc_time")]
|
||||
public int? CalcTime { get; set; }
|
||||
public int? CalcTimeUnix { get; set; }
|
||||
[NotMapped]
|
||||
public DateTime? CalcTime => CalcTimeUnix != null ? DateTimeOffset.FromUnixTimeSeconds((long)CalcTimeUnix).UtcDateTime.ToLocalTime() : null;
|
||||
|
||||
[Column("comment")]
|
||||
public string? Comment { get; set; }
|
||||
|
@ -55,6 +55,22 @@ namespace Elwig.Models.Entities {
|
||||
set => PenaltyNoneValue = value != null ? DecToDb(value.Value) : null;
|
||||
}
|
||||
|
||||
[Column("penalty_per_bs_amount")]
|
||||
public long? PenaltyPerBsAmountValue { get; set; }
|
||||
[NotMapped]
|
||||
public decimal? PenaltyPerBsAmount {
|
||||
get => PenaltyPerBsAmountValue != null ? DecFromDb(PenaltyPerBsAmountValue.Value) : null;
|
||||
set => PenaltyPerBsAmountValue = value != null ? DecToDb(value.Value) : null;
|
||||
}
|
||||
|
||||
[Column("penalty_per_bs_none")]
|
||||
public long? PenaltyPerBsNoneValue { get; set; }
|
||||
[NotMapped]
|
||||
public decimal? PenaltyPerBsNone {
|
||||
get => PenaltyPerBsNoneValue != null ? DecFromDb(PenaltyPerBsNoneValue.Value) : null;
|
||||
set => PenaltyPerBsNoneValue = value != null ? DecToDb(value.Value) : null;
|
||||
}
|
||||
|
||||
[Column("bs_value")]
|
||||
public long? BusinessShareValueValue { get; set; }
|
||||
[NotMapped]
|
||||
|
@ -1,6 +1,6 @@
|
||||
using Elwig.Models.Entities;
|
||||
|
||||
namespace Elwig.Helpers {
|
||||
namespace Elwig.Models {
|
||||
public interface IAddress {
|
||||
string Name { get; }
|
||||
string Address { get; }
|
@ -12,6 +12,7 @@
|
||||
"consider_contract_penalties": {"type": "boolean"},
|
||||
"consider_total_penalty": {"type": "boolean"},
|
||||
"consider_auto_business_shares": {"type": "boolean"},
|
||||
"consider_custom_modifiers": {"type": "boolean"},
|
||||
"net_weight_modifier": {"type": "number"},
|
||||
"gross_weight_modifier": {"type": "number"},
|
||||
"payment": {"$ref": "#/definitions/payment_1"},
|
||||
|
17
Elwig/Resources/Sql/18-19.sql
Normal file
17
Elwig/Resources/Sql/18-19.sql
Normal file
@ -0,0 +1,17 @@
|
||||
-- schema version 18 to 19
|
||||
|
||||
CREATE VIEW v_stat_total AS
|
||||
SELECT d.year, d.zwstid, v.type, v.sortid,
|
||||
IIF(b.discr = a.attrid OR NOT a.area_com, a.attrid, NULL) AS attrid,
|
||||
p.cultid, q.qualid,
|
||||
IIF(b.discr = '_', 'ungeb', 'geb') AS geb,
|
||||
SUM(value) AS weight
|
||||
FROM delivery_part p
|
||||
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_quality_level q ON q.qualid = p.qualid
|
||||
LEFT JOIN delivery_part_bucket b ON (b.year, b.did, b.dpnr) = (p.year, p.did, p.dpnr)
|
||||
LEFT JOIN v_wine_attribute a ON a.attrid = p.attrid
|
||||
GROUP BY d.year, d.zwstid, v.type, v.sortid, IIF(b.discr = a.attrid OR NOT a.area_com, a.attrid, NULL), p.cultid, q.qualid, geb
|
||||
HAVING SUM(value) > 0
|
||||
ORDER BY d.year, d.zwstid, v.type DESC, v.sortid, IIF(b.discr = a.attrid OR NOT a.area_com, a.attrid, NULL), p.cultid, q.min_kmw, geb;
|
7
Elwig/Resources/Sql/19-20.sql
Normal file
7
Elwig/Resources/Sql/19-20.sql
Normal file
@ -0,0 +1,7 @@
|
||||
-- schema version 19 to 20
|
||||
|
||||
ALTER TABLE season ADD COLUMN penalty_per_bs_amount INTEGER DEFAULT NULL;
|
||||
ALTER TABLE season ADD COLUMN penalty_per_bs_none INTEGER DEFAULT NULL;
|
||||
DROP VIEW v_penalty_business_shares;
|
||||
|
||||
UPDATE season SET penalty_none = NULL;
|
16
Elwig/Resources/Sql/20-21.sql
Normal file
16
Elwig/Resources/Sql/20-21.sql
Normal file
@ -0,0 +1,16 @@
|
||||
-- schema version 20 to 21
|
||||
|
||||
DROP TABLE member_history;
|
||||
CREATE TABLE member_history (
|
||||
mgnr INTEGER NOT NULL,
|
||||
date TEXT NOT NULL CHECK (date REGEXP '^[1-9][0-9]{3}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])$') DEFAULT CURRENT_DATE,
|
||||
type TEXT NOT NULL CHECK (type REGEXP '^[a-z_]+$'),
|
||||
|
||||
business_shares INTEGER NOT NULL,
|
||||
comment TEXT DEFAULT NULL,
|
||||
|
||||
CONSTRAINT pk_member_history PRIMARY KEY (mgnr, date, type),
|
||||
CONSTRAINT fk_member_history_member FOREIGN KEY (mgnr) REFERENCES member (mgnr)
|
||||
ON UPDATE CASCADE
|
||||
ON DELETE CASCADE
|
||||
) STRICT;
|
7
Elwig/Themes/Generic.xaml
Normal file
7
Elwig/Themes/Generic.xaml
Normal file
@ -0,0 +1,7 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="/Elwig;component/Controls/UnitTextBox.xaml"/>
|
||||
<ResourceDictionary Source="/Elwig;component/Controls/IntegerUpDown.xaml"/>
|
||||
<ResourceDictionary Source="/Elwig;component/Controls/CheckComboBox.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
@ -1,4 +1,3 @@
|
||||
using Elwig.Controls;
|
||||
using Elwig.Helpers;
|
||||
using Elwig.Models.Entities;
|
||||
using System;
|
||||
@ -10,7 +9,6 @@ using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Threading;
|
||||
using Xceed.Wpf.Toolkit;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace Elwig.Windows {
|
||||
@ -21,14 +19,14 @@ namespace Elwig.Windows {
|
||||
|
||||
private bool _isEditing;
|
||||
private bool _isCreating;
|
||||
protected bool IsEditing {
|
||||
public bool IsEditing {
|
||||
get { return _isEditing; }
|
||||
set {
|
||||
_isEditing = value;
|
||||
LockContext = IsEditing || IsCreating;
|
||||
}
|
||||
}
|
||||
protected bool IsCreating {
|
||||
public bool IsCreating {
|
||||
get { return _isCreating; }
|
||||
set {
|
||||
_isCreating = value;
|
||||
@ -42,7 +40,7 @@ namespace Elwig.Windows {
|
||||
private TextBox[] PlzInputs;
|
||||
private ComboBox[] ComboBoxInputs;
|
||||
private ComboBox[] PlzOrtInputs;
|
||||
private CheckComboBox[] CheckComboBoxInputs;
|
||||
private ListBox[] ListBoxInputs;
|
||||
private CheckBox[] CheckBoxInputs;
|
||||
private RadioButton[] RadioButtonInputs;
|
||||
private readonly Dictionary<Control, bool> Valid;
|
||||
@ -68,7 +66,7 @@ namespace Elwig.Windows {
|
||||
TextBoxInputs = [];
|
||||
PlzInputs = [];
|
||||
ComboBoxInputs = [];
|
||||
CheckComboBoxInputs = [];
|
||||
ListBoxInputs = [];
|
||||
PlzOrtInputs = [];
|
||||
CheckBoxInputs = [];
|
||||
RadioButtonInputs = [];
|
||||
@ -97,7 +95,7 @@ namespace Elwig.Windows {
|
||||
TextBoxInputs = ControlUtils.FindAllChildren<TextBox>(this, ExemptInputs).ToArray();
|
||||
ComboBoxInputs = ControlUtils.FindAllChildren<ComboBox>(this, ExemptInputs).ToArray();
|
||||
CheckBoxInputs = ControlUtils.FindAllChildren<CheckBox>(this, ExemptInputs).ToArray();
|
||||
CheckComboBoxInputs = ControlUtils.FindAllChildren<CheckComboBox>(this, ExemptInputs).ToArray();
|
||||
ListBoxInputs = ControlUtils.FindAllChildren<ListBox>(this, ExemptInputs).ToArray();
|
||||
RadioButtonInputs = ControlUtils.FindAllChildren<RadioButton>(this, ExemptInputs).ToArray();
|
||||
PlzInputs = ControlUtils.FindAllChildren<TextBox>(this).Where(tb => "PLZ".Equals(tb.Tag)).ToArray();
|
||||
PlzOrtInputs = PlzInputs.Select(tb => ControlUtils.FindNextSibling<ComboBox>(tb) ?? throw new MissingMemberException()).ToArray();
|
||||
@ -105,8 +103,8 @@ namespace Elwig.Windows {
|
||||
Valid[tb] = true;
|
||||
foreach (var cb in ComboBoxInputs)
|
||||
cb.SelectionChanged += ComboBox_SelectionChanged;
|
||||
foreach (var cb in CheckComboBoxInputs)
|
||||
cb.ItemSelectionChanged += ComboBox_SelectionChanged;
|
||||
foreach (var lb in ListBoxInputs)
|
||||
lb.SelectionChanged += ComboBox_SelectionChanged;
|
||||
}
|
||||
|
||||
private void OnClosing(object? sender, CancelEventArgs evt) {
|
||||
@ -133,7 +131,6 @@ namespace Elwig.Windows {
|
||||
}
|
||||
|
||||
protected void ValidateInput(Control input, bool valid) {
|
||||
if (input is UnitTextBox utbx) input = utbx.TextBox;
|
||||
Valid[input] = valid;
|
||||
}
|
||||
|
||||
@ -152,8 +149,8 @@ namespace Elwig.Windows {
|
||||
ControlUtils.ClearInputState(tb);
|
||||
foreach (var cb in ComboBoxInputs)
|
||||
ControlUtils.ClearInputState(cb);
|
||||
foreach (var ccb in CheckComboBoxInputs)
|
||||
ControlUtils.ClearInputState(ccb);
|
||||
foreach (var lb in ListBoxInputs)
|
||||
ControlUtils.ClearInputState(lb);
|
||||
foreach (var cb in CheckBoxInputs)
|
||||
ControlUtils.ClearInputState(cb);
|
||||
foreach (var rb in RadioButtonInputs)
|
||||
@ -167,7 +164,7 @@ namespace Elwig.Windows {
|
||||
Valid[input] = false;
|
||||
} else if (input is ComboBox cb && cb.SelectedItem == null && cb.ItemsSource != null) {
|
||||
ControlUtils.SetInputInvalid(input);
|
||||
} else if (input is CheckComboBox ccb && ccb.SelectedItem == null && ccb.ItemsSource != null) {
|
||||
} else if (input is ListBox lb && lb.SelectedItem == null && lb.ItemsSource != null) {
|
||||
ControlUtils.SetInputInvalid(input);
|
||||
} else if (input is CheckBox ckb && ckb.IsChecked != true) {
|
||||
ControlUtils.SetInputInvalid(input);
|
||||
@ -191,8 +188,8 @@ namespace Elwig.Windows {
|
||||
tb.IsReadOnly = true;
|
||||
foreach (var cb in ComboBoxInputs)
|
||||
cb.IsEnabled = false;
|
||||
foreach (var ccb in CheckComboBoxInputs)
|
||||
ccb.IsEnabled = false;
|
||||
foreach (var lb in ListBoxInputs)
|
||||
lb.IsEnabled = false;
|
||||
foreach (var cb in CheckBoxInputs)
|
||||
cb.IsEnabled = false;
|
||||
foreach (var rb in RadioButtonInputs)
|
||||
@ -204,8 +201,8 @@ namespace Elwig.Windows {
|
||||
tb.IsReadOnly = false;
|
||||
foreach (var cb in ComboBoxInputs)
|
||||
cb.IsEnabled = true;
|
||||
foreach (var ccb in CheckComboBoxInputs)
|
||||
ccb.IsEnabled = true;
|
||||
foreach (var lb in ListBoxInputs)
|
||||
lb.IsEnabled = true;
|
||||
foreach (var cb in CheckBoxInputs)
|
||||
cb.IsEnabled = true;
|
||||
foreach (var rb in RadioButtonInputs)
|
||||
@ -225,8 +222,8 @@ namespace Elwig.Windows {
|
||||
OriginalValues[tb] = ControlUtils.GetInputHashCode(tb);
|
||||
foreach (var cb in ComboBoxInputs)
|
||||
OriginalValues[cb] = ControlUtils.GetInputHashCode(cb);
|
||||
foreach (var ccb in CheckComboBoxInputs)
|
||||
OriginalValues[ccb] = ControlUtils.GetInputHashCode(ccb);
|
||||
foreach (var lb in ListBoxInputs)
|
||||
OriginalValues[lb] = ControlUtils.GetInputHashCode(lb);
|
||||
foreach (var cb in CheckBoxInputs)
|
||||
OriginalValues[cb] = ControlUtils.GetInputHashCode(cb);
|
||||
foreach (var rb in RadioButtonInputs)
|
||||
@ -234,7 +231,6 @@ namespace Elwig.Windows {
|
||||
}
|
||||
|
||||
protected void SetOriginalValue(Control input, object? value) {
|
||||
if (input is UnitTextBox utbx) input = utbx.TextBox;
|
||||
OriginalValues[input] = Utils.GetEntityIdentifier(value);
|
||||
if (InputHasChanged(input)) {
|
||||
ControlUtils.SetInputChanged(input);
|
||||
@ -244,18 +240,15 @@ namespace Elwig.Windows {
|
||||
}
|
||||
|
||||
protected void SetOriginalValue(Control input) {
|
||||
if (input is UnitTextBox utbx) input = utbx.TextBox;
|
||||
SetOriginalValue(input, ControlUtils.GetInputHashCode(input));
|
||||
}
|
||||
|
||||
protected void UnsetOriginalValue(Control input) {
|
||||
if (input is UnitTextBox utbx) input = utbx.TextBox;
|
||||
OriginalValues.Remove(input);
|
||||
ControlUtils.ClearInputState(input);
|
||||
}
|
||||
|
||||
protected void SetDefaultValue(Control input, object? value) {
|
||||
if (input is UnitTextBox utbx) input = utbx.TextBox;
|
||||
DefaultValues[input] = Utils.GetEntityIdentifier(value);
|
||||
if (!InputHasChanged(input)) {
|
||||
if (InputIsNotDefault(input)) {
|
||||
@ -267,12 +260,10 @@ namespace Elwig.Windows {
|
||||
}
|
||||
|
||||
protected void SetDefaultValue(Control input) {
|
||||
if (input is UnitTextBox utbx) input = utbx.TextBox;
|
||||
SetDefaultValue(input, ControlUtils.GetInputHashCode(input));
|
||||
}
|
||||
|
||||
protected void UnsetDefaultValue(Control input) {
|
||||
if (input is UnitTextBox utbx) input = utbx.TextBox;
|
||||
DefaultValues.Remove(input);
|
||||
if (!InputHasChanged(input)) {
|
||||
ControlUtils.ClearInputState(input);
|
||||
@ -284,8 +275,8 @@ namespace Elwig.Windows {
|
||||
tb.Text = "";
|
||||
foreach (var cb in ComboBoxInputs)
|
||||
cb.SelectedItem = null;
|
||||
foreach (var ccb in CheckComboBoxInputs)
|
||||
ccb.SelectedItems.Clear();
|
||||
foreach (var lb in ListBoxInputs)
|
||||
lb.SelectedItems.Clear();
|
||||
foreach (var cb in CheckBoxInputs)
|
||||
cb.IsChecked = cb.IsThreeState ? null : false;
|
||||
foreach (var rb in RadioButtonInputs)
|
||||
@ -296,12 +287,10 @@ namespace Elwig.Windows {
|
||||
protected bool IsValid => Valid.All(kv => kv.Value);
|
||||
|
||||
protected bool GetInputValid(Control input) {
|
||||
if (input is UnitTextBox utbx) input = utbx.TextBox;
|
||||
return Valid[input];
|
||||
}
|
||||
|
||||
protected bool InputHasChanged(Control input) {
|
||||
if (input is UnitTextBox utbx) input = utbx.TextBox;
|
||||
if (!OriginalValues.TryGetValue(input, out int? original)) {
|
||||
return false;
|
||||
} else {
|
||||
@ -311,7 +300,6 @@ namespace Elwig.Windows {
|
||||
}
|
||||
|
||||
protected bool InputIsNotDefault(Control input) {
|
||||
if (input is UnitTextBox utbx) input = utbx.TextBox;
|
||||
if (!DefaultValues.TryGetValue(input, out int? defaultValue)) {
|
||||
return false;
|
||||
} else {
|
||||
@ -325,13 +313,13 @@ namespace Elwig.Windows {
|
||||
!IsValid ||
|
||||
TextBoxInputs.Any(InputHasChanged) ||
|
||||
ComboBoxInputs.Any(InputHasChanged) ||
|
||||
CheckComboBoxInputs.Any(InputHasChanged) ||
|
||||
ListBoxInputs.Any(InputHasChanged) ||
|
||||
CheckBoxInputs.Any(InputHasChanged) ||
|
||||
RadioButtonInputs.Any(InputHasChanged)
|
||||
) || IsCreating && (
|
||||
TextBoxInputs.Any(i => InputIsNotDefault(i) || (!i.IsReadOnly && i.Text != "")) ||
|
||||
ComboBoxInputs.Any(i => InputIsNotDefault(i) || (i.IsEnabled && i.SelectedItem != null)) ||
|
||||
CheckComboBoxInputs.Any(i => InputIsNotDefault(i) || i.SelectedItem != null) ||
|
||||
ListBoxInputs.Any(i => InputIsNotDefault(i) || i.SelectedItem != null) ||
|
||||
CheckBoxInputs.Any(InputIsNotDefault) ||
|
||||
RadioButtonInputs.Any(InputIsNotDefault)
|
||||
);
|
||||
@ -436,7 +424,7 @@ namespace Elwig.Windows {
|
||||
|
||||
protected void TextBox_TextChanged(object sender, RoutedEventArgs? evt) {
|
||||
var input = (Control)sender;
|
||||
var tb = input as TextBox ?? (input as UnitTextBox)?.TextBox;
|
||||
var tb = input as TextBox;
|
||||
if (SenderIsRequired(input) && tb?.Text.Length == 0) {
|
||||
ValidateInput(input, false);
|
||||
ControlUtils.SetInputInvalid(input);
|
||||
@ -457,8 +445,8 @@ namespace Elwig.Windows {
|
||||
bool valid = false;
|
||||
if (input is ComboBox cb) {
|
||||
valid = cb.ItemsSource == null || cb.SelectedItem != null || !RequiredInputs.Contains(input);
|
||||
} else if (input is CheckComboBox ccb) {
|
||||
valid = ccb.ItemsSource == null || ccb.SelectedItem != null || !RequiredInputs.Contains(input);
|
||||
} else if (input is ListBox lb) {
|
||||
valid = lb.ItemsSource == null || lb.SelectedItem != null || !RequiredInputs.Contains(input);
|
||||
}
|
||||
if (valid) {
|
||||
ValidateInput(input, true);
|
||||
@ -482,12 +470,12 @@ namespace Elwig.Windows {
|
||||
|
||||
protected void IntegerInput_TextChanged(object sender, TextChangedEventArgs evt) {
|
||||
// FIXME
|
||||
InputTextChanged((sender as UnitTextBox)?.TextBox ?? (TextBox)sender, Validator.CheckInteger);
|
||||
InputTextChanged((TextBox)sender, Validator.CheckInteger);
|
||||
}
|
||||
|
||||
protected void DecimalInput_TextChanged(object sender, TextChangedEventArgs evt) {
|
||||
// FIXME
|
||||
InputTextChanged((sender as UnitTextBox)?.TextBox ?? (TextBox)sender, Validator.CheckDecimal);
|
||||
InputTextChanged((TextBox)sender, Validator.CheckDecimal);
|
||||
}
|
||||
|
||||
protected void PartialDateInput_TextChanged(object sender, TextChangedEventArgs evt) {
|
||||
|
@ -6,7 +6,6 @@
|
||||
xmlns:local="clr-namespace:Elwig.Windows"
|
||||
xmlns:ctrl="clr-namespace:Elwig.Controls"
|
||||
mc:Ignorable="d"
|
||||
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
|
||||
Title="Flächenbindungen - Elwig" Height="500" MinHeight="440" Width="920" MinWidth="860"
|
||||
Loaded="Window_Loaded">
|
||||
<Window.Resources>
|
||||
@ -25,14 +24,16 @@
|
||||
<Setter Property="Height" Value="25"/>
|
||||
<Setter Property="TextWrapping" Value="NoWrap"/>
|
||||
</Style>
|
||||
<Style TargetType="ComboBox">
|
||||
<Setter Property="IsEnabled" Value="False"/>
|
||||
<Setter Property="Height" Value="25"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Style TargetType="ctrl:UnitTextBox">
|
||||
<Setter Property="HorizontalAlignment" Value="Stretch"/>
|
||||
<Setter Property="VerticalAlignment" Value="Top"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="Padding" Value="2"/>
|
||||
<Setter Property="IsReadOnly" Value="True"/>
|
||||
<Setter Property="Height" Value="25"/>
|
||||
<Setter Property="TextWrapping" Value="NoWrap"/>
|
||||
</Style>
|
||||
<Style TargetType="xctk:CheckComboBox">
|
||||
<Style TargetType="ComboBox">
|
||||
<Setter Property="IsEnabled" Value="False"/>
|
||||
<Setter Property="Height" Value="25"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
|
@ -7,7 +7,6 @@ using Elwig.Models.Entities;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Generic;
|
||||
using Xceed.Wpf.Toolkit.Primitives;
|
||||
|
||||
namespace Elwig.Windows {
|
||||
public partial class AreaComAdminWindow : AdministrationWindow {
|
||||
@ -29,7 +28,7 @@ namespace Elwig.Windows {
|
||||
];
|
||||
RequiredInputs = [
|
||||
FbNrInput, YearFromInput, KgInput, RdInput,
|
||||
GstNrInput, AreaInput.TextBox, AreaComTypeInput, WineCultivationInput
|
||||
GstNrInput, AreaInput, AreaComTypeInput, WineCultivationInput
|
||||
];
|
||||
}
|
||||
|
||||
@ -431,7 +430,7 @@ namespace Elwig.Windows {
|
||||
RefreshInputs();
|
||||
}
|
||||
|
||||
private void AttributesInput_SelectionChanged(object sender, ItemSelectionChangedEventArgs evt) {
|
||||
private void AttributesInput_SelectionChanged(object sender, SelectionChangedEventArgs evt) {
|
||||
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,14 @@
|
||||
<Setter Property="Height" Value="25"/>
|
||||
<Setter Property="TextWrapping" Value="NoWrap"/>
|
||||
</Style>
|
||||
<Style TargetType="ctrl:UnitTextBox">
|
||||
<Setter Property="HorizontalAlignment" Value="Stretch"/>
|
||||
<Setter Property="VerticalAlignment" Value="Top"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="Padding" Value="2"/>
|
||||
<Setter Property="Height" Value="25"/>
|
||||
<Setter Property="TextWrapping" Value="NoWrap"/>
|
||||
</Style>
|
||||
<Style TargetType="ComboBox">
|
||||
<Setter Property="Height" Value="25"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
@ -347,8 +355,12 @@
|
||||
|
||||
<Label Content="Sorte:" Margin="10,40,0,10"/>
|
||||
<ComboBox x:Name="AreaCommitmentTypeWineVariantInput" Grid.Column="1" Grid.ColumnSpan="2" Margin="0,40,10,10" Width="250" HorizontalAlignment="Left"
|
||||
ItemTemplate="{StaticResource WineVarietyTemplate}" TextSearch.TextPath="Name"
|
||||
SelectionChanged="AreaCommitmentType_Changed"/>
|
||||
TextSearch.TextPath="Name"
|
||||
SelectionChanged="AreaCommitmentType_Changed">
|
||||
<ComboBox.ItemTemplateSelector>
|
||||
<ctrl:WineVarietyTemplateSelector/>
|
||||
</ComboBox.ItemTemplateSelector>
|
||||
</ComboBox>
|
||||
|
||||
<Label Content="Attribut:" Margin="10,70,0,10"/>
|
||||
<ComboBox x:Name="AreaCommitmentTypeWineAttributeInput" Grid.Column="1" Grid.ColumnSpan="2" Margin="0,70,10,10" Width="250" HorizontalAlignment="Left"
|
||||
@ -383,11 +395,11 @@
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="205"/>
|
||||
<RowDefinition Height="180"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<ListBox x:Name="SeasonList" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10,10,10,10" Grid.RowSpan="2"
|
||||
<ListBox x:Name="SeasonList" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10,10,10,40" Grid.RowSpan="2"
|
||||
SelectionChanged="SeasonList_SelectionChanged">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
@ -399,11 +411,17 @@
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
<Button x:Name="SeasonAddButton" Content="Neu anlegen..." FontSize="12" Height="25" Grid.Row="2"
|
||||
VerticalAlignment="Bottom" Margin="10,10,40,10" Padding="0,0,0,0"
|
||||
Click="SeasonAddButton_Click"/>
|
||||
<Button x:Name="SeasonRemoveButton" Content="" FontFamily="Segoe MDL2 Assets" FontSize="16" Grid.Row="2" Height="25" Width="25"
|
||||
VerticalAlignment="Bottom" HorizontalAlignment="Right" Margin="10,10,10,10" Padding="0.5,0,0,0"
|
||||
Click="SeasonRemoveButton_Click"/>
|
||||
|
||||
<Grid Grid.Column="1" Margin="0,10,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="130"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="150"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
@ -428,29 +446,32 @@
|
||||
<TextBox x:Name="SeasonEndInput" Grid.Column="1" Margin="0,130,10,10" Width="78" IsEnabled="False"
|
||||
HorizontalAlignment="Left"/>
|
||||
|
||||
<Label Content="Lieferpflicht:" Margin="10,10,0,10" Grid.Column="2"/>
|
||||
<Label Content="Lieferpflicht/-recht:" Margin="10,10,0,10" Grid.Column="2"/>
|
||||
<ctrl:UnitTextBox x:Name="SeasonMinKgPerBsInput" Unit="kg/GA" TextChanged="SeasonMinMaxKgInput_TextChanged"
|
||||
Grid.Column="3" Width="80" Margin="0,10,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"/>
|
||||
|
||||
<Label Content="Lieferrecht:" Margin="10,40,0,10" Grid.Column="2"/>
|
||||
<ctrl:UnitTextBox x:Name="SeasonMaxKgPerBsInput" Unit="kg/GA" TextChanged="SeasonMinMaxKgInput_TextChanged"
|
||||
Grid.Column="3" Width="80" Margin="85,10,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"/>
|
||||
|
||||
<Label Content="Strafe (pro unterl. kg):" Margin="10,40,0,10" Grid.Column="2"/>
|
||||
<ctrl:UnitTextBox x:Name="SeasonPenaltyPerKgInput" Unit="€/kg" TextChanged="SeasonPenaltyPerKgInput_TextChanged"
|
||||
Grid.Column="3" Width="80" Margin="0,40,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"/>
|
||||
|
||||
<Label Content="Strafe (pro unterl. kg):" Margin="10,70,0,10" Grid.Column="2"/>
|
||||
<ctrl:UnitTextBox x:Name="SeasonPenaltyPerKgInput" Unit="€/kg" TextChanged="SeasonPenaltyPerKgInput_TextChanged"
|
||||
Grid.Column="3" Width="80" Margin="0,70,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"/>
|
||||
|
||||
<Label Content="Strafe (Unterlieferung):" Margin="10,100,0,10" Grid.Column="2"/>
|
||||
<Label Content="Strafe (Unterlieferung):" Margin="10,70,0,10" Grid.Column="2"/>
|
||||
<ctrl:UnitTextBox x:Name="SeasonPenaltyInput" Unit="€" TextChanged="SeasonPenaltyInput_TextChanged"
|
||||
Grid.Column="3" Width="68" Margin="0,70,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"/>
|
||||
<ctrl:UnitTextBox x:Name="SeasonPenaltyPerBsInput" Unit="€/GA" TextChanged="SeasonPenaltyPerBsInput_TextChanged"
|
||||
Grid.Column="3" Width="100" Margin="72,70,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"/>
|
||||
|
||||
<Label Content="Strafe (Nicht-Lieferung):" Margin="10,100,0,10" Grid.Column="2"/>
|
||||
<ctrl:UnitTextBox x:Name="SeasonPenaltyNoneInput" Unit="€" TextChanged="SeasonPenaltyInput_TextChanged" IsEnabled="False"
|
||||
Grid.Column="3" Width="68" Margin="0,100,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"/>
|
||||
<ctrl:UnitTextBox x:Name="SeasonPenaltyPerBsNoneInput" Unit="€/GA" TextChanged="SeasonPenaltyPerBsInput_TextChanged" IsEnabled="False"
|
||||
Grid.Column="3" Width="100" Margin="72,100,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"/>
|
||||
|
||||
<Label Content="Strafe (Nicht-Lieferung):" Margin="10,130,0,10" Grid.Column="2"/>
|
||||
<ctrl:UnitTextBox x:Name="SeasonPenaltyNoneInput" Unit="€" TextChanged="SeasonPenaltyInput_TextChanged"
|
||||
Grid.Column="3" Width="68" Margin="0,130,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"/>
|
||||
|
||||
<Label Content="GA-Wert:" Margin="10,160,0,10" Grid.Column="2"/>
|
||||
<Label Content="GA-Wert (Nachz.):" Margin="10,130,0,10" Grid.Column="2"/>
|
||||
<ctrl:UnitTextBox x:Name="SeasonBsValueInput" Unit="€/GA" TextChanged="SeasonPenaltyInput_TextChanged"
|
||||
Grid.Column="3" Width="85" Margin="0,160,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"/>
|
||||
Grid.Column="3" Width="85" Margin="0,130,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"/>
|
||||
</Grid>
|
||||
|
||||
<GroupBox Grid.Column="1" Grid.Row="1" Header="Zu-/Abschläge" Margin="0,0,10,10" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
|
||||
@ -505,7 +526,48 @@
|
||||
</Grid>
|
||||
</TabItem>
|
||||
<TabItem Header="Parameter">
|
||||
<StackPanel>
|
||||
<GroupBox x:Name="ParameterAreaComGroup" Header="Berechnung Flächenbindungen (aktuelle Saison)" Margin="10,10,10,0" VerticalAlignment="Top">
|
||||
<Grid>
|
||||
<CheckBox x:Name="ParameterAllowAttrIntoLowerInput" Content="Erlauben Lieferungen auch auf (konfigurierte) "schlechtere" Flächenbindungen aufzuteilen"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Left" Margin="10,10,10,10"
|
||||
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"/>
|
||||
<CheckBox x:Name="ParameterAvoidUnderDeliveriesInput" Content="Unterlieferungen durch Abzug bei "besseren" Flächenbindungen vermeiden"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Left" Margin="10,30,10,10"
|
||||
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"/>
|
||||
<CheckBox x:Name="ParameterHonorGebundenInput" Margin="10,50,10,10" VerticalAlignment="Top"
|
||||
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed">
|
||||
<TextBlock>Bei Lieferungen das Feld <Italic>Gebunden</Italic> berücksichtigen</TextBlock>
|
||||
</CheckBox>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Header="Daten-Export" Margin="10,10,10,10">
|
||||
<Grid>
|
||||
<Label Content="Version EBICS-Überweisung:" Margin="10,10,10,10"/>
|
||||
<ComboBox x:Name="ParameterExportEbicsVersion" Margin="180,10,10,10" Width="50"
|
||||
HorizontalAlignment="Left">
|
||||
<ComboBoxItem>3</ComboBoxItem>
|
||||
<ComboBoxItem>4</ComboBoxItem>
|
||||
<ComboBoxItem>5</ComboBoxItem>
|
||||
<ComboBoxItem>6</ComboBoxItem>
|
||||
<ComboBoxItem>7</ComboBoxItem>
|
||||
<ComboBoxItem>8</ComboBoxItem>
|
||||
<ComboBoxItem IsSelected="True">9</ComboBoxItem>
|
||||
<ComboBoxItem>10</ComboBoxItem>
|
||||
<ComboBoxItem>11</ComboBoxItem>
|
||||
</ComboBox>
|
||||
|
||||
<Label Content="Adressen EBICS-Überweisung:" Margin="10,40,10,10"/>
|
||||
<ComboBox x:Name="ParameterExportEbicsAddress" Margin="180,40,10,10" Width="150"
|
||||
HorizontalAlignment="Left">
|
||||
<ComboBoxItem>Nicht anführen</ComboBoxItem>
|
||||
<ComboBoxItem>Adresszeilen</ComboBoxItem>
|
||||
<ComboBoxItem IsSelected="True">Vollwertig</ComboBoxItem>
|
||||
</ComboBox>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
</StackPanel>
|
||||
</TabItem>
|
||||
<TabItem Header="Textelemente">
|
||||
<ScrollViewer VerticalScrollBarVisibility="Visible">
|
||||
|
@ -31,7 +31,11 @@ namespace Elwig.Windows {
|
||||
}
|
||||
|
||||
private async Task AreaCommitmentTypesFinishEditing(AppDbContext ctx) {
|
||||
ControlUtils.RenewItemsSource(AreaCommitmentTypeList, await ctx.AreaCommitmentTypes.OrderBy(v => v.SortId).ToListAsync());
|
||||
ControlUtils.RenewItemsSource(AreaCommitmentTypeList, await ctx.AreaCommitmentTypes
|
||||
.OrderBy(v => v.VtrgId)
|
||||
.Include(t => t.WineVar)
|
||||
.Include(t => t.WineAttr)
|
||||
.ToListAsync());
|
||||
_actList = null;
|
||||
_acts = null;
|
||||
_actIds = null;
|
||||
|
@ -22,7 +22,10 @@ namespace Elwig.Windows {
|
||||
private async Task ModifiersInitEditing(AppDbContext ctx) {
|
||||
SeasonList.IsEnabled = false;
|
||||
var year = (SeasonList.SelectedItem as Season)?.Year;
|
||||
_modList = new(await ctx.Modifiers.Where(m => m.Year == year).OrderBy(m => m.Ordering).ToListAsync());
|
||||
_modList = new(await ctx.Modifiers
|
||||
.Where(m => m.Year == year)
|
||||
.OrderBy(m => m.Ordering)
|
||||
.ToListAsync());
|
||||
_mods = _modList.ToDictionary(m => m.ModId, m => (string?)m.ModId);
|
||||
_modIds = _modList.ToDictionary(m => m, m => m.ModId);
|
||||
ControlUtils.RenewItemsSource(SeasonModifierList, _modList);
|
||||
@ -31,7 +34,10 @@ namespace Elwig.Windows {
|
||||
|
||||
private async Task ModifiersFinishEditing(AppDbContext ctx) {
|
||||
var year = (SeasonList.SelectedItem as Season)?.Year;
|
||||
ControlUtils.RenewItemsSource(SeasonModifierList, await ctx.Modifiers.Where(m => m.Year == year).OrderBy(m => m.Ordering).ToListAsync());
|
||||
ControlUtils.RenewItemsSource(SeasonModifierList, await ctx.Modifiers
|
||||
.Where(m => m.Year == year)
|
||||
.OrderBy(m => m.Ordering)
|
||||
.ToListAsync());
|
||||
_modList = null;
|
||||
_mods = null;
|
||||
_modIds = null;
|
||||
|
@ -1,10 +1,14 @@
|
||||
using Elwig.Helpers;
|
||||
using Elwig.Dialogs;
|
||||
using Elwig.Helpers;
|
||||
using Elwig.Models.Entities;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace Elwig.Windows {
|
||||
public partial class BaseDataWindow {
|
||||
@ -13,12 +17,24 @@ namespace Elwig.Windows {
|
||||
private bool _seasonUpdate = false;
|
||||
|
||||
private async Task SeasonsInitEditing(AppDbContext ctx) {
|
||||
ControlUtils.RenewItemsSource(SeasonList, await ctx.Seasons.OrderByDescending(s => s.Year).ToListAsync());
|
||||
SeasonAddButton.IsEnabled = false;
|
||||
SeasonRemoveButton.IsEnabled = false;
|
||||
ControlUtils.RenewItemsSource(SeasonList, await ctx.Seasons
|
||||
.OrderByDescending(s => s.Year)
|
||||
.Include(s => s.Modifiers)
|
||||
.Include(s => s.Currency)
|
||||
.ToListAsync());
|
||||
SeasonList_SelectionChanged(null, null);
|
||||
}
|
||||
|
||||
private async Task SeasonsFinishEditing(AppDbContext ctx) {
|
||||
ControlUtils.RenewItemsSource(SeasonList, await ctx.Seasons.OrderByDescending(s => s.Year).Include(s => s.Modifiers).ToListAsync());
|
||||
SeasonAddButton.IsEnabled = true;
|
||||
SeasonRemoveButton.IsEnabled = true;
|
||||
ControlUtils.RenewItemsSource(SeasonList, await ctx.Seasons
|
||||
.OrderByDescending(s => s.Year)
|
||||
.Include(s => s.Modifiers)
|
||||
.Include(s => s.Currency)
|
||||
.ToListAsync());
|
||||
_seasonChanged = false;
|
||||
}
|
||||
|
||||
@ -43,13 +59,17 @@ namespace Elwig.Windows {
|
||||
SeasonPenaltyPerKgInput.Text = s.PenaltyPerKg?.ToString() ?? "";
|
||||
SeasonPenaltyInput.Text = s.PenaltyAmount?.ToString() ?? "";
|
||||
SeasonPenaltyNoneInput.Text = s.PenaltyNone?.ToString() ?? "";
|
||||
SeasonPenaltyPerBsInput.Text = s.PenaltyPerBsAmount?.ToString() ?? "";
|
||||
SeasonPenaltyPerBsNoneInput.Text = s.PenaltyPerBsNone?.ToString() ?? "";
|
||||
SeasonBsValueInput.Text = s.BusinessShareValue?.ToString() ?? "";
|
||||
|
||||
var sym = s.Currency.Symbol ?? "";
|
||||
var sym = s.Currency.Symbol ?? s.Currency.Code;
|
||||
SeasonModifierAbsInput.Unit = $"{sym}/kg";
|
||||
SeasonPenaltyPerKgInput.Unit = $"{sym}/kg";
|
||||
SeasonPenaltyInput.Unit = sym;
|
||||
SeasonPenaltyNoneInput.Unit = sym;
|
||||
SeasonPenaltyPerBsInput.Unit = $"{sym}/GA";
|
||||
SeasonPenaltyPerBsNoneInput.Unit = $"{sym}/GA";
|
||||
SeasonBsValueInput.Unit = $"{sym}/GA";
|
||||
AreaCommitmentTypePenaltyPerKgInput.Unit = $"{sym}/kg";
|
||||
AreaCommitmentTypePenaltyInput.Unit = sym;
|
||||
@ -66,6 +86,8 @@ namespace Elwig.Windows {
|
||||
SeasonPenaltyPerKgInput.Text = "";
|
||||
SeasonPenaltyInput.Text = "";
|
||||
SeasonPenaltyNoneInput.Text = "";
|
||||
SeasonPenaltyPerBsInput.Text = "";
|
||||
SeasonPenaltyPerBsNoneInput.Text = "";
|
||||
SeasonBsValueInput.Text = "";
|
||||
}
|
||||
_seasonUpdate = false;
|
||||
@ -88,6 +110,8 @@ namespace Elwig.Windows {
|
||||
s.PenaltyPerKg = (SeasonPenaltyPerKgInput.Text.Length > 0) ? decimal.Parse(SeasonPenaltyPerKgInput.Text) : null;
|
||||
s.PenaltyAmount = (SeasonPenaltyInput.Text.Length > 0) ? decimal.Parse(SeasonPenaltyInput.Text) : null;
|
||||
s.PenaltyNone = (SeasonPenaltyNoneInput.Text.Length > 0) ? decimal.Parse(SeasonPenaltyNoneInput.Text) : null;
|
||||
s.PenaltyPerBsAmount = (SeasonPenaltyPerBsInput.Text.Length > 0) ? decimal.Parse(SeasonPenaltyPerBsInput.Text) : null;
|
||||
s.PenaltyPerBsNone = (SeasonPenaltyPerBsNoneInput.Text.Length > 0) ? decimal.Parse(SeasonPenaltyPerBsNoneInput.Text) : null;
|
||||
s.BusinessShareValue = (SeasonBsValueInput.Text.Length > 0) ? decimal.Parse(SeasonBsValueInput.Text) : null;
|
||||
|
||||
UpdateButtons();
|
||||
@ -113,5 +137,92 @@ namespace Elwig.Windows {
|
||||
InputTextChanged((TextBox)sender, Validator.CheckDecimal((TextBox)sender, false, 4, 2));
|
||||
Season_Changed(sender, evt);
|
||||
}
|
||||
|
||||
private void SeasonPenaltyPerBsInput_TextChanged(object sender, TextChangedEventArgs evt) {
|
||||
if (SeasonList.SelectedItem is not Season s) return;
|
||||
InputTextChanged((TextBox)sender, Validator.CheckDecimal((TextBox)sender, false, 4, s.Precision));
|
||||
Season_Changed(sender, evt);
|
||||
}
|
||||
|
||||
private async void SeasonAddButton_Click(object sender, RoutedEventArgs evt) {
|
||||
var s = SeasonList.ItemsSource.Cast<Season>().FirstOrDefault();
|
||||
var year = Utils.CurrentYear;
|
||||
if (year == s?.Year) year++;
|
||||
|
||||
List<Currency> currencies;
|
||||
using (var ctx = new AppDbContext()) {
|
||||
currencies = await ctx.Currencies
|
||||
.OrderBy(c => c.Code)
|
||||
.ToListAsync();
|
||||
}
|
||||
var d = new NewSeasonDialog(s, currencies);
|
||||
if (d.ShowDialog() == true) {
|
||||
Mouse.OverrideCursor = Cursors.AppStarting;
|
||||
try {
|
||||
using var ctx = new AppDbContext();
|
||||
ctx.Add(new Season {
|
||||
Year = year,
|
||||
CurrencyCode = d.CurrencyCode,
|
||||
Precision = d.Precision,
|
||||
MaxKgPerHa = s?.MaxKgPerHa ?? 10000,
|
||||
VatNormal = s?.VatNormal ?? 0.10,
|
||||
VatFlatrate = s?.VatFlatrate ?? 0.13,
|
||||
MinKgPerBusinessShare = s?.MinKgPerBusinessShare ?? 500,
|
||||
MaxKgPerBusinessShare = s?.MaxKgPerBusinessShare ?? 1000,
|
||||
PenaltyPerKgValue = s?.PenaltyPerKgValue,
|
||||
PenaltyAmoutValue = s?.PenaltyAmoutValue,
|
||||
PenaltyNoneValue = s?.PenaltyNoneValue,
|
||||
PenaltyPerBsAmountValue = s?.PenaltyPerBsAmountValue,
|
||||
PenaltyPerBsNoneValue = s?.PenaltyPerBsNoneValue,
|
||||
BusinessShareValueValue = s?.BusinessShareValueValue,
|
||||
CalcMode = s?.CalcMode ?? 0,
|
||||
});
|
||||
if (s != null && d.CopyModifiers) {
|
||||
int mult = d.Precision > s.Precision ? (int)Math.Pow(10, d.Precision - s.Precision) : 1;
|
||||
int div = d.Precision < s.Precision ? (int)Math.Pow(10, s.Precision - d.Precision) : 1;
|
||||
ctx.AddRange(s.Modifiers.Select(m => new Modifier {
|
||||
Year = year,
|
||||
ModId = m.ModId,
|
||||
Ordering = m.Ordering,
|
||||
Name = m.Name,
|
||||
AbsValue = m.AbsValue * mult / div,
|
||||
RelValue = m.RelValue,
|
||||
IsStandard = m.IsStandard,
|
||||
IsQuickSelect = m.IsQuickSelect,
|
||||
}));
|
||||
}
|
||||
await ctx.SaveChangesAsync();
|
||||
} 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, "Saison anlegen", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
await App.HintContextChange();
|
||||
Mouse.OverrideCursor = null;
|
||||
SeasonList.SelectedIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private async void SeasonRemoveButton_Click(object sender, RoutedEventArgs evt) {
|
||||
if (SeasonList.SelectedItem is not Season s)
|
||||
return;
|
||||
var r = MessageBox.Show(
|
||||
$"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;
|
||||
try {
|
||||
using var ctx = new AppDbContext();
|
||||
ctx.Remove(s);
|
||||
await ctx.SaveChangesAsync();
|
||||
} 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, "Saison löschen", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
await App.HintContextChange();
|
||||
Mouse.OverrideCursor = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,9 @@ namespace Elwig.Windows {
|
||||
private bool _attrUpdate = false;
|
||||
|
||||
private async Task WineAttributesInitEditing(AppDbContext ctx) {
|
||||
_attrList = new(await ctx.WineAttributes.OrderBy(a => a.Name).ToListAsync());
|
||||
_attrList = new(await ctx.WineAttributes
|
||||
.OrderBy(a => a.Name)
|
||||
.ToListAsync());
|
||||
_attrs = _attrList.ToDictionary(a => a.AttrId, a => (string?)a.AttrId);
|
||||
_attrIds = _attrList.ToDictionary(a => a, a => a.AttrId);
|
||||
ControlUtils.RenewItemsSource(WineAttributeList, _attrList);
|
||||
@ -27,7 +29,9 @@ namespace Elwig.Windows {
|
||||
}
|
||||
|
||||
private async Task WineAttributesFinishEditing(AppDbContext ctx) {
|
||||
ControlUtils.RenewItemsSource(WineAttributeList, await ctx.WineAttributes.OrderBy(a => a.Name).ToListAsync());
|
||||
ControlUtils.RenewItemsSource(WineAttributeList, await ctx.WineAttributes
|
||||
.OrderBy(a => a.Name)
|
||||
.ToListAsync());
|
||||
_attrList = null;
|
||||
_attrs = null;
|
||||
_attrIds = null;
|
||||
|
@ -19,7 +19,9 @@ namespace Elwig.Windows {
|
||||
private bool _cultUpdate = false;
|
||||
|
||||
private async Task WineCultivationsInitEditing(AppDbContext ctx) {
|
||||
_cultList = new(await ctx.WineCultivations.OrderBy(c => c.Name).ToListAsync());
|
||||
_cultList = new(await ctx.WineCultivations
|
||||
.OrderBy(c => c.Name)
|
||||
.ToListAsync());
|
||||
_cults = _cultList.ToDictionary(c => c.CultId, c => (string?)c.CultId);
|
||||
_cultIds = _cultList.ToDictionary(c => c, c => c.CultId);
|
||||
ControlUtils.RenewItemsSource(WineCultivationList, _cultList);
|
||||
@ -27,7 +29,9 @@ namespace Elwig.Windows {
|
||||
}
|
||||
|
||||
private async Task WineCultivationsFinishEditing(AppDbContext ctx) {
|
||||
ControlUtils.RenewItemsSource(WineCultivationList, await ctx.WineCultivations.OrderBy(c => c.Name).ToListAsync());
|
||||
ControlUtils.RenewItemsSource(WineCultivationList, await ctx.WineCultivations
|
||||
.OrderBy(c => c.Name)
|
||||
.ToListAsync());
|
||||
_cultList = null;
|
||||
_cults = null;
|
||||
_cultIds = null;
|
||||
|
@ -19,22 +19,25 @@ namespace Elwig.Windows {
|
||||
ClientAddressInput, ClientPlzInput, ClientOrtInput,
|
||||
];
|
||||
ExemptInputs = [
|
||||
BranchList, AreaCommitmentTypeList, WineAttributeList, WineCultivationList, SeasonList, SeasonModifierList,
|
||||
ClientNameFull,
|
||||
BranchIdInput, BranchNameInput, BranchPlzInput, BranchOrtInput,
|
||||
BranchAddressInput, BranchPhoneNrInput, BranchFaxNrInput, BranchMobileNrInput,
|
||||
WineAttributeIdInput, WineAttributeNameInput, WineAttributeActiveInput,
|
||||
WineAttributeMaxKgPerHaInput.TextBox, WineAttributeStrictInput, WineAttributeFillLowerInput,
|
||||
WineAttributeMaxKgPerHaInput, WineAttributeStrictInput, WineAttributeFillLowerInput,
|
||||
WineCultivationIdInput, WineCultivationNameInput, WineCultivationDescriptionInput,
|
||||
AreaCommitmentTypeIdInput, AreaCommitmentTypeWineVariantInput, AreaCommitmentTypeWineAttributeInput,
|
||||
AreaCommitmentTypeMinKgPerHaInput.TextBox, AreaCommitmentTypePenaltyPerKgInput.TextBox,
|
||||
AreaCommitmentTypePenaltyInput.TextBox, AreaCommitmentTypePenaltyNoneInput.TextBox,
|
||||
SeasonMaxKgPerHaInput.TextBox, SeasonVatNormalInput.TextBox, SeasonVatFlatrateInput.TextBox, SeasonStartInput, SeasonEndInput,
|
||||
SeasonMinKgPerBsInput.TextBox, SeasonMaxKgPerBsInput.TextBox, SeasonBsValueInput.TextBox,
|
||||
SeasonPenaltyPerKgInput.TextBox, SeasonPenaltyInput.TextBox, SeasonPenaltyNoneInput.TextBox,
|
||||
SeasonModifierIdInput, SeasonModifierNameInput, SeasonModifierRelInput.TextBox, SeasonModifierAbsInput.TextBox,
|
||||
AreaCommitmentTypeMinKgPerHaInput, AreaCommitmentTypePenaltyPerKgInput,
|
||||
AreaCommitmentTypePenaltyInput, AreaCommitmentTypePenaltyNoneInput,
|
||||
SeasonMaxKgPerHaInput, SeasonVatNormalInput, SeasonVatFlatrateInput, SeasonStartInput, SeasonEndInput,
|
||||
SeasonMinKgPerBsInput, SeasonMaxKgPerBsInput, SeasonBsValueInput,
|
||||
SeasonPenaltyPerKgInput, SeasonPenaltyInput, SeasonPenaltyNoneInput,
|
||||
SeasonPenaltyPerBsInput, SeasonPenaltyPerBsNoneInput,
|
||||
SeasonModifierIdInput, SeasonModifierNameInput, SeasonModifierRelInput, SeasonModifierAbsInput,
|
||||
];
|
||||
WineAttributeFillLowerInput.Visibility = Visibility.Hidden;
|
||||
WineAttributeFillLowerLabel.Visibility = Visibility.Hidden;
|
||||
ParameterAreaComGroup.Header = ParameterAreaComGroup.Header.ToString()!.Split('(')[0] + $"({Utils.CurrentLastSeason})";
|
||||
}
|
||||
|
||||
protected override void ShortcutNew() { }
|
||||
@ -56,7 +59,7 @@ namespace Elwig.Windows {
|
||||
WineAttributeIdInput.IsReadOnly = true;
|
||||
WineAttributeNameInput.IsReadOnly = true;
|
||||
WineAttributeActiveInput.IsEnabled = false;
|
||||
WineAttributeMaxKgPerHaInput.TextBox.IsReadOnly = true;
|
||||
WineAttributeMaxKgPerHaInput.IsReadOnly = true;
|
||||
WineAttributeStrictInput.IsEnabled = false;
|
||||
WineAttributeFillLowerInput.IsEnabled = false;
|
||||
|
||||
@ -66,25 +69,33 @@ namespace Elwig.Windows {
|
||||
|
||||
AreaCommitmentTypeWineVariantInput.IsEnabled = false;
|
||||
AreaCommitmentTypeWineAttributeInput.IsEnabled = false;
|
||||
AreaCommitmentTypeMinKgPerHaInput.TextBox.IsReadOnly = true;
|
||||
AreaCommitmentTypePenaltyPerKgInput.TextBox.IsReadOnly = true;
|
||||
AreaCommitmentTypePenaltyInput.TextBox.IsReadOnly = true;
|
||||
AreaCommitmentTypePenaltyNoneInput.TextBox.IsReadOnly = true;
|
||||
AreaCommitmentTypeMinKgPerHaInput.IsReadOnly = true;
|
||||
AreaCommitmentTypePenaltyPerKgInput.IsReadOnly = true;
|
||||
AreaCommitmentTypePenaltyInput.IsReadOnly = true;
|
||||
AreaCommitmentTypePenaltyNoneInput.IsReadOnly = true;
|
||||
|
||||
SeasonMaxKgPerHaInput.TextBox.IsReadOnly = true;
|
||||
SeasonVatNormalInput.TextBox.IsReadOnly = true;
|
||||
SeasonVatFlatrateInput.TextBox.IsReadOnly = true;
|
||||
SeasonMinKgPerBsInput.TextBox.IsReadOnly = true;
|
||||
SeasonMaxKgPerBsInput.TextBox.IsReadOnly = true;
|
||||
SeasonPenaltyPerKgInput.TextBox.IsReadOnly = true;
|
||||
SeasonPenaltyInput.TextBox.IsReadOnly = true;
|
||||
SeasonPenaltyNoneInput.TextBox.IsReadOnly = true;
|
||||
SeasonBsValueInput.TextBox.IsReadOnly = true;
|
||||
SeasonMaxKgPerHaInput.IsReadOnly = true;
|
||||
SeasonVatNormalInput.IsReadOnly = true;
|
||||
SeasonVatFlatrateInput.IsReadOnly = true;
|
||||
SeasonMinKgPerBsInput.IsReadOnly = true;
|
||||
SeasonMaxKgPerBsInput.IsReadOnly = true;
|
||||
SeasonPenaltyPerKgInput.IsReadOnly = true;
|
||||
SeasonPenaltyInput.IsReadOnly = true;
|
||||
SeasonPenaltyNoneInput.IsReadOnly = true;
|
||||
SeasonPenaltyPerBsInput.IsReadOnly = true;
|
||||
SeasonPenaltyPerBsNoneInput.IsReadOnly = true;
|
||||
SeasonBsValueInput.IsReadOnly = true;
|
||||
|
||||
SeasonModifierIdInput.IsReadOnly = true;
|
||||
SeasonModifierNameInput.IsReadOnly = true;
|
||||
SeasonModifierRelInput.TextBox.IsReadOnly = true;
|
||||
SeasonModifierAbsInput.TextBox.IsReadOnly = true;
|
||||
SeasonModifierRelInput.IsReadOnly = true;
|
||||
SeasonModifierAbsInput.IsReadOnly = true;
|
||||
|
||||
ParameterAllowAttrIntoLowerInput.IsEnabled = false;
|
||||
ParameterAvoidUnderDeliveriesInput.IsEnabled = false;
|
||||
ParameterHonorGebundenInput.IsEnabled = false;
|
||||
ParameterExportEbicsVersion.IsEnabled = false;
|
||||
ParameterExportEbicsAddress.IsEnabled = false;
|
||||
}
|
||||
|
||||
new protected void UnlockInputs() {
|
||||
@ -102,7 +113,7 @@ namespace Elwig.Windows {
|
||||
WineAttributeIdInput.IsReadOnly = false;
|
||||
WineAttributeNameInput.IsReadOnly = false;
|
||||
WineAttributeActiveInput.IsEnabled = true;
|
||||
WineAttributeMaxKgPerHaInput.TextBox.IsReadOnly = false;
|
||||
WineAttributeMaxKgPerHaInput.IsReadOnly = false;
|
||||
WineAttributeStrictInput.IsEnabled = true;
|
||||
WineAttributeFillLowerInput.IsEnabled = true;
|
||||
|
||||
@ -112,25 +123,33 @@ namespace Elwig.Windows {
|
||||
|
||||
AreaCommitmentTypeWineVariantInput.IsEnabled = true;
|
||||
AreaCommitmentTypeWineAttributeInput.IsEnabled = true;
|
||||
AreaCommitmentTypeMinKgPerHaInput.TextBox.IsReadOnly = false;
|
||||
AreaCommitmentTypePenaltyPerKgInput.TextBox.IsReadOnly = false;
|
||||
AreaCommitmentTypePenaltyInput.TextBox.IsReadOnly = false;
|
||||
AreaCommitmentTypePenaltyNoneInput.TextBox.IsReadOnly = false;
|
||||
AreaCommitmentTypeMinKgPerHaInput.IsReadOnly = false;
|
||||
AreaCommitmentTypePenaltyPerKgInput.IsReadOnly = false;
|
||||
AreaCommitmentTypePenaltyInput.IsReadOnly = false;
|
||||
AreaCommitmentTypePenaltyNoneInput.IsReadOnly = false;
|
||||
|
||||
SeasonMaxKgPerHaInput.TextBox.IsReadOnly = false;
|
||||
SeasonVatNormalInput.TextBox.IsReadOnly = false;
|
||||
SeasonVatFlatrateInput.TextBox.IsReadOnly = false;
|
||||
SeasonMinKgPerBsInput.TextBox.IsReadOnly = false;
|
||||
SeasonMaxKgPerBsInput.TextBox.IsReadOnly = false;
|
||||
SeasonPenaltyPerKgInput.TextBox.IsReadOnly = false;
|
||||
SeasonPenaltyInput.TextBox.IsReadOnly = false;
|
||||
SeasonPenaltyNoneInput.TextBox.IsReadOnly = false;
|
||||
SeasonBsValueInput.TextBox.IsReadOnly = false;
|
||||
SeasonMaxKgPerHaInput.IsReadOnly = false;
|
||||
SeasonVatNormalInput.IsReadOnly = false;
|
||||
SeasonVatFlatrateInput.IsReadOnly = false;
|
||||
SeasonMinKgPerBsInput.IsReadOnly = false;
|
||||
SeasonMaxKgPerBsInput.IsReadOnly = false;
|
||||
SeasonPenaltyPerKgInput.IsReadOnly = false;
|
||||
SeasonPenaltyInput.IsReadOnly = false;
|
||||
SeasonPenaltyNoneInput.IsReadOnly = false;
|
||||
SeasonPenaltyPerBsInput.IsReadOnly = false;
|
||||
SeasonPenaltyPerBsNoneInput.IsReadOnly = false;
|
||||
SeasonBsValueInput.IsReadOnly = false;
|
||||
|
||||
SeasonModifierIdInput.IsReadOnly = false;
|
||||
SeasonModifierNameInput.IsReadOnly = false;
|
||||
SeasonModifierRelInput.TextBox.IsReadOnly = false;
|
||||
SeasonModifierAbsInput.TextBox.IsReadOnly = false;
|
||||
SeasonModifierRelInput.IsReadOnly = false;
|
||||
SeasonModifierAbsInput.IsReadOnly = false;
|
||||
|
||||
ParameterAllowAttrIntoLowerInput.IsEnabled = true;
|
||||
ParameterAvoidUnderDeliveriesInput.IsEnabled = true;
|
||||
ParameterHonorGebundenInput.IsEnabled = true;
|
||||
ParameterExportEbicsVersion.IsEnabled = true;
|
||||
ParameterExportEbicsAddress.IsEnabled = true;
|
||||
}
|
||||
|
||||
private void Window_Loaded(object sender, RoutedEventArgs evt) {
|
||||
@ -139,9 +158,11 @@ namespace Elwig.Windows {
|
||||
|
||||
protected override async Task OnRenewContext(AppDbContext ctx) {
|
||||
await base.OnRenewContext(ctx);
|
||||
FillInputs(App.Client);
|
||||
FillInputs(App.Client, await ctx.Seasons.FindAsync(Utils.CurrentLastSeason));
|
||||
ControlUtils.RenewItemsSource(SeasonList, await ctx.Seasons
|
||||
.OrderByDescending(s => s.Year)
|
||||
.Include(s => s.Modifiers)
|
||||
.Include(s => s.Currency)
|
||||
.ToListAsync(), null, ControlUtils.RenewSourceDefault.First);
|
||||
var year = (SeasonList.SelectedItem as Season)?.Year;
|
||||
ControlUtils.RenewItemsSource(BranchList, await ctx.Branches
|
||||
@ -210,6 +231,7 @@ namespace Elwig.Windows {
|
||||
|
||||
private async Task Save() {
|
||||
await UpdateClientParameters(App.Client);
|
||||
await UpdateParameters(Utils.CurrentLastSeason);
|
||||
using var tx = await EditContext!.Database.BeginTransactionAsync();
|
||||
await BranchesSave(EditContext!);
|
||||
await WineAttributesSave(EditContext!);
|
||||
@ -261,8 +283,9 @@ namespace Elwig.Windows {
|
||||
|
||||
await FinishEditing();
|
||||
|
||||
using var ctx = new AppDbContext();
|
||||
ClearInputStates();
|
||||
FillInputs(App.Client);
|
||||
FillInputs(App.Client, await ctx.Seasons.FindAsync(Utils.CurrentLastSeason));
|
||||
LockInputs();
|
||||
}
|
||||
|
||||
@ -280,8 +303,9 @@ namespace Elwig.Windows {
|
||||
|
||||
await InitEditing();
|
||||
|
||||
using var ctx = new AppDbContext();
|
||||
ClearInputStates();
|
||||
FillInputs(App.Client);
|
||||
FillInputs(App.Client, await ctx.Seasons.FindAsync(Utils.CurrentLastSeason));
|
||||
UpdateButtons();
|
||||
}
|
||||
|
||||
@ -310,14 +334,16 @@ namespace Elwig.Windows {
|
||||
|
||||
await FinishEditing();
|
||||
|
||||
ClearInputStates();
|
||||
FillInputs(App.Client);
|
||||
LockInputs();
|
||||
using (var ctx = new AppDbContext()) {
|
||||
ClearInputStates();
|
||||
FillInputs(App.Client, await ctx.Seasons.FindAsync(Utils.CurrentLastSeason));
|
||||
LockInputs();
|
||||
}
|
||||
|
||||
await HintContextChange();
|
||||
await App.HintContextChange();
|
||||
}
|
||||
|
||||
private void FillInputs(ClientParameters p) {
|
||||
private void FillInputs(ClientParameters p, Season? s) {
|
||||
ClearOriginalValues();
|
||||
ClearDefaultValues();
|
||||
|
||||
@ -348,6 +374,12 @@ namespace Elwig.Windows {
|
||||
TextElementDeliveryConfirmation.Text = p.TextDeliveryConfirmation;
|
||||
TextElementCreditNote.Text = p.TextCreditNote;
|
||||
|
||||
ParameterAllowAttrIntoLowerInput.IsChecked = s?.Billing_AllowAttrsIntoLower ?? false;
|
||||
ParameterAvoidUnderDeliveriesInput.IsChecked = s?.Billing_AvoidUnderDeliveries ?? false;
|
||||
ParameterHonorGebundenInput.IsChecked = s?.Billing_HonorGebunden ?? false;
|
||||
ParameterExportEbicsVersion.SelectedIndex = p.ExportEbicsVersion - 3;
|
||||
ParameterExportEbicsAddress.SelectedIndex = p.ExportEbicsAddress;
|
||||
|
||||
FinishInputFilling();
|
||||
}
|
||||
|
||||
@ -374,6 +406,9 @@ namespace Elwig.Windows {
|
||||
p.TextDeliveryConfirmation = TextElementDeliveryConfirmation.Text.Length > 0 ? TextElementDeliveryConfirmation.Text : null;
|
||||
p.TextCreditNote = TextElementCreditNote.Text.Length > 0 ? TextElementCreditNote.Text : null;
|
||||
|
||||
p.ExportEbicsVersion = ParameterExportEbicsVersion.SelectedIndex + 3;
|
||||
p.ExportEbicsAddress = ParameterExportEbicsAddress.SelectedIndex;
|
||||
|
||||
await p.UpdateValues();
|
||||
}
|
||||
|
||||
@ -382,5 +417,19 @@ namespace Elwig.Windows {
|
||||
ClientNameFull.Text = $"{ClientNameInput.Text}{(suffix != null ? $", {suffix}," : "")} {ClientNameTypeInput.Text}";
|
||||
TextBox_TextChanged(sender, evt);
|
||||
}
|
||||
|
||||
private async Task UpdateParameters(int year) {
|
||||
try {
|
||||
using var ctx = new AppDbContext();
|
||||
if (await ctx.Seasons.FindAsync(year) is not Season s)
|
||||
return;
|
||||
|
||||
s.Billing_AllowAttrsIntoLower = ParameterAllowAttrIntoLowerInput.IsChecked ?? false;
|
||||
s.Billing_AvoidUnderDeliveries = ParameterAvoidUnderDeliveriesInput.IsChecked ?? false;
|
||||
s.Billing_HonorGebunden = ParameterHonorGebundenInput.IsChecked ?? false;
|
||||
ctx.Update(s);
|
||||
await ctx.SaveChangesAsync();
|
||||
} catch { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,6 @@
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:Elwig.Windows"
|
||||
xmlns:ctrl="clr-namespace:Elwig.Controls"
|
||||
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
|
||||
xmlns:ScottPlot="clr-namespace:ScottPlot.WPF;assembly=ScottPlot.WPF"
|
||||
mc:Ignorable="d"
|
||||
Title="Auszahlung - Elwig" Height="700" Width="1500" MinWidth="1000" MinHeight="500"
|
||||
@ -29,6 +28,15 @@
|
||||
<Setter Property="Height" Value="25"/>
|
||||
<Setter Property="TextWrapping" Value="NoWrap"/>
|
||||
</Style>
|
||||
<Style TargetType="ctrl:UnitTextBox">
|
||||
<Setter Property="HorizontalAlignment" Value="Stretch"/>
|
||||
<Setter Property="VerticalAlignment" Value="Top"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="Padding" Value="2"/>
|
||||
<Setter Property="IsReadOnly" Value="True"/>
|
||||
<Setter Property="Height" Value="25"/>
|
||||
<Setter Property="TextWrapping" Value="NoWrap"/>
|
||||
</Style>
|
||||
<Style TargetType="ComboBox">
|
||||
<Setter Property="IsEnabled" Value="False"/>
|
||||
<Setter Property="Height" Value="25"/>
|
||||
@ -61,10 +69,10 @@
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label Content="Für:" Margin="10,-2,0,0" FontSize="14" Grid.Column="0" VerticalAlignment="Center"/>
|
||||
<xctk:CheckComboBox x:Name="VaributeInput" Margin="50,0,0,0" Grid.Column="0" Width="500" Height="25" HorizontalAlignment="Left"
|
||||
<ctrl:CheckComboBox x:Name="VaributeInput" Margin="50,0,0,0" Grid.Column="0" Width="500" Height="25" HorizontalAlignment="Left"
|
||||
IsSelectAllActive="True" SelectAllContent="Alle Sorten" Delimiter=", " AllItemsSelectedContent="Alle Sorten"
|
||||
IsEnabled="False" ItemSelectionChanged="VaributeInput_Changed">
|
||||
<xctk:CheckComboBox.ItemTemplate>
|
||||
IsEnabled="False" SelectionChanged="VaributeInput_Changed">
|
||||
<ctrl:CheckComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding Variety.Name}" Width="150"/>
|
||||
@ -75,8 +83,8 @@
|
||||
<TextBlock Text="{Binding AssignedAbgewGraphId}" Width="30"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</xctk:CheckComboBox.ItemTemplate>
|
||||
</xctk:CheckComboBox>
|
||||
</ctrl:CheckComboBox.ItemTemplate>
|
||||
</ctrl:CheckComboBox>
|
||||
|
||||
<CheckBox x:Name="AbgewertetInput" Content="Abgewertet" IsEnabled="False" Checked="AbgewertetInput_Changed" Unchecked="AbgewertetInput_Changed"
|
||||
VerticalAlignment="Center" HorizontalAlignment="Left" Margin="0,0,0,0" Grid.Column="1"/>
|
||||
@ -130,12 +138,12 @@
|
||||
|
||||
<Label Content="Oechsle:" Margin="10,10,0,0" Grid.Column="0"/>
|
||||
<ctrl:UnitTextBox x:Name="OechsleInput" Unit="°Oe" TextChanged="OechsleInput_TextChanged" IsEnabled="False" LostFocus="OechsleInput_LostFocus"
|
||||
Grid.Column="1" Width="90" Margin="0,10,0,0" HorizontalAlignment="Left" VerticalAlignment="Top"/>
|
||||
Grid.Column="1" Width="90" Margin="0,10,0,0" HorizontalAlignment="Left" VerticalAlignment="Top"/>
|
||||
|
||||
|
||||
<Label Content="Preis:" Margin="10,40,0,0" Grid.Column="0"/>
|
||||
<ctrl:UnitTextBox x:Name="PriceInput" Unit="€/kg" TextChanged="PriceInput_TextChanged" IsEnabled="False" LostFocus="PriceInput_LostFocus"
|
||||
Grid.Column="1" Width="90" Margin="0,40,0,0" HorizontalAlignment="Left" VerticalAlignment="Top"/>
|
||||
Grid.Column="1" Width="90" Margin="0,40,0,0" HorizontalAlignment="Left" VerticalAlignment="Top"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
|
@ -9,13 +9,9 @@ using Elwig.Controls;
|
||||
using Elwig.Helpers;
|
||||
using Elwig.Helpers.Billing;
|
||||
using Elwig.Models.Entities;
|
||||
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
||||
using ScottPlot.Plottables;
|
||||
using ScottPlot;
|
||||
using Xceed.Wpf.Toolkit.Primitives;
|
||||
using ScottPlot.Control;
|
||||
using System.Text.Json;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Internal;
|
||||
|
||||
namespace Elwig.Windows {
|
||||
public partial class ChartWindow : ContextWindow {
|
||||
@ -38,21 +34,21 @@ namespace Elwig.Windows {
|
||||
|
||||
private static readonly LegendItem
|
||||
UngebundenLegend = new() {
|
||||
Label = "Ungebunden", LineWidth = 1, LineColor = ColorUngebunden,
|
||||
Marker = new(MarkerShape.FilledCircle, 5, ColorUngebunden)
|
||||
LabelText = "Ungebunden", LineWidth = 1, LineColor = ColorUngebunden,
|
||||
MarkerStyle = new(MarkerShape.FilledCircle, 5, ColorUngebunden)
|
||||
},
|
||||
GebundenLegend = new() {
|
||||
Label = "Gebunden", LineWidth = 1, LineColor = ColorGebunden,
|
||||
Marker = new(MarkerShape.FilledCircle, 5, ColorGebunden)
|
||||
LabelText = "Gebunden", LineWidth = 1, LineColor = ColorGebunden,
|
||||
MarkerStyle = new(MarkerShape.FilledCircle, 5, ColorGebunden)
|
||||
},
|
||||
LdwLegend = new() {
|
||||
Label = "68 °Oe (LDW)", LineWidth = 2, LineColor = Colors.Red, Marker = MarkerStyle.None
|
||||
LabelText = "68 °Oe (LDW)", LineWidth = 2, LineColor = Colors.Red, MarkerStyle = MarkerStyle.None
|
||||
},
|
||||
QuwLegend = new() {
|
||||
Label = "73 °Oe (QUW)", LineWidth = 2, LineColor = Colors.Orange, Marker = MarkerStyle.None
|
||||
LabelText = "73 °Oe (QUW)", LineWidth = 2, LineColor = Colors.Orange, MarkerStyle = MarkerStyle.None
|
||||
},
|
||||
KabLegend = new() {
|
||||
Label = "84 °Oe (KAB)", LineWidth = 2, LineColor = Colors.Green, Marker = MarkerStyle.None
|
||||
LabelText = "84 °Oe (KAB)", LineWidth = 2, LineColor = Colors.Green, MarkerStyle = MarkerStyle.None
|
||||
};
|
||||
|
||||
private (Graph? Graph, int Index) LastHighlighted = (null, -1);
|
||||
@ -379,7 +375,7 @@ namespace Elwig.Windows {
|
||||
}
|
||||
|
||||
private void ShowLegend() {
|
||||
OechslePricePlot.Plot.Legend.Location = Alignment.UpperLeft;
|
||||
OechslePricePlot.Plot.Legend.Alignment = Alignment.UpperLeft;
|
||||
OechslePricePlot.Plot.Legend.IsVisible = true;
|
||||
|
||||
OechslePricePlot.Plot.Legend.ManualItems.Add(LdwLegend);
|
||||
@ -429,7 +425,7 @@ namespace Elwig.Windows {
|
||||
|
||||
private void PriceInput_TextChanged(object sender, TextChangedEventArgs evt) {
|
||||
if (PrimaryMarkedPoint != -1 && ActiveGraph != null && PriceInput.IsKeyboardFocusWithin == true) {
|
||||
var res = Validator.CheckDecimal(PriceInput.TextBox, true, 2, Season.Precision);
|
||||
var res = Validator.CheckDecimal(PriceInput, true, 2, Season.Precision);
|
||||
if (res.IsValid && double.TryParse(PriceInput.Text, out double price)) {
|
||||
ActiveGraph.SetPriceAt(PrimaryMarkedPoint, price);
|
||||
PrimaryMarkedPointPlot.Location = new Coordinates(PrimaryMarkedPointPlot.Location.X, price);
|
||||
@ -509,7 +505,7 @@ namespace Elwig.Windows {
|
||||
ChangeMarker(PrimaryMarkedPointPlot, true, ActiveGraph!.GetOechsleAt(PrimaryMarkedPoint), ActiveGraph.GetPriceAt(PrimaryMarkedPoint));
|
||||
|
||||
OechsleInput.Text = Highlighted.Graph!.GetOechsleAt(Highlighted.Index).ToString();
|
||||
PriceInput.Text = Highlighted.Graph.GetPriceAt(Highlighted.Index).ToString();
|
||||
PriceInput.Text = Math.Round(Highlighted.Graph.GetPriceAt(Highlighted.Index), Season.Precision).ToString();
|
||||
|
||||
EnableActionButtons();
|
||||
} else {
|
||||
@ -592,13 +588,13 @@ namespace Elwig.Windows {
|
||||
Pixel mousePixel = new(p.X, p.Y - 30);
|
||||
Coordinates mouseLocation = OechslePricePlot.Plot.GetCoordinates(mousePixel);
|
||||
TooltipPlot = OechslePricePlot.Plot.Add.Text($"Oechsle: {pointX:N2}, Preis: {Math.Round(pointY, Season.Precision)}€/kg", mouseLocation.X, mouseLocation.Y);
|
||||
TooltipPlot.Label.FontSize = 12;
|
||||
TooltipPlot.Label.Bold = true;
|
||||
TooltipPlot.Label.BorderColor = Colors.Black;
|
||||
TooltipPlot.Label.BorderWidth = 2;
|
||||
TooltipPlot.Label.BackColor = Colors.White;
|
||||
TooltipPlot.Label.Padding = 10;
|
||||
TooltipPlot.Label.Alignment = Alignment.MiddleLeft;
|
||||
TooltipPlot.LabelFontSize = 12;
|
||||
TooltipPlot.LabelBold = true;
|
||||
TooltipPlot.LabelBorderColor = Colors.Black;
|
||||
TooltipPlot.LabelBorderWidth = 2;
|
||||
TooltipPlot.LabelBackgroundColor = Colors.White;
|
||||
TooltipPlot.LabelPadding = 10;
|
||||
TooltipPlot.LabelAlignment = Alignment.MiddleLeft;
|
||||
}
|
||||
LastHighlighted = (g, pointIndex);
|
||||
HoverChanged = false;
|
||||
@ -667,13 +663,13 @@ namespace Elwig.Windows {
|
||||
private void EnableUnitTextBox(UnitTextBox u) {
|
||||
if (PaymentVar.TestVariant) {
|
||||
u.IsEnabled = true;
|
||||
u.TextBox.IsReadOnly = false;
|
||||
u.IsReadOnly = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void DisableUnitTextBox(UnitTextBox u) {
|
||||
u.IsEnabled = false;
|
||||
u.TextBox.IsReadOnly = true;
|
||||
u.IsReadOnly = true;
|
||||
}
|
||||
|
||||
private void ChangeActiveGraph(Graph? g) {
|
||||
@ -716,7 +712,7 @@ namespace Elwig.Windows {
|
||||
|
||||
private void GebundenFlatBonus_TextChanged(object sender, TextChangedEventArgs e) {
|
||||
if (FillingInputs) return;
|
||||
var r = Validator.CheckDecimal(GebundenFlatBonus.TextBox, true, 2, Season.Precision);
|
||||
var r = Validator.CheckDecimal(GebundenFlatBonus, true, 2, Season.Precision);
|
||||
if (r.IsValid && SelectedGraphEntry != null) {
|
||||
SelectedGraphEntry.GebundenFlatBonus = double.Parse(GebundenFlatBonus.Text);
|
||||
ResetPlot();
|
||||
@ -724,26 +720,31 @@ namespace Elwig.Windows {
|
||||
}
|
||||
}
|
||||
|
||||
private void VaributeInput_Changed(object sender, ItemSelectionChangedEventArgs e) {
|
||||
if (FillingInputs || e.Item is not Varibute v) return;
|
||||
private void VaributeInput_Changed(object sender, SelectionChangedEventArgs evt) {
|
||||
if (FillingInputs) return;
|
||||
var isOpen = VaributeInput.IsDropDownOpen;
|
||||
if (e.IsSelected) {
|
||||
if (RemoveVaributeFromOthers(e.Item.ToString())) {
|
||||
|
||||
foreach (var i in evt.AddedItems) {
|
||||
if (i is not Varibute v) continue;
|
||||
if (RemoveVaributeFromOthers(v.ToString())) {
|
||||
if (AbgewertetInput.IsChecked == true) {
|
||||
v.AssignedAbgewGraphId = SelectedGraphEntry?.Id;
|
||||
} else {
|
||||
v.AssignedGraphId = SelectedGraphEntry?.Id;
|
||||
}
|
||||
} else {
|
||||
VaributeInput.SelectedItems.Remove(e.Item);
|
||||
VaributeInput.SelectedItems.Remove(v);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
foreach (var i in evt.RemovedItems) {
|
||||
if (i is not Varibute v) continue;
|
||||
if (AbgewertetInput.IsChecked == true) {
|
||||
v.AssignedAbgewGraphId = null;
|
||||
} else {
|
||||
v.AssignedGraphId = null;
|
||||
}
|
||||
}
|
||||
|
||||
SelectedGraphEntry!.Vaributes = VaributeInput.SelectedItems.Cast<Varibute>().ToList();
|
||||
SetHasChanged();
|
||||
GraphList.Items.Refresh();
|
||||
|
@ -3,7 +3,6 @@
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:Elwig.Windows"
|
||||
xmlns:ctrl="clr-namespace:Elwig.Controls"
|
||||
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
|
||||
Title="Lieferungen - Elwig" Height="720" Width="1100" MinHeight="720" MinWidth="1000"
|
||||
Loaded="Window_Loaded">
|
||||
<Window.Resources>
|
||||
@ -21,13 +20,21 @@
|
||||
<Setter Property="Height" Value="25"/>
|
||||
<Setter Property="TextWrapping" Value="NoWrap"/>
|
||||
</Style>
|
||||
<Style TargetType="ctrl:UnitTextBox">
|
||||
<Setter Property="HorizontalAlignment" Value="Stretch"/>
|
||||
<Setter Property="VerticalAlignment" Value="Top"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="Padding" Value="2"/>
|
||||
<Setter Property="Height" Value="25"/>
|
||||
<Setter Property="TextWrapping" Value="NoWrap"/>
|
||||
</Style>
|
||||
<Style TargetType="ComboBox">
|
||||
<Setter Property="Height" Value="25"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="HorizontalAlignment" Value="Stretch"/>
|
||||
<Setter Property="VerticalAlignment" Value="Top"/>
|
||||
</Style>
|
||||
<Style TargetType="xctk:CheckComboBox">
|
||||
<Style TargetType="ctrl:CheckComboBox">
|
||||
<Setter Property="Height" Value="25"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="HorizontalAlignment" Value="Stretch"/>
|
||||
@ -81,7 +88,7 @@
|
||||
<MenuItem x:Name="Menu_DeliveryJournal_PrintToday" Header="...von heute drucken"
|
||||
Click="Menu_DeliveryJournal_PrintToday_Click" InputGestureText="Strg+J"/>
|
||||
</MenuItem>
|
||||
<MenuItem Header="Qualitätsstatistik">
|
||||
<MenuItem Header="Qualitätsstatistik" x:Name="Menu_WineQualityStatistics">
|
||||
<MenuItem x:Name="Menu_WineQualityStatistics_ShowFilters" Header="...aus Filtern anzeigen (PDF)"
|
||||
Click="Menu_WineQualityStatistics_ShowFilters_Click"/>
|
||||
<MenuItem x:Name="Menu_WineQualityStatistics_SavePdfFilters" Header="...aus Filtern speichern... (PDF)"
|
||||
@ -95,10 +102,32 @@
|
||||
Click="Menu_WineQualityStatistics_SavePdfToday_Click"/>
|
||||
<MenuItem x:Name="Menu_WineQualityStatistics_PrintToday" Header="...von heute drucken"
|
||||
Click="Menu_WineQualityStatistics_PrintToday_Click" InputGestureText="Strg+Q"/>
|
||||
<Separator/>
|
||||
<MenuItem x:Name="Menu_WineQualityStatistics_ModeOe" Header="...nach °Oe aufschlüsseln" IsCheckable="True" IsChecked="True"
|
||||
Click="Menu_WineQualityStatistics_Mode_Click"/>
|
||||
<MenuItem x:Name="Menu_WineQualityStatistics_ModeKmw10" Header="...nach °KMW aufschlüsseln (⅒)" IsCheckable="True"
|
||||
Click="Menu_WineQualityStatistics_Mode_Click"/>
|
||||
<MenuItem x:Name="Menu_WineQualityStatistics_ModeKmw5" Header="...nach °KMW aufschlüsseln (⅕)" IsCheckable="True"
|
||||
Click="Menu_WineQualityStatistics_Mode_Click"/>
|
||||
<MenuItem x:Name="Menu_WineQualityStatistics_ModeKmw2" Header="...nach °KMW aufschlüsseln (½)" IsCheckable="True"
|
||||
Click="Menu_WineQualityStatistics_Mode_Click"/>
|
||||
<MenuItem x:Name="Menu_WineQualityStatistics_ModeKmw1" Header="...nach °KMW aufschlüsseln (ganze)" IsCheckable="True"
|
||||
Click="Menu_WineQualityStatistics_Mode_Click"/>
|
||||
</MenuItem>
|
||||
<MenuItem Header="BKI">
|
||||
<MenuItem x:Name="Menu_Bki_SaveList" Header="Traubentransportscheinliste speichern..."/>
|
||||
</MenuItem>
|
||||
<MenuItem Header="Export">
|
||||
<MenuItem x:Name="Menu_Export_ExportFilters" Header="...aus Filtern speichern..."
|
||||
Click="Menu_Export_ExportFilters_Click"/>
|
||||
<MenuItem x:Name="Menu_Export_UploadFilters" Header="...aus Filtern hochladen"
|
||||
Click="Menu_Export_UploadFilters_Click"/>
|
||||
<Separator/>
|
||||
<MenuItem x:Name="Menu_Export_ExportToday" Header="...von heute speichern..."
|
||||
Click="Menu_Export_ExportToday_Click"/>
|
||||
<MenuItem x:Name="Menu_Export_UploadToday" Header="...von heute hochladen"
|
||||
Click="Menu_Export_UploadToday_Click" InputGestureText="Strg+H"/>
|
||||
</MenuItem>
|
||||
<MenuItem Header="Einstellungen">
|
||||
<MenuItem x:Name="Menu_Settings_EnableFreeEditing" Header="Freie Bearbeitung aktivieren"
|
||||
IsCheckable="True" Checked="Menu_Settings_EnableFreeEditing_Checked" Unchecked="Menu_Settings_EnableFreeEditing_Unchecked"/>
|
||||
@ -145,9 +174,9 @@
|
||||
</TextBlock>
|
||||
</TextBox.ToolTip>
|
||||
</TextBox>
|
||||
<xctk:IntegerUpDown x:Name="SeasonInput" Grid.ColumnSpan="3" Height="25" Width="56" FontSize="14" Minimum="1000" Maximum="9999"
|
||||
Margin="0,10,100,0" VerticalAlignment="Top" HorizontalAlignment="Right"
|
||||
ValueChanged="SeasonInput_ValueChanged"/>
|
||||
<ctrl:IntegerUpDown x:Name="SeasonInput" Grid.ColumnSpan="3" Height="25" Width="56" FontSize="14" Minimum="1900" Maximum="9999"
|
||||
Margin="0,10,100,0" VerticalAlignment="Top" HorizontalAlignment="Right" Text="2020"
|
||||
TextChanged="SeasonInput_TextChanged"/>
|
||||
<CheckBox x:Name="TodayOnlyInput" Content="Nur heute"
|
||||
HorizontalAlignment="Right" Margin="0,7,18,0" VerticalAlignment="Top" Grid.Column="1" Grid.ColumnSpan="2"
|
||||
Checked="TodayOnlyInput_Changed" Unchecked="TodayOnlyInput_Changed"/>
|
||||
@ -353,8 +382,12 @@
|
||||
<TextBox x:Name="SortIdInput" 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" Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2" Margin="41,10,10,10"
|
||||
ItemTemplate="{StaticResource WineVarietyTemplate}" TextSearch.TextPath="Name"
|
||||
SelectionChanged="WineVarietyInput_SelectionChanged" KeyUp="Input_KeyUp"/>
|
||||
TextSearch.TextPath="Name"
|
||||
SelectionChanged="WineVarietyInput_SelectionChanged" KeyUp="Input_KeyUp">
|
||||
<ComboBox.ItemTemplateSelector>
|
||||
<ctrl:WineVarietyTemplateSelector/>
|
||||
</ComboBox.ItemTemplateSelector>
|
||||
</ComboBox>
|
||||
|
||||
<Label Content="Attr./Bewirt.:" Margin="10,40,0,0" Grid.Column="0"/>
|
||||
<ComboBox x:Name="AttributeInput" Grid.Row="1" Grid.Column="1" Margin="0,40,5,10"
|
||||
@ -382,8 +415,12 @@
|
||||
|
||||
<Label Content="Qualitätsstufe:" Margin="10,40,10,10"/>
|
||||
<ComboBox x:Name="WineQualityLevelInput" Width="146" Margin="0,40,10,10" Grid.Column="1" HorizontalAlignment="Left"
|
||||
ItemTemplate="{StaticResource WineQualityLevelTemplate}"
|
||||
SelectionChanged="WineQualityLevelInput_SelectionChanged" KeyUp="Input_KeyUp"/>
|
||||
TextSearch.TextPath="Name"
|
||||
SelectionChanged="WineQualityLevelInput_SelectionChanged" KeyUp="Input_KeyUp">
|
||||
<ComboBox.ItemTemplateSelector>
|
||||
<ctrl:WineQualityLevelTemplateSelector/>
|
||||
</ComboBox.ItemTemplateSelector>
|
||||
</ComboBox>
|
||||
|
||||
<CheckBox x:Name="AbgewertetInput" Content="Abgewertet" IsEnabled="False"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Left" Margin="10,75,10,10" Grid.Column="0" Grid.ColumnSpan="2"/>
|
||||
@ -436,9 +473,9 @@
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label Content="Zu-/Abschläge:" Margin="10,10,0,10"/>
|
||||
<xctk:CheckComboBox x:Name="ModifiersInput" Margin="0,10,10,10" Grid.Column="1" Grid.ColumnSpan="2"
|
||||
<ctrl:CheckComboBox x:Name="ModifiersInput" Margin="0,10,10,10" Grid.Column="1" Grid.ColumnSpan="2"
|
||||
ItemTemplate="{StaticResource ModifierTemplate}" Delimiter=", " AllItemsSelectedContent="Alle"
|
||||
ItemSelectionChanged="ModifiersInput_SelectionChanged"/>
|
||||
SelectionChanged="ModifiersInput_SelectionChanged"/>
|
||||
|
||||
<Label Content="Anmerkung:" Margin="10,40,0,10"/>
|
||||
<TextBox x:Name="PartCommentInput" Grid.Column="1" Margin="0,40,10,10" Grid.ColumnSpan="2"
|
||||
@ -505,7 +542,11 @@
|
||||
|
||||
<Label Content="Weinbaugebiet:" Margin="10,10,0,10" Grid.Column="0"/>
|
||||
<ComboBox x:Name="WineOriginInput" Margin="0,10,10,10" Grid.Column="1"
|
||||
ItemTemplate="{StaticResource WineOriginComboTemplate}"/>
|
||||
TextSearch.TextPath="Name">
|
||||
<ComboBox.ItemTemplateSelector>
|
||||
<ctrl:WineOriginTemplateSelector/>
|
||||
</ComboBox.ItemTemplateSelector>
|
||||
</ComboBox>
|
||||
|
||||
<Label Content="Weinbau-KG:" Margin="10,40,0,10" Grid.Column="0"/>
|
||||
<ComboBox x:Name="WineKgInput" Margin="0,40,10,10" Grid.Column="1"
|
||||
|
@ -11,6 +11,7 @@ using Microsoft.Win32;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Threading.Tasks;
|
||||
@ -18,7 +19,6 @@ using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Threading;
|
||||
using Xceed.Wpf.Toolkit.Primitives;
|
||||
|
||||
namespace Elwig.Windows {
|
||||
public partial class DeliveryAdminWindow : AdministrationWindow {
|
||||
@ -37,6 +37,7 @@ namespace Elwig.Windows {
|
||||
private readonly RoutedCommand CtrlO = new("CtrlO", typeof(DeliveryAdminWindow), [new KeyGesture(Key.O, ModifierKeys.Control)]);
|
||||
private readonly RoutedCommand CtrlJ = new("CtrlJ", typeof(DeliveryAdminWindow), [new KeyGesture(Key.J, ModifierKeys.Control)]);
|
||||
private readonly RoutedCommand CtrlQ = new("CtrlQ", typeof(DeliveryAdminWindow), [new KeyGesture(Key.Q, ModifierKeys.Control)]);
|
||||
private readonly RoutedCommand CtrlH = new("CtrlH", typeof(DeliveryAdminWindow), [new KeyGesture(Key.H, ModifierKeys.Control)]);
|
||||
private readonly RoutedCommand CtrlShiftP = new("CtrlShiftP", typeof(DeliveryAdminWindow), [new KeyGesture(Key.P, ModifierKeys.Control | ModifierKeys.Shift)]);
|
||||
private readonly RoutedCommand CtrlShiftO = new("CtrlShiftO", typeof(DeliveryAdminWindow), [new KeyGesture(Key.O, ModifierKeys.Control | ModifierKeys.Shift)]);
|
||||
|
||||
@ -54,15 +55,16 @@ namespace Elwig.Windows {
|
||||
CommandBindings.Add(new CommandBinding(CtrlO, Menu_DeliveryJournal_ShowFilters_Click));
|
||||
CommandBindings.Add(new CommandBinding(CtrlJ, Menu_DeliveryJournal_PrintToday_Click));
|
||||
CommandBindings.Add(new CommandBinding(CtrlQ, Menu_WineQualityStatistics_PrintToday_Click));
|
||||
CommandBindings.Add(new CommandBinding(CtrlH, Menu_Export_UploadToday_Click));
|
||||
CommandBindings.Add(new CommandBinding(CtrlShiftP, Menu_DeliveryNote_Print_Click));
|
||||
CommandBindings.Add(new CommandBinding(CtrlShiftO, Menu_DeliveryJournal_PrintFilters_Click));
|
||||
RequiredInputs = [
|
||||
MgNrInput, MemberInput,
|
||||
LsNrInput, DateInput, BranchInput,
|
||||
SortIdInput, WineVarietyInput,
|
||||
GradationOeInput.TextBox, GradationKmwInput.TextBox, WineQualityLevelInput,
|
||||
GradationOeInput, GradationKmwInput, WineQualityLevelInput,
|
||||
WineOriginInput, WineKgInput,
|
||||
WeightInput.TextBox
|
||||
WeightInput
|
||||
];
|
||||
ExemptInputs = [
|
||||
SearchInput, SeasonInput, TodayOnlyInput, AllSeasonsInput,
|
||||
@ -108,6 +110,22 @@ namespace Elwig.Windows {
|
||||
WeighingCButton.Visibility = Visibility.Hidden;
|
||||
WeighingDButton.Visibility = Visibility.Hidden;
|
||||
}
|
||||
|
||||
Menu_WineQualityStatistics_ModeOe.IsChecked = false;
|
||||
Menu_WineQualityStatistics_ModeKmw1.IsChecked = false;
|
||||
Menu_WineQualityStatistics_ModeKmw2.IsChecked = false;
|
||||
Menu_WineQualityStatistics_ModeKmw5.IsChecked = false;
|
||||
Menu_WineQualityStatistics_ModeKmw10.IsChecked = false;
|
||||
switch (App.Client.OrderingMemberList) {
|
||||
case 0: Menu_WineQualityStatistics_ModeOe.IsChecked = true; break;
|
||||
case 1: Menu_WineQualityStatistics_ModeKmw1.IsChecked = true; break;
|
||||
case 2: Menu_WineQualityStatistics_ModeKmw2.IsChecked = true; break;
|
||||
case 3: Menu_WineQualityStatistics_ModeKmw5.IsChecked = true; break;
|
||||
case 4: Menu_WineQualityStatistics_ModeKmw10.IsChecked = true; break;
|
||||
}
|
||||
|
||||
Menu_Export_UploadFilters.IsEnabled = App.Config.SyncUrl != null;
|
||||
Menu_Export_UploadToday.IsEnabled = App.Config.SyncUrl != null;
|
||||
}
|
||||
|
||||
public DeliveryAdminWindow(int mgnr) : this() {
|
||||
@ -209,6 +227,15 @@ namespace Elwig.Windows {
|
||||
await GenerateDeliveryJournal(1, ExportMode.Show);
|
||||
}
|
||||
|
||||
private async void Menu_Export_ExportToday_Click(object sender, RoutedEventArgs evt) {
|
||||
await GenerateDeliveryJournal(1, ExportMode.Export);
|
||||
}
|
||||
|
||||
private async void Menu_Export_UploadToday_Click(object sender, RoutedEventArgs evt) {
|
||||
if (App.Config.SyncUrl == null) return;
|
||||
await GenerateDeliveryJournal(1, ExportMode.Upload);
|
||||
}
|
||||
|
||||
private async void Menu_DeliveryJournal_PrintToday_Click(object sender, RoutedEventArgs evt) {
|
||||
await GenerateDeliveryJournal(1, ExportMode.Print);
|
||||
}
|
||||
@ -229,6 +256,15 @@ namespace Elwig.Windows {
|
||||
await GenerateDeliveryJournal(0, ExportMode.Print);
|
||||
}
|
||||
|
||||
private async void Menu_Export_ExportFilters_Click(object sender, RoutedEventArgs evt) {
|
||||
await GenerateDeliveryJournal(0, ExportMode.Export);
|
||||
}
|
||||
|
||||
private async void Menu_Export_UploadFilters_Click(object sender, RoutedEventArgs evt) {
|
||||
if (App.Config.SyncUrl == null) return;
|
||||
await GenerateDeliveryJournal(0, ExportMode.Upload);
|
||||
}
|
||||
|
||||
private async Task GenerateDeliveryJournal(int modeWho, ExportMode exportMode) {
|
||||
using var ctx = new AppDbContext();
|
||||
IQueryable<DeliveryPart> query;
|
||||
@ -243,6 +279,10 @@ namespace Elwig.Windows {
|
||||
.Where(p => p.Delivery.DateString == date);
|
||||
filterNames.Add($"{Utils.Today:dd.MM.yyyy}");
|
||||
}
|
||||
if (exportMode == ExportMode.Upload && !filterNames.Contains($"Zweigstelle {App.BranchName}")) {
|
||||
query = query.Where(p => p.Delivery.ZwstId == App.ZwstId);
|
||||
filterNames.Add($"Zweigstelle {App.BranchName}");
|
||||
}
|
||||
|
||||
query = query
|
||||
.OrderBy(p => p.Delivery.DateString)
|
||||
@ -268,6 +308,41 @@ namespace Elwig.Windows {
|
||||
}
|
||||
Mouse.OverrideCursor = null;
|
||||
}
|
||||
} else if (exportMode == ExportMode.Export) {
|
||||
var d = new SaveFileDialog() {
|
||||
FileName = $"Lieferungen.zip",
|
||||
DefaultExt = "zip",
|
||||
Filter = "ZIP-Datei (*.zip)|*.zip",
|
||||
Title = $"{DeliveryJournal.Name} speichern unter - Elwig"
|
||||
};
|
||||
if (d.ShowDialog() == true) {
|
||||
Mouse.OverrideCursor = Cursors.AppStarting;
|
||||
try {
|
||||
await ElwigData.ExportDeliveries(d.FileName, await query.Select(p => p.Delivery).Distinct().ToListAsync(), filterNames);
|
||||
} catch (Exception exc) {
|
||||
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
Mouse.OverrideCursor = null;
|
||||
}
|
||||
} else if (exportMode == ExportMode.Upload && App.Config.SyncUrl != null) {
|
||||
Mouse.OverrideCursor = Cursors.AppStarting;
|
||||
try {
|
||||
var filename = $"{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{App.ZwstId}.zip";
|
||||
var path = Path.Combine(App.TempPath, filename);
|
||||
var list = await query.Select(p => p.Delivery).Distinct().ToListAsync();
|
||||
if (list.Count == 0) {
|
||||
MessageBox.Show("Es wurden keine Lieferungen zum Hochladen ausgewählt!", "Fehler",
|
||||
MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
} else {
|
||||
await ElwigData.ExportDeliveries(path, list, filterNames);
|
||||
await Utils.UploadExportData(path, App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
|
||||
MessageBox.Show($"Lieferungen erfolgreich hochgeladen!", "Lieferungen hochgeladen",
|
||||
MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
} catch (Exception exc) {
|
||||
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
Mouse.OverrideCursor = null;
|
||||
} else {
|
||||
Mouse.OverrideCursor = Cursors.AppStarting;
|
||||
try {
|
||||
@ -322,7 +397,7 @@ namespace Elwig.Windows {
|
||||
|
||||
Mouse.OverrideCursor = Cursors.AppStarting;
|
||||
try {
|
||||
var data = await WineQualityStatisticsData.FromQuery(query);
|
||||
var data = await WineQualityStatisticsData.FromQuery(query, App.Client.OrderingMemberList);
|
||||
using var doc = new WineQualityStatistics(string.Join(" / ", filterNames), data);
|
||||
await Utils.ExportDocument(doc, exportMode);
|
||||
} catch (Exception exc) {
|
||||
@ -331,6 +406,27 @@ namespace Elwig.Windows {
|
||||
Mouse.OverrideCursor = null;
|
||||
}
|
||||
|
||||
private async void Menu_WineQualityStatistics_Mode_Click(object sender, RoutedEventArgs evt) {
|
||||
Menu_WineQualityStatistics.IsSubmenuOpen = true;
|
||||
if (sender == Menu_WineQualityStatistics_ModeOe) {
|
||||
App.Client.OrderingMemberList = 0;
|
||||
} else if (sender == Menu_WineQualityStatistics_ModeKmw1) {
|
||||
App.Client.OrderingMemberList = 1;
|
||||
} else if (sender == Menu_WineQualityStatistics_ModeKmw2) {
|
||||
App.Client.OrderingMemberList = 2;
|
||||
} else if (sender == Menu_WineQualityStatistics_ModeKmw5) {
|
||||
App.Client.OrderingMemberList = 3;
|
||||
} else if (sender == Menu_WineQualityStatistics_ModeKmw10) {
|
||||
App.Client.OrderingMemberList = 4;
|
||||
}
|
||||
Menu_WineQualityStatistics_ModeOe.IsChecked = App.Client.OrderingMemberList == 0;
|
||||
Menu_WineQualityStatistics_ModeKmw1.IsChecked = App.Client.OrderingMemberList == 1;
|
||||
Menu_WineQualityStatistics_ModeKmw2.IsChecked = App.Client.OrderingMemberList == 2;
|
||||
Menu_WineQualityStatistics_ModeKmw5.IsChecked = App.Client.OrderingMemberList == 3;
|
||||
Menu_WineQualityStatistics_ModeKmw10.IsChecked = App.Client.OrderingMemberList == 4;
|
||||
await App.Client.UpdateValues();
|
||||
}
|
||||
|
||||
private void Menu_Settings_EnableFreeEditing_Checked(object sender, RoutedEventArgs evt) {
|
||||
if (IsEditing || IsCreating) {
|
||||
DateInput.IsReadOnly = false;
|
||||
@ -432,7 +528,7 @@ namespace Elwig.Windows {
|
||||
SortIdInput.SelectAll();
|
||||
} else if (ctrl == SortIdInput || ctrl == WineVarietyInput || ctrl == AttributeInput || ctrl == CultivationInput) {
|
||||
GradationOeInput.Focus();
|
||||
GradationOeInput.TextBox.SelectAll();
|
||||
GradationOeInput.SelectAll();
|
||||
} else if (ctrl == GradationKmwInput || ctrl == GradationOeInput || ctrl == WineQualityLevelInput) {
|
||||
if (WeighingAButton.IsVisible) WeighingAButton.Focus();
|
||||
else WeighingManualButton.Focus();
|
||||
@ -970,7 +1066,7 @@ namespace Elwig.Windows {
|
||||
|
||||
await RefreshDeliveryList();
|
||||
var d = DeliveryList.SelectedItem as Delivery;
|
||||
var y = d?.Year ?? Utils.CurrentLastSeason;
|
||||
var y = d?.Year ?? SeasonInput.Value;
|
||||
ControlUtils.RenewItemsSource(MemberInput, await ctx.Members
|
||||
.Where(m => m.IsActive || !IsCreating)
|
||||
.Include(m => m.PostalDest.AtPlz!.Ort)
|
||||
@ -987,7 +1083,11 @@ namespace Elwig.Windows {
|
||||
cultList.Insert(0, new NullItem(""));
|
||||
ControlUtils.RenewItemsSource(CultivationInput, cultList, null, ControlUtils.RenewSourceDefault.First);
|
||||
ControlUtils.RenewItemsSource(WineQualityLevelInput, await ctx.WineQualityLevels.ToListAsync());
|
||||
ControlUtils.RenewItemsSource(ModifiersInput, await ctx.Modifiers.Where(m => m.Year == y).OrderBy(m => m.Ordering).ToListAsync());
|
||||
ControlUtils.RenewItemsSource(ModifiersInput, await ctx.Modifiers
|
||||
.Where(m => m.Year == y)
|
||||
.OrderBy(m => m.Ordering)
|
||||
.Include(m => m.Season.Currency)
|
||||
.ToListAsync());
|
||||
ControlUtils.RenewItemsSource(WineOriginInput, (await ctx.WineOrigins.ToListAsync()).OrderByDescending(o => o.SortKey).ThenBy(o => o.HkId));
|
||||
var kgList = (await ctx.Katastralgemeinden
|
||||
.Where(k => k.WbKg != null)
|
||||
@ -1015,10 +1115,18 @@ namespace Elwig.Windows {
|
||||
private async Task RefreshDeliveryParts() {
|
||||
using var ctx = new AppDbContext();
|
||||
if (DeliveryList.SelectedItem is Delivery d) {
|
||||
ControlUtils.RenewItemsSource(ModifiersInput, await ctx.Modifiers.Where(m => m.Year == d.Year).OrderBy(m => m.Ordering).ToListAsync());
|
||||
ControlUtils.RenewItemsSource(ModifiersInput, await ctx.Modifiers
|
||||
.Where(m => m.Year == d.Year)
|
||||
.OrderBy(m => m.Ordering)
|
||||
.Include(m => m.Season.Currency)
|
||||
.ToListAsync());
|
||||
ControlUtils.RenewItemsSource(DeliveryPartList, d.FilteredParts.OrderBy(p => p.DPNr).ToList(), DeliveryPartList_SelectionChanged, ControlUtils.RenewSourceDefault.First);
|
||||
} else {
|
||||
ControlUtils.RenewItemsSource(ModifiersInput, await ctx.Modifiers.Where(m => m.Year == Utils.CurrentLastSeason).OrderBy(m => m.Ordering).ToListAsync());
|
||||
ControlUtils.RenewItemsSource(ModifiersInput, await ctx.Modifiers
|
||||
.Where(m => m.Year == SeasonInput.Value)
|
||||
.OrderBy(m => m.Ordering)
|
||||
.Include(m => m.Season.Currency)
|
||||
.ToListAsync());
|
||||
DeliveryPartList.ItemsSource = null;
|
||||
}
|
||||
}
|
||||
@ -1170,7 +1278,10 @@ namespace Elwig.Windows {
|
||||
ctx.Add(p);
|
||||
}
|
||||
|
||||
ctx.UpdateDeliveryPartModifiers(p, ModifiersInput.SelectedItems.Cast<Modifier>());
|
||||
ctx.UpdateDeliveryPartModifiers(p, await ctx.DeliveryPartModifiers
|
||||
.Where(m => m.Year == p.Year && m.DId == p.DId && m.DPNr == p.DPNr)
|
||||
.Select(m => m.Modifier)
|
||||
.ToListAsync(), ModifiersInput.SelectedItems.Cast<Modifier>());
|
||||
|
||||
if (originalMgNr != null && originalMgNr.Value != d.MgNr) {
|
||||
// update origin (KgNr), if default is selected
|
||||
@ -1247,8 +1358,8 @@ namespace Elwig.Windows {
|
||||
await RefreshDeliveryListQuery(true);
|
||||
}
|
||||
|
||||
private async void SeasonInput_ValueChanged(object sender, RoutedEventArgs evt) {
|
||||
if (SeasonInput.Value == null) return;
|
||||
private async void SeasonInput_TextChanged(object sender, TextChangedEventArgs evt) {
|
||||
if (SeasonInput.Value == null || TodayOnlyInput == null || AllSeasonsInput == null) return;
|
||||
TodayOnlyInput.IsChecked = false;
|
||||
AllSeasonsInput.IsChecked = false;
|
||||
await RefreshDeliveryListQuery();
|
||||
@ -1495,7 +1606,7 @@ namespace Elwig.Windows {
|
||||
p2.HkId = "OEST";
|
||||
ctx.Add(p2);
|
||||
|
||||
ctx.UpdateDeliveryPartModifiers(p2, p.Modifiers);
|
||||
ctx.UpdateDeliveryPartModifiers(p2, [], p.Modifiers);
|
||||
}
|
||||
await ctx.SaveChangesAsync();
|
||||
await RefreshDeliveryParts();
|
||||
@ -1797,7 +1908,7 @@ namespace Elwig.Windows {
|
||||
WineOriginInput.IsEnabled = false;
|
||||
if (WineKgInput.SelectedItem == null)
|
||||
WineRdInput.IsEnabled = false;
|
||||
WeightInput.TextBox.IsReadOnly = true;
|
||||
WeightInput.IsReadOnly = true;
|
||||
AbgewertetInput.IsEnabled = false;
|
||||
ManualWeighingInput.IsEnabled = false;
|
||||
LsNrInput.IsReadOnly = true;
|
||||
@ -1899,17 +2010,17 @@ namespace Elwig.Windows {
|
||||
|
||||
private void UpdateGradationKmw() {
|
||||
IsUpdatingGradation = true;
|
||||
var caret = GradationKmwInput.TextBox.CaretIndex;
|
||||
var caret = GradationKmwInput.CaretIndex;
|
||||
GradationKmwInput.Text = $"{Utils.OeToKmw(double.Parse(GradationOeInput.Text)):#.0}";
|
||||
GradationKmwInput.TextBox.CaretIndex = caret;
|
||||
GradationKmwInput.CaretIndex = caret;
|
||||
IsUpdatingGradation = false;
|
||||
}
|
||||
|
||||
private void UpdateGradationOe() {
|
||||
IsUpdatingGradation = true;
|
||||
var caret = GradationOeInput.TextBox.CaretIndex;
|
||||
var caret = GradationOeInput.CaretIndex;
|
||||
GradationOeInput.Text = $"{Utils.KmwToOe(double.Parse(GradationKmwInput.Text)):#}";
|
||||
GradationOeInput.TextBox.CaretIndex = caret;
|
||||
GradationOeInput.CaretIndex = caret;
|
||||
IsUpdatingGradation = false;
|
||||
}
|
||||
|
||||
@ -1950,7 +2061,7 @@ namespace Elwig.Windows {
|
||||
|
||||
}
|
||||
|
||||
private void ModifiersInput_SelectionChanged(object sender, ItemSelectionChangedEventArgs evt) {
|
||||
private void ModifiersInput_SelectionChanged(object sender, SelectionChangedEventArgs evt) {
|
||||
if (!IsEditing && !IsCreating) return;
|
||||
var mod = ModifiersInput.SelectedItems.Cast<Modifier>();
|
||||
var source = ModifiersInput.ItemsSource.Cast<Modifier>();
|
||||
|
@ -5,7 +5,7 @@
|
||||
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:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
|
||||
xmlns:ctrl="clr-namespace:Elwig.Controls"
|
||||
mc:Ignorable="d"
|
||||
MinWidth="650" MinHeight="400" Height="600" Width="950"
|
||||
Closed="Window_Closed"
|
||||
@ -54,7 +54,7 @@
|
||||
<Button x:Name="DocumentAddButton" Content="" FontFamily="Segoe MDL2 Assets" FontSize="14"
|
||||
Grid.Column="1" Margin="0,0,0,30" VerticalAlignment="Center" Height="25" IsEnabled="False"
|
||||
Click="DocumentAddButton_Click"/>
|
||||
<Button x:Name="DocumentRemoveButton" Content="" FontFamily="Segoe MDL2 Assets" FontSize="14" Padding="1.5,0,0,0"
|
||||
<Button x:Name="DocumentRemoveButton" Content="" FontFamily="Segoe MDL2 Assets" FontSize="16" Padding="1.5,0,0,0"
|
||||
Grid.Column="1" Margin="0,30,0,0" VerticalAlignment="Center" Height="25" IsEnabled="False"
|
||||
Click="DocumentRemoveButton_Click"/>
|
||||
|
||||
@ -117,26 +117,26 @@
|
||||
Checked="RecipientsInput_Changed" Unchecked="RecipientsInput_Changed"/>
|
||||
|
||||
<Label Content="Zwst.:" x:Name="MemberBranchLabel" Margin="10,120,0,10"/>
|
||||
<xctk:CheckComboBox x:Name="MemberBranchInput" AllItemsSelectedContent="Alle Stammzweigstellen" Delimiter=", " DisplayMemberPath="Name"
|
||||
<ctrl:CheckComboBox x:Name="MemberBranchInput" AllItemsSelectedContent="Alle Stammzweigstellen" Delimiter=", " DisplayMemberPath="Name"
|
||||
Margin="50,120,10,10" VerticalAlignment="Top" HorizontalAlignment="Stretch" Height="25"
|
||||
ItemSelectionChanged="MemberInput_SelectionChanged"/>
|
||||
SelectionChanged="MemberInput_SelectionChanged"/>
|
||||
|
||||
<Label Content="Gem.:" x:Name="MemberKgLabel" Margin="10,150,0,10"/>
|
||||
<xctk:CheckComboBox x:Name="MemberKgInput" AllItemsSelectedContent="Alle Stammgemeinden" Delimiter=", " DisplayMemberPath="Name"
|
||||
<ctrl:CheckComboBox x:Name="MemberKgInput" AllItemsSelectedContent="Alle Stammgemeinden" Delimiter=", " DisplayMemberPath="Name"
|
||||
IsSelectAllActive="True" SelectAllContent="Alle Stammgemeinden"
|
||||
Margin="50,150,10,10" VerticalAlignment="Top" HorizontalAlignment="Stretch" Height="25"
|
||||
ItemSelectionChanged="MemberInput_SelectionChanged"/>
|
||||
SelectionChanged="MemberInput_SelectionChanged"/>
|
||||
|
||||
<Label Content="Vtrg.:" x:Name="MemberAreaComLabel" Margin="10,180,0,10"/>
|
||||
<xctk:CheckComboBox x:Name="MemberAreaComInput" AllItemsSelectedContent="Alle Vertragsarten" Delimiter=", " DisplayMemberPath="VtrgId"
|
||||
<ctrl:CheckComboBox x:Name="MemberAreaComInput" AllItemsSelectedContent="Alle Vertragsarten" Delimiter=", " DisplayMemberPath="VtrgId"
|
||||
IsSelectAllActive="True" SelectAllContent="Alle Vertragsarten"
|
||||
Margin="50,180,10,10" VerticalAlignment="Top" HorizontalAlignment="Stretch" Height="25"
|
||||
ItemSelectionChanged="MemberInput_SelectionChanged"/>
|
||||
SelectionChanged="MemberInput_SelectionChanged"/>
|
||||
|
||||
<xctk:CheckComboBox x:Name="MemberCustomInput" AllItemsSelectedContent="Alle Mitglieder" Delimiter=", " DisplayMemberPath="AdministrativeName"
|
||||
<ctrl:CheckComboBox x:Name="MemberCustomInput" AllItemsSelectedContent="Alle Mitglieder" Delimiter=", " DisplayMemberPath="AdministrativeName"
|
||||
IsSelectAllActive="True" SelectAllContent="Alle Mitglieder"
|
||||
Margin="10,120,10,10" VerticalAlignment="Top" HorizontalAlignment="Stretch" Height="25"
|
||||
ItemSelectionChanged="MemberInput_SelectionChanged"/>
|
||||
SelectionChanged="MemberInput_SelectionChanged"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
|
@ -53,7 +53,7 @@ namespace Elwig.Windows {
|
||||
CreditNote.Name,
|
||||
];
|
||||
|
||||
public readonly int? Year;
|
||||
public readonly int Year;
|
||||
public ObservableCollection<SelectedDoc> SelectedDocs = [];
|
||||
public IEnumerable<Member> Recipients = [];
|
||||
|
||||
@ -103,7 +103,7 @@ namespace Elwig.Windows {
|
||||
public MailWindow(int? year = null) {
|
||||
InitializeComponent();
|
||||
using (var ctx = new AppDbContext()) {
|
||||
Year = year ?? ctx.Seasons.OrderBy(s => s.Year).LastOrDefault()?.Year;
|
||||
Year = year ?? ctx.Seasons.OrderBy(s => s.Year).LastOrDefault()!.Year;
|
||||
Title = $"Rundschreiben - Lese {Year} - Elwig";
|
||||
}
|
||||
|
||||
@ -143,36 +143,44 @@ namespace Elwig.Windows {
|
||||
.OrderBy(b => b.Name)
|
||||
.ToListAsync(), MemberInput_SelectionChanged);
|
||||
if (MemberBranchInput.SelectedItems.Count == 0) {
|
||||
MemberBranchInput.ItemSelectionChanged -= MemberInput_SelectionChanged;
|
||||
MemberBranchInput.SelectionChanged -= MemberInput_SelectionChanged;
|
||||
MemberBranchInput.SelectAll();
|
||||
MemberBranchInput.ItemSelectionChanged += MemberInput_SelectionChanged;
|
||||
MemberBranchInput.SelectionChanged += MemberInput_SelectionChanged;
|
||||
}
|
||||
ControlUtils.RenewItemsSource(MemberKgInput, await ctx.Katastralgemeinden
|
||||
.Where(k => k.WbKg!.Members.Any())
|
||||
.OrderBy(k => k.Name)
|
||||
.ToListAsync(), MemberInput_SelectionChanged);
|
||||
if (MemberKgInput.SelectedItems.Count == 0) {
|
||||
MemberKgInput.ItemSelectionChanged -= MemberInput_SelectionChanged;
|
||||
MemberKgInput.SelectionChanged -= MemberInput_SelectionChanged;
|
||||
MemberKgInput.SelectAll();
|
||||
MemberKgInput.ItemSelectionChanged += MemberInput_SelectionChanged;
|
||||
MemberKgInput.SelectionChanged += MemberInput_SelectionChanged;
|
||||
}
|
||||
ControlUtils.RenewItemsSource(MemberAreaComInput, await ctx.AreaCommitmentTypes
|
||||
.OrderBy(a => a.VtrgId)
|
||||
.ToListAsync(), MemberInput_SelectionChanged);
|
||||
if (MemberAreaComInput.SelectedItems.Count == 0) {
|
||||
MemberAreaComInput.ItemSelectionChanged -= MemberInput_SelectionChanged;
|
||||
MemberAreaComInput.SelectionChanged -= MemberInput_SelectionChanged;
|
||||
MemberAreaComInput.SelectAll();
|
||||
MemberAreaComInput.ItemSelectionChanged += MemberInput_SelectionChanged;
|
||||
MemberAreaComInput.SelectionChanged += MemberInput_SelectionChanged;
|
||||
}
|
||||
ControlUtils.RenewItemsSource(MemberCustomInput, await ctx.Members
|
||||
.Where(m => m.IsActive)
|
||||
.OrderBy(m => m.FamilyName)
|
||||
.ThenBy(m => m.GivenName)
|
||||
.Include(m => m.Branch)
|
||||
.Include(m => m.DefaultWbKg!.AtKg)
|
||||
.Include(m => m.EmailAddresses)
|
||||
.Include(m => m.TelephoneNumbers)
|
||||
.Include(m => m.PostalDest.AtPlz!.Ort)
|
||||
.Include(m => m.PostalDest.AtPlz!.Country)
|
||||
.Include(m => m.BillingAddress!.PostalDest.AtPlz!.Ort)
|
||||
.Include(m => m.BillingAddress!.PostalDest.AtPlz!.Country)
|
||||
.ToListAsync(), MemberInput_SelectionChanged);
|
||||
if (MemberCustomInput.SelectedItems.Count == 0) {
|
||||
MemberCustomInput.ItemSelectionChanged -= MemberInput_SelectionChanged;
|
||||
MemberCustomInput.SelectionChanged -= MemberInput_SelectionChanged;
|
||||
MemberCustomInput.SelectAll();
|
||||
MemberCustomInput.ItemSelectionChanged += MemberInput_SelectionChanged;
|
||||
MemberCustomInput.SelectionChanged += MemberInput_SelectionChanged;
|
||||
}
|
||||
|
||||
await UpdateRecipients(ctx);
|
||||
@ -245,12 +253,14 @@ namespace Elwig.Windows {
|
||||
if (idx == 0) {
|
||||
SelectedDocs.Add(new(DocType.MemberDataSheet, s, null));
|
||||
} else if (idx == 1) {
|
||||
SelectedDocs.Add(new(DocType.DeliveryConfirmation, s, ((int)Year!, DocumentNonDeliverersInput.IsChecked == true)));
|
||||
SelectedDocs.Add(new(DocType.DeliveryConfirmation, s, (Year, DocumentNonDeliverersInput.IsChecked == true)));
|
||||
RecipientsDeliveryMembersInput.IsChecked = true;
|
||||
} else if (idx >= 2) {
|
||||
using var ctx = new AppDbContext();
|
||||
var name = s.Split(" – ")[^1];
|
||||
var pv = ctx.PaymentVariants.Single(v => v.Year == Year && v.Name == name)!;
|
||||
SelectedDocs.Add(new(DocType.CreditNote, s, (pv.Year, pv.AvNr)));
|
||||
RecipientsDeliveryMembersInput.IsChecked = true;
|
||||
}
|
||||
SelectedDocumentsList.SelectedIndex = SelectedDocs.Count - 1;
|
||||
}
|
||||
@ -288,7 +298,7 @@ namespace Elwig.Windows {
|
||||
await UpdateRecipients(ctx);
|
||||
}
|
||||
|
||||
private async void MemberInput_SelectionChanged(object sender, RoutedEventArgs evt) {
|
||||
private async void MemberInput_SelectionChanged(object sender, SelectionChangedEventArgs evt) {
|
||||
using var ctx = new AppDbContext();
|
||||
await UpdateRecipients(ctx);
|
||||
}
|
||||
@ -297,25 +307,25 @@ namespace Elwig.Windows {
|
||||
if (RecipientsCustomInput.IsChecked == true) {
|
||||
Recipients = MemberCustomInput.SelectedItems.Cast<Member>().ToList();
|
||||
} else {
|
||||
var year = (!await ctx.Deliveries.AnyAsync()) ? 0 : await ctx.Deliveries.MaxAsync(d => d.Year);
|
||||
|
||||
IQueryable<Member> query = ctx.Members.Where(m => m.IsActive);
|
||||
IQueryable<Member> query = ctx.Members;
|
||||
if (MemberBranchInput.SelectedItems.Count != MemberBranchInput.Items.Count) {
|
||||
var zwst = MemberBranchInput.SelectedItems.Cast<Branch>().Select(b => b.ZwstId).ToList();
|
||||
query = query.Where(m => zwst.Contains(m.ZwstId));
|
||||
query = query.Where(m => zwst.Contains(m.ZwstId!));
|
||||
}
|
||||
if (MemberKgInput.SelectedItems.Count != MemberKgInput.Items.Count) {
|
||||
var kgs = MemberKgInput.SelectedItems.Cast<AT_Kg>().Select(k => k.KgNr).ToList();
|
||||
query = query.Where(m => kgs.Contains((int)m.DefaultKgNr));
|
||||
query = query.Where(m => kgs.Contains((int)m.DefaultKgNr!));
|
||||
}
|
||||
|
||||
if (RecipientsAreaComMembersInput.IsChecked == true) {
|
||||
var vtrg = MemberAreaComInput.SelectedItems.Cast<AreaComType>().Select(a => a.VtrgId).ToList();
|
||||
query = query.Where(m => Utils.ActiveAreaCommitments(m.AreaCommitments).Any(c => vtrg.Contains(c.VtrgId)));
|
||||
} else if (year > 0 && RecipientsDeliveryMembersInput.IsChecked == true) {
|
||||
query = query.Where(m => m.Deliveries.Any(d => d.Year == year));
|
||||
} else if (year > 0 && RecipientsNonDeliveryMembersInput.IsChecked == true) {
|
||||
query = query.Where(m => !m.Deliveries.Any(d => d.Year == year));
|
||||
query = query.Where(m => m.IsActive && m.AreaCommitments.AsQueryable().Where(Utils.ActiveAreaCommitments(Year)).Any(c => vtrg.Contains(c.VtrgId)));
|
||||
} else if (RecipientsDeliveryMembersInput.IsChecked == true) {
|
||||
query = query.Where(m => m.Deliveries.Any(d => d.Year == Year));
|
||||
} else if (RecipientsNonDeliveryMembersInput.IsChecked == true) {
|
||||
query = query.Where(m => m.IsActive && !m.Deliveries.Any(d => d.Year == Year));
|
||||
} else {
|
||||
query = query.Where(m => m.IsActive);
|
||||
}
|
||||
Recipients = await query
|
||||
.Include(m => m.Branch)
|
||||
@ -449,7 +459,20 @@ namespace Elwig.Windows {
|
||||
if (doc.Type == DocType.DeliveryConfirmation) {
|
||||
var details = ((int, bool))doc.Details!;
|
||||
var year = details.Item1;
|
||||
dcData[year] = await DeliveryConfirmationDeliveryData.ForSeason(ctx.DeliveryParts, year);
|
||||
|
||||
try {
|
||||
var b = new Billing(year);
|
||||
await b.FinishSeason();
|
||||
await b.CalculateBuckets();
|
||||
await App.HintContextChange();
|
||||
|
||||
dcData[year] = await DeliveryConfirmationDeliveryData.ForSeason(ctx.DeliveryParts, year);
|
||||
} catch (Exception exc) {
|
||||
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
GenerateButton.IsEnabled = true;
|
||||
Mouse.OverrideCursor = null;
|
||||
return;
|
||||
}
|
||||
} else if (doc.Type == DocType.CreditNote) {
|
||||
var details = ((int, int))doc.Details!;
|
||||
var year = details.Item1;
|
||||
@ -694,8 +717,9 @@ namespace Elwig.Windows {
|
||||
AvaiableDocumentsList.SelectedIndex = 1;
|
||||
if (AvaiableDocumentsList.SelectedItem is not string s || SelectedDocs.Any(d => d.Type == DocType.DeliveryConfirmation))
|
||||
return;
|
||||
SelectedDocs.Add(new(DocType.DeliveryConfirmation, s, ((int)Year!, DocumentNonDeliverersInput.IsChecked == true)));
|
||||
SelectedDocs.Add(new(DocType.DeliveryConfirmation, s, (Year, DocumentNonDeliverersInput.IsChecked == true)));
|
||||
SelectedDocumentsList.SelectedIndex = SelectedDocs.Count - 1;
|
||||
RecipientsDeliveryMembersInput.IsChecked = true;
|
||||
}
|
||||
|
||||
public void AddCreditNote(int index) {
|
||||
@ -707,6 +731,7 @@ namespace Elwig.Windows {
|
||||
var pv = ctx.PaymentVariants.Single(v => v.Year == Year && v.Name == name)!;
|
||||
SelectedDocs.Add(new(DocType.CreditNote, s, (pv.Year, pv.AvNr)));
|
||||
SelectedDocumentsList.SelectedIndex = SelectedDocs.Count - 1;
|
||||
RecipientsDeliveryMembersInput.IsChecked = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
<Window x:Class="Elwig.Windows.MainWindow"
|
||||
<local:ContextWindow
|
||||
x:Class="Elwig.Windows.MainWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:Elwig.Windows"
|
||||
xmlns:ctrl="clr-namespace:Elwig.Controls"
|
||||
Title="Elwig" Height="390" Width="520" ResizeMode="CanMinimize"
|
||||
Loaded="Window_Loaded" Closing="Window_Closing">
|
||||
<Window.Resources>
|
||||
@ -9,21 +12,25 @@
|
||||
<Setter Property="HorizontalAlignment" Value="Center"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="Padding" Value="9,3"/>
|
||||
<Setter Property="Height" Value="32"/>
|
||||
<Setter Property="Height" Value="35"/>
|
||||
<Setter Property="Width" Value="200"/>
|
||||
</Style>
|
||||
</Window.Resources>
|
||||
<Grid>
|
||||
<Menu BorderThickness="0,0,0,1" VerticalAlignment="Top" Height="19" BorderBrush="LightGray" Background="White">
|
||||
<MenuItem Header="Datenbank">
|
||||
<MenuItem Header="Daten exportieren..." Click="Menu_Database_Export_Click"/>
|
||||
<MenuItem Header="Daten importieren..." Click="Menu_Database_Import_Click"/>
|
||||
<MenuItem x:Name="Menu_Database_Sync" Header="Daten synchronisieren" Click="Menu_Database_Sync_Click"/>
|
||||
<Separator/>
|
||||
<MenuItem Header="Abfragen stellen" Click="Menu_Database_Query_Click"/>
|
||||
<!--MenuItem Header="Backup erstellen"/-->
|
||||
<MenuItem Header="Speicherort öffnen..." Click="Menu_Database_Open_Click"/>
|
||||
</MenuItem>
|
||||
<MenuItem x:Name="HelpMenu" Header="Hilfe">
|
||||
<MenuItem Header="Über"/>
|
||||
<MenuItem x:Name="Menu_Help_Update" Header="Nach Updates suchen" Click="Menu_Help_Update_Click"/>
|
||||
<MenuItem x:Name="Menu_Help_Smtp" Header="E-Mail-Einstellungen testen" Click="Menu_Help_Smtp_Click"/>
|
||||
<MenuItem x:Name="Menu_Help_TestWindow" Header="Test-Fenster" Click="Menu_Help_TestWindow_Click"/>
|
||||
<MenuItem x:Name="Menu_Help_Config" Header="Konfigurationsspeicherort öffnen..." Click="Menu_Help_Config_Click"/>
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
|
||||
@ -47,16 +54,44 @@
|
||||
</Grid>
|
||||
|
||||
<Button x:Name="MemberAdminButton" Content="Mitglieder" Click="MemberAdminButton_Click"
|
||||
Margin="0,180,210,0"/>
|
||||
Margin="0,170,205,0"/>
|
||||
<Button x:Name="MailButton" Content="Rundschreiben" Click="MailButton_Click"
|
||||
Margin="210,180,0,0"/>
|
||||
Margin="205,170,0,0"/>
|
||||
<Button x:Name="DeliveryAdminButton" Content="Lieferungen" Click="DeliveryAdminButton_Click"
|
||||
Margin="0,220,210,0"/>
|
||||
Margin="0,210,205,0"/>
|
||||
<Button x:Name="ReceiptButton" Content="Übernahme" Click="ReceiptButton_Click"
|
||||
Margin="210,220,0,0"/>
|
||||
Margin="205,210,0,0"/>
|
||||
<Button x:Name="BaseDataButton" Content="Stammdaten" Click="BaseDataButton_Click"
|
||||
Margin="0,260,210,0"/>
|
||||
<Button x:Name="SeasonFinishButton" Content="Leseabschluss" Click="SeasonFinishButton_Click"
|
||||
Margin="210,260,0,0"/>
|
||||
Margin="0,250,205,0"/>
|
||||
<Button x:Name="RegistrationButton" Content="Anmeldungen" IsEnabled="False"
|
||||
Margin="205,250,0,0"/>
|
||||
|
||||
<Expander x:Name="SeasonFinish" Header="Leseabschluss" SnapsToDevicePixels="True"
|
||||
Expanded="SeasonFinish_Expanded" Collapsed="SeasonFinish_Collapsed"
|
||||
HorizontalAlignment="Center" Width="407" Margin="0,290,0,0" VerticalAlignment="Top">
|
||||
<Grid>
|
||||
<Border BorderBrush="LightGray" BorderThickness="1"/>
|
||||
<Label Content="Saison:" Margin="0,13,100,0" VerticalAlignment="Top" HorizontalAlignment="Center" Padding="2,4,2,4" Height="25"/>
|
||||
<ctrl:IntegerUpDown x:Name="SeasonInput" Height="25" Width="56" FontSize="14" Minimum="1900" Maximum="9999"
|
||||
Margin="0,13,0,0" VerticalAlignment="Top" HorizontalAlignment="Center"
|
||||
TextChanged="SeasonInput_TextChanged"/>
|
||||
|
||||
<Button x:Name="OverUnderDeliveryButton" Content="Über-/Unterlieferungen"
|
||||
Click="OverUnderDeliveryButton_Click"
|
||||
Margin="0,50,195,10" Width="190"/>
|
||||
|
||||
<Button x:Name="DeliveryConfirmationButton" Content="Anlieferungsbestätigung"
|
||||
Click="DeliveryConfirmationButton_Click"
|
||||
Margin="195,50,0,10" Width="190"/>
|
||||
|
||||
<Button x:Name="BreakdownButton" Content="Sorten-/Qual.aufteilung"
|
||||
Click="BreakdownButton_Click"
|
||||
Margin="0,90,195,10" Width="190"/>
|
||||
|
||||
<Button x:Name="PaymentButton" Content="Auszahlung"
|
||||
Click="PaymentButton_Click"
|
||||
Margin="195,90,0,10" Width="190"/>
|
||||
</Grid>
|
||||
</Expander>
|
||||
</Grid>
|
||||
</Window>
|
||||
</local:ContextWindow>
|
||||
|
@ -1,30 +1,41 @@
|
||||
using Elwig.Helpers;
|
||||
using Elwig.Helpers.Billing;
|
||||
using Elwig.Helpers.Export;
|
||||
using Elwig.Models.Dtos;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Win32;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace Elwig.Windows {
|
||||
public partial class MainWindow : Window {
|
||||
public partial class MainWindow : ContextWindow {
|
||||
|
||||
public MainWindow() {
|
||||
InitializeComponent();
|
||||
var v = Assembly.GetExecutingAssembly().GetName().Version;
|
||||
VersionField.Text = "Version: " + (v == null ? "?" : $"{v.Major}.{v.Minor}.{v.Build}") + $" – {App.BranchName}";
|
||||
if (App.Client.Client == null) VersionField.Text += " (Unbekannt)";
|
||||
if (!App.Config.Debug) {
|
||||
HelpMenu.Items.Remove(Menu_Help_TestWindow);
|
||||
//QueryWindowButton.Visibility = Visibility.Hidden;
|
||||
}
|
||||
if (App.Config.UpdateUrl == null) Menu_Help_Update.IsEnabled = false;
|
||||
if (App.Config.Smtp == null) Menu_Help_Smtp.IsEnabled = false;
|
||||
Menu_Help_Update.IsEnabled = App.Config.UpdateUrl != null;
|
||||
Menu_Help_Smtp.IsEnabled = App.Config.Smtp != null;
|
||||
Menu_Database_Sync.IsEnabled = App.Config.SyncUrl != null;
|
||||
}
|
||||
|
||||
private void Window_Loaded(object sender, RoutedEventArgs evt) { }
|
||||
private void Window_Loaded(object sender, RoutedEventArgs evt) {
|
||||
SeasonInput.Value = Utils.CurrentLastSeason;
|
||||
}
|
||||
|
||||
private void Window_Closing(object sender, CancelEventArgs evt) {
|
||||
if (App.NumWindows > 1 && !App.ForceShutdown) {
|
||||
if (App.NumWindows > 1 && !App.ForceShutdown && !App.Current.Windows.Cast<Window>().Any(w => ((w as AdministrationWindow)?.IsEditing ?? false) || ((w as AdministrationWindow)?.IsCreating ?? false))) {
|
||||
var res = MessageBox.Show("Es sind noch weitere Fenster geöffnet.\nSollen alle Fenster geschlossen werden?",
|
||||
"Elwig beenden", MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No);
|
||||
if (res != MessageBoxResult.Yes) {
|
||||
@ -35,13 +46,8 @@ namespace Elwig.Windows {
|
||||
}
|
||||
}
|
||||
|
||||
private void Menu_Help_TestWindow_Click(object sender, RoutedEventArgs evt) {
|
||||
var w = new TestWindow();
|
||||
w.Show();
|
||||
}
|
||||
|
||||
private async void Menu_Help_Update_Click(object sender, RoutedEventArgs evt) {
|
||||
await App.CheckForUpdates();
|
||||
await App.CheckForUpdates(true);
|
||||
}
|
||||
|
||||
private async void Menu_Help_Smtp_Click(object sender, RoutedEventArgs evt) {
|
||||
@ -56,11 +62,69 @@ namespace Elwig.Windows {
|
||||
Mouse.OverrideCursor = null;
|
||||
}
|
||||
|
||||
private void Menu_Help_Config_Click(object sender, RoutedEventArgs evt) {
|
||||
Process.Start("explorer.exe", App.DataPath);
|
||||
}
|
||||
|
||||
private void Menu_Database_Query_Click(object sender, RoutedEventArgs evt) {
|
||||
var w = new QueryWindow();
|
||||
w.Show();
|
||||
}
|
||||
|
||||
private void Menu_Database_Open_Click(object sender, RoutedEventArgs evt) {
|
||||
if (Path.GetDirectoryName(App.Config.DatabaseFile) is string path)
|
||||
Process.Start("explorer.exe", path);
|
||||
}
|
||||
|
||||
private void Menu_Database_Export_Click(object sender, RoutedEventArgs evt) {
|
||||
// TODO Menu_Database_Export_Click
|
||||
}
|
||||
|
||||
private void Menu_Database_Import_Click(object sender, RoutedEventArgs evt) {
|
||||
// TODO Menu_Database_Import_Click
|
||||
}
|
||||
|
||||
private async void Menu_Database_Sync_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!["zwstid"]?.AsValue().GetValue<string>(),
|
||||
DeliveryNum = f!["meta"]?["deliveries"]?["count"]!.AsValue().GetValue<int>(),
|
||||
DeliveryPartNum = f!["meta"]?["deliveries"]?["parts"]!.AsValue().GetValue<int>(),
|
||||
Filters = f!["meta"]?["deliveries"]?["filters"]!.AsArray().Select(i => i!.AsValue().GetValue<string>()).ToArray(),
|
||||
Device = f!["meta"]?["device"]!.AsValue().GetValue<string>(),
|
||||
Url = f!["url"]!.AsValue().GetValue<string>(),
|
||||
Size = f!["size"]!.AsValue().GetValue<long>(),
|
||||
})
|
||||
.Where(f => f.DeliveryNum > 0 && f.Timestamp >= new DateTime(Utils.CurrentLastSeason, 7, 1))
|
||||
.ToList();
|
||||
|
||||
var imported = await ElwigData.GetImportedFiles();
|
||||
var import = files
|
||||
.Where(f => f.Filters != null && f.Filters.Length > 0 && 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, false);
|
||||
} catch (Exception exc) {
|
||||
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
Mouse.OverrideCursor = null;
|
||||
}
|
||||
|
||||
private void MemberAdminButton_Click(object sender, RoutedEventArgs evt) {
|
||||
var w = new MemberAdminWindow();
|
||||
w.Show();
|
||||
@ -79,12 +143,110 @@ namespace Elwig.Windows {
|
||||
App.FocusBaseData();
|
||||
}
|
||||
|
||||
private void SeasonFinishButton_Click(object sender, RoutedEventArgs evt) {
|
||||
App.FocusSeasonFinish();
|
||||
}
|
||||
|
||||
private void MailButton_Click(object sender, RoutedEventArgs evt) {
|
||||
App.FocusMailWindow();
|
||||
}
|
||||
|
||||
protected override Task OnRenewContext(AppDbContext ctx) {
|
||||
SeasonInput_TextChanged(null, null);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private void SeasonFinish_Expanded(object sender, RoutedEventArgs evt) {
|
||||
Height = 530;
|
||||
}
|
||||
|
||||
private void SeasonFinish_Collapsed(object sender, RoutedEventArgs evt) {
|
||||
Height = 390;
|
||||
}
|
||||
|
||||
private async void SeasonInput_TextChanged(object? sender, TextChangedEventArgs? evt) {
|
||||
using var ctx = new AppDbContext();
|
||||
var s0 = await ctx.Seasons.FindAsync(SeasonInput.Value);
|
||||
var valid = (s0 != null);
|
||||
DeliveryConfirmationButton.IsEnabled = valid;
|
||||
OverUnderDeliveryButton.IsEnabled = valid;
|
||||
PaymentButton.IsEnabled = valid;
|
||||
BreakdownButton.IsEnabled = valid;
|
||||
}
|
||||
|
||||
private void DeliveryConfirmationButton_Click(object sender, RoutedEventArgs evt) {
|
||||
if (SeasonInput.Value is not int year)
|
||||
return;
|
||||
var w = App.FocusMailWindow(year);
|
||||
w.AddDeliveryConfirmation();
|
||||
}
|
||||
|
||||
private async void OverUnderDeliveryButton_Click(object sender, RoutedEventArgs evt) {
|
||||
if (SeasonInput.Value is not int year)
|
||||
return;
|
||||
var d = new SaveFileDialog() {
|
||||
FileName = $"Über-Unterlieferungen-{year}.ods",
|
||||
DefaultExt = "ods",
|
||||
Filter = "OpenDocument Format Spreadsheet (*.ods)|*.ods",
|
||||
Title = $"Über-/Unterlieferungen {year} speichern unter - Elwig"
|
||||
};
|
||||
if (d.ShowDialog() == false)
|
||||
return;
|
||||
|
||||
Mouse.OverrideCursor = Cursors.AppStarting;
|
||||
try {
|
||||
var b = new Billing(year);
|
||||
await b.FinishSeason();
|
||||
await b.CalculateBuckets();
|
||||
await App.HintContextChange();
|
||||
|
||||
using var ctx = new AppDbContext();
|
||||
var tbl1 = await OverUnderDeliveryData.ForSeason(ctx.OverUnderDeliveryRows, year);
|
||||
var tbl2 = await AreaComUnderDeliveryData.ForSeason(ctx.AreaComUnderDeliveryRows, year);
|
||||
var tbl3 = await MemberDeliveryPerVariantData.ForSeason(ctx.MemberDeliveryPerVariantRows, year);
|
||||
using var ods = new OdsFile(d.FileName);
|
||||
await ods.AddTable(tbl1);
|
||||
await ods.AddTable(tbl2);
|
||||
await ods.AddTable(tbl3);
|
||||
} catch (Exception exc) {
|
||||
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
Mouse.OverrideCursor = null;
|
||||
}
|
||||
|
||||
private void PaymentButton_Click(object sender, RoutedEventArgs evt) {
|
||||
if (SeasonInput.Value is not int year)
|
||||
return;
|
||||
App.FocusPaymentVariants(year);
|
||||
}
|
||||
|
||||
private async void BreakdownButton_Click(object sender, RoutedEventArgs evt) {
|
||||
if (SeasonInput.Value is not int year)
|
||||
return;
|
||||
var d = new SaveFileDialog() {
|
||||
FileName = $"Aufschlüsselung-{year}.ods",
|
||||
DefaultExt = "ods",
|
||||
Filter = "OpenDocument Format Spreadsheet (*.ods)|*.ods",
|
||||
Title = $"Sorten-/Qualitätsaufschlüsselung {year} speichern unter - Elwig"
|
||||
};
|
||||
if (d.ShowDialog() == false)
|
||||
return;
|
||||
|
||||
Mouse.OverrideCursor = Cursors.AppStarting;
|
||||
try {
|
||||
var b = new Billing(year);
|
||||
await b.FinishSeason();
|
||||
await b.CalculateBuckets();
|
||||
await 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);
|
||||
}
|
||||
} catch (Exception exc) {
|
||||
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
Mouse.OverrideCursor = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,12 +14,14 @@ using System.Diagnostics;
|
||||
using Elwig.Models.Dtos;
|
||||
using Elwig.Helpers.Export;
|
||||
using Microsoft.Win32;
|
||||
using Elwig.Helpers.Billing;
|
||||
using Elwig.Dialogs;
|
||||
|
||||
namespace Elwig.Windows {
|
||||
public partial class MemberAdminWindow : AdministrationWindow {
|
||||
|
||||
protected bool TransferPredecessorAreaComs = false;
|
||||
protected bool CancelAreaComs = false;
|
||||
protected int? TransferPredecessorAreaComs = null;
|
||||
protected int? CancelAreaComs = null;
|
||||
protected List<string> TextFilter = [];
|
||||
|
||||
private readonly (ComboBox Type, TextBox Number, TextBox Comment)[] PhoneNrInputs;
|
||||
@ -411,8 +413,8 @@ namespace Elwig.Windows {
|
||||
IsCreating = true;
|
||||
MemberList.IsEnabled = false;
|
||||
MemberList.SelectedItem = null;
|
||||
TransferPredecessorAreaComs = false;
|
||||
CancelAreaComs = false;
|
||||
TransferPredecessorAreaComs = null;
|
||||
CancelAreaComs = null;
|
||||
HideNewEditDeleteButtons();
|
||||
ShowSaveResetCancelButtons();
|
||||
UnlockInputs();
|
||||
@ -433,8 +435,8 @@ namespace Elwig.Windows {
|
||||
|
||||
IsEditing = true;
|
||||
MemberList.IsEnabled = false;
|
||||
TransferPredecessorAreaComs = false;
|
||||
CancelAreaComs = false;
|
||||
TransferPredecessorAreaComs = null;
|
||||
CancelAreaComs = null;
|
||||
|
||||
HideNewEditDeleteButtons();
|
||||
ShowSaveResetCancelButtons();
|
||||
@ -453,20 +455,38 @@ namespace Elwig.Windows {
|
||||
if (MemberList.SelectedItem is not Member m)
|
||||
return;
|
||||
|
||||
var r = MessageBox.Show(
|
||||
$"Soll das Mitglied \"{m.AdministrativeName}\" (MgNr. {m.MgNr}) wirklich unwiderruflich gelöscht werden?\n" +
|
||||
$"Sämtliche Lieferungen und Flächenbindungen dieses Mitglieds werden auch gelöscht!",
|
||||
"Mitglied löschen", MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
|
||||
if (r == MessageBoxResult.OK) {
|
||||
int areaComs = 0, deliveries = 0, credits = 0;
|
||||
using (var ctx = new AppDbContext()) {
|
||||
var l = (await ctx.Members.FindAsync(m.MgNr))!;
|
||||
areaComs = l.AreaCommitments.Count;
|
||||
deliveries = l.Deliveries.Count;
|
||||
credits = l.Credits.Count;
|
||||
}
|
||||
var d = new DeleteMemberDialog(m.MgNr, m.AdministrativeName, areaComs, deliveries, credits);
|
||||
if (d.ShowDialog() == true) {
|
||||
Mouse.OverrideCursor = Cursors.AppStarting;
|
||||
try {
|
||||
using (var ctx = new AppDbContext()) {
|
||||
ctx.Remove(m);
|
||||
var l = (await ctx.Members.FindAsync(m.MgNr))!;
|
||||
if (d.DeletePaymentData) {
|
||||
ctx.RemoveRange(l.Credits);
|
||||
}
|
||||
if (d.DeleteDeliveries) {
|
||||
ctx.RemoveRange(l.Deliveries);
|
||||
}
|
||||
if (d.DeleteAreaComs) {
|
||||
ctx.RemoveRange(l.AreaCommitments);
|
||||
}
|
||||
ctx.Remove(l);
|
||||
await ctx.SaveChangesAsync();
|
||||
}
|
||||
await App.HintContextChange();
|
||||
} catch (Exception exc) {
|
||||
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
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 löschen", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
Mouse.OverrideCursor = null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -508,8 +528,8 @@ namespace Elwig.Windows {
|
||||
}
|
||||
|
||||
private void ResetButton_Click(object? sender, RoutedEventArgs? evt) {
|
||||
TransferPredecessorAreaComs = false;
|
||||
CancelAreaComs = false;
|
||||
TransferPredecessorAreaComs = null;
|
||||
CancelAreaComs = null;
|
||||
if (IsEditing) {
|
||||
RefreshInputs();
|
||||
} else if (IsCreating) {
|
||||
@ -523,8 +543,8 @@ namespace Elwig.Windows {
|
||||
IsEditing = false;
|
||||
IsCreating = false;
|
||||
MemberList.IsEnabled = true;
|
||||
TransferPredecessorAreaComs = false;
|
||||
CancelAreaComs = false;
|
||||
TransferPredecessorAreaComs = null;
|
||||
CancelAreaComs = null;
|
||||
HideSaveResetCancelButtons();
|
||||
ShowNewEditDeleteButtons();
|
||||
RefreshInputs();
|
||||
@ -637,6 +657,11 @@ namespace Elwig.Windows {
|
||||
private 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();
|
||||
await 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);
|
||||
@ -903,8 +928,7 @@ namespace Elwig.Windows {
|
||||
|
||||
await ctx.SaveChangesAsync();
|
||||
|
||||
if (TransferPredecessorAreaComs && m.PredecessorMgNr is int predecessor) {
|
||||
var year = Utils.FollowingSeason;
|
||||
if (TransferPredecessorAreaComs is int year && m.PredecessorMgNr is int predecessor) {
|
||||
var areaComs = await ctx.AreaCommitments
|
||||
.Where(c => c.MgNr == predecessor && (c.YearTo == null || c.YearTo >= year))
|
||||
.ToListAsync();
|
||||
@ -928,20 +952,19 @@ namespace Elwig.Windows {
|
||||
ctx.UpdateRange(areaComs);
|
||||
await ctx.SaveChangesAsync();
|
||||
}
|
||||
TransferPredecessorAreaComs = false;
|
||||
TransferPredecessorAreaComs = null;
|
||||
|
||||
if (CancelAreaComs) {
|
||||
var year = Utils.FollowingSeason;
|
||||
if (CancelAreaComs is int yearTo) {
|
||||
var areaComs = await ctx.AreaCommitments
|
||||
.Where(c => c.MgNr == m.MgNr && (c.YearTo == null || c.YearTo >= year))
|
||||
.Where(c => c.MgNr == m.MgNr && (c.YearTo == null || c.YearTo > yearTo))
|
||||
.ToListAsync();
|
||||
|
||||
foreach (var ac in areaComs)
|
||||
ac.YearTo = year - 1;
|
||||
ac.YearTo = yearTo;
|
||||
ctx.UpdateRange(areaComs);
|
||||
await ctx.SaveChangesAsync();
|
||||
}
|
||||
CancelAreaComs = false;
|
||||
CancelAreaComs = null;
|
||||
|
||||
if (newMgNr != m.MgNr) {
|
||||
await ctx.Database.ExecuteSqlAsync($"UPDATE member SET mgnr = {newMgNr} WHERE mgnr = {oldMgNr}");
|
||||
@ -1111,7 +1134,7 @@ namespace Elwig.Windows {
|
||||
var valid = InputLostFocus((TextBox)sender, Validator.CheckPredecessorMgNr);
|
||||
if (valid && PredecessorMgNrInput.Text != "" && (IsEditing || IsCreating)) {
|
||||
var mgnr = int.Parse(PredecessorMgNrInput.Text);
|
||||
if (MemberList.SelectedItem is Member m && m.MgNr == mgnr)
|
||||
if (MemberList.SelectedItem is not Member m || m.MgNr == mgnr)
|
||||
return;
|
||||
using var ctx = new AppDbContext();
|
||||
var areaComs = await ctx.AreaCommitments
|
||||
@ -1119,13 +1142,12 @@ namespace Elwig.Windows {
|
||||
.ToListAsync();
|
||||
if (areaComs.Count == 0)
|
||||
return;
|
||||
var res = MessageBox.Show("Sollen die aktiven Flächenbindungen des angegebenen\n" +
|
||||
$"Vorgängers übernommen werden? ({areaComs.Sum(c => c.Area)} m²)\n\n" +
|
||||
"Die Änderungen werden erst beim Speichern übernommen!",
|
||||
"Aktive Flächenbindungen übernehmen", MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No);
|
||||
if (res != MessageBoxResult.Yes)
|
||||
|
||||
var oldMember = (await ctx.Members.FindAsync(mgnr))!;
|
||||
var d = new AreaComDialog(oldMember.AdministrativeName, m.AdministrativeName, areaComs.Count, areaComs.Sum(c => c.Area));
|
||||
if (d.ShowDialog() != true)
|
||||
return;
|
||||
TransferPredecessorAreaComs = true;
|
||||
TransferPredecessorAreaComs = d.SuccessorSeason;
|
||||
SetOriginalValue(PredecessorMgNrInput, -1); // hack to allow user to save
|
||||
UpdateButtons();
|
||||
}
|
||||
@ -1167,18 +1189,18 @@ namespace Elwig.Windows {
|
||||
}
|
||||
|
||||
private async void ActiveInput_Changed(object sender, RoutedEventArgs evt) {
|
||||
if (MemberList.SelectedItem is not Member m)
|
||||
return;
|
||||
if ((IsEditing || IsCreating) && ActiveInput.IsChecked == false && int.TryParse(MgNrInput.Text, out var mgnr)) {
|
||||
using var ctx = new AppDbContext();
|
||||
var areaComs = await ctx.AreaCommitments
|
||||
.Where(c => c.MgNr == mgnr && (c.YearTo == null || c.YearTo >= Utils.FollowingSeason))
|
||||
.ToListAsync();
|
||||
if (areaComs.Count >= 0) {
|
||||
var res = MessageBox.Show($"Sollen die aktiven Flächenbindungen gekündigt werden? ({areaComs.Sum(c => c.Area)} m²)\n" +
|
||||
"Falls die Flächenbindungen später an ein neues Mitglied\n" +
|
||||
"übertragen werden sollen bitte \"Nein\" auswählen!\n\n" +
|
||||
"Die Änderungen werden erst beim Speichern übernommen!",
|
||||
"Flächenbindungen kündigen", MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No);
|
||||
CancelAreaComs = res == MessageBoxResult.Yes;
|
||||
if (areaComs.Count > 0) {
|
||||
var d = new AreaComDialog(m.AdministrativeName, areaComs.Count, areaComs.Sum(c => c.Area));
|
||||
if (d.ShowDialog() == true) {
|
||||
CancelAreaComs = d.CancelSeason;
|
||||
}
|
||||
}
|
||||
}
|
||||
CheckBox_Changed(sender, evt);
|
||||
|
128
Elwig/Windows/PaymentAdjustmentWindow.xaml
Normal file
128
Elwig/Windows/PaymentAdjustmentWindow.xaml
Normal file
@ -0,0 +1,128 @@
|
||||
<local:ContextWindow
|
||||
x:Class="Elwig.Windows.PaymentAdjustmentWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:Elwig.Windows"
|
||||
xmlns:ctrl="clr-namespace:Elwig.Controls"
|
||||
Title="Auszahlung anpassen - Elwig" Height="500" Width="850" MinHeight="400" MinWidth="850">
|
||||
<Window.Resources>
|
||||
<Style TargetType="Label">
|
||||
<Setter Property="HorizontalAlignment" Value="Left"/>
|
||||
<Setter Property="VerticalAlignment" Value="Top"/>
|
||||
<Setter Property="Padding" Value="2,4,2,4"/>
|
||||
<Setter Property="Height" Value="25"/>
|
||||
</Style>
|
||||
<Style TargetType="TextBox">
|
||||
<Setter Property="HorizontalAlignment" Value="Stretch"/>
|
||||
<Setter Property="VerticalAlignment" Value="Top"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="Padding" Value="2"/>
|
||||
<Setter Property="Height" Value="25"/>
|
||||
<Setter Property="TextWrapping" Value="NoWrap"/>
|
||||
</Style>
|
||||
<Style TargetType="ctrl:UnitTextBox">
|
||||
<Setter Property="HorizontalAlignment" Value="Left"/>
|
||||
<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="FontSize" Value="14"/>
|
||||
<Setter Property="Padding" Value="9,3"/>
|
||||
<Setter Property="Height" Value="27"/>
|
||||
</Style>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="19"/>
|
||||
<RowDefinition Height="1*"/>
|
||||
<RowDefinition Height="24"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="450"/>
|
||||
<ColumnDefinition Width="2.5*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Menu Grid.ColumnSpan="2" BorderThickness="0,0,0,1" BorderBrush="LightGray" Background="White">
|
||||
</Menu>
|
||||
|
||||
<Grid Grid.Row="1">
|
||||
<DataGrid x:Name="MemberList" AutoGenerateColumns="False" HeadersVisibility="Column" IsReadOnly="True" GridLinesVisibility="None" SelectionMode="Single"
|
||||
CanUserDeleteRows="False" CanUserResizeRows="False" CanUserAddRows="False" Margin="10,10,10,10">
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="MgNr." Binding="{Binding MgNr, StringFormat='{}{0} '}" Width="45">
|
||||
<DataGridTextColumn.CellStyle>
|
||||
<Style>
|
||||
<Setter Property="TextBlock.TextAlignment" Value="Right"/>
|
||||
</Style>
|
||||
</DataGridTextColumn.CellStyle>
|
||||
</DataGridTextColumn>
|
||||
<DataGridTextColumn Header="Nachname" Binding="{Binding FamilyName}" Width="100"/>
|
||||
<DataGridTextColumn Header="Vorname" Binding="{Binding GivenName}" Width="100"/>
|
||||
<DataGridTextColumn Header="GA" Binding="{Binding BusinessShares, StringFormat='{}{0} '}" Width="35">
|
||||
<DataGridTextColumn.CellStyle>
|
||||
<Style>
|
||||
<Setter Property="TextBlock.TextAlignment" Value="Right"/>
|
||||
</Style>
|
||||
</DataGridTextColumn.CellStyle>
|
||||
</DataGridTextColumn>
|
||||
<DataGridTextColumn Header="Ü.-/U.-Lfrg." Binding="{Binding OverUnder, StringFormat='{}{0} kg '}" Width="70">
|
||||
<DataGridTextColumn.CellStyle>
|
||||
<Style>
|
||||
<Setter Property="TextBlock.TextAlignment" Value="Right"/>
|
||||
</Style>
|
||||
</DataGridTextColumn.CellStyle>
|
||||
</DataGridTextColumn>
|
||||
<DataGridTextColumn Header="Nachz." Binding="{Binding Adjust, StringFormat='{}{0} '}" Width="45">
|
||||
<DataGridTextColumn.CellStyle>
|
||||
<Style>
|
||||
<Setter Property="TextBlock.TextAlignment" Value="Right"/>
|
||||
</Style>
|
||||
</DataGridTextColumn.CellStyle>
|
||||
</DataGridTextColumn>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Column="1" Grid.Row="1">
|
||||
<GroupBox Header="Automatische Nachzeichnung der Geschäftsanteile" Margin="10,10,10,10" Height="180" Width="360"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Left">
|
||||
<Grid>
|
||||
<Label Content="Absoluter Freibetrag:" Margin="10,10,10,10"/>
|
||||
<ctrl:UnitTextBox x:Name="AllowanceKgInput" Unit="kg" Margin="140,10,10,10" Width="70"
|
||||
TextChanged="KgInput_TextChanged"/>
|
||||
<ctrl:UnitTextBox x:Name="AllowanceBsInput" Unit="GA" Margin="215,10,10,10" Width="60"
|
||||
TextChanged="PercentInput_TextChanged"/>
|
||||
|
||||
<Label Content="Relativer Freibetrag:" Margin="10,40,10,10"/>
|
||||
<ctrl:UnitTextBox x:Name="AllowanceKgPerBsInput" Unit="kg/GA" Margin="140,40,10,10" Width="87"
|
||||
TextChanged="KgInput_TextChanged"/>
|
||||
<ctrl:UnitTextBox x:Name="AllowancePercentInput" Unit="%" Margin="232,40,10,10" Width="60"
|
||||
TextChanged="PercentInput_TextChanged"/>
|
||||
|
||||
<Label Content="Nur mind. nachz.:" Margin="10,70,10,10"/>
|
||||
<ctrl:UnitTextBox x:Name="MinBsInput" Unit="GA" Margin="140,70,10,10" Width="50"
|
||||
TextChanged="BsInput_TextChanged"/>
|
||||
|
||||
<Button x:Name="SeasonButton" Content="GA-Wert" Margin="10,10,10,42" Width="120"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Bottom"
|
||||
Click="SeasonButton_Click"/>
|
||||
<Button x:Name="AutoAdjustBsButton" Content="Nachzeichnen" Margin="10,10,135,10" Width="120"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Bottom"
|
||||
Click="AutoAdjustBsButton_Click"/>
|
||||
<Button x:Name="UnAdjustBsButton" Content="Rückgängig" Margin="10,10,10,10" Width="120"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Bottom"
|
||||
Click="UnAdjustBsButton_Click"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
</Grid>
|
||||
|
||||
<StatusBar Grid.Row="2" Grid.ColumnSpan="2" BorderThickness="0,1,0,0" BorderBrush="Gray">
|
||||
</StatusBar>
|
||||
</Grid>
|
||||
</local:ContextWindow>
|
143
Elwig/Windows/PaymentAdjustmentWindow.xaml.cs
Normal file
143
Elwig/Windows/PaymentAdjustmentWindow.xaml.cs
Normal file
@ -0,0 +1,143 @@
|
||||
using Elwig.Helpers;
|
||||
using Elwig.Helpers.Billing;
|
||||
using Elwig.Models.Dtos;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace Elwig.Windows {
|
||||
public partial class PaymentAdjustmentWindow : ContextWindow {
|
||||
|
||||
public readonly int Year;
|
||||
public readonly bool SeasonLocked;
|
||||
|
||||
public PaymentAdjustmentWindow(int year) {
|
||||
InitializeComponent();
|
||||
Year = year;
|
||||
using (var ctx = new AppDbContext()) {
|
||||
SeasonLocked = ctx.Seasons.Find(Year + 1) != null;
|
||||
}
|
||||
Title = $"Auszahlung anpassen - Lese {Year} - Elwig";
|
||||
|
||||
AllowanceKgInput.Text = $"{App.Client.AutoAdjustBs.AllowanceKg}";
|
||||
AllowanceBsInput.Text = $"{App.Client.AutoAdjustBs.AllowanceBs}";
|
||||
AllowanceKgPerBsInput.Text = $"{App.Client.AutoAdjustBs.AllowanceKgPerBs}";
|
||||
AllowancePercentInput.Text = $"{App.Client.AutoAdjustBs.AllowancePercent}";
|
||||
MinBsInput.Text = $"{App.Client.AutoAdjustBs.MinBs}";
|
||||
}
|
||||
|
||||
protected override async Task OnRenewContext(AppDbContext ctx) {
|
||||
var members = await ctx.Members
|
||||
.Select(m => new {
|
||||
m.MgNr,
|
||||
m.FamilyName,
|
||||
m.GivenName,
|
||||
m.BusinessShares,
|
||||
})
|
||||
.OrderBy(m => m.FamilyName)
|
||||
.ThenBy(m => m.GivenName)
|
||||
.ThenBy(m => m.MgNr)
|
||||
.ToListAsync();
|
||||
var season = (await ctx.Seasons.FindAsync(Year))!;
|
||||
|
||||
var tbl = await OverUnderDeliveryData.ForSeason(ctx.OverUnderDeliveryRows, Year);
|
||||
var weight = tbl.Rows.ToDictionary(r => r.MgNr, r => r.Weight);
|
||||
|
||||
var history = await ctx.MemberHistory
|
||||
.Where(h => h.DateString.CompareTo($"{Year}-01-01") >= 0 && h.DateString.CompareTo($"{Year}-12-31") <= 0 && h.Type == "auto" && h.BusinessShares > 0)
|
||||
.GroupBy(h => h.Member)
|
||||
.ToDictionaryAsync(h => h.Key.MgNr, h => h.Sum(g => g.BusinessShares));
|
||||
|
||||
var list = members
|
||||
.Select(m => new {
|
||||
m.MgNr,
|
||||
m.FamilyName,
|
||||
m.GivenName,
|
||||
BusinessShares = m.BusinessShares - history.GetValueOrDefault(m.MgNr, 0),
|
||||
DeliveryObligation = (m.BusinessShares - history.GetValueOrDefault(m.MgNr, 0)) * season.MinKgPerBusinessShare,
|
||||
DeliveryRight = (m.BusinessShares - history.GetValueOrDefault(m.MgNr, 0)) * season.MaxKgPerBusinessShare,
|
||||
})
|
||||
.Select(m => new {
|
||||
m.MgNr,
|
||||
m.FamilyName,
|
||||
m.GivenName,
|
||||
m.BusinessShares,
|
||||
OverUnder = weight.TryGetValue(m.MgNr, out int v1) ?
|
||||
(v1 < m.DeliveryObligation ? (int?)v1 - m.DeliveryObligation :
|
||||
v1 > m.DeliveryRight ? (int?)v1 - m.DeliveryRight : null)
|
||||
: null,
|
||||
Adjust = history.TryGetValue(m.MgNr, out int v2) ? (int?)v2 : null
|
||||
})
|
||||
.Where(m => m.OverUnder != null || m.Adjust != null)
|
||||
.OrderByDescending(m => m.OverUnder)
|
||||
.ThenBy(m => m.FamilyName)
|
||||
.ThenBy(m => m.GivenName)
|
||||
.ThenBy(m => m.MgNr)
|
||||
.ToList();
|
||||
|
||||
MemberList.ItemsSource = list;
|
||||
}
|
||||
|
||||
private async void AutoAdjustBsButton_Click(object sender, RoutedEventArgs evt) {
|
||||
Mouse.OverrideCursor = Cursors.AppStarting;
|
||||
try {
|
||||
int? kg = AllowanceKgInput.Text == "" ? null : int.Parse(AllowanceKgInput.Text);
|
||||
double? bs = AllowanceBsInput.Text == "" ? null : double.Parse(AllowanceBsInput.Text);
|
||||
int? kgPerBs = AllowanceKgPerBsInput.Text == "" ? null : int.Parse(AllowanceKgPerBsInput.Text);
|
||||
double? percent = AllowancePercentInput.Text == "" ? null : double.Parse(AllowancePercentInput.Text);
|
||||
int? minBs = MinBsInput.Text == "" ? null : int.Parse(MinBsInput.Text);
|
||||
|
||||
App.Client.AutoAdjustBs.AllowanceKg = kg;
|
||||
App.Client.AutoAdjustBs.AllowanceBs = bs;
|
||||
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 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, "GA Nachzeichnen", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
Mouse.OverrideCursor = null;
|
||||
}
|
||||
|
||||
private async void UnAdjustBsButton_Click(object sender, RoutedEventArgs evt) {
|
||||
Mouse.OverrideCursor = Cursors.AppStarting;
|
||||
try {
|
||||
var b = new Billing(Year);
|
||||
await b.UnAdjustBusinessShares();
|
||||
await 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, "GA Nachzeichnen", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
Mouse.OverrideCursor = null;
|
||||
}
|
||||
|
||||
private void SeasonButton_Click(object sender, RoutedEventArgs evt) {
|
||||
App.FocusBaseDataSeason(Year);
|
||||
}
|
||||
|
||||
private void KgInput_TextChanged(object sender, TextChangedEventArgs evt) {
|
||||
Validator.CheckInteger((TextBox)sender, false, 6);
|
||||
}
|
||||
|
||||
private void BsInput_TextChanged(object sender, TextChangedEventArgs evt) {
|
||||
Validator.CheckInteger((TextBox)sender, false, 3);
|
||||
}
|
||||
|
||||
private void PercentInput_TextChanged(object sender, TextChangedEventArgs evt) {
|
||||
Validator.CheckDecimal((TextBox)sender, false, 3, 2);
|
||||
}
|
||||
}
|
||||
}
|
@ -6,8 +6,7 @@
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:Elwig.Windows"
|
||||
xmlns:ctrl="clr-namespace:Elwig.Controls"
|
||||
mc:Ignorable="d"
|
||||
Title="Auszahlungsvarianten - Elwig" Height="510" Width="820" MinHeight="500" MinWidth="820">
|
||||
Title="Auszahlungsvarianten - Elwig" Height="480" Width="850" MinHeight="400" MinWidth="830">
|
||||
<Window.Resources>
|
||||
<Style TargetType="Label">
|
||||
<Setter Property="HorizontalAlignment" Value="Left"/>
|
||||
@ -23,6 +22,14 @@
|
||||
<Setter Property="Height" Value="25"/>
|
||||
<Setter Property="TextWrapping" Value="NoWrap"/>
|
||||
</Style>
|
||||
<Style TargetType="ctrl:UnitTextBox">
|
||||
<Setter Property="HorizontalAlignment" Value="Stretch"/>
|
||||
<Setter Property="VerticalAlignment" Value="Top"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="Padding" Value="2"/>
|
||||
<Setter Property="Height" Value="25"/>
|
||||
<Setter Property="TextWrapping" Value="NoWrap"/>
|
||||
</Style>
|
||||
<Style TargetType="ComboBox">
|
||||
<Setter Property="Height" Value="25"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
@ -36,179 +43,230 @@
|
||||
</Style>
|
||||
</Window.Resources>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="19"/>
|
||||
<RowDefinition Height="1*"/>
|
||||
<RowDefinition Height="24"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="320"/>
|
||||
<ColumnDefinition Width="100"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="2.5*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="220"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<ListBox x:Name="PaymentVariantList" Margin="10,10,35,10" Grid.RowSpan="2" SelectionChanged="PaymentVariantList_SelectionChanged">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding Name}" Width="200"/>
|
||||
<TextBlock Text="{Binding Date}" Width="60"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
<Button x:Name="AddButton" Content="" 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="" FontFamily="Segoe MDL2 Assets" FontSize="12" Padding="0,0,0,0" IsEnabled="False" 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="" FontFamily="Segoe MDL2 Assets" FontSize="11" Padding="0,1.5,0,0" IsEnabled="False" 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"/>
|
||||
<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"
|
||||
Click="Menu_SummaryShow_Click" InputGestureText="Strg+P"/>
|
||||
<MenuItem x:Name="Menu_SummarySave" Header="...speichern... (PDF)" IsEnabled="False"
|
||||
Click="Menu_SummarySave_Click"/>
|
||||
<MenuItem x:Name="Menu_SummaryExport" Header="...speichern... (Excel)" IsEnabled="False"
|
||||
Click="Menu_SummaryExport_Click"/>
|
||||
<MenuItem x:Name="Menu_SummaryPrint" Header="...drucken" IsEnabled="False"
|
||||
Click="Menu_SummaryPrint_Click" InputGestureText="Strg+Shift+P"/>
|
||||
</MenuItem>
|
||||
<MenuItem Header="Buchungsliste">
|
||||
<MenuItem x:Name="Menu_ExportSave" Header="...speichern... (Excel)" IsEnabled="False"
|
||||
Click="Menu_ExportSave_Click" InputGestureText="Strg+L"/>
|
||||
</MenuItem>
|
||||
<MenuItem Header="Überweisungsdaten">
|
||||
<MenuItem x:Name="Menu_EbicsSave" Header="...exportieren... (EBICS)" IsEnabled="False"
|
||||
Click="Menu_EbicsSave_Click" InputGestureText="Strg+Ü"/>
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
|
||||
<TextBox x:Name="DataInput" Margin="10,200,35,10" Grid.Column="0" Grid.RowSpan="2"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Height="auto"
|
||||
AcceptsReturn="True" VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Auto"
|
||||
FontFamily="Cascadia Code Light" FontSize="13"
|
||||
TextChanged="DataInput_TextChanged"/>
|
||||
<Grid Grid.Row="1">
|
||||
<ListBox x:Name="PaymentVariantList" Margin="10,10,35,10" Grid.RowSpan="2" SelectionChanged="PaymentVariantList_SelectionChanged">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding Name}" Width="200"/>
|
||||
<TextBlock Text="{Binding Date}" Width="60"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
<Button x:Name="AddButton" Content="" 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="" FontFamily="Segoe MDL2 Assets" FontSize="12" Padding="0,0,0,0" IsEnabled="False" 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="" FontFamily="Segoe MDL2 Assets" FontSize="11" Padding="0,1.5,0,0" IsEnabled="False" 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"/>
|
||||
|
||||
<Label Content="Name:" Margin="10,10,0,0" Grid.Column="1"/>
|
||||
<TextBox x:Name="NameInput" Width="200" Grid.Column="2" HorizontalAlignment="Left" Margin="0,10,0,0"
|
||||
TextChanged="NameInput_TextChanged"/>
|
||||
|
||||
<Label Content="Beschreibung:" Margin="10,40,0,0" Grid.Column="1"/>
|
||||
<TextBox x:Name="CommentInput" Grid.Column="2" HorizontalAlignment="Stretch" Margin="0,40,10,0"
|
||||
TextChanged="CommentInput_TextChanged"/>
|
||||
|
||||
<Label Content="Erstellt am:" Margin="10,70,0,0" Grid.Column="1"/>
|
||||
<TextBox x:Name="DateInput" Grid.Column="2" Width="77" HorizontalAlignment="Left" Margin="0,70,10,0" IsReadOnly="True"/>
|
||||
|
||||
<Label Content="Überwiesen am:" Margin="10,100,0,0" Grid.Column="1"/>
|
||||
<TextBox x:Name="TransferDateInput" Grid.Column="2" Width="77" HorizontalAlignment="Left" Margin="0,100,10,0"
|
||||
TextChanged="TransferDateInput_TextChanged"/>
|
||||
|
||||
<Label Content="Rebelzuschlag:" Margin="10,130,0,0" Grid.Column="1"/>
|
||||
<ctrl:UnitTextBox x:Name="WeightModifierInput" Grid.Column="2" Width="60" Margin="0,130,10,0" Unit="%"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Top"
|
||||
TextChanged="WeightModifierInput_TextChanged" LostFocus="WeightModifierInput_LostFocus"/>
|
||||
|
||||
<Label Content="Berücksichtigen:" Margin="90,70,10,10" Grid.Column="2"/>
|
||||
<CheckBox x:Name="ConsiderModifiersInput" Content="Zu-/Abschläge bei Lieferungen"
|
||||
Margin="110,95,10,10" Grid.Column="2" HorizontalAlignment="Left" VerticalAlignment="Top"
|
||||
Checked="ConsiderModifiersInput_Changed" Unchecked="ConsiderModifiersInput_Changed"/>
|
||||
<CheckBox x:Name="ConsiderPenaltiesInput" Content="Pönalen bei Unterlieferungen (FB)"
|
||||
Margin="110,115,10,10" Grid.Column="2" HorizontalAlignment="Left" VerticalAlignment="Top"
|
||||
Checked="ConsiderPenaltiesInput_Changed" Unchecked="ConsiderPenaltiesInput_Changed"/>
|
||||
<CheckBox x:Name="ConsiderPenaltyInput" Content="Strafen bei Unterlieferungen (GA)"
|
||||
Margin="110,135,10,10" Grid.Column="2" HorizontalAlignment="Left" VerticalAlignment="Top"
|
||||
Checked="ConsiderPenaltyInput_Changed" Unchecked="ConsiderPenaltyInput_Changed"/>
|
||||
<CheckBox x:Name="ConsiderAutoInput" Content="Automatische Nachzeichnungen der GA"
|
||||
Margin="110,155,10,10" Grid.Column="2" HorizontalAlignment="Left" VerticalAlignment="Top"
|
||||
Checked="ConsiderAutoInput_Changed" Unchecked="ConsiderAutoInput_Changed"/>
|
||||
<Label Content="" FontFamily="Segoe MDL2 Assets" FontSize="16" Grid.Row="0" Grid.Column="2" Margin="108,175,10,10"/>
|
||||
|
||||
<Grid Grid.Column="1" Grid.ColumnSpan="2" VerticalAlignment="Bottom" HorizontalAlignment="Center" Margin="10,10,10,10">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="110"/>
|
||||
<ColumnDefinition Width="27"/>
|
||||
<ColumnDefinition Width="110"/>
|
||||
<ColumnDefinition Width="27"/>
|
||||
<ColumnDefinition Width="110"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="27"/>
|
||||
<RowDefinition Height="5"/>
|
||||
<RowDefinition Height="27"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid.Resources>
|
||||
<Style TargetType="Label">
|
||||
<Setter Property="HorizontalAlignment" Value="Center"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
<Setter Property="Padding" Value="0"/>
|
||||
<Setter Property="Height" Value="auto"/>
|
||||
</Style>
|
||||
<Style TargetType="Button">
|
||||
<Setter Property="HorizontalAlignment" Value="Stretch"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
</Style>
|
||||
</Grid.Resources>
|
||||
|
||||
<Button x:Name="ModifierButton" Content="Zu-/Abschläge" Grid.Column="0" Grid.Row="0"
|
||||
Click="ModifierButton_Click"/>
|
||||
<Label Content="" FontFamily="Segoe MDL2 Assets" FontSize="16" Grid.Row="0" Grid.Column="1" RenderTransformOrigin="0.5,0.5" >
|
||||
<Label.RenderTransform>
|
||||
<TransformGroup>
|
||||
<RotateTransform Angle="45"/>
|
||||
<TranslateTransform Y="5"/>
|
||||
</TransformGroup>
|
||||
</Label.RenderTransform>
|
||||
</Label>
|
||||
<Button x:Name="EditButton" Content="Bearbeiten" Grid.Column="0" Grid.Row="2"
|
||||
Click="EditButton_Click"/>
|
||||
<Label Content="" FontFamily="Segoe MDL2 Assets" FontSize="16" Grid.Row="2" Grid.Column="1"/>
|
||||
<Button x:Name="CalculateButton" Content="Berechnen" Grid.Column="2" Grid.Row="2"
|
||||
Click="CalculateButton_Click"/>
|
||||
<Label Content="" FontFamily="Segoe MDL2 Assets" FontSize="16" Grid.Row="2" Grid.Column="3" x:Name="Arrow3"/>
|
||||
<Button x:Name="CommitButton" Content="Festsetzen" Grid.Column="4" Grid.Row="2"
|
||||
Click="CommitButton_Click"/>
|
||||
<Button x:Name="RevertButton" Content="Freigeben" Grid.Column="4" Grid.Row="2"
|
||||
Click="RevertButton_Click"/>
|
||||
<Button x:Name="SaveButton" Content="Speichern" Grid.Column="4" Grid.Row="0"
|
||||
Click="SaveButton_Click"/>
|
||||
<TextBox x:Name="DataInput" Margin="10,200,35,10"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Height="auto"
|
||||
AcceptsReturn="True" VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Auto"
|
||||
FontFamily="Cascadia Code Light" FontSize="13"
|
||||
TextChanged="DataInput_TextChanged"/>
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2">
|
||||
<Grid Grid.Column="1" Grid.Row="1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="100"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="250"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<GroupBox Header="Abschluss" Margin="10,0,5,10">
|
||||
<Grid>
|
||||
<Button x:Name="ExportButton" Content="Exportieren" FontSize="14" Width="180" Margin="10,10,10,10" Height="27" IsEnabled="False"
|
||||
Click="ExportButton_Click"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Left"/>
|
||||
<Button x:Name="TransactionButton" Content="Buchungsliste" FontSize="14" Width="180" Margin="10,42,10,10" Height="27" IsEnabled="False"
|
||||
Click="TransactionButton_Click"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Left"/>
|
||||
<Button x:Name="MailButton" Content="Traubengutschriften" FontSize="14" Width="180" Margin="10,74,10,10" Height="27" IsEnabled="False"
|
||||
Click="MailButton_Click"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Left"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
<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"
|
||||
TextChanged="NameInput_TextChanged"/>
|
||||
|
||||
<GroupBox Header="Ergebnis" Margin="5,0,10,10" Grid.Column="1">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="100"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.Resources>
|
||||
<Style TargetType="TextBlock">
|
||||
<Setter Property="Grid.Column" Value="1"/>
|
||||
<Setter Property="VerticalAlignment" Value="Top"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="TextAlignment" Value="Right"/>
|
||||
</Style>
|
||||
</Grid.Resources>
|
||||
<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"
|
||||
TextChanged="CommentInput_TextChanged"/>
|
||||
|
||||
<Label Content="Zu-/Abschläge:" Margin="10,10,0,0"/>
|
||||
<TextBlock x:Name="ModifierSum" Margin="0,12,10,0"/>
|
||||
<Label Content="Erstellt am:" Margin="10,70,0,0" Grid.Column="0"/>
|
||||
<TextBox x:Name="DateInput" Grid.Column="1" Width="77" HorizontalAlignment="Left" Margin="0,70,10,0" IsReadOnly="True"/>
|
||||
|
||||
<Label Content="Gesamtbeträge:" Margin="10,40,0,0"/>
|
||||
<TextBlock x:Name="TotalSum" Margin="0,42,10,0"/>
|
||||
<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"
|
||||
TextChanged="TransferDateInput_TextChanged"/>
|
||||
|
||||
<Label Content="Mehrwertsteuer:" Margin="10,70,0,0"/>
|
||||
<TextBlock x:Name="VatSum" Margin="0,72,10,0"/>
|
||||
<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="%"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Top"
|
||||
TextChanged="WeightModifierInput_TextChanged" LostFocus="WeightModifierInput_LostFocus"/>
|
||||
|
||||
<Label Content="Abzüge:" Margin="10,100,0,0"/>
|
||||
<TextBlock x:Name="DeductionSum" Margin="0,102,10,0"/>
|
||||
<Label Content="Berücksichtigen:" Margin="90,70,10,10" Grid.Column="1"/>
|
||||
<CheckBox x:Name="ConsiderModifiersInput" Content="Zu-/Abschläge bei Lieferungen"
|
||||
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)"
|
||||
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)"
|
||||
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"
|
||||
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"
|
||||
Margin="110,175,10,10" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Top"
|
||||
Checked="ConsiderCustomInput_Changed" Unchecked="ConsiderCustomInput_Changed"/>
|
||||
<Label Content="" FontFamily="Segoe MDL2 Assets" FontSize="16" Grid.Row="0" Grid.Column="1" Margin="108,195,10,10"/>
|
||||
|
||||
<Label Content="Auszuzahlen:" Margin="10,130,0,0"/>
|
||||
<TextBlock x:Name="PaymentSum" Margin="0,132,10,0"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
<Grid Grid.Column="0" Grid.ColumnSpan="2" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="50,200,10,10">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="110"/>
|
||||
<ColumnDefinition Width="27"/>
|
||||
<ColumnDefinition Width="110"/>
|
||||
<ColumnDefinition Width="27"/>
|
||||
<ColumnDefinition Width="110"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="27"/>
|
||||
<RowDefinition Height="5"/>
|
||||
<RowDefinition Height="27"/>
|
||||
<RowDefinition Height="5"/>
|
||||
<RowDefinition Height="27"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid.Resources>
|
||||
<Style TargetType="Label">
|
||||
<Setter Property="HorizontalAlignment" Value="Center"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
<Setter Property="Padding" Value="0"/>
|
||||
<Setter Property="Height" Value="auto"/>
|
||||
</Style>
|
||||
<Style TargetType="Button">
|
||||
<Setter Property="HorizontalAlignment" Value="Stretch"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
</Style>
|
||||
</Grid.Resources>
|
||||
|
||||
<Button x:Name="ModifierButton" Content="Zu-/Abschläge" Grid.Column="0" Grid.Row="0"
|
||||
Click="ModifierButton_Click"/>
|
||||
<Label Content="" FontFamily="Segoe MDL2 Assets" FontSize="16" Grid.Row="0" Grid.Column="1" RenderTransformOrigin="0.5,0.5" >
|
||||
<Label.RenderTransform>
|
||||
<TransformGroup>
|
||||
<RotateTransform Angle="45"/>
|
||||
<TranslateTransform Y="5"/>
|
||||
</TransformGroup>
|
||||
</Label.RenderTransform>
|
||||
</Label>
|
||||
<Button x:Name="EditButton" Content="Bearbeiten" Grid.Column="0" Grid.Row="2"
|
||||
Click="EditButton_Click"/>
|
||||
<Label Content="" FontFamily="Segoe MDL2 Assets" FontSize="16" Grid.Row="2" Grid.Column="1"/>
|
||||
<Button x:Name="PaymentAdjustmentButton" Content="Anpassen" Grid.Column="0" Grid.Row="4"
|
||||
Click="PaymentAdjustmentButton_Click"/>
|
||||
<Label Content="" FontFamily="Segoe MDL2 Assets" FontSize="16" Grid.Row="4" Grid.Column="1" RenderTransformOrigin="0.5,0.5" >
|
||||
<Label.RenderTransform>
|
||||
<TransformGroup>
|
||||
<RotateTransform Angle="-45"/>
|
||||
<TranslateTransform Y="-5"/>
|
||||
</TransformGroup>
|
||||
</Label.RenderTransform>
|
||||
</Label>
|
||||
<Button x:Name="CalculateButton" Content="Berechnen" Grid.Column="2" Grid.Row="2"
|
||||
Click="CalculateButton_Click"/>
|
||||
<Label Content="" FontFamily="Segoe MDL2 Assets" FontSize="16" Grid.Row="2" Grid.Column="3" x:Name="Arrow3"/>
|
||||
<Button x:Name="CommitButton" Content="Festsetzen" Grid.Column="4" Grid.Row="2"
|
||||
Click="CommitButton_Click"/>
|
||||
<Button x:Name="RevertButton" Content="Freigeben" Grid.Column="4" Grid.Row="2"
|
||||
Click="RevertButton_Click"/>
|
||||
<Button x:Name="SaveButton" Content="Speichern" Grid.Column="4" Grid.Row="0"
|
||||
Click="SaveButton_Click"/>
|
||||
</Grid>
|
||||
|
||||
<Button x:Name="MailButton" Content="Traubengutschriften"
|
||||
FontSize="14" Width="160" Margin="10,10,10,10" Height="27" IsEnabled="False"
|
||||
Click="MailButton_Click"
|
||||
VerticalAlignment="Bottom" HorizontalAlignment="Right" Grid.Column="1"/>
|
||||
</Grid>
|
||||
|
||||
<StatusBar Grid.Row="2" Grid.ColumnSpan="2" BorderThickness="0,1,0,0" BorderBrush="Gray">
|
||||
<StatusBar.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
</Grid>
|
||||
</ItemsPanelTemplate>
|
||||
</StatusBar.ItemsPanel>
|
||||
<StatusBarItem Grid.Column="0" HorizontalContentAlignment="Stretch">
|
||||
<DockPanel>
|
||||
<TextBlock Text="Zu-/Abschl.:"/>
|
||||
<TextBlock x:Name="ModifierSum" Text="-" 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"/>
|
||||
</DockPanel>
|
||||
</StatusBarItem>
|
||||
<Separator Grid.Column="3"/>
|
||||
<StatusBarItem Grid.Column="4" HorizontalContentAlignment="Stretch">
|
||||
<DockPanel>
|
||||
<TextBlock Text="MwSt.:"/>
|
||||
<TextBlock x:Name="VatSum" Text="-" 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"/>
|
||||
</DockPanel>
|
||||
</StatusBarItem>
|
||||
<Separator Grid.Column="7"/>
|
||||
<StatusBarItem Grid.Column="8" HorizontalContentAlignment="Stretch">
|
||||
<DockPanel>
|
||||
<TextBlock Text="Auszahl.:"/>
|
||||
<TextBlock x:Name="PaymentSum" Text="-" TextAlignment="Right"/>
|
||||
</DockPanel>
|
||||
</StatusBarItem>
|
||||
</StatusBar>
|
||||
</Grid>
|
||||
</local:ContextWindow>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user