Compare commits
202 Commits
d6059e724b
...
v0.2.0
Author | SHA1 | Date | |
---|---|---|---|
b2a78907cf | |||
7bcf532b26 | |||
595f9a049c | |||
80ed90941d | |||
77cee53f2d | |||
1a673f4b3a | |||
5ad8c88319 | |||
30aaa64f59 | |||
352bf840c3 | |||
898cece0d3 | |||
0b05cc4e10 | |||
74fa08e95d | |||
bc6148624c | |||
f5f00a7739 | |||
2de4739e9d | |||
47e8ab7e62 | |||
8a678509c5 | |||
de53bfdd2b | |||
f9d95a48f2 | |||
be734b880f | |||
1c45e95ef3 | |||
7086a72fab | |||
540236f878 | |||
aab95ee444 | |||
2b7d19199a | |||
28b424fe65 | |||
324c5db94e | |||
faaeefe6ce | |||
b76d43a5ff | |||
8b48882c86 | |||
286279b89f | |||
c933fa3423 | |||
0958728418 | |||
cb8d405dcf | |||
6f4e3474b8 | |||
545622a2ab | |||
3a0736a73f | |||
048a7e0f13 | |||
cad475fc20 | |||
8b0f1e35c8 | |||
67dbf62eb7 | |||
9b59208373 | |||
146560c796 | |||
286e3515d4 | |||
c1d3a9042d | |||
e656bde54d | |||
33d763d968 | |||
56a0eb794e | |||
effc9f9230 | |||
4817a2aedc | |||
b67628c566 | |||
5aa8e45652 | |||
1f377483a5 | |||
9b84452b86 | |||
75e6c1bd5d | |||
a96a05d3de | |||
3f09e62c74 | |||
a98bc3ae4a | |||
93d4365d36 | |||
33e10d00bf | |||
7c2bf711c7 | |||
ff7fe34d5b | |||
973f49fabc | |||
8899e8bd32 | |||
6dda9e09cf | |||
c0a6f16374 | |||
ba71618463 | |||
6261217e7c | |||
5dd56d9666 | |||
83a82c17c6 | |||
03cf88a058 | |||
4bb0acb4a2 | |||
04db3fe0c5 | |||
28bb8f2d3f | |||
5074f945cf | |||
3a12837706 | |||
cfa1f1eeea | |||
85e4ccd215 | |||
0e13e269d0 | |||
4aa8fe2e2d | |||
a94bf651de | |||
00078a1f4e | |||
ded7dbec06 | |||
8534ff6bba | |||
f735da0059 | |||
5093706a4a | |||
8f7d699b4e | |||
b87710cc67 | |||
0d609c1013 | |||
58235e3b02 | |||
3ab2b8a8dc | |||
258b2b3c5b | |||
9e1ea293aa | |||
12a81bd924 | |||
84edec2b54 | |||
c871dea873 | |||
99a6f53307 | |||
f8af155c60 | |||
244de52b19 | |||
0ea77656e3 | |||
65bcc7bbb1 | |||
cbb57f7039 | |||
644362f492 | |||
b11dcd273d | |||
041e674af9 | |||
c65ffaf161 | |||
e7cb698026 | |||
2800b8b3e6 | |||
94a0adc55a | |||
a24edfffa3 | |||
dfda5e36c8 | |||
29b8f046f4 | |||
8290b57cd4 | |||
e1630e9919 | |||
91a20662da | |||
7af27ab5de | |||
f4c24d9578 | |||
1226e85c4a | |||
d05eb145b6 | |||
a984c4f16c | |||
921871cab1 | |||
baf694621c | |||
75dfdb155b | |||
704337aa1d | |||
a62fb9ab16 | |||
d06ea4f045 | |||
69d89ecd56 | |||
4571b06279 | |||
c68c798b49 | |||
bfedf436d8 | |||
fd7a15bc5a | |||
5cee928978 | |||
75322da405 | |||
9ba45e58f6 | |||
d43633cb65 | |||
cf1b1f7865 | |||
df4e254305 | |||
05f9e94260 | |||
75b87719b3 | |||
2eef0496ba | |||
9584f12fc5 | |||
8c0df674ec | |||
592df9e56d | |||
c0e584143e | |||
cb2534d678 | |||
db5f6dbef0 | |||
5c2f7ae69a | |||
7c2a0ca1a6 | |||
f90319fc9f | |||
fd26ee4f52 | |||
e8919cc629 | |||
8d9e713c81 | |||
ad538ba767 | |||
79a92be9d2 | |||
8b55490b76 | |||
c1b8b68513 | |||
70ad8188c4 | |||
ee7aaf81d9 | |||
a6699320ef | |||
1abe8de810 | |||
4c402d81ab | |||
df7f2174e5 | |||
577a3a0a63 | |||
ad47aa2a79 | |||
fb077bc557 | |||
9229f27cf7 | |||
7468af3970 | |||
27abf559e8 | |||
5b9aedd1a4 | |||
3315b758ad | |||
4cd1114def | |||
2281ec80ae | |||
dc236bab62 | |||
3bf7d65dea | |||
2ee7e90bcc | |||
d2c0884b44 | |||
2210b6b829 | |||
92ff8a5dc9 | |||
4d78cdd8a5 | |||
f49f7534e9 | |||
b70608966d | |||
bfe6363d95 | |||
9e61ead3ad | |||
c8f0537976 | |||
54aaf9fda0 | |||
735f16731e | |||
4b52af6fe9 | |||
0dfb42a5ce | |||
3f11a498bc | |||
351a0b8d57 | |||
a65345c0d9 | |||
af6bcb4a96 | |||
35421bb585 | |||
4456b2228d | |||
77781d227c | |||
15f999869a | |||
8ffd478ca9 | |||
7b252a5bb5 | |||
26ec59507d | |||
50d0de57f5 | |||
0365669ea2 | |||
6acdbee154 |
76
Elwig.sln
76
Elwig.sln
@@ -4,22 +4,88 @@ VisualStudioVersion = 17.3.32929.385
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elwig", "Elwig\Elwig.csproj", "{00868460-16F6-4B48-AA9B-998F6263693B}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{AF4B84F8-08E6-409C-9E94-D7D990469597}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests", "Tests\Tests.csproj", "{30D7700A-7B0A-4E5D-B839-B4C1D95E307E}"
|
||||
EndProject
|
||||
Project("{B7DD6F7E-DEF8-4E67-B5B7-07EF123DB6F0}") = "Installer", "Installer\Installer.wixproj", "{4A82C9C0-EB6D-409C-B0B2-09A5F727D16F}"
|
||||
EndProject
|
||||
Project("{B7DD6F7E-DEF8-4E67-B5B7-07EF123DB6F0}") = "Setup", "Setup\Setup.wixproj", "{952E309C-2090-4978-8996-65900D8E8FA4}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|ARM64 = Debug|ARM64
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|ARM64 = Release|ARM64
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{00868460-16F6-4B48-AA9B-998F6263693B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{00868460-16F6-4B48-AA9B-998F6263693B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{00868460-16F6-4B48-AA9B-998F6263693B}.Debug|ARM64.ActiveCfg = Debug|Any CPU
|
||||
{00868460-16F6-4B48-AA9B-998F6263693B}.Debug|ARM64.Build.0 = Debug|Any CPU
|
||||
{00868460-16F6-4B48-AA9B-998F6263693B}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{00868460-16F6-4B48-AA9B-998F6263693B}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{00868460-16F6-4B48-AA9B-998F6263693B}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{00868460-16F6-4B48-AA9B-998F6263693B}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{00868460-16F6-4B48-AA9B-998F6263693B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{00868460-16F6-4B48-AA9B-998F6263693B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{AF4B84F8-08E6-409C-9E94-D7D990469597}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{AF4B84F8-08E6-409C-9E94-D7D990469597}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AF4B84F8-08E6-409C-9E94-D7D990469597}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{AF4B84F8-08E6-409C-9E94-D7D990469597}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{00868460-16F6-4B48-AA9B-998F6263693B}.Release|ARM64.ActiveCfg = Release|Any CPU
|
||||
{00868460-16F6-4B48-AA9B-998F6263693B}.Release|ARM64.Build.0 = Release|Any CPU
|
||||
{00868460-16F6-4B48-AA9B-998F6263693B}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{00868460-16F6-4B48-AA9B-998F6263693B}.Release|x64.Build.0 = Release|Any CPU
|
||||
{00868460-16F6-4B48-AA9B-998F6263693B}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{00868460-16F6-4B48-AA9B-998F6263693B}.Release|x86.Build.0 = Release|Any CPU
|
||||
{30D7700A-7B0A-4E5D-B839-B4C1D95E307E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{30D7700A-7B0A-4E5D-B839-B4C1D95E307E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{30D7700A-7B0A-4E5D-B839-B4C1D95E307E}.Debug|ARM64.ActiveCfg = Debug|Any CPU
|
||||
{30D7700A-7B0A-4E5D-B839-B4C1D95E307E}.Debug|ARM64.Build.0 = Debug|Any CPU
|
||||
{30D7700A-7B0A-4E5D-B839-B4C1D95E307E}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{30D7700A-7B0A-4E5D-B839-B4C1D95E307E}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{30D7700A-7B0A-4E5D-B839-B4C1D95E307E}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{30D7700A-7B0A-4E5D-B839-B4C1D95E307E}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{30D7700A-7B0A-4E5D-B839-B4C1D95E307E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{30D7700A-7B0A-4E5D-B839-B4C1D95E307E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{30D7700A-7B0A-4E5D-B839-B4C1D95E307E}.Release|ARM64.ActiveCfg = Release|Any CPU
|
||||
{30D7700A-7B0A-4E5D-B839-B4C1D95E307E}.Release|ARM64.Build.0 = Release|Any CPU
|
||||
{30D7700A-7B0A-4E5D-B839-B4C1D95E307E}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{30D7700A-7B0A-4E5D-B839-B4C1D95E307E}.Release|x64.Build.0 = Release|Any CPU
|
||||
{30D7700A-7B0A-4E5D-B839-B4C1D95E307E}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{30D7700A-7B0A-4E5D-B839-B4C1D95E307E}.Release|x86.Build.0 = Release|Any CPU
|
||||
{4A82C9C0-EB6D-409C-B0B2-09A5F727D16F}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{4A82C9C0-EB6D-409C-B0B2-09A5F727D16F}.Debug|Any CPU.Build.0 = Debug|x64
|
||||
{4A82C9C0-EB6D-409C-B0B2-09A5F727D16F}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{4A82C9C0-EB6D-409C-B0B2-09A5F727D16F}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{4A82C9C0-EB6D-409C-B0B2-09A5F727D16F}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{4A82C9C0-EB6D-409C-B0B2-09A5F727D16F}.Debug|x64.Build.0 = Debug|x64
|
||||
{4A82C9C0-EB6D-409C-B0B2-09A5F727D16F}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{4A82C9C0-EB6D-409C-B0B2-09A5F727D16F}.Debug|x86.Build.0 = Debug|x86
|
||||
{4A82C9C0-EB6D-409C-B0B2-09A5F727D16F}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{4A82C9C0-EB6D-409C-B0B2-09A5F727D16F}.Release|Any CPU.Build.0 = Release|x64
|
||||
{4A82C9C0-EB6D-409C-B0B2-09A5F727D16F}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{4A82C9C0-EB6D-409C-B0B2-09A5F727D16F}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{4A82C9C0-EB6D-409C-B0B2-09A5F727D16F}.Release|x64.ActiveCfg = Release|x64
|
||||
{4A82C9C0-EB6D-409C-B0B2-09A5F727D16F}.Release|x64.Build.0 = Release|x64
|
||||
{4A82C9C0-EB6D-409C-B0B2-09A5F727D16F}.Release|x86.ActiveCfg = Release|x86
|
||||
{4A82C9C0-EB6D-409C-B0B2-09A5F727D16F}.Release|x86.Build.0 = Release|x86
|
||||
{952E309C-2090-4978-8996-65900D8E8FA4}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{952E309C-2090-4978-8996-65900D8E8FA4}.Debug|Any CPU.Build.0 = Debug|x64
|
||||
{952E309C-2090-4978-8996-65900D8E8FA4}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{952E309C-2090-4978-8996-65900D8E8FA4}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{952E309C-2090-4978-8996-65900D8E8FA4}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{952E309C-2090-4978-8996-65900D8E8FA4}.Debug|x64.Build.0 = Debug|x64
|
||||
{952E309C-2090-4978-8996-65900D8E8FA4}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{952E309C-2090-4978-8996-65900D8E8FA4}.Debug|x86.Build.0 = Debug|x86
|
||||
{952E309C-2090-4978-8996-65900D8E8FA4}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{952E309C-2090-4978-8996-65900D8E8FA4}.Release|Any CPU.Build.0 = Release|x64
|
||||
{952E309C-2090-4978-8996-65900D8E8FA4}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{952E309C-2090-4978-8996-65900D8E8FA4}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{952E309C-2090-4978-8996-65900D8E8FA4}.Release|x64.ActiveCfg = Release|x64
|
||||
{952E309C-2090-4978-8996-65900D8E8FA4}.Release|x64.Build.0 = Release|x64
|
||||
{952E309C-2090-4978-8996-65900D8E8FA4}.Release|x86.ActiveCfg = Release|x86
|
||||
{952E309C-2090-4978-8996-65900D8E8FA4}.Release|x86.Build.0 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@@ -2,32 +2,105 @@
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:Elwig"
|
||||
xmlns:controls="clr-namespace:Elwig.Controls"
|
||||
StartupUri="Windows\MainWindow.xaml"
|
||||
xmlns:ui="http://schemas.modernwpf.com/2019">
|
||||
<Application.Resources>
|
||||
<!--<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ui:ThemeResources />
|
||||
<ui:XamlControlsResources />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>-->
|
||||
<DataTemplate x:Key="PostalDestComboBoxTemplate">
|
||||
<controls:BoolToStringConverter x:Key="BoolToStarConverter" FalseValue="" TrueValue="*"/>
|
||||
|
||||
<DataTemplate x:Key="PostalDestTemplate">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding Dest}"/>
|
||||
<TextBlock Text=" ("/>
|
||||
<TextBlock Text="{Binding Ort.Name}"/>
|
||||
<TextBlock Text=")"/>
|
||||
<TextBlock Text="{Binding Ort.Name, StringFormat='{} ({0})'}"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
<DataTemplate x:Key="BranchTemplate">
|
||||
<DataTemplate x:Key="KgNrTemplate">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding Name}"/>
|
||||
<TextBlock Text="{Binding KgNr, StringFormat='{} ({0:00000})'}"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
<DataTemplate x:Key="MemberAdminNameTemplate">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding MgNr}" MinWidth="48" Margin="0,0,10,0" TextAlignment="Right"/>
|
||||
<TextBlock Text="{Binding AdministrativeName1}" MinWidth="100" Margin="0,0,5,0"/>
|
||||
<TextBlock Text="{Binding AdministrativeName2}"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
|
||||
<ControlTemplate x:Key="WineVarietyTemplateSimple">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding Name}"/>
|
||||
</StackPanel>
|
||||
</ControlTemplate>
|
||||
<ControlTemplate x:Key="WineVarietyTemplateExtended">
|
||||
<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="KgTemplate">
|
||||
|
||||
<DataTemplate x:Key="ModifierTemplate">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding Name}" MinWidth="250" Margin="0,0,10,0"/>
|
||||
<TextBlock Text="{Binding ValueStr}"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="WineAttributeTemplate">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding Name}" MinWidth="150" Margin="0,0,10,0"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
|
||||
<ControlTemplate x:Key="WineQualityLevelTemplateSimple">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding Name}"/>
|
||||
</StackPanel>
|
||||
</ControlTemplate>
|
||||
<ControlTemplate x:Key="WineQualityLevelTemplateExtended">
|
||||
<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>
|
||||
|
||||
<ControlTemplate x:Key="WineOriginTemplateSimple">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding Name}"/>
|
||||
</StackPanel>
|
||||
</ControlTemplate>
|
||||
<ControlTemplate x:Key="WineOriginTemplateExtended">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding HkIdLevel}" MinWidth="70" Margin="0,0,10,0"/>
|
||||
<TextBlock Text="{Binding Name}"/>
|
||||
</StackPanel>
|
||||
</ControlTemplate>
|
||||
<DataTemplate x:Key="WineOriginTemplate">
|
||||
<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>
|
||||
</Application.Resources>
|
||||
</Application>
|
||||
|
@@ -8,63 +8,134 @@ using Elwig.Helpers;
|
||||
using Elwig.Helpers.Weighing;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows.Threading;
|
||||
using System.Globalization;
|
||||
using System.Threading;
|
||||
using System.Windows.Markup;
|
||||
|
||||
namespace Elwig {
|
||||
public partial class App : Application {
|
||||
|
||||
public static readonly string DataPath = @"C:\ProgramData\Elwig\";
|
||||
public static readonly string ExePath = @"C:\Program Files\Elwig\";
|
||||
public static readonly string TempPath = Path.Combine(Path.GetTempPath(), "Elwig");
|
||||
public static readonly Config Config = new(DataPath + "config.ini");
|
||||
public static IEnumerable<IScale> Scales { get; private set; }
|
||||
|
||||
public static string ZwstId { get; private set; }
|
||||
public static string BranchName { get; private set; }
|
||||
public static int? BranchPlz { get; private set; }
|
||||
public static string? BranchOrt { get; private set; }
|
||||
public static string? BranchAddress { get; private set; }
|
||||
public static string? BranchPhoneNr { get; private set; }
|
||||
public static string? BranchFaxNr { get; private set; }
|
||||
public static string? BranchMobileNr { get; private set; }
|
||||
public static IList<IScale> Scales { get; private set; }
|
||||
public static ClientParameters Client { get; private set; }
|
||||
|
||||
public static bool IsPrintingReady => Documents.Html.IsReady && Documents.Pdf.IsReady;
|
||||
public static Dispatcher MainDispatcher { get; private set; }
|
||||
|
||||
public App() : base() {
|
||||
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
|
||||
Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), "Elwig"));
|
||||
Directory.CreateDirectory(App.TempPath);
|
||||
Directory.CreateDirectory(DataPath);
|
||||
MainDispatcher = Dispatcher;
|
||||
Scales = Array.Empty<IScale>();
|
||||
}
|
||||
|
||||
protected override void OnStartup(StartupEventArgs evt) {
|
||||
var locale = new CultureInfo("de-AT");
|
||||
locale.NumberFormat.CurrencyGroupSeparator = "\u202f";
|
||||
locale.NumberFormat.NumberGroupSeparator = "\u202f";
|
||||
locale.NumberFormat.PercentGroupSeparator = "\u202f";
|
||||
Thread.CurrentThread.CurrentCulture = locale;
|
||||
Thread.CurrentThread.CurrentUICulture = locale;
|
||||
CultureInfo.DefaultThreadCurrentCulture = locale;
|
||||
CultureInfo.DefaultThreadCurrentUICulture = locale;
|
||||
FrameworkElement.LanguageProperty.OverrideMetadata(
|
||||
typeof(FrameworkElement),
|
||||
new FrameworkPropertyMetadata(XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag))
|
||||
);
|
||||
|
||||
Dictionary<string, (string, string, int?, string?, string?, string?, string?, string?)> branches = new();
|
||||
using (var ctx = new AppDbContext()) {
|
||||
if (!ctx.Database.CanConnect()) {
|
||||
MessageBox.Show($"Invalid Database:\n\n{Config.DatabaseFile}", "Invalid Database", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
try {
|
||||
if (!ctx.Database.CanConnect()) {
|
||||
MessageBox.Show($"Invalid Database:\n\n{Config.DatabaseFile}", "Invalid Database", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
Shutdown();
|
||||
return;
|
||||
} else {
|
||||
branches = ctx.Branches.ToDictionary(b => b.Name.ToLower(), b => (b.ZwstId, b.Name, b.PostalDest?.AtPlz?.Plz, b.PostalDest?.AtPlz?.Dest, b.Address, b.PhoneNr, b.FaxNr, b.MobileNr));
|
||||
try {
|
||||
Client = new(ctx);
|
||||
} catch (Exception e) {
|
||||
MessageBox.Show($"Fehler beim Laden der Mandantendaten:\n\n{e.Message}", "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
Shutdown();
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
MessageBox.Show($"Invalid Database:\n\n{e.Message}", "Invalid Database", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
Shutdown();
|
||||
return;
|
||||
}
|
||||
}
|
||||
Utils.RunBackground("HTML Initialization", () => Documents.Html.Init(PrintingReadyChanged));
|
||||
Utils.RunBackground("PDF Initialization", () => Documents.Pdf.Init(PrintingReadyChanged));
|
||||
|
||||
var list = new LinkedList<IScale>();
|
||||
var list = new List<IScale>();
|
||||
foreach (var s in Config.Scales) {
|
||||
var id = s[0];
|
||||
try {
|
||||
var scaleNr = int.Parse(s[0]);
|
||||
var type = s[1].ToLower();
|
||||
var type = s[1]?.ToLower();
|
||||
var model = s[2];
|
||||
var cnx = s[3];
|
||||
var empty = s[4];
|
||||
var filling = s[5];
|
||||
int? limit = s[6] == null ? null : int.Parse(s[6]);
|
||||
var log = s[7];
|
||||
if (type == "systec") {
|
||||
list.AddLast(new SystecScale(scaleNr, model, cnx, empty, filling, limit));
|
||||
list.Add(new SystecScale(id, model, cnx, empty, filling, limit, log));
|
||||
} else {
|
||||
throw new ArgumentException($"Invalid scale type: \"{type}\"");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
list.Add(new InvalidScale(id));
|
||||
MessageBox.Show($"Unable to create scale {s[0]}:\n\n{e.Message}", "Scale Error", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
Scales = list;
|
||||
|
||||
base.OnStartup(evt);
|
||||
}
|
||||
if (Config.Branch != null) {
|
||||
if (!branches.ContainsKey(Config.Branch.ToLower())) {
|
||||
MessageBox.Show("Invalid branch name in config!", "Invalid Branch Config", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
Shutdown();
|
||||
} else {
|
||||
var entry = branches[Config.Branch.ToLower()];
|
||||
ZwstId = entry.Item1;
|
||||
BranchName = entry.Item2;
|
||||
BranchPlz = entry.Item3;
|
||||
BranchOrt = entry.Item4;
|
||||
BranchAddress = entry.Item5;
|
||||
BranchPhoneNr = entry.Item6;
|
||||
BranchFaxNr = entry.Item7;
|
||||
BranchMobileNr = entry.Item8;
|
||||
}
|
||||
} else if (branches.Count == 1) {
|
||||
var entry = branches.First().Value;
|
||||
ZwstId = entry.Item1;
|
||||
BranchName = entry.Item2;
|
||||
BranchPlz = entry.Item3;
|
||||
BranchOrt = entry.Item4;
|
||||
BranchAddress = entry.Item5;
|
||||
BranchPhoneNr = entry.Item6;
|
||||
BranchFaxNr = entry.Item7;
|
||||
BranchMobileNr = entry.Item8;
|
||||
} else {
|
||||
MessageBox.Show("Unable to determine local branch!", "Invalid Branch Config", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
protected override void OnExit(ExitEventArgs evt) {
|
||||
Utils.RunBackground("PDF Close", () => Documents.Pdf.Close());
|
||||
base.OnExit(evt);
|
||||
base.OnStartup(evt);
|
||||
}
|
||||
|
||||
private void PrintingReadyChanged() {
|
||||
@@ -73,7 +144,7 @@ namespace Elwig {
|
||||
|
||||
protected void OnPrintingReadyChanged(EventArgs evt) {
|
||||
foreach (Window w in Windows) {
|
||||
foreach (var b in Utils.FindAllChildren<Button>(w).Where(b => "Print".Equals(b.Tag))) {
|
||||
foreach (var b in ControlUtils.FindAllChildren<Button>(w).Where(b => "Print".Equals(b.Tag))) {
|
||||
b.IsEnabled = IsPrintingReady;
|
||||
}
|
||||
}
|
||||
|
19
Elwig/Controls/BoolToValueConverter.cs
Normal file
19
Elwig/Controls/BoolToValueConverter.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Elwig.Controls {
|
||||
public class BoolToValueConverter<T> : IValueConverter {
|
||||
public T FalseValue { get; set; }
|
||||
public T TrueValue { get; set; }
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
|
||||
return (bool)value ? TrueValue : FalseValue;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
|
||||
return value?.Equals(TrueValue) ?? false;
|
||||
}
|
||||
}
|
||||
|
||||
public class BoolToStringConverter : BoolToValueConverter<string> { }
|
||||
}
|
59
Elwig/Dialogs/AbwertenDialog.xaml
Normal file
59
Elwig/Dialogs/AbwertenDialog.xaml
Normal file
@@ -0,0 +1,59 @@
|
||||
<Window x:Class="Elwig.Dialogs.AbwertenDialog"
|
||||
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"
|
||||
mc:Ignorable="d"
|
||||
ResizeMode="NoResize"
|
||||
ShowInTaskbar="False"
|
||||
Topmost="True"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
FocusManager.FocusedElement="{Binding ElementName=WeightInput}"
|
||||
Title="Teillieferung abwerten" Height="190" 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="Button">
|
||||
<Setter Property="HorizontalAlignment" Value="Right"/>
|
||||
<Setter Property="VerticalAlignment" Value="Bottom"/>
|
||||
<Setter Property="Width" Value="100"/>
|
||||
<Setter Property="Height" Value="25"/>
|
||||
</Style>
|
||||
</Window.Resources>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="70"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock Margin="10,10,10,10" Grid.ColumnSpan="2" TextWrapping="Wrap" TextAlignment="Center">
|
||||
Welche Menge der Teillieferung <Run x:Name="TextLsNr" FontWeight="Bold" Text="20201010A000/1"/><LineBreak/>
|
||||
von <Run x:Name="TextMember" FontWeight="Bold" Text="Max Mustermann"/><LineBreak/>
|
||||
mit <Run x:Name="TextWeight" FontWeight="Bold" Text="1 000 kg"/> soll abgewertet werden?
|
||||
</TextBlock>
|
||||
|
||||
<Label Content="Gewicht:" Margin="10,70,10,10"/>
|
||||
<Grid Grid.Column="1" Width="70" Height="25" Margin="0,70,10,10" HorizontalAlignment="Left" VerticalAlignment="Top">
|
||||
<TextBox x:Name="WeightInput" TextAlignment="Right" Padding="2,2,17,2"
|
||||
TextChanged="WeightInput_TextChanged"/>
|
||||
<Label Content="kg" Margin="0,4,3,0" HorizontalAlignment="Right" FontSize="10" Padding="2,4,2,4"/>
|
||||
</Grid>
|
||||
|
||||
<Button x:Name="ConfirmButton" Content="Bestätigen" Margin="10,10,115,10" Grid.Column="1" IsEnabled="False" IsDefault="True"
|
||||
Click="ConfirmButton_Click"/>
|
||||
<Button x:Name="CancelButton" Content="Abbrechen" Margin="10,10,10,10" Grid.Column="1" IsCancel="True"/>
|
||||
</Grid>
|
||||
</Window>
|
33
Elwig/Dialogs/AbwertenDialog.xaml.cs
Normal file
33
Elwig/Dialogs/AbwertenDialog.xaml.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using Elwig.Helpers;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Elwig.Dialogs {
|
||||
public partial class AbwertenDialog : Window {
|
||||
|
||||
public int Weight;
|
||||
|
||||
public AbwertenDialog(string lsnr, string name, int weight) {
|
||||
Weight = weight;
|
||||
InitializeComponent();
|
||||
TextLsNr.Text = lsnr;
|
||||
TextMember.Text = name;
|
||||
TextWeight.Text = $"{weight:N0}\u202fkg";
|
||||
}
|
||||
|
||||
private void ConfirmButton_Click(object sender, RoutedEventArgs evt) {
|
||||
DialogResult = true;
|
||||
Weight = int.Parse(WeightInput.Text);
|
||||
Close();
|
||||
}
|
||||
|
||||
private void UpdateButtons() {
|
||||
ConfirmButton.IsEnabled = int.TryParse(WeightInput.Text, out var w) && w > 0 && w <= Weight;
|
||||
}
|
||||
|
||||
private void WeightInput_TextChanged(object sender, TextChangedEventArgs evt) {
|
||||
Validator.CheckInteger(WeightInput, true, 5);
|
||||
UpdateButtons();
|
||||
}
|
||||
}
|
||||
}
|
60
Elwig/Dialogs/DeliveryExtractionDialog.xaml
Normal file
60
Elwig/Dialogs/DeliveryExtractionDialog.xaml
Normal file
@@ -0,0 +1,60 @@
|
||||
<Window x:Class="Elwig.Dialogs.DeliveryExtractionDialog"
|
||||
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"
|
||||
mc:Ignorable="d"
|
||||
ResizeMode="NoResize"
|
||||
ShowInTaskbar="False"
|
||||
Topmost="True"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
FocusManager.FocusedElement="{Binding ElementName=WeightInput}"
|
||||
Title="Teillieferung extrahieren" Height="210" Width="380">
|
||||
<Window.Resources>
|
||||
<Style TargetType="Label">
|
||||
<Setter Property="HorizontalAlignment" Value="Left"/>
|
||||
<Setter Property="VerticalAlignment" Value="Top"/>
|
||||
<Setter Property="Padding" Value="2,4,2,4"/>
|
||||
<Setter Property="Height" Value="25"/>
|
||||
</Style>
|
||||
<Style TargetType="TextBox">
|
||||
<Setter Property="HorizontalAlignment" Value="Stretch"/>
|
||||
<Setter Property="VerticalAlignment" Value="Top"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="Padding" Value="2"/>
|
||||
<Setter Property="Height" Value="25"/>
|
||||
<Setter Property="TextWrapping" Value="NoWrap"/>
|
||||
</Style>
|
||||
<Style TargetType="Button">
|
||||
<Setter Property="HorizontalAlignment" Value="Right"/>
|
||||
<Setter Property="VerticalAlignment" Value="Bottom"/>
|
||||
<Setter Property="Width" Value="100"/>
|
||||
<Setter Property="Height" Value="25"/>
|
||||
</Style>
|
||||
</Window.Resources>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="200"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock Margin="10,10,0,10" TextWrapping="Wrap">
|
||||
Was soll mit der Teillieferung <Run x:Name="TextLsNr" FontWeight="Bold" Text="20201010A000/1"/><LineBreak/>
|
||||
von <Run x:Name="TextMember" FontWeight="Bold" Text="Max Mustermann"/> geschehen?
|
||||
</TextBlock>
|
||||
<RadioButton x:Name="NewDeliveryButton" Content="Neue Lieferung erstellen"
|
||||
Margin="10,80,0,10" HorizontalAlignment="Left" VerticalAlignment="Top"
|
||||
Checked="Selection_Changed" Unchecked="Selection_Changed"/>
|
||||
<RadioButton x:Name="AddToDeliveryButton" Content="Zu Lieferung hinzufügen"
|
||||
Margin="10,100,0,10" HorizontalAlignment="Left" VerticalAlignment="Top"
|
||||
Checked="Selection_Changed" Unchecked="Selection_Changed"/>
|
||||
|
||||
<ListBox x:Name="DeliveryList" Grid.Column="1" Margin="10,10,10,45"
|
||||
SelectionChanged="DeliveryList_SelectionChanged"/>
|
||||
|
||||
<Button x:Name="ConfirmButton" Content="Bestätigen" Margin="10,10,115,10" Grid.ColumnSpan="2" IsEnabled="False" IsDefault="True"
|
||||
Click="ConfirmButton_Click"/>
|
||||
<Button x:Name="CancelButton" Content="Abbrechen" Margin="10,10,10,10" Grid.ColumnSpan="2" IsCancel="True"/>
|
||||
</Grid>
|
||||
</Window>
|
37
Elwig/Dialogs/DeliveryExtractionDialog.xaml.cs
Normal file
37
Elwig/Dialogs/DeliveryExtractionDialog.xaml.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Windows;
|
||||
|
||||
namespace Elwig.Dialogs {
|
||||
public partial class DeliveryExtractionDialog : Window {
|
||||
|
||||
public string? AddTo;
|
||||
|
||||
public DeliveryExtractionDialog(string lsnr, string name, bool single, IEnumerable<string> lsnrs) {
|
||||
InitializeComponent();
|
||||
TextLsNr.Text = lsnr;
|
||||
TextMember.Text = name;
|
||||
NewDeliveryButton.IsEnabled = !single;
|
||||
DeliveryList.IsEnabled = false;
|
||||
DeliveryList.ItemsSource = lsnrs;
|
||||
}
|
||||
|
||||
private void ConfirmButton_Click(object sender, RoutedEventArgs evt) {
|
||||
DialogResult = true;
|
||||
AddTo = NewDeliveryButton.IsChecked == true ? "new" : DeliveryList.SelectedItem as string;
|
||||
Close();
|
||||
}
|
||||
|
||||
private void UpdateButtons() {
|
||||
ConfirmButton.IsEnabled = NewDeliveryButton.IsChecked == true || (AddToDeliveryButton.IsChecked == true && DeliveryList.SelectedItem != null);
|
||||
DeliveryList.IsEnabled = AddToDeliveryButton.IsChecked == true;
|
||||
}
|
||||
|
||||
private void Selection_Changed(object sender, RoutedEventArgs evt) {
|
||||
UpdateButtons();
|
||||
}
|
||||
|
||||
private void DeliveryList_SelectionChanged(object sender, RoutedEventArgs evt) {
|
||||
UpdateButtons();
|
||||
}
|
||||
}
|
||||
}
|
53
Elwig/Dialogs/LinearPriceIncreaseDialog.xaml
Normal file
53
Elwig/Dialogs/LinearPriceIncreaseDialog.xaml
Normal file
@@ -0,0 +1,53 @@
|
||||
<Window x:Class="Elwig.Dialogs.LinearPriceIncreaseDialog"
|
||||
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"
|
||||
mc:Ignorable="d"
|
||||
ResizeMode="NoResize"
|
||||
ShowInTaskbar="False"
|
||||
Topmost="True"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
FocusManager.FocusedElement="{Binding ElementName=PriceInput}"
|
||||
Title="Linear wachsen" Height="140" Width="270">
|
||||
<Window.Resources>
|
||||
<Style TargetType="Label">
|
||||
<Setter Property="HorizontalAlignment" Value="Left"/>
|
||||
<Setter Property="VerticalAlignment" Value="Top"/>
|
||||
<Setter Property="Padding" Value="2,4,2,4"/>
|
||||
<Setter Property="Height" Value="25"/>
|
||||
</Style>
|
||||
<Style TargetType="TextBox">
|
||||
<Setter Property="HorizontalAlignment" Value="Stretch"/>
|
||||
<Setter Property="VerticalAlignment" Value="Top"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="Padding" Value="2"/>
|
||||
<Setter Property="Height" Value="25"/>
|
||||
<Setter Property="TextWrapping" Value="NoWrap"/>
|
||||
</Style>
|
||||
<Style TargetType="Button">
|
||||
<Setter Property="HorizontalAlignment" Value="Right"/>
|
||||
<Setter Property="VerticalAlignment" Value="Bottom"/>
|
||||
<Setter Property="Width" Value="100"/>
|
||||
<Setter Property="Height" Value="25"/>
|
||||
</Style>
|
||||
</Window.Resources>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="55"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label Content="Preis:" Margin="10,20,10,10"/>
|
||||
<Grid Grid.Column="1" Width="145" Height="25" Margin="0,20,0,0" HorizontalAlignment="Left" VerticalAlignment="Top">
|
||||
<TextBox x:Name="PriceInput" TextAlignment="Right" Padding="2,2,30,2"
|
||||
TextChanged="PriceInput_TextChanged"/>
|
||||
<Label Content="€/kg" Margin="0,4,3,0" HorizontalAlignment="Right" FontSize="10" Padding="2,4,2,4"/>
|
||||
</Grid>
|
||||
|
||||
<Button x:Name="ConfirmButton" Content="Bestätigen" Margin="17,0,133,10" IsEnabled="False" IsDefault="True"
|
||||
Click="ConfirmButton_Click" Grid.ColumnSpan="2" HorizontalAlignment="Stretch"/>
|
||||
<Button x:Name="CancelButton" Content="Abbrechen" Margin="0,0,20,10" Grid.Column="1" IsCancel="True"/>
|
||||
</Grid>
|
||||
</Window>
|
30
Elwig/Dialogs/LinearPriceIncreaseDialog.xaml.cs
Normal file
30
Elwig/Dialogs/LinearPriceIncreaseDialog.xaml.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using Elwig.Helpers;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Elwig.Dialogs {
|
||||
public partial class LinearPriceIncreaseDialog : Window {
|
||||
|
||||
public double Price = 0.0;
|
||||
|
||||
public LinearPriceIncreaseDialog() {
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void ConfirmButton_Click(object sender, RoutedEventArgs evt) {
|
||||
DialogResult = true;
|
||||
Price = double.Parse(PriceInput.Text.Replace("\u202f", ""));
|
||||
Close();
|
||||
}
|
||||
|
||||
private void UpdateButtons(ValidationResult res) {
|
||||
ConfirmButton.IsEnabled = res.IsValid;
|
||||
}
|
||||
|
||||
private void PriceInput_TextChanged(object sender, TextChangedEventArgs evt) {
|
||||
var res = Validator.CheckDecimal(PriceInput, true, 2, 8);
|
||||
UpdateButtons(res);
|
||||
}
|
||||
}
|
||||
}
|
57
Elwig/Dialogs/ManualWeighingDialog.xaml
Normal file
57
Elwig/Dialogs/ManualWeighingDialog.xaml
Normal file
@@ -0,0 +1,57 @@
|
||||
<Window x:Class="Elwig.Dialogs.ManualWeighingDialog"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:Elwig.Dialogs"
|
||||
mc:Ignorable="d"
|
||||
ResizeMode="NoResize"
|
||||
ShowInTaskbar="False"
|
||||
Topmost="True"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
FocusManager.FocusedElement="{Binding ElementName=WeightInput}"
|
||||
Title="Handwiegung" Height="170" 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="Button">
|
||||
<Setter Property="HorizontalAlignment" Value="Right"/>
|
||||
<Setter Property="VerticalAlignment" Value="Bottom"/>
|
||||
<Setter Property="Width" Value="100"/>
|
||||
<Setter Property="Height" Value="25"/>
|
||||
</Style>
|
||||
</Window.Resources>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="70"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label Content="Gewicht:" Margin="10,20,10,10"/>
|
||||
<Grid Grid.Column="1" Width="70" Height="25" Margin="0,20,10,10" HorizontalAlignment="Left" VerticalAlignment="Top">
|
||||
<TextBox x:Name="WeightInput" TextAlignment="Right" Padding="2,2,17,2"
|
||||
TextChanged="WeightInput_TextChanged"/>
|
||||
<Label Content="kg" Margin="0,4,3,0" HorizontalAlignment="Right" FontSize="10" Padding="2,4,2,4"/>
|
||||
</Grid>
|
||||
|
||||
<Label Content="Grund:" Margin="10,50,10,10"/>
|
||||
<TextBox x:Name="ReasonInput" Grid.Column="1" Margin="0,50,10,10"
|
||||
TextChanged="ReasonInput_TextChanged"/>
|
||||
|
||||
<Button x:Name="ConfirmButton" Content="Bestätigen" Margin="10,10,115,10" Grid.Column="1" IsEnabled="False" IsDefault="True"
|
||||
Click="ConfirmButton_Click"/>
|
||||
<Button x:Name="CancelButton" Content="Abbrechen" Margin="10,10,10,10" Grid.Column="1" IsCancel="True"/>
|
||||
</Grid>
|
||||
</Window>
|
41
Elwig/Dialogs/ManualWeighingDialog.xaml.cs
Normal file
41
Elwig/Dialogs/ManualWeighingDialog.xaml.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using Elwig.Helpers;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Elwig.Dialogs {
|
||||
public partial class ManualWeighingDialog : Window {
|
||||
|
||||
public int Weight = 0;
|
||||
public string? Reason = null;
|
||||
|
||||
public ManualWeighingDialog() {
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void ConfirmButton_Click(object sender, RoutedEventArgs evt) {
|
||||
DialogResult = true;
|
||||
Weight = int.Parse(WeightInput.Text);
|
||||
Reason = Regex.Replace(ReasonInput.Text, @"\s+", "").Trim();
|
||||
if (Reason == "") {
|
||||
Reason = null;
|
||||
} else if (!Reason.EndsWith(".") || !Reason.EndsWith("!") || !Reason.EndsWith("?")) {
|
||||
Reason += ".";
|
||||
}
|
||||
Close();
|
||||
}
|
||||
|
||||
private void UpdateButtons() {
|
||||
ConfirmButton.IsEnabled = WeightInput.Text.Length > 0;
|
||||
}
|
||||
|
||||
private void WeightInput_TextChanged(object sender, TextChangedEventArgs evt) {
|
||||
Validator.CheckInteger(WeightInput, true, 5);
|
||||
UpdateButtons();
|
||||
}
|
||||
|
||||
private void ReasonInput_TextChanged(object sender, TextChangedEventArgs evt) {
|
||||
UpdateButtons();
|
||||
}
|
||||
}
|
||||
}
|
@@ -2,17 +2,17 @@
|
||||
@inherits TemplatePage<Elwig.Documents.BusinessDocument>
|
||||
@model Elwig.Documents.BusinessDocument
|
||||
@{ Layout = "Document"; }
|
||||
|
||||
<link rel="stylesheet" href="file:///@Raw(Model.DataPath)\resources\style-businessdocument.css" />
|
||||
<div class="info-wrapper">
|
||||
<div class="address-wrapper">
|
||||
<div class="sender">
|
||||
<div>WG Matzen | Schloßstraße 6 | 2243 Matzen</div>
|
||||
<div>E Österreichische Post AG Eco Brief</div>
|
||||
@if (Model.IncludeSender) {
|
||||
<div>@Elwig.App.Client.Sender1</div>
|
||||
<div>@Elwig.App.Client.Sender2</div>
|
||||
}
|
||||
</div>
|
||||
<address>@Model.Address</address>
|
||||
</div>
|
||||
<aside></aside>
|
||||
<aside>@Raw(Model.Aside)</aside>
|
||||
</div>
|
||||
<main>
|
||||
@RenderBody()
|
||||
</main>
|
||||
@RenderBody()
|
||||
|
@@ -3,16 +3,35 @@ using Elwig.Models;
|
||||
namespace Elwig.Documents {
|
||||
public abstract class BusinessDocument : Document {
|
||||
|
||||
public BusinessDocument(string title, Member m) : base(title) {
|
||||
Member = m;
|
||||
}
|
||||
public Member Member;
|
||||
public bool IncludeSender = false;
|
||||
public bool UseBillingAddress = false;
|
||||
public string Aside;
|
||||
public string? Location;
|
||||
|
||||
public Member Member { get; set; }
|
||||
public BusinessDocument(string title, Member m, bool includeSender = false) : base(title) {
|
||||
Member = m;
|
||||
Location = App.BranchName;
|
||||
IncludeSender = includeSender;
|
||||
var uid = (m.UstIdNr ?? "-") + (m.IsBuchführend ? "" : " <i>(pauschaliert)</i>");
|
||||
Aside = $"<table><colgroup><col span='1' style='width: 22.5mm;'/><col span='1' style='width: 42.5mm;'/></colgroup>" +
|
||||
$"<thead><tr><th colspan='2'>Mitglied</th></tr></thead><tbody>" +
|
||||
$"<tr><th>Mitglieds-Nr.</th><td>{m.MgNr}</td></tr>" +
|
||||
$"<tr><th>Betriebs-Nr.</th><td>{m.LfbisNr}</td></tr>" +
|
||||
$"<tr><th>UID</th><td>{uid}</td></tr>" +
|
||||
$"</tbody></table>";
|
||||
}
|
||||
|
||||
public string Address {
|
||||
get {
|
||||
// TODO Name/Rechnungsadresse
|
||||
return $"{Member.GivenName} {Member.FamilyName}\n{Member.Address}";
|
||||
var b = Member.BillingAddress;
|
||||
if (b != null && UseBillingAddress) {
|
||||
var plz = b.PostalDest.AtPlz;
|
||||
return $"{b.Name}\n{Member.AdministrativeName}\n{b.Address}\n{plz.Plz} {plz.Dest}\nÖsterreich";
|
||||
} else {
|
||||
var plz = Member.PostalDest.AtPlz;
|
||||
return $"{Member.AdministrativeName}\n{Member.Address}\n{plz.Plz} {plz.Dest}\nÖsterreich";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -2,7 +2,8 @@
|
||||
@inherits TemplatePage<Elwig.Documents.BusinessLetter>
|
||||
@model Elwig.Documents.BusinessLetter
|
||||
@{ Layout = "BusinessDocument"; }
|
||||
|
||||
<main>
|
||||
<p>Sehr geehrtes Mitglied,</p>
|
||||
<p>nein.</p>
|
||||
<p>Mit freundlichen Grüßen<br/>Ihre Winzergenossenschaft</p>
|
||||
</main>
|
||||
|
@@ -2,8 +2,6 @@ using Elwig.Models;
|
||||
|
||||
namespace Elwig.Documents {
|
||||
public class BusinessLetter : BusinessDocument {
|
||||
public BusinessLetter(string title, Member m) : base(title, m) {
|
||||
|
||||
}
|
||||
public BusinessLetter(string title, Member m) : base(title, m) { }
|
||||
}
|
||||
}
|
||||
|
86
Elwig/Documents/CreditNote.cshtml
Normal file
86
Elwig/Documents/CreditNote.cshtml
Normal file
@@ -0,0 +1,86 @@
|
||||
@using RazorLight
|
||||
@inherits TemplatePage<Elwig.Documents.CreditNote>
|
||||
@model Elwig.Documents.CreditNote
|
||||
@{ Layout = "BusinessDocument"; }
|
||||
<link rel="stylesheet" href="file:///@Raw(Model.DataPath)\resources\style-creditnote.css"/>
|
||||
@{
|
||||
var bucketNum = Model.BucketNames.Length;
|
||||
}
|
||||
<main>
|
||||
<div class="date">@Model.Location, am @($"{Model.Date:dd.MM.yyyy}")</div>
|
||||
<h1>@Model.Title</h1>
|
||||
<table class="credit">
|
||||
<colgroup>
|
||||
<col style="width: 24mm;"/>
|
||||
<col style="width: 6mm;"/>
|
||||
<col style="width: 31mm;"/>
|
||||
<col style="width: 15mm;"/>
|
||||
<col style="width: 8mm;"/>
|
||||
<col style="width: 10mm;"/>
|
||||
<col style="width: 12mm;"/>
|
||||
<col style="width: 10mm;"/>
|
||||
<col style="width: 12mm;"/>
|
||||
<col style="width: 15mm;"/>
|
||||
<col style="width: 17mm;"/>
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th rowspan="3" style="text-align: left;">Lieferschein-Nr.</th>
|
||||
<th rowspan="3">Pos.</th>
|
||||
<th rowspan="3" style="text-align: left;">Sorte</th>
|
||||
<th rowspan="3" style="text-align: left;">Attribut(e)</th>
|
||||
<th rowspan="2" colspan="2">Gradation</th>
|
||||
<th colspan="2">Zu-/Abschläge</th>
|
||||
<th colspan="2">@Raw(string.Join("<br/>", Model.BucketNames))</th>
|
||||
<th rowspan="2">Betrag</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Abs.</th>
|
||||
<th>Rel.</th>
|
||||
<th>Gewicht</th>
|
||||
<th>Preis</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>[°Oe]</th>
|
||||
<th>[°KMW]</th>
|
||||
<th>[@Model.CurrencySymbol/kg]</th>
|
||||
<th>[%]</th>
|
||||
<th>[kg]</th>
|
||||
<th>[@Model.CurrencySymbol/kg]</th>
|
||||
<th>[@Model.CurrencySymbol]</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@{
|
||||
string FormatRow(int? weight, decimal? amount) {
|
||||
var w = weight == null || weight == 0 ? "-" : $"{weight:N0}";
|
||||
return $"<td class='weight'>{w}</td><td class='amount'>{amount?.ToString("0." + string.Concat(Enumerable.Repeat('0', Model.Precision)))}</td>";
|
||||
}
|
||||
string? last = null;
|
||||
}
|
||||
@foreach (var part in Model.Parts) {
|
||||
var pmt = part.Payment;
|
||||
var abs = pmt?.ModAbs == null || pmt?.ModAbs == 0 ? "-" : pmt?.ModAbs.ToString("0." + string.Concat(Enumerable.Repeat('0', Model.Precision)));
|
||||
var rel = pmt?.ModRel == null || pmt?.ModRel == 0 ? "-" : $"{pmt?.ModRel * 100:0.00##}";
|
||||
<tr class="first @(bucketNum <= 1 ? "last" : "") @(last != null && last != part.SortId ? "new" : "")">
|
||||
<td rowspan="@bucketNum" class="lsnr">@part.Delivery.LsNr</td>
|
||||
<td rowspan="@bucketNum" class="dpnr">@part.DPNr</td>
|
||||
<td rowspan="@bucketNum" class="variant">@part.Variant.Name</td>
|
||||
<td rowspan="@bucketNum" class="attribute">@string.Join(" / ", part.PartAttributes.Select(a => a.AttrId))</td>
|
||||
<td rowspan="@bucketNum" class="oe">@($"{part.Oe:N0}")</td>
|
||||
<td rowspan="@bucketNum" class="kmw">@($"{part.Kmw:N1}")</td>
|
||||
<td rowspan="@bucketNum" class="abs">@abs</td>
|
||||
<td rowspan="@bucketNum" class="rel">@rel</td>
|
||||
@Raw(FormatRow(pmt?.Buckets?.ElementAtOrDefault(0), pmt?.Prices?.ElementAtOrDefault(0)))
|
||||
<td rowspan="@bucketNum" class="amount sum">@($"{pmt?.Amount:N2}")</td>
|
||||
</tr>
|
||||
@for (int i = 1; i < bucketNum; i++) {
|
||||
<tr class="@(i == bucketNum - 1 ? "last" : "")">
|
||||
@Raw(FormatRow(pmt?.Buckets?.ElementAtOrDefault(i), pmt?.Prices?.ElementAtOrDefault(i)))
|
||||
</tr>
|
||||
}
|
||||
last = part.SortId;
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</main>
|
39
Elwig/Documents/CreditNote.cshtml.cs
Normal file
39
Elwig/Documents/CreditNote.cshtml.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using Elwig.Helpers;
|
||||
using Elwig.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Elwig.Documents {
|
||||
public class CreditNote : BusinessDocument {
|
||||
|
||||
public Credit Credit;
|
||||
public string? Text;
|
||||
public string CurrencySymbol;
|
||||
public string[] BucketNames;
|
||||
public int Precision;
|
||||
public IEnumerable<DeliveryPart> Parts;
|
||||
|
||||
public CreditNote(Credit c, AppDbContext ctx) : base($"Traubengutschrift Nr. {c.TgId} – {c.Payment.Variant.Name}", c.Member) {
|
||||
UseBillingAddress = true;
|
||||
Credit = c;
|
||||
Aside = Aside.Replace("</table>", "") +
|
||||
$"<thead><tr><th colspan='2'>Gutschrift</th></tr></thead><tbody>" +
|
||||
$"<tr><th>TG-Nr.</th><td>{c.TgId}</td></tr>" +
|
||||
$"<tr><th>Überw. am</th><td>{c.Payment.Variant.TransferDate:dd.MM.yyyy}</td></tr>" +
|
||||
$"<tr><th>Datum/Zeit</th><td>{c.ModifiedTimestamp:dd.MM.yyyy} / {c.ModifiedTimestamp:HH:mm}</td></tr>" +
|
||||
$"</tbody></table>";
|
||||
Text = App.Client.TextDeliveryNote;
|
||||
DocumentId = $"Tr.-Gutschr. {c.TgId}";
|
||||
CurrencySymbol = c.Payment.Variant.Season.Currency.Symbol ?? c.Payment.Variant.Season.Currency.Code;
|
||||
BucketNames = c.Payment.Variant.BucketNames;
|
||||
Precision = c.Payment.Variant.Season.Precision;
|
||||
Parts = ctx.DeliveryParts.FromSql($"""
|
||||
SELECT p.*
|
||||
FROM v_delivery v
|
||||
JOIN delivery_part p ON (p.year, p.did, p.dpnr) = (v.year, v.did, v.dpnr)
|
||||
WHERE (v.year, v.mgnr) = ({c.Year}, {c.Member.MgNr})
|
||||
ORDER BY sortid, LENGTH(attributes) DESC, attributes, kmw DESC, date, time, dpnr
|
||||
""").ToList();
|
||||
}
|
||||
}}
|
178
Elwig/Documents/DeliveryNote.cshtml
Normal file
178
Elwig/Documents/DeliveryNote.cshtml
Normal file
@@ -0,0 +1,178 @@
|
||||
@using RazorLight
|
||||
@inherits TemplatePage<Elwig.Documents.DeliveryNote>
|
||||
@model Elwig.Documents.DeliveryNote
|
||||
@{ Layout = "BusinessDocument"; }
|
||||
<link rel="stylesheet" href="file:///@Raw(Model.DataPath)\resources\style-deliverynote.css" />
|
||||
<main>
|
||||
<div class="date">@Model.Location, am @($"{Model.Date:dd.MM.yyyy}")</div>
|
||||
<h1>@Model.Title</h1>
|
||||
@{
|
||||
bool displayStats = true; // Model.Delivery.Year == Model.CurrentNextSeason
|
||||
}
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
const hidden = document.getElementsByClassName("hidden")[0];
|
||||
const table = document.getElementsByClassName("delivery")[0];
|
||||
const stats = document.getElementById("delivery-stats");
|
||||
const mm = px2mm(0, hidden.offsetTop + hidden.offsetHeight);
|
||||
const heightTable = px2mm(table.offsetTop, hidden.offsetTop + hidden.offsetHeight);
|
||||
|
||||
if (mm >= heightA4 - heightFooter) {
|
||||
if (heightTable + 10 >= heightMain) {
|
||||
// force page break in table
|
||||
const tblOff = px2mm(0, table.offsetTop);
|
||||
let last = null;
|
||||
for (const tr of table.getElementsByTagName("tr")) {
|
||||
if (!tr.classList.contains("main")) continue;
|
||||
const mm2 = tblOff + px2mm(0, tr.offsetTop);
|
||||
if (mm2 >= heightA4 - heightFooter) {
|
||||
last.classList.add("page-break");
|
||||
break;
|
||||
}
|
||||
last = tr;
|
||||
}
|
||||
} else {
|
||||
// force page break
|
||||
const hr = document.createElement("hr");
|
||||
hr.classList.add("page-break");
|
||||
table.before(hr);
|
||||
|
||||
const p = document.createElement("p");
|
||||
p.innerText = "Siehe nächste Seite."
|
||||
hr.before(p);
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<table class="delivery">
|
||||
<colgroup>
|
||||
<col style="width: 10.00mm;"/>
|
||||
<col style="width: 21.25mm;"/>
|
||||
<col style="width: 21.25mm;"/>
|
||||
<col style="width: 21.25mm;"/>
|
||||
<col style="width: 21.25mm;"/>
|
||||
<col style="width: 30.00mm;"/>
|
||||
<col style="width: 12.50mm;"/>
|
||||
<col style="width: 12.50mm;"/>
|
||||
<col style="width: 15.00mm;"/>
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="main" rowspan="2" style="text-align: center;">Pos.</th>
|
||||
<th class="main" rowspan="2" colspan="2">Sorte</th>
|
||||
<th class="main" rowspan="2" colspan="2">Attribut(e)</th>
|
||||
<th class="main" rowspan="2">Qualitätsstufe</th>
|
||||
<th colspan="2">Gradation</th>
|
||||
<th>Gewicht</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th style="font-size: 8pt;">[°Oe]</th>
|
||||
<th style="font-size: 8pt;">[°KMW]</th>
|
||||
<th style="font-size: 8pt;">[kg]</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var part in Model.Delivery.Parts.OrderBy(p => p.DPNr)) {
|
||||
<tr class="main">
|
||||
<td style="text-align: center;">@part.DPNr</td>
|
||||
<td colspan="2">@part.Variant.Name</td>
|
||||
<td colspan="2">@string.Join(" / ", part.Attributes)</td>
|
||||
<td>@part.Quality.Name</td>
|
||||
<td class="narrow" style="text-align: center;">@($"{part.Oe:N0}")</td>
|
||||
<td class="narrow" style="text-align: center;">@($"{part.Kmw:N1}")</td>
|
||||
<td class="narrow" style="text-align: right;">@($"{part.Weight:N0}")</td>
|
||||
</tr>
|
||||
<tr><td></td><td colspan="5" style="white-space: pre;"><i>Herkunft:</i> @part.OriginString</td></tr>
|
||||
@if (part.Modifiers.Count() > 0) {
|
||||
var first = true;
|
||||
foreach (var mod in part.Modifiers) {
|
||||
<tr class="tight @(first ? "first" : "")"><td></td><td>@Raw(first ? "<i>Zu-/Abschläge:</i>" : "")</td><td colspan="3"><b>@mod.Name</b></td><td style="white-space: pre;">@mod.ValueStr</td></tr>
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
<tr><td></td><td colspan="5">
|
||||
@Raw(part.ManualWeighing ? "<i>Handwiegung</i>" : $"<i>Waage:</i> {part.ScaleId ?? "?"}, <i>ID:</i> {part.WeighingId ?? "?"}") (@(part.IsGerebelt ? "gerebelt gewogen" : "nicht gerebelt gewogen"))
|
||||
</td></tr>
|
||||
@if (part.Comment != null) {
|
||||
<tr><td></td><td colspan="5"><i>Anmerkung:</i> @part.Comment</td></tr>
|
||||
}
|
||||
@if (part.Temperature != null || part.Acid != null) {
|
||||
<tr><td></td><td colspan="5">@Raw(part.Temperature != null ? $"<i>Temperatur:</i> {part.Temperature:N1} °C" : "")@(part.Temperature != null && part.Acid != null ? ", " : "")@Raw(part.Acid != null ? $"<i>Säure:</i> {part.Acid:N1} g/l" : "")</td></tr>
|
||||
}
|
||||
}
|
||||
@if (Model.Delivery.Parts.Count() > 1) {
|
||||
<tr class="main sum">
|
||||
<td colspan="6">Gesamt:</td>
|
||||
<td style="text-align: center;">@($"{Model.Delivery.Oe:N0}")</td>
|
||||
<td style="text-align: center;">@($"{Model.Delivery.Kmw:N1}")</td>
|
||||
<td style="text-align: right;">@($"{Model.Delivery.Weight:N0}")</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
@if (Model.Delivery.Comment != null) {
|
||||
<p class="comment">Amerkung zur Lieferung: @Model.Delivery.Comment</p>
|
||||
}
|
||||
@if (displayStats) {
|
||||
<div id="delivery-stats">
|
||||
<table class="delivery-stats">
|
||||
<colgroup>
|
||||
<col style="width: 45mm;"/>
|
||||
<col style="width: 20mm;"/>
|
||||
<col style="width: 20mm;"/>
|
||||
<col style="width: 20mm;"/>
|
||||
<col style="width: 20mm;"/>
|
||||
<col style="width: 20mm;"/>
|
||||
<col style="width: 20mm;"/>
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th><b>Gesamtlieferung</b> [kg]</th>
|
||||
<th>Lieferpflicht</th>
|
||||
<th>Lieferrecht</th>
|
||||
<th>Unterliefert</th>
|
||||
<th>Noch zu liefern</th>
|
||||
<th>Überliefert</th>
|
||||
<th>Geliefert</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@{
|
||||
string FormatRow(int obligation, int right, int sum) {
|
||||
return $"<td>{obligation:N0}</td>" +
|
||||
$"<td>{right:N0}</td>" +
|
||||
$"<td>{(sum < obligation ? $"{obligation - sum:N0}" : "-")}</td>" +
|
||||
$"<td>{(sum >= obligation && sum <= right ? $"{right - sum:N0}" : "-")}</td>" +
|
||||
$"<td>{(sum > right ? $"{sum - right:N0}" : "-")}</td>" +
|
||||
$"<td>{sum:N0}</td>";
|
||||
}
|
||||
var sortids = Model.Delivery.Parts.Select(p => p.SortId).ToList();
|
||||
}
|
||||
<tr>
|
||||
<th>Geschäftsanteile</th>
|
||||
@Raw(FormatRow(Model.Member.DeliveryObligation, Model.Member.DeliveryRight, Model.Member.Deliveries.Where(d => d.Year == Model.Delivery.Year).Sum(d => d.Weight)))
|
||||
</tr>
|
||||
@foreach (var (id, name, right, obligation, sum) in Model.MemberBuckets.OrderBy(b => b.Item1)) {
|
||||
if (right > 0 && obligation > 0) {
|
||||
<tr class="@(sortids.Contains(id[..2]) ? "" : "optional")">
|
||||
<th>@name</th>
|
||||
@Raw(FormatRow(obligation, right, sum))
|
||||
</tr>
|
||||
}
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
}
|
||||
</main>
|
||||
@for (int i = 0; i < 2; i++) {
|
||||
<div class="@(i == 0 ? "hidden" : "bottom")">
|
||||
@if (Model.Text != null) {
|
||||
<p class="comment">@Model.Text</p>
|
||||
}
|
||||
<div class="signatures">
|
||||
<div>Genossenschaft</div>
|
||||
<div>Mitglied</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
26
Elwig/Documents/DeliveryNote.cshtml.cs
Normal file
26
Elwig/Documents/DeliveryNote.cshtml.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using Elwig.Helpers;
|
||||
using Elwig.Models;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Elwig.Documents {
|
||||
public class DeliveryNote : BusinessDocument {
|
||||
|
||||
public Delivery Delivery;
|
||||
public string? Text;
|
||||
public IEnumerable<(string, string, int, int, int)> MemberBuckets;
|
||||
|
||||
public DeliveryNote(Delivery d, AppDbContext ctx) : base($"Traubenübernahmeschein Nr. {d.LsNr}", d.Member) {
|
||||
UseBillingAddress = true;
|
||||
Delivery = d;
|
||||
Aside = Aside.Replace("</table>", "") +
|
||||
$"<thead><tr><th colspan='2'>Lieferung</th></tr></thead><tbody>" +
|
||||
$"<tr><th>LS-Nr.</th><td>{d.LsNr}</td></tr>" +
|
||||
$"<tr><th>Datum/Zeit</th><td>{d.Date:dd.MM.yyyy} / {d.Time:HH:mm}</td></tr>" +
|
||||
$"<tr><th>Zweigstelle</th><td>{d.Branch.Name}</td></tr>" +
|
||||
$"</tbody></table>";
|
||||
Text = App.Client.TextDeliveryNote;
|
||||
DocumentId = d.LsNr;
|
||||
MemberBuckets = ctx.GetMemberBuckets(d.Member, d.Year).GetAwaiter().GetResult();
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,34 +1,38 @@
|
||||
@using RazorLight
|
||||
@inherits TemplatePage<Elwig.Documents.Document>
|
||||
@model Elwig.Documents.Document
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="de-AT">
|
||||
<head>
|
||||
<title>@Model.Title</title>
|
||||
<meta charset="UTF-8"/>
|
||||
<title>@Model.Title</title>
|
||||
<meta name="author" value="@Model.Author"/>
|
||||
<meta charset="UTF-8"/>
|
||||
<script>
|
||||
window.PagedConfig = { auto: false };
|
||||
if (!navigator.webdriver) {
|
||||
window.addEventListener("beforeprint", async () => { await window.PagedPolyfill.preview(); });
|
||||
window.addEventListener("afterprint", () => { location.reload(); });
|
||||
const heightA4 = 297, widhtA4 = 210, heightFooter = 35, heightHeader = 25;
|
||||
const heightMain = heightA4 - heightFooter - heightHeader;
|
||||
function px2mm(px1, px2) {
|
||||
return (px2 - px1 + 1) * 2.54 / 96 * window.devicePixelRatio * 10;
|
||||
}
|
||||
</script>
|
||||
<script src="@Raw(Model.DataPath)\resources\paged.polyfill.js"></script>
|
||||
<link rel="stylesheet" href="@Raw(Model.DataPath)\resources\style.css" />
|
||||
<link rel="stylesheet" href="file:///@Raw(Model.DataPath)\resources\style.css"/>
|
||||
<link rel="stylesheet" href="file:///@Raw(Model.DataPath)\resources\style-page.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<div class="m1"></div>
|
||||
<div class="m2"></div>
|
||||
<div class="m3"></div>
|
||||
<header>@Raw(Model.Header)</header>
|
||||
<div class="m1 r"></div>
|
||||
<div class="m2 r"></div>
|
||||
<div class="m3 r"></div>
|
||||
<div class="footer-wrapper">
|
||||
<div class="pre-footer">
|
||||
<span class="date">@Model.FullDateString</span>
|
||||
<span class="date">@($"{Model.Date:dddd, d. MMMM yyyy}")</span>
|
||||
<span class="doc-id">@Model.DocumentId</span>
|
||||
<span class="page"></span>
|
||||
</div>
|
||||
<footer>@Raw(Model.Footer)</footer>
|
||||
</div>
|
||||
<header>@Raw(Model.Header)</header>
|
||||
<div class="spacing"></div>
|
||||
<div class="main-wrapper">
|
||||
@RenderBody()
|
||||
|
@@ -8,11 +8,28 @@ namespace Elwig.Documents {
|
||||
|
||||
private TempFile? PdfFile = null;
|
||||
|
||||
public string DataPath;
|
||||
public int CurrentNextSeason;
|
||||
public string? DocumentId;
|
||||
public string Title;
|
||||
public string Author;
|
||||
public string Header;
|
||||
public string Footer;
|
||||
public DateTime Date;
|
||||
|
||||
public Document(string title) {
|
||||
var c = App.Client;
|
||||
DataPath = App.DataPath;
|
||||
CurrentNextSeason = Utils.CurrentNextSeason;
|
||||
Title = title;
|
||||
Header = "<h1>Winzergenossenschaft Matzen</h1>";
|
||||
Footer = "Winzergenossenschaft für Matzen und Umgebung reg. Gen.m.b.H.";
|
||||
Author = App.Client.NameFull;
|
||||
Header = $"<h1>{c.Name}</h1>";
|
||||
Footer = Utils.GenerateFooter("<br/>", " \u00b7 ")
|
||||
.Item(c.NameFull).NextLine()
|
||||
.Item(c.Address).Item($"{c.Plz} {c.Ort}").Item("Österreich").Item("Tel.", c.PhoneNr).Item("Fax", c.FaxNr).NextLine()
|
||||
.Item(c.EmailAddress).Item(c.Website).Item("Betriebs-Nr.", c.LfbisNr).Item("UID", c.UstIdNr).NextLine()
|
||||
.Item("BIC", c.Bic).Item("IBAN", c.Iban)
|
||||
.ToString();
|
||||
Date = DateTime.Today;
|
||||
}
|
||||
|
||||
@@ -23,39 +40,33 @@ namespace Elwig.Documents {
|
||||
public void Dispose() {
|
||||
PdfFile?.Dispose();
|
||||
PdfFile = null;
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
public string DataPath { get; set; }
|
||||
|
||||
public string Title { get; set; }
|
||||
|
||||
public string Header { get; set; }
|
||||
|
||||
public string Footer { get; set; }
|
||||
|
||||
public string FullDateString {
|
||||
get => Date.ToString("dddd, d. MMMM yyyy");
|
||||
}
|
||||
|
||||
public DateTime Date { get; set; }
|
||||
|
||||
private async Task<string> Render() {
|
||||
private Task<string> Render() {
|
||||
string name;
|
||||
if (this is BusinessLetter) {
|
||||
name = "BusinessLetter";
|
||||
} else if (this is DeliveryNote) {
|
||||
name = "DeliveryNote";
|
||||
} else if (this is CreditNote) {
|
||||
name = "CreditNote";
|
||||
} else {
|
||||
throw new InvalidOperationException();
|
||||
throw new InvalidOperationException("Invalid document object");
|
||||
}
|
||||
return await Html.CompileRenderAsync(name, this);
|
||||
return Render(name);
|
||||
}
|
||||
|
||||
private Task<string> Render(string name) {
|
||||
return Html.CompileRenderAsync(name, this);
|
||||
}
|
||||
|
||||
public async Task Generate() {
|
||||
var pdf = new TempFile("pdf");
|
||||
using (var tmpHtml = new TempFile("html")) {
|
||||
await File.WriteAllTextAsync(tmpHtml.FilePath, await Render());
|
||||
await File.WriteAllTextAsync(tmpHtml.FilePath, await Render(), Utils.UTF8);
|
||||
await Pdf.Convert(tmpHtml.FilePath, pdf.FilePath);
|
||||
}
|
||||
Pdf.UpdateMetadata(pdf.FilePath, Title, "Winzergenossenschaft für Matzen und Umgebung reg. Gen.m.b.H.");
|
||||
PdfFile = pdf;
|
||||
}
|
||||
|
||||
@@ -64,9 +75,9 @@ namespace Elwig.Documents {
|
||||
File.Copy(PdfFile.FilePath, pdfPath);
|
||||
}
|
||||
|
||||
public async Task Print() {
|
||||
public async Task Print(int copies = 1) {
|
||||
if (PdfFile == null) throw new InvalidOperationException("Pdf file has not been generated yet");
|
||||
Pdf.Print(PdfFile.FilePath);
|
||||
await Pdf.Print(PdfFile.FilePath, copies);
|
||||
}
|
||||
|
||||
public void Show() {
|
||||
|
@@ -17,6 +17,8 @@ namespace Elwig.Documents {
|
||||
await e.CompileTemplateAsync("Document");
|
||||
await e.CompileTemplateAsync("BusinessDocument");
|
||||
await e.CompileTemplateAsync("BusinessLetter");
|
||||
await e.CompileTemplateAsync("DeliveryNote");
|
||||
await e.CompileTemplateAsync("CreditNote");
|
||||
|
||||
Engine = e;
|
||||
evtHandler();
|
||||
|
@@ -1,62 +1,45 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using PdfSharp.Pdf.IO;
|
||||
using PuppeteerSharp;
|
||||
using Elwig.Helpers;
|
||||
using Elwig.Windows;
|
||||
using System.Diagnostics;
|
||||
using Balbarak.WeasyPrint;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Elwig.Documents {
|
||||
public static class Pdf {
|
||||
|
||||
private static readonly string Chromium = @"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe";
|
||||
private static IBrowser? Browser = null;
|
||||
public static bool IsReady => Browser != null;
|
||||
private static readonly string PdfToPrinter = App.ExePath + "PDFtoPrinter.exe";
|
||||
private static readonly FilesManager WeasyPrintManager = new();
|
||||
private static string? WeasyPrintPython = null;
|
||||
private static string? WeasyPrintDir => WeasyPrintManager.FolderPath;
|
||||
public static bool IsReady => WeasyPrintPython != null && WeasyPrintDir != null;
|
||||
|
||||
public static async Task Init(Action evtHandler) {
|
||||
Browser = await Puppeteer.LaunchAsync(new LaunchOptions {
|
||||
Headless = true,
|
||||
ExecutablePath = Chromium,
|
||||
// paged.js uses XHRs to load styles, so this is needed
|
||||
Args = new[] { "--allow-file-access-from-files" },
|
||||
});
|
||||
if (!WeasyPrintManager.IsFilesExsited()) {
|
||||
await WeasyPrintManager.InitFilesAsync();
|
||||
}
|
||||
WeasyPrintPython = Path.Combine(WeasyPrintManager.FolderPath, "python.exe");
|
||||
evtHandler();
|
||||
}
|
||||
|
||||
public static async Task Close() {
|
||||
if (Browser == null) return;
|
||||
await Browser.CloseAsync();
|
||||
Browser = null;
|
||||
}
|
||||
|
||||
public static async Task Convert(string htmlPath, string pdfPath) {
|
||||
if (Browser == null) throw new InvalidOperationException("The puppeteer engine has not been initialized yet");
|
||||
using var page = await Browser.NewPageAsync();
|
||||
page.Console += OnConsole;
|
||||
await page.GoToAsync($"file://{htmlPath}");
|
||||
await page.EvaluateFunctionAsync("async () => { await window.PagedPolyfill.preview(); }");
|
||||
await page.PdfAsync(pdfPath, new() {
|
||||
PreferCSSPageSize = true,
|
||||
//Format = PaperFormat.A4,
|
||||
DisplayHeaderFooter = false,
|
||||
MarginOptions = new() {
|
||||
Top = "0mm",
|
||||
Right = "0mm",
|
||||
Bottom = "0mm",
|
||||
Left = "0mm",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
private static void OnConsole(object sender, ConsoleEventArgs e) {
|
||||
MessageBox.Show(e.Message.Text);
|
||||
}
|
||||
|
||||
public static void UpdateMetadata(string path, string title, string author) {
|
||||
using var doc = PdfReader.Open(path);
|
||||
doc.Info.Title = title;
|
||||
doc.Info.Author = author;
|
||||
doc.Save(path);
|
||||
var p = new Process() { StartInfo = new() {
|
||||
FileName = WeasyPrintPython,
|
||||
CreateNoWindow = true,
|
||||
WorkingDirectory = WeasyPrintDir,
|
||||
RedirectStandardError = true,
|
||||
} };
|
||||
p.StartInfo.EnvironmentVariables["PATH"] = "Scripts;gtk3;" + Environment.GetEnvironmentVariable("PATH");
|
||||
p.StartInfo.ArgumentList.Add("scripts/weasyprint.exe");
|
||||
p.StartInfo.ArgumentList.Add("-e");
|
||||
p.StartInfo.ArgumentList.Add("utf8");
|
||||
p.StartInfo.ArgumentList.Add(htmlPath);
|
||||
p.StartInfo.ArgumentList.Add(pdfPath);
|
||||
p.Start();
|
||||
await p.WaitForExitAsync();
|
||||
var stderr = await p.StandardError.ReadToEndAsync();
|
||||
if (p.ExitCode != 0) throw new Exception(stderr);
|
||||
}
|
||||
|
||||
public static void Show(TempFile file, string title) {
|
||||
@@ -73,8 +56,12 @@ namespace Elwig.Documents {
|
||||
});
|
||||
}
|
||||
|
||||
public static void Print(string path) {
|
||||
// TODO print pdf
|
||||
public static async Task Print(string path, int copies = 1) {
|
||||
var p = new Process() { StartInfo = new() { FileName = PdfToPrinter } };
|
||||
p.StartInfo.ArgumentList.Add(path);
|
||||
p.StartInfo.ArgumentList.Add($"copies={copies}");
|
||||
p.Start();
|
||||
await p.WaitForExitAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
131
Elwig/Documents/style-businessdocument.css
Normal file
131
Elwig/Documents/style-businessdocument.css
Normal file
@@ -0,0 +1,131 @@
|
||||
|
||||
.address-wrapper, aside, main {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.spacing {
|
||||
height: 20mm;
|
||||
}
|
||||
|
||||
.info-wrapper {
|
||||
width: 100%;
|
||||
height: 45mm;
|
||||
margin: 0 0 2mm 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.address-wrapper {
|
||||
height: 45mm;
|
||||
width: 85mm;
|
||||
margin: 0;
|
||||
padding: 5mm;
|
||||
position: absolute;
|
||||
left: -5mm;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.address-wrapper .sender {
|
||||
height: 4em;
|
||||
font-size: 8pt;
|
||||
padding: 1em 0;
|
||||
}
|
||||
|
||||
address {
|
||||
height: 5em;
|
||||
white-space: pre-line;
|
||||
font-size: 12pt;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
aside {
|
||||
height: 40mm;
|
||||
width: 75mm;
|
||||
margin: 0;
|
||||
position: absolute;
|
||||
left: 100mm;
|
||||
top: 5mm;
|
||||
}
|
||||
|
||||
aside table {
|
||||
border-collapse: collapse;
|
||||
border: 0.5pt solid #808080;
|
||||
width: 65mm;
|
||||
margin-right: 10mm;
|
||||
}
|
||||
|
||||
aside table thead:not(:first-child) tr {
|
||||
border-top: 0.5pt solid #808080;
|
||||
}
|
||||
|
||||
aside table thead th {
|
||||
background-color: #E0E0E0;
|
||||
font-size: 10pt;
|
||||
}
|
||||
|
||||
aside table tbody th,
|
||||
aside table tbody td {
|
||||
text-align: left;
|
||||
font-size: 10pt;
|
||||
}
|
||||
|
||||
aside table tbody th {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
main {
|
||||
margin: 2em 0 1em 0;
|
||||
}
|
||||
|
||||
main > *:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.main-wrapper h1, .main-wrapper p {
|
||||
font-size: 12pt;
|
||||
margin: 1em 0;
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
.main-wrapper p {
|
||||
widows: 3;
|
||||
orphans: 3;
|
||||
hyphens: manual;
|
||||
}
|
||||
|
||||
.main-wrapper .date {
|
||||
margin-bottom: 2em;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.main-wrapper h1 {
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
|
||||
.main-wrapper p.comment {
|
||||
font-size: 10pt;
|
||||
}
|
||||
|
||||
.main-wrapper .hidden {
|
||||
break-before: avoid;
|
||||
}
|
||||
|
||||
.main-wrapper .bottom {
|
||||
bottom: 0;
|
||||
position: absolute;
|
||||
width: 165mm;
|
||||
}
|
||||
|
||||
.main-wrapper .signatures {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
margin: 20mm 0 2mm 0;
|
||||
}
|
||||
|
||||
.main-wrapper .signatures > * {
|
||||
width: 50mm;
|
||||
border-top: 0.5pt solid black;
|
||||
padding-top: 1mm;
|
||||
text-align: center;
|
||||
font-size: 10pt;
|
||||
}
|
64
Elwig/Documents/style-creditnote.css
Normal file
64
Elwig/Documents/style-creditnote.css
Normal file
@@ -0,0 +1,64 @@
|
||||
|
||||
table.credit {
|
||||
font-size: 10pt;
|
||||
}
|
||||
|
||||
table.credit th,
|
||||
table.credit td {
|
||||
padding: 0 0.25mm;
|
||||
}
|
||||
|
||||
table.credit thead {
|
||||
font-size: 8pt
|
||||
}
|
||||
|
||||
table.credit thead th {
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
|
||||
table.credit td {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
table.credit .oe,
|
||||
table.credit .kmw {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
table.credit .dpnr {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
table.credit .amount,
|
||||
table.credit .weight {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
table.credit .rel,
|
||||
table.credit .abs {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
table.credit .amount.sum {
|
||||
vertical-align: bottom;
|
||||
padding-bottom: 1mm;
|
||||
}
|
||||
|
||||
table.credit tbody tr:not(.first):not(.last) {
|
||||
break-before: avoid;
|
||||
break-after: avoid;
|
||||
}
|
||||
|
||||
table.credit tbody tr.first td {
|
||||
padding-top: 1mm;
|
||||
}
|
||||
|
||||
table.credit tbody tr.last td {
|
||||
padding-bottom: 1mm;
|
||||
}
|
||||
|
||||
table.credit tbody tr.new {
|
||||
border-top: 0.5pt solid black;
|
||||
}
|
95
Elwig/Documents/style-deliverynote.css
Normal file
95
Elwig/Documents/style-deliverynote.css
Normal file
@@ -0,0 +1,95 @@
|
||||
|
||||
table.delivery {
|
||||
margin-bottom: 5mm;
|
||||
}
|
||||
|
||||
table.delivery tr:not(.main) {
|
||||
break-before: avoid;
|
||||
}
|
||||
|
||||
table.delivery th {
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
font-size: 10pt;
|
||||
}
|
||||
|
||||
table.delivery th.main {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
table.delivery tr.main td {
|
||||
font-weight: bold;
|
||||
padding-top: 2mm;
|
||||
}
|
||||
|
||||
table.delivery tbody tr:not(.main) td {
|
||||
font-size: 8pt;
|
||||
}
|
||||
|
||||
table.delivery tr.tight:not(.first) td {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
table.delivery tr.tight.first td {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
/* FIXME update version of WeasyPrint
|
||||
table.delivery tr.tight:has(+ tr:not(.tight)) td {
|
||||
padding-bottom: 0.5mm !important;
|
||||
}
|
||||
*/
|
||||
|
||||
table.delivery tr.sum {
|
||||
border-top: 0.5pt solid black;
|
||||
break-before: avoid;
|
||||
}
|
||||
|
||||
table.delivery tr.sum td {
|
||||
padding-top: 1mm;
|
||||
}
|
||||
|
||||
table.delivery-stats {
|
||||
font-size: 8pt;
|
||||
break-inside: avoid;
|
||||
break-after: avoid;
|
||||
}
|
||||
|
||||
table.delivery-stats.expanded th,
|
||||
table.delivery-stats.expanded td {
|
||||
padding: 0.25mm 0;
|
||||
}
|
||||
|
||||
table.delivery-stats:not(.expanded) th,
|
||||
table.delivery-stats:not(.expanded) td {
|
||||
padding: 0.125mm 0;
|
||||
}
|
||||
|
||||
table.delivery-stats:not(.expanded) tr.optional {
|
||||
display: none;
|
||||
}
|
||||
|
||||
table.delivery-stats thead th {
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
table.delivery-stats thead th:first-child {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
table.delivery-stats.expanded tbody {
|
||||
font-size: 10pt;
|
||||
}
|
||||
|
||||
table.delivery-stats td {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
table.delivery-stats tbody th {
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
text-align: left;
|
||||
}
|
71
Elwig/Documents/style-page.css
Normal file
71
Elwig/Documents/style-page.css
Normal file
@@ -0,0 +1,71 @@
|
||||
|
||||
.m1, .m2, .m3 {
|
||||
height: 0;
|
||||
width: 10mm;
|
||||
position: fixed;
|
||||
left: -25mm;
|
||||
border-top: 0.5pt solid black;
|
||||
}
|
||||
.m1.r, .m2.r, .m3.r {
|
||||
left: initial;
|
||||
right: -20mm;
|
||||
}
|
||||
.m1 {top: 80mm;}
|
||||
.m2 {top: 123.5mm;}
|
||||
.m3 {top: 185mm;}
|
||||
|
||||
.page-break {
|
||||
break-before: page;
|
||||
}
|
||||
hr.page-break {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@page {
|
||||
size: A4;
|
||||
margin: 25mm 20mm 35mm 25mm;
|
||||
|
||||
@bottom-center {
|
||||
content: element(page-footer);
|
||||
}
|
||||
}
|
||||
|
||||
@media screen {
|
||||
body, header, .footer-wrapper {
|
||||
width: 210mm;
|
||||
}
|
||||
|
||||
header, .address-wrapper, aside, main {
|
||||
border: 1px solid lightgray;
|
||||
}
|
||||
|
||||
.m1, .m2, .m3 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
header {
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.spacing {
|
||||
height: 45mm;
|
||||
}
|
||||
|
||||
.main-wrapper {
|
||||
margin: 0 20mm 40mm 25mm;
|
||||
}
|
||||
|
||||
.footer-wrapper {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: white;
|
||||
}
|
||||
}
|
||||
|
||||
@media print {
|
||||
.page::after {
|
||||
content: "Seite " counter(page) " von " counter(pages) !important;
|
||||
}
|
||||
}
|
@@ -12,17 +12,20 @@ body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.m1, .m2, .m3 {
|
||||
height: 0;
|
||||
width: 1cm;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
border-top: 1pt solid black;
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
.m1 {top: 105mm;}
|
||||
.m2 {top: 148.5mm;}
|
||||
.m3 {top: 210mm;}
|
||||
table td,
|
||||
table th {
|
||||
padding: 0.5mm 1mm;
|
||||
}
|
||||
|
||||
table th {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
header {
|
||||
height: 45mm;
|
||||
@@ -32,145 +35,61 @@ header {
|
||||
left: 0;
|
||||
right: 0;
|
||||
text-align: center;
|
||||
}
|
||||
.spacing {height: 20mm;}
|
||||
.info-wrapper {
|
||||
width: 100%;
|
||||
height:45mm;
|
||||
margin: 0 0 8.46mm 0;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.address-wrapper {
|
||||
height: 45mm;
|
||||
width: 85mm;
|
||||
margin: 0;
|
||||
padding: 5mm;
|
||||
position: absolute;
|
||||
left: 20mm;
|
||||
top: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.address-wrapper .sender {
|
||||
flex: 17.7mm 1 1;
|
||||
font-size: 8pt;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
padding-bottom: 2mm;
|
||||
}
|
||||
|
||||
address {
|
||||
flex: 27.3mm 1 1;
|
||||
white-space: pre-line;
|
||||
font-size: 12pt;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
aside {
|
||||
height: 40mm;
|
||||
width: 75mm;
|
||||
margin: 0;
|
||||
position: absolute;
|
||||
left: 125mm;
|
||||
top: 5mm;
|
||||
}
|
||||
|
||||
main {
|
||||
margin: 8.46mm 20mm 4.23mm 25mm;
|
||||
}
|
||||
|
||||
main :first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
main h1, main p {
|
||||
font-size: 12pt;
|
||||
margin: 1em 0;
|
||||
text-align: justify;
|
||||
widows: 3;
|
||||
orphans: 3;
|
||||
}
|
||||
|
||||
main .date {
|
||||
margin-bottom: 2em;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
main h1 {
|
||||
margin-bottom: 2em;
|
||||
header h1 {
|
||||
font-size: 18pt;
|
||||
margin-top: 10mm;
|
||||
}
|
||||
|
||||
.footer-wrapper {
|
||||
padding: 0 20mm 0 25mm;
|
||||
position: running(page-footer);
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: 165mm;
|
||||
}
|
||||
|
||||
.pre-footer {
|
||||
margin: 4.23mm 0;
|
||||
margin: 1em 0;
|
||||
font-size: 10pt;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.pre-footer .date, .pre-footer .page {
|
||||
flex: 100px 1 1;
|
||||
.pre-footer > * {
|
||||
display: inline-block;
|
||||
width: 33%;
|
||||
}
|
||||
|
||||
.pre-footer .date {text-align: left;}
|
||||
.pre-footer .page {text-align: right;}
|
||||
.page::after {
|
||||
.pre-footer .date {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.pre-footer .doc-id {
|
||||
text-align: center;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.pre-footer .page {
|
||||
text-align: right;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.pre-footer .page::after {
|
||||
content: "Seite 1 von 1";
|
||||
}
|
||||
|
||||
footer {
|
||||
font-size: 10pt;
|
||||
border-top: 1pt solid black;
|
||||
border-top: 0.5pt solid black;
|
||||
height: 25mm;
|
||||
padding-top: 1mm;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@page {
|
||||
size: A4;
|
||||
margin: 25mm 0 35mm 0;
|
||||
@bottom-center {
|
||||
content: element(page-footer);
|
||||
}
|
||||
.hidden {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
@media screen {
|
||||
body, header, .footer-wrapper {
|
||||
width: 210mm;
|
||||
}
|
||||
header, .address-wrapper, aside, main {
|
||||
border: 1px solid lightgray;
|
||||
}
|
||||
.m1, .m2, .m3 {display: none;}
|
||||
header {top: 0;}
|
||||
.spacing {height: 45mm;}
|
||||
.main-wrapper {
|
||||
margin-bottom: 40mm;
|
||||
}
|
||||
.footer-wrapper {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: white;
|
||||
}
|
||||
}
|
||||
|
||||
@media print {
|
||||
.page::after {
|
||||
content: "Seite " counter(page) " von " counter(pages);
|
||||
}
|
||||
.footer-wrapper {
|
||||
display: none;
|
||||
}
|
||||
hr {
|
||||
border: none;
|
||||
border-top: 0.5pt solid black;
|
||||
margin: 5mm 0;
|
||||
}
|
||||
|
@@ -7,6 +7,8 @@
|
||||
<UseWPF>true</UseWPF>
|
||||
<PreserveCompilationContext>true</PreserveCompilationContext>
|
||||
<ApplicationIcon>elwig.ico</ApplicationIcon>
|
||||
<Version>0.2.0</Version>
|
||||
<SatelliteResourceLanguages>de-AT</SatelliteResourceLanguages>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -14,20 +16,23 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Balbarak.WeasyPrint" Version="2.0.2" />
|
||||
<PackageReference Include="Extended.Wpf.Toolkit" Version="4.5.1" />
|
||||
<PackageReference Include="ini-parser" Version="2.5.2" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Razor" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Razor.Language" Version="6.0.16" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="7.0.5" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.5" />
|
||||
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.1722.45" />
|
||||
<PackageReference Include="PdfSharp" Version="1.50.5147" />
|
||||
<PackageReference Include="PuppeteerSharp" Version="9.1.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Razor.Language" Version="6.0.21" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="7.0.10" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.10" />
|
||||
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.1938.49" />
|
||||
<PackageReference Include="RazorLight" Version="2.3.1" />
|
||||
<PackageReference Include="ScottPlot.WPF" Version="4.1.67" />
|
||||
<PackageReference Include="System.IO.Ports" Version="7.0.0" />
|
||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="7.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Resource Include="elwig.png" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
|
||||
<Exec Command="call fetch-resources.bat" />
|
||||
</Target>
|
||||
|
@@ -6,34 +6,52 @@ using System.IO;
|
||||
using System;
|
||||
using System.Windows;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Data.Sqlite;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Elwig.Helpers {
|
||||
public class AppDbContext : DbContext {
|
||||
|
||||
public DbSet<Country> Countries { get; set; }
|
||||
public DbSet<Currency> Currencies { get; set; }
|
||||
public DbSet<Member> Members { get; set; }
|
||||
public DbSet<BillingAddr> BillingAddresses { get; set; }
|
||||
public DbSet<AT_Gem> Gemeinden { get; set; }
|
||||
public DbSet<AT_Kg> Katastralgemeinden { get; set; }
|
||||
public DbSet<AT_Ort> Orte { get; set; }
|
||||
public DbSet<AT_Plz> Postleitzahlen { get; set; }
|
||||
public DbSet<AT_PlzDest> PlzDestinations { get; set; }
|
||||
public DbSet<PostalDest> PostalDestinations { get; set; }
|
||||
public DbSet<Branch> Branches { get; set; }
|
||||
public DbSet<WbKg> WbKgs { get; set; }
|
||||
public DbSet<WbRd> WbRde { get; set; }
|
||||
public DbSet<AreaCom> AreaCommitments { get; set; }
|
||||
public DbSet<AreaComParcel> AreaCommitmentParcels { get; set; }
|
||||
public DbSet<AreaComAttr> AreaCommitmentAttributes { get; set; }
|
||||
public DbSet<Contract> Contracts { get; set; }
|
||||
public DbSet<WineAttr> WineAttributes { get; set; }
|
||||
public DbSet<WineCult> WineCultivations { get; set; }
|
||||
public DbSet<WineQual> WineQualities { get; set; }
|
||||
public DbSet<WineVar> WineVarieties { get; set; }
|
||||
public DbSet<Season> Seasons { get; set; }
|
||||
public DbSet<Country> Countries { get; private set; }
|
||||
public DbSet<Currency> Currencies { get; private set; }
|
||||
public DbSet<AT_Gem> Gemeinden { get; private set; }
|
||||
public DbSet<AT_Kg> Katastralgemeinden { get; private set; }
|
||||
public DbSet<AT_Ort> Orte { get; private set; }
|
||||
public DbSet<AT_Plz> Postleitzahlen { get; private set; }
|
||||
public DbSet<AT_PlzDest> PlzDestinations { get; private set; }
|
||||
public DbSet<PostalDest> PostalDestinations { get; private set; }
|
||||
public DbSet<WineOrigin> WineOrigins { get; private set; }
|
||||
public DbSet<WineQualLevel> WineQualityLevels { get; private set; }
|
||||
public DbSet<WineVar> WineVarieties { get; private set; }
|
||||
|
||||
public DbSet<ClientParam> ClientParameters { get; private set; }
|
||||
public DbSet<WbKg> WbKgs { get; private set; }
|
||||
public DbSet<WbRd> WbRde { get; private set; }
|
||||
public DbSet<WineAttr> WineAttributes { get; private set; }
|
||||
public DbSet<WineCult> WineCultivations { get; private set; }
|
||||
public DbSet<Branch> Branches { get; private set; }
|
||||
public DbSet<AreaComType> AreaCommitmentTypes { get; private set; }
|
||||
public DbSet<Member> Members { get; private set; }
|
||||
public DbSet<BillingAddr> BillingAddresses { get; private set; }
|
||||
public DbSet<MemberTelNr> MemberTelephoneNrs { get; private set; }
|
||||
public DbSet<AreaCom> AreaCommitments { get; private set; }
|
||||
public DbSet<Season> Seasons { get; private set; }
|
||||
public DbSet<Modifier> Modifiers { get; private set; }
|
||||
public DbSet<Delivery> Deliveries { get; private set; }
|
||||
public DbSet<DeliveryPart> DeliveryParts { get; private set; }
|
||||
public DbSet<DeliveryPartAttr> DeliveryPartAttributes { get; private set; }
|
||||
public DbSet<DeliveryPartModifier> DeliveryPartModifiers { get; private set; }
|
||||
public DbSet<PaymentVar> PaymentVariants { get; private set; }
|
||||
public DbSet<PaymentMember> MemberPayments { get; private set; }
|
||||
public DbSet<Credit> Credits { get; private set; }
|
||||
|
||||
private readonly StreamWriter? LogFile = null;
|
||||
public static DateTime LastWriteTime => File.GetLastWriteTime(App.Config.DatabaseFile);
|
||||
public DateTime SavedLastWriteTime { get; private set; }
|
||||
public bool HasBackendChanged => SavedLastWriteTime != LastWriteTime;
|
||||
|
||||
public static string ConnectionString => $"Data Source=\"{App.Config.DatabaseFile}\"; Foreign Keys=True; Mode=ReadWrite; Cache=Default";
|
||||
|
||||
public AppDbContext() {
|
||||
if (App.Config.DatabaseLog != null) {
|
||||
@@ -46,10 +64,26 @@ namespace Elwig.Helpers {
|
||||
MessageBox.Show($"Unable to open database log file:\n\n{e.Message}", "Database Log", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
SavedLastWriteTime = LastWriteTime;
|
||||
SavedChanges += OnSavedChanges;
|
||||
}
|
||||
|
||||
public static SqliteConnection Connect() {
|
||||
var cnx = new SqliteConnection(ConnectionString);
|
||||
cnx.CreateFunction<string, string?, bool?>("REGEXP", (pattern, value) => value == null ? null : Regex.Match(value, pattern).Success, true);
|
||||
cnx.Open();
|
||||
return cnx;
|
||||
}
|
||||
|
||||
public static async Task<SqliteConnection> ConnectAsync() {
|
||||
var cnx = new SqliteConnection(ConnectionString);
|
||||
cnx.CreateFunction<string, string?, bool?>("REGEXP", (pattern, value) => value == null ? null : Regex.Match(value, pattern).Success, true);
|
||||
await cnx.OpenAsync();
|
||||
return cnx;
|
||||
}
|
||||
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
|
||||
optionsBuilder.UseSqlite($"Data Source=\"{App.Config.DatabaseFile}\"; Foreign Keys=True; Mode=ReadWrite; Cache=Default");
|
||||
optionsBuilder.UseSqlite(ConnectionString);
|
||||
optionsBuilder.UseLazyLoadingProxies();
|
||||
optionsBuilder.LogTo(Log, LogLevel.Information);
|
||||
base.OnConfiguring(optionsBuilder);
|
||||
@@ -61,6 +95,10 @@ namespace Elwig.Helpers {
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
private void OnSavedChanges(object? sender, SavedChangesEventArgs evt) {
|
||||
SavedLastWriteTime = LastWriteTime;
|
||||
}
|
||||
|
||||
protected void Log(string msg) {
|
||||
LogFile?.WriteLine(msg);
|
||||
}
|
||||
@@ -69,22 +107,125 @@ namespace Elwig.Helpers {
|
||||
return await Members.FindAsync(mgnr) != null;
|
||||
}
|
||||
|
||||
public async Task<bool> VNrExists(int vnr) {
|
||||
return await Contracts.FindAsync(vnr) != null;
|
||||
public async Task<bool> FbNrExists(int fbnr) {
|
||||
return await AreaCommitments.FindAsync(fbnr) != null;
|
||||
}
|
||||
|
||||
public async Task<bool> SortIdExists(string sortId) {
|
||||
return await WineVarieties.FindAsync(sortId) != null;
|
||||
}
|
||||
|
||||
public async Task<bool> AttrIdExists(string attrId) {
|
||||
return await WineAttributes.FindAsync(attrId) != null;
|
||||
}
|
||||
|
||||
public async Task<int> NextMgNr() {
|
||||
int c = await Members.Select(m => m.MgNr).MinAsync();
|
||||
(await Members.OrderBy(m => m.MgNr).Select(m => m.MgNr).ToListAsync())
|
||||
.ForEach(a => { if (a <= c + 1000) c = a; });
|
||||
return c + 1;
|
||||
}
|
||||
|
||||
public async Task<int> NextFbNr() {
|
||||
int c = await AreaCommitments.Select(ac => ac.FbNr).MinAsync();
|
||||
(await AreaCommitments.OrderBy(ac => ac.FbNr).Select(ac => ac.FbNr).ToListAsync())
|
||||
.ForEach(a => { if (a <= c + 1000) c = a; });
|
||||
return c + 1;
|
||||
}
|
||||
|
||||
public async Task<int> NextLNr(DateOnly date) {
|
||||
var dateStr = date.ToString("yyyy-MM-dd");
|
||||
int c = 0;
|
||||
(await Deliveries.Where(d => d.DateString == dateStr).Select(d => d.LNr).ToListAsync())
|
||||
.ForEach(a => { if (a <= c + 100) c = a; });
|
||||
return c + 1;
|
||||
}
|
||||
|
||||
public async Task<int> NextVNr() {
|
||||
int c = await Contracts.Select(co => co.VNr).MinAsync();
|
||||
(await Contracts.OrderBy(co => co.VNr).Select(co => co.VNr).ToListAsync())
|
||||
public async Task<int> NextDId(int year) {
|
||||
int c = 0;
|
||||
(await Deliveries.Where(d => d.Year == year).Select(d => d.DId).ToListAsync())
|
||||
.ForEach(a => { if (a <= c + 100) c = a; });
|
||||
return c + 1;
|
||||
}
|
||||
|
||||
public async Task<int> NextDPNr(int year, int did) {
|
||||
int c = 0;
|
||||
(await DeliveryParts.Where(p => p.Year == year && p.DId == did).Select(d => d.DPNr).ToListAsync())
|
||||
.ForEach(a => { if (a <= c + 100) c = a; });
|
||||
return c + 1;
|
||||
}
|
||||
|
||||
public async Task<WineQualLevel> GetWineQualityLevel(double kmw) {
|
||||
return await WineQualityLevels
|
||||
.Where(q => !q.IsPredicate && (q.MinKmw == null || q.MinKmw <= kmw))
|
||||
.OrderBy(q => q.MinKmw)
|
||||
.LastOrDefaultAsync();
|
||||
}
|
||||
|
||||
public async Task UpdateDeliveryPartAttributes(DeliveryPart part, IEnumerable<WineAttr> attributes) {
|
||||
foreach (var a in WineAttributes) {
|
||||
var attr = part.PartAttributes.Where(pa => pa.AttrId == a.AttrId).FirstOrDefault();
|
||||
if (attributes.Contains(a)) {
|
||||
DeliveryPartAttr dpa = attr ?? this.CreateProxy<DeliveryPartAttr>();
|
||||
dpa.Year = part.Year;
|
||||
dpa.DId = part.DId;
|
||||
dpa.DPNr = part.DPNr;
|
||||
dpa.AttrId = a.AttrId;
|
||||
if (attr == null) {
|
||||
await AddAsync(dpa);
|
||||
} else {
|
||||
Update(dpa);
|
||||
}
|
||||
} else {
|
||||
if (attr != null) {
|
||||
Remove(attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task UpdateDeliveryPartModifiers(DeliveryPart part, IEnumerable<Modifier> modifiers) {
|
||||
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)) {
|
||||
DeliveryPartModifier dpm = mod ?? this.CreateProxy<DeliveryPartModifier>();
|
||||
dpm.Year = part.Year;
|
||||
dpm.DId = part.DId;
|
||||
dpm.DPNr = part.DPNr;
|
||||
dpm.ModId = m.ModId;
|
||||
if (mod == null) {
|
||||
await AddAsync(dpm);
|
||||
} else {
|
||||
Update(dpm);
|
||||
}
|
||||
} else {
|
||||
if (mod != null) {
|
||||
Remove(mod);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<(string, string, int, int, int)>> GetMemberBuckets(Member m, int year) {
|
||||
using var cnx = await ConnectAsync();
|
||||
var (rights, obligations) = await Billing.Billing.GetMemberRightsObligations(m.MgNr, year, cnx);
|
||||
var buckets = await Billing.Billing.GetMemberBucketWeights(m.MgNr, year, cnx);
|
||||
|
||||
var list = new List<(string, string, int, int, int)>();
|
||||
foreach (var id in rights.Keys.Union(obligations.Keys).Union(buckets.Keys)) {
|
||||
var s = await WineVarieties.FindAsync(id[..2]);
|
||||
var attrIds = id[2..];
|
||||
var a = await WineAttributes.Where(a => attrIds.Contains(a.AttrId)).ToListAsync();
|
||||
var name = (s?.Name ?? "") + (a.Count > 0 ? $" ({string.Join(" / ", a.Select(a => a.Name))})" : "");
|
||||
list.Add((
|
||||
id, name,
|
||||
rights.TryGetValue(id, out var v1) ? v1 : 0,
|
||||
obligations.TryGetValue(id, out var v2) ? v2 : 0,
|
||||
buckets.TryGetValue(id, out var v3) ? v3 : 0
|
||||
));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
130
Elwig/Helpers/Billing/Billing.cs
Normal file
130
Elwig/Helpers/Billing/Billing.cs
Normal file
@@ -0,0 +1,130 @@
|
||||
using Microsoft.Data.Sqlite;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Elwig.Helpers.Billing {
|
||||
public class Billing {
|
||||
|
||||
private readonly int Year;
|
||||
private readonly int AvNr;
|
||||
private readonly AppDbContext Context;
|
||||
private readonly Dictionary<string, string> Attributes;
|
||||
private readonly Dictionary<string, (decimal?, decimal?)> Modifiers;
|
||||
private readonly Dictionary<string, (string, string?, string?, string?, int?, int?, decimal?)> AreaComTypes;
|
||||
|
||||
public Billing(int year, int avnr) {
|
||||
Year = year;
|
||||
AvNr = avnr;
|
||||
Context = new AppDbContext();
|
||||
Attributes = Context.WineAttributes.ToDictionary(a => a.AttrId, a => a.Name);
|
||||
Modifiers = Context.Modifiers.Where(m => m.Year == Year).ToDictionary(m => m.ModId, m => (m.Abs, m.Rel));
|
||||
AreaComTypes = Context.AreaCommitmentTypes.ToDictionary(v => v.VtrgId, v => (v.SortId, v.AttrId1, v.AttrId2, v.Discriminator, v.MinKgPerHa, v.MaxKgPerHa, v.PenaltyAmount));
|
||||
}
|
||||
|
||||
protected async Task DeleteInDb() {
|
||||
using var cnx = await AppDbContext.ConnectAsync();
|
||||
using (var cmd = cnx.CreateCommand()) {
|
||||
cmd.CommandText = $"DELETE FROM payment_delivery_part WHERE (year, avnr) = ({Year}, {AvNr})";
|
||||
await cmd.ExecuteNonQueryAsync();
|
||||
}
|
||||
using (var cmd = cnx.CreateCommand()) {
|
||||
cmd.CommandText = $"DELETE FROM payment_member WHERE (year, avnr) = ({Year}, {AvNr})";
|
||||
await cmd.ExecuteNonQueryAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task Calculate() {
|
||||
await DeleteInDb();
|
||||
var tasks = new List<Task>();
|
||||
foreach (var mgnr in Context.Members.Select(m => m.MgNr)) {
|
||||
tasks.Add(Task.Run(() => CalculateMember(mgnr)));
|
||||
}
|
||||
await Task.WhenAll(tasks);
|
||||
}
|
||||
|
||||
public static async Task<(Dictionary<string, int>, Dictionary<string, int>)> GetMemberRightsObligations(int mgnr, int year, SqliteConnection cnx) {
|
||||
var rights = new Dictionary<string, int>();
|
||||
var obligations = new Dictionary<string, int>();
|
||||
|
||||
using var cmd = cnx.CreateCommand();
|
||||
cmd.CommandText = $"""
|
||||
SELECT t.vtrgid,
|
||||
SUM(COALESCE(area * min_kg_per_ha, 0)) / 10000 AS min_kg,
|
||||
SUM(COALESCE(area * max_kg_per_ha, 0)) / 10000 AS max_kg
|
||||
FROM area_commitment c
|
||||
JOIN area_commitment_type t ON t.vtrgid = c.vtrgid
|
||||
WHERE mgnr = {mgnr} AND (year_from IS NULL OR year_from <= {year}) AND (year_to IS NULL OR year_to >= {year})
|
||||
GROUP BY t.vtrgid
|
||||
ORDER BY LENGTH(t.vtrgid) DESC, t.vtrgid
|
||||
""";
|
||||
|
||||
var reader = await cmd.ExecuteReaderAsync();
|
||||
while (await reader.ReadAsync()) {
|
||||
var vtrgid = reader.GetString(0);
|
||||
obligations[vtrgid] = reader.GetInt32(1);
|
||||
rights[vtrgid] = reader.GetInt32(2);
|
||||
}
|
||||
|
||||
return (rights, obligations);
|
||||
}
|
||||
|
||||
public static async Task<Dictionary<string, int>> GetMemberBucketWeights(int mgnr, int year, SqliteConnection cnx) {
|
||||
var buckets = new Dictionary<string, int>();
|
||||
|
||||
using var cmd = cnx.CreateCommand();
|
||||
cmd.CommandText = $"""
|
||||
SELECT bucket, weight
|
||||
FROM v_bucket
|
||||
WHERE (year, mgnr) = ({year}, {mgnr})
|
||||
""";
|
||||
|
||||
var reader = await cmd.ExecuteReaderAsync();
|
||||
while (await reader.ReadAsync()) {
|
||||
var bucket = reader.GetString(0);
|
||||
buckets[bucket] = reader.GetInt32(1);
|
||||
}
|
||||
|
||||
return buckets;
|
||||
}
|
||||
|
||||
protected async Task CalculateMember(int mgnr) {
|
||||
using var cnx = await AppDbContext.ConnectAsync();
|
||||
var (rights, obligations) = await GetMemberRightsObligations(mgnr, Year, cnx);
|
||||
|
||||
var deliveries = new List<(int, int, string, int, double, string, string[], string[])>();
|
||||
using (var cmd = cnx.CreateCommand()) {
|
||||
cmd.CommandText = $"""
|
||||
SELECT did, dpnr, sortid, weight, kmw, qualid, attributes, modifiers
|
||||
FROM v_delivery
|
||||
WHERE (year, mgnr) = ({Year}, {mgnr})
|
||||
ORDER BY kmw DESC, weight DESC, did, dpnr
|
||||
""";
|
||||
var reader = await cmd.ExecuteReaderAsync();
|
||||
while (await reader.ReadAsync()) {
|
||||
deliveries.Add((
|
||||
reader.GetInt32(0), reader.GetInt32(1), reader.GetString(2), reader.GetInt32(3),
|
||||
reader.GetDouble(4), reader.GetString(5), reader.GetString(6).Split(","), reader.GetString(7).Split(",")
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var (did, dpnr, sortid, weight, kmw, qualid, attributes, modifiers) in deliveries) {
|
||||
if (qualid == "WEI" || qualid == "RSW" || qualid == "LDW") {
|
||||
// Nicht mindestens Qualitätswein (QUW)
|
||||
using var cmd = cnx.CreateCommand();
|
||||
// TODO
|
||||
cmd.CommandText = $"""
|
||||
INSERT INTO payment_delivery_part (year, did, dpnr, avnr, mod_abs, mod_rel, )
|
||||
VALUES ({Year}, {did}, {dpnr}, {AvNr}, )
|
||||
""";
|
||||
await cmd.ExecuteNonQueryAsync();
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
119
Elwig/Helpers/Billing/Graph.cs
Normal file
119
Elwig/Helpers/Billing/Graph.cs
Normal file
@@ -0,0 +1,119 @@
|
||||
using ScottPlot;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Nodes;
|
||||
|
||||
namespace Elwig.Helpers.Billing {
|
||||
public class Graph : ICloneable {
|
||||
|
||||
public string Type { get; set; }
|
||||
public int Num { get; set; }
|
||||
private int MinX { get; set; }
|
||||
private int MaxX { get; set; }
|
||||
public string Contracts { get; set; }
|
||||
public double[] DataX { get; set; }
|
||||
public double[] DataY { get; set; }
|
||||
|
||||
public Graph(int num, int minX, int maxX) {
|
||||
Type = "oe";
|
||||
Num = num;
|
||||
Contracts = "";
|
||||
MinX = minX;
|
||||
MaxX = maxX;
|
||||
|
||||
DataX = DataGen.Range(MinX, MaxX + 1);
|
||||
DataY = DataGen.Zeros(MaxX - MinX + 1);
|
||||
}
|
||||
|
||||
public Graph(string type, int num, JsonObject graphData, string contracts, int minX, int maxX) {
|
||||
Type = type;
|
||||
Num = num;
|
||||
Contracts = contracts;
|
||||
MinX = minX;
|
||||
MaxX = maxX;
|
||||
|
||||
DataX = DataGen.Range(MinX, MaxX + 1);
|
||||
DataY = DataGen.Zeros(MaxX - MinX + 1);
|
||||
ParseGraphData(graphData);
|
||||
}
|
||||
|
||||
public Graph(string type, int num, int minX, int maxX, string contracts, double[] dataX, double[] dataY) {
|
||||
Type = type;
|
||||
Num = num;
|
||||
MinX = minX;
|
||||
MaxX = maxX;
|
||||
Contracts = contracts;
|
||||
DataX = dataX;
|
||||
DataY = dataY;
|
||||
}
|
||||
|
||||
private void ParseGraphData(JsonObject graphData) {
|
||||
var GraphPoints = graphData.ToDictionary(p => int.Parse(p.Key[..^2]), p => (double)p.Value?.AsValue());
|
||||
|
||||
if (GraphPoints.Keys.Count < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
var minKey = GraphPoints.Keys.Order().First();
|
||||
var maxKey = GraphPoints.Keys.OrderDescending().First();
|
||||
|
||||
if (!GraphPoints.ContainsKey(MinX)) {
|
||||
GraphPoints.Add(MinX, GraphPoints.GetValueOrDefault(minKey));
|
||||
}
|
||||
if (!GraphPoints.ContainsKey(MaxX)) {
|
||||
GraphPoints.Add(MaxX, GraphPoints.GetValueOrDefault(maxKey));
|
||||
}
|
||||
|
||||
var keys = GraphPoints.Keys.Order().ToArray();
|
||||
|
||||
for (int i = 0; i < keys.Length; i++) {
|
||||
double point1Value = GraphPoints[keys[i]];
|
||||
if (i + 1 < keys.Length) {
|
||||
double point2Value = GraphPoints[keys[i + 1]];
|
||||
if (point1Value == point2Value) {
|
||||
for (int j = keys[i] - MinX; j < keys[i + 1] - MinX; j++) {
|
||||
DataY[j] = point1Value;
|
||||
}
|
||||
} else {
|
||||
int steps = Math.Abs(keys[i + 1] - keys[i]);
|
||||
double step = (point2Value - point1Value) / steps;
|
||||
|
||||
DataY[keys[i] - MinX] = point1Value;
|
||||
DataY[keys[i + 1] - MinX] = point2Value;
|
||||
|
||||
for (int j = keys[i] - MinX; j < keys[i + 1] - MinX - 1; j++) {
|
||||
DataY[j + 1] = Math.Round(DataY[j] + step, 4); // TODO richtig runden
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int j = keys[i] - MinX; j < DataX.Length; j++) {
|
||||
DataY[j] = point1Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public JsonObject ToJson() {
|
||||
JsonObject graph = new();
|
||||
|
||||
if (DataY[0] != DataY[1]) {
|
||||
graph.Add(new KeyValuePair<string, JsonNode?>(DataX[0] + Type.ToLower(), Math.Round(DataY[0], 4)));
|
||||
}
|
||||
for (int i = 1; i < DataX.Length - 1; i++) {
|
||||
if (Math.Round(DataY[i] - DataY[i - 1], 4) != Math.Round(DataY[i + 1] - DataY[i], 4)) {
|
||||
graph.Add(new KeyValuePair<string, JsonNode?>(DataX[i] + Type.ToLower(), Math.Round(DataY[i], 4)));
|
||||
}
|
||||
}
|
||||
if (DataY[^1] != DataY[^2]) {
|
||||
graph.Add(new KeyValuePair<string, JsonNode?>(DataX[^1] + Type.ToLower(), Math.Round(DataY[^1], 4)));
|
||||
}
|
||||
return graph;
|
||||
}
|
||||
|
||||
public object Clone() {
|
||||
return new Graph(Type, Num, MinX, MaxX, Contracts, (double[])DataX.Clone(), (double[])DataY.Clone());
|
||||
}
|
||||
}
|
||||
}
|
32
Elwig/Helpers/Billing/Transaction.cs
Normal file
32
Elwig/Helpers/Billing/Transaction.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using Elwig.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Elwig.Helpers.Billing {
|
||||
public class Transaction {
|
||||
|
||||
public readonly Member Member;
|
||||
public readonly long AmountCent;
|
||||
public readonly string Currency;
|
||||
public readonly int Nr;
|
||||
|
||||
public Transaction(Member m, decimal amount, string currency, int nr) {
|
||||
Member = m;
|
||||
AmountCent = (long)Math.Round(amount * 100);
|
||||
Currency = currency;
|
||||
Nr = nr;
|
||||
}
|
||||
|
||||
public static IEnumerable<Transaction> FromPaymentVariant(PaymentVar variant) {
|
||||
var last = variant.Season.PaymentVariants.Where(v => v.TransferDate != null).OrderBy(v => v.TransferDate).LastOrDefault();
|
||||
var dict = last?.MemberPayments.ToDictionary(m => m.MgNr, m => m.Amount) ?? new();
|
||||
return variant.Credits
|
||||
.OrderBy(c => c.MgNr)
|
||||
.Select(c => new Transaction(c.Member, c.Amount, variant.Season.CurrencyCode, c.TgNr))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public static string FormatAmountCent(long cents) => $"{cents / 100}.{cents % 100:00}";
|
||||
}
|
||||
}
|
142
Elwig/Helpers/ClientParameters.cs
Normal file
142
Elwig/Helpers/ClientParameters.cs
Normal file
@@ -0,0 +1,142 @@
|
||||
using Elwig.Models;
|
||||
using Microsoft.Data.Sqlite;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Elwig.Helpers {
|
||||
public class ClientParameters {
|
||||
|
||||
public enum Type { Matzen, Winzerkeller };
|
||||
|
||||
public bool IsMatzen => Client == Type.Matzen;
|
||||
public bool IsWinzerkeller => Client == Type.Winzerkeller;
|
||||
public bool IsWolkersdorf => Client == Type.Winzerkeller && App.ZwstId == "W";
|
||||
public bool IsHaugsdorf => Client == Type.Winzerkeller && App.ZwstId == "H";
|
||||
public bool IsSitzendorf => Client == Type.Winzerkeller && App.ZwstId == "S";
|
||||
|
||||
public string NameToken;
|
||||
public string NameShort;
|
||||
public string Name;
|
||||
public string? NameSuffix;
|
||||
public string NameType;
|
||||
public string NameFull => NameSuffix == null ? $"{Name} {NameType}" : $"{Name}, {NameSuffix}, {NameType}";
|
||||
public Type? Client;
|
||||
|
||||
public PostalDest PostalDest {
|
||||
set {
|
||||
Plz = value.AtPlz.Plz;
|
||||
Ort = value.AtPlz.Ort.Name;
|
||||
}
|
||||
}
|
||||
public int Plz;
|
||||
public string Ort;
|
||||
public string Address;
|
||||
public string Sender1 => $"{NameShort} | {Address} | {Plz} {Ort}";
|
||||
public string Sender2;
|
||||
|
||||
public string? Iban;
|
||||
public string? Bic;
|
||||
public string? UstIdNr;
|
||||
public string? LfbisNr;
|
||||
|
||||
public string? PhoneNr;
|
||||
public string? FaxNr;
|
||||
public string? EmailAddress;
|
||||
public string? Website;
|
||||
|
||||
public int DeliveryObligation;
|
||||
public int DeliveryRight;
|
||||
public decimal VatNormal;
|
||||
public decimal VatReduced;
|
||||
public decimal VatFlatRate;
|
||||
|
||||
public string? TextDeliveryNote;
|
||||
|
||||
public ClientParameters(AppDbContext ctx) : this(ctx.ClientParameters.ToDictionary(e => e.Param, e => e.Value)) { }
|
||||
|
||||
public ClientParameters(Dictionary<string, string?> parameters) {
|
||||
try {
|
||||
NameToken = parameters["CLIENT_NAME_TOKEN"] ?? throw new KeyNotFoundException();
|
||||
NameShort = parameters["CLIENT_NAME_SHORT"] ?? throw new KeyNotFoundException();
|
||||
Name = parameters["CLIENT_NAME"] ?? throw new KeyNotFoundException();
|
||||
NameSuffix = parameters.GetValueOrDefault("CLIENT_NAME_SUFFIX");
|
||||
NameType = parameters["CLIENT_NAME_TYPE"] ?? throw new KeyNotFoundException();
|
||||
switch (Name) {
|
||||
case "Winzergenossenschaft für Matzen und Umgebung": Client = Type.Matzen; break;
|
||||
case "Winzerkeller im Weinviertel": Client = Type.Winzerkeller; break;
|
||||
};
|
||||
|
||||
Plz = int.Parse(parameters["CLIENT_PLZ"] ?? "");
|
||||
Ort = parameters["CLIENT_ORT"] ?? throw new KeyNotFoundException();
|
||||
Address = parameters["CLIENT_ADDRESS"] ?? throw new KeyNotFoundException();
|
||||
PhoneNr = parameters.GetValueOrDefault("CLIENT_PHONE");
|
||||
FaxNr = parameters.GetValueOrDefault("CLIENT_FAX");
|
||||
EmailAddress = parameters.GetValueOrDefault("CLIENT_EMAIL");
|
||||
Website = parameters.GetValueOrDefault("CLIENT_WEBSITE");
|
||||
LfbisNr = parameters.GetValueOrDefault("CLIENT_LFBISNR");
|
||||
UstIdNr = parameters.GetValueOrDefault("CLIENT_USTIDNR");
|
||||
Bic = parameters.GetValueOrDefault("CLIENT_BIC");
|
||||
Iban = parameters.GetValueOrDefault("CLIENT_IBAN");
|
||||
|
||||
DeliveryObligation = int.Parse(parameters["DELIVERY_OBLIGATION"] ?? "");
|
||||
DeliveryRight = int.Parse(parameters["DELIVERY_RIGHT"] ?? "");
|
||||
VatNormal = decimal.Parse((parameters["VAT_NORMAL"] ?? "").Replace(".", ","));
|
||||
VatReduced = decimal.Parse((parameters["VAT_REDUCED"] ?? "").Replace(".", ","));
|
||||
VatFlatRate = decimal.Parse((parameters["VAT_FLATRATE"] ?? "").Replace(".", ","));
|
||||
|
||||
Sender2 = parameters.GetValueOrDefault("DOCUMENT_SENDER") ?? "";
|
||||
TextDeliveryNote = parameters.GetValueOrDefault("TEXT_DELIVERYNOTE");
|
||||
} catch {
|
||||
throw new KeyNotFoundException();
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<(string, string?)> GetParamValues() {
|
||||
return new (string, string?)[] {
|
||||
("CLIENT_NAME_TOKEN", NameToken),
|
||||
("CLIENT_NAME_SHORT", NameShort),
|
||||
("CLIENT_NAME", Name),
|
||||
("CLIENT_NAME_SUFFIX", NameSuffix),
|
||||
("CLIENT_NAME_TYPE", NameType),
|
||||
("CLIENT_PLZ", Plz.ToString()),
|
||||
("CLIENT_ORT", Ort),
|
||||
("CLIENT_ADDRESS", Address),
|
||||
("CLIENT_PHONE", PhoneNr),
|
||||
("CLIENT_FAX", FaxNr),
|
||||
("CLIENT_EMAIL", EmailAddress),
|
||||
("CLIENT_WEBSITE", Website),
|
||||
("CLIENT_LFBISNR", LfbisNr),
|
||||
("CLIENT_USTIDNR", UstIdNr),
|
||||
("CLIENT_BIC", Bic),
|
||||
("CLIENT_IBAN", Iban),
|
||||
("DELIVERY_OBLIGATION", DeliveryObligation.ToString()),
|
||||
("DELIVERY_RIGHT", DeliveryRight.ToString()),
|
||||
("VAT_NORMAL", VatNormal.ToString().Replace(",", ".")),
|
||||
("VAT_REDUCED", VatReduced.ToString().Replace(",", ".")),
|
||||
("VAT_FLATRATE", VatFlatRate.ToString().Replace(",", ".")),
|
||||
("DOCUMENT_SENDER", Sender2),
|
||||
("TEXT_DELIVERYNOTE", TextDeliveryNote),
|
||||
};
|
||||
}
|
||||
|
||||
public async Task UpdateValues() {
|
||||
using var cnx = await AppDbContext.ConnectAsync();
|
||||
using var cmd = cnx.CreateCommand();
|
||||
var pv = GetParamValues();
|
||||
cmd.CommandText = "INSERT INTO client_parameter (param, value) VALUES " +
|
||||
string.Join(", ", pv.Select((pv, i) => $"(@p{i}, " + (pv.Item2 != null ? $"@v{i}" : "NULL") + ")")) +
|
||||
" ON CONFLICT DO UPDATE SET value = excluded.value";
|
||||
|
||||
int i = 0;
|
||||
foreach (var (p, v) in pv) {
|
||||
cmd.Parameters.Add(new SqliteParameter($"@p{i}", p));
|
||||
if (v != null)
|
||||
cmd.Parameters.Add(new SqliteParameter($"@v{i}", v));
|
||||
i++;
|
||||
}
|
||||
|
||||
await cmd.ExecuteNonQueryAsync();
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,7 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using IniParser;
|
||||
using IniParser.Model;
|
||||
|
||||
@@ -11,8 +10,9 @@ namespace Elwig.Helpers {
|
||||
private readonly string FileName;
|
||||
public string DatabaseFile = App.DataPath + "database.sqlite3";
|
||||
public string? DatabaseLog = null;
|
||||
public IEnumerable<string[]> Scales;
|
||||
private readonly LinkedList<string[]> ScaleList = new();
|
||||
public string? Branch = null;
|
||||
public IList<string?[]> Scales;
|
||||
private readonly List<string?[]> ScaleList = new();
|
||||
|
||||
public Config(string filename) {
|
||||
FileName = filename;
|
||||
@@ -24,7 +24,7 @@ namespace Elwig.Helpers {
|
||||
var parser = new FileIniDataParser();
|
||||
IniData? ini = null;
|
||||
try {
|
||||
ini = parser.ReadFile(FileName, Encoding.UTF8);
|
||||
ini = parser.ReadFile(FileName, Utils.UTF8);
|
||||
} catch {}
|
||||
|
||||
if (ini == null || !ini.TryGetKey("database.file", out string db)) {
|
||||
@@ -43,20 +43,35 @@ namespace Elwig.Helpers {
|
||||
DatabaseLog = App.DataPath + log;
|
||||
}
|
||||
|
||||
if (ini == null || !ini.TryGetKey("general.branch", out string branch)) {
|
||||
Branch = null;
|
||||
} else {
|
||||
Branch = branch;
|
||||
}
|
||||
|
||||
ScaleList.Clear();
|
||||
Scales = ScaleList;
|
||||
if (ini != null) {
|
||||
foreach (var s in ini.Sections.Where(s => s.SectionName.StartsWith("scale."))) {
|
||||
ScaleList.AddLast(new string[] {
|
||||
string? scaleLog = null;
|
||||
if (s.Keys["log"] != null) {
|
||||
scaleLog = s.Keys["log"];
|
||||
if (scaleLog.Length <= 1 || (scaleLog[1] != ':' && scaleLog[0] != '/' && scaleLog[0] != '\\')) {
|
||||
scaleLog = App.DataPath + scaleLog;
|
||||
}
|
||||
}
|
||||
ScaleList.Add(new string?[] {
|
||||
s.SectionName[6..], s.Keys["type"], s.Keys["model"], s.Keys["connection"],
|
||||
s.Keys["empty"], s.Keys["filling"], s.Keys["limit"]
|
||||
s.Keys["empty"], s.Keys["filling"], s.Keys["limit"], scaleLog
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Write() {
|
||||
using var file = new StreamWriter(FileName, false, Encoding.UTF8);
|
||||
using var file = new StreamWriter(FileName, false, Utils.UTF8);
|
||||
file.Write($"\r\n[general]\r\n");
|
||||
if (Branch != null) file.Write($"branch = {Branch}\r\n");
|
||||
file.Write($"\r\n[database]\r\nfile = {DatabaseFile}\r\n");
|
||||
if (DatabaseLog != null) file.Write($"log = {DatabaseLog}\r\n");
|
||||
foreach (var s in ScaleList) {
|
||||
@@ -64,6 +79,7 @@ namespace Elwig.Helpers {
|
||||
if (s[4] != null) file.Write($"empty = {s[4]}\r\n");
|
||||
if (s[5] != null) file.Write($"filling = {s[5]}\r\n");
|
||||
if (s[6] != null) file.Write($"limit = {s[6]}\r\n");
|
||||
if (s[7] != null) file.Write($"log = {s[7]}\r\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
223
Elwig/Helpers/ControlUtils.cs
Normal file
223
Elwig/Helpers/ControlUtils.cs
Normal file
@@ -0,0 +1,223 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace Elwig.Helpers {
|
||||
public class ControlUtils {
|
||||
|
||||
public enum RenewSourceDefault {
|
||||
None,
|
||||
IfOnly,
|
||||
First
|
||||
}
|
||||
|
||||
private static void SetControlBrush(Control input, Brush brush) {
|
||||
if (input is ComboBox cb) {
|
||||
var border = GetComboBoxBorder(cb);
|
||||
if (border != null) border.BorderBrush = brush;
|
||||
} else {
|
||||
input.BorderBrush = brush;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetInputNotDefault(Control input) {
|
||||
SetControlBrush(input, Brushes.Gold);
|
||||
}
|
||||
|
||||
public static void SetInputChanged(Control input) {
|
||||
SetControlBrush(input, Brushes.Orange);
|
||||
}
|
||||
|
||||
public static void SetInputInvalid(Control input) {
|
||||
SetControlBrush(input, Brushes.Red);
|
||||
}
|
||||
|
||||
public static void ClearInputState(Control input) {
|
||||
if (input is ComboBox cb) {
|
||||
GetComboBoxBorder(cb)?.ClearValue(Border.BorderBrushProperty);
|
||||
} else {
|
||||
input.ClearValue(Control.BorderBrushProperty);
|
||||
}
|
||||
}
|
||||
|
||||
private static Border? GetComboBoxBorder(ComboBox cb) {
|
||||
var toggleButton = cb.Template.FindName("toggleButton", cb) as ToggleButton;
|
||||
return toggleButton?.Template.FindName("templateRoot", toggleButton) as Border;
|
||||
}
|
||||
|
||||
public static IEnumerable<T> FindAllChildren<T>(DependencyObject depObj) where T : DependencyObject {
|
||||
if (depObj == null)
|
||||
yield return (T)Enumerable.Empty<T>();
|
||||
foreach (var child in LogicalTreeHelper.GetChildren(depObj)) {
|
||||
if (child == null) {
|
||||
continue;
|
||||
} else if (child is T t) {
|
||||
yield return t;
|
||||
} else if (child is DependencyObject childDepOpj) {
|
||||
foreach (T childOfChild in FindAllChildren<T>(childDepOpj)) {
|
||||
yield return childOfChild;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<T> FindAllChildren<T>(DependencyObject depObj, IEnumerable<DependencyObject> exempt) where T : DependencyObject {
|
||||
return FindAllChildren<T>(depObj).Where(c => !exempt.Contains(c));
|
||||
}
|
||||
|
||||
public static T? FindNextSibling<T>(Control me) where T : DependencyObject {
|
||||
var found = false;
|
||||
foreach (var child in LogicalTreeHelper.GetChildren(me.Parent)) {
|
||||
if (found && child is T c) {
|
||||
return c;
|
||||
} else if (child == me) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void RenewItemsSource(Selector selector, IEnumerable? source, Func<object?, object?> getId, SelectionChangedEventHandler? handler = null, RenewSourceDefault def = RenewSourceDefault.None) {
|
||||
if (selector.ItemsSource == source)
|
||||
return;
|
||||
var selectedId = getId(selector.SelectedItem);
|
||||
object? selItem = null;
|
||||
if (selectedId != null && source != null)
|
||||
selItem = source.Cast<object>().FirstOrDefault(i => selectedId.Equals(getId(i)));
|
||||
if (source != null && selItem == null) {
|
||||
if ((def == RenewSourceDefault.IfOnly && source.Cast<object>().Count() == 1) || def == RenewSourceDefault.First) {
|
||||
selItem = source.Cast<object>().First();
|
||||
}
|
||||
}
|
||||
if (handler != null && selItem != null) selector.SelectionChanged -= handler;
|
||||
selector.ItemsSource = source;
|
||||
if (handler != null && selItem != null) selector.SelectionChanged += handler;
|
||||
selector.SelectedItem = selItem;
|
||||
}
|
||||
|
||||
public static void RenewItemsSource(Xceed.Wpf.Toolkit.Primitives.Selector selector, IEnumerable? source, Func<object?, object?> getId) {
|
||||
if (selector.ItemsSource == source)
|
||||
return;
|
||||
var selectedIds = selector.SelectedItems.Cast<object>().Select(i => getId(i)).ToList();
|
||||
selector.ItemsSource = source;
|
||||
if (source != null) {
|
||||
selector.SelectedItems.Clear();
|
||||
foreach (var i in source.Cast<object>().Where(i => selectedIds.Contains(getId(i))))
|
||||
selector.SelectedItems.Add(i);
|
||||
}
|
||||
}
|
||||
|
||||
public static void RenewItemsSource(DataGrid dataGrid, IEnumerable? source, Func<object?, object?> getId, SelectionChangedEventHandler? handler = null, RenewSourceDefault def = RenewSourceDefault.None, bool keepSort = true) {
|
||||
if (dataGrid.ItemsSource == source)
|
||||
return;
|
||||
var column = dataGrid.CurrentCell.Column;
|
||||
var sortColumns = dataGrid.Columns.Select(c => c.SortDirection).ToList();
|
||||
var sort = dataGrid.Items.SortDescriptions.ToList();
|
||||
var selectedId = getId(dataGrid.SelectedItem);
|
||||
object? selItem = null;
|
||||
if (selectedId != null && source != null)
|
||||
selItem = source.Cast<object>().FirstOrDefault(i => selectedId.Equals(getId(i)));
|
||||
if (source != null && selItem == null) {
|
||||
if ((def == RenewSourceDefault.IfOnly && source.Cast<object>().Count() == 1) || def == RenewSourceDefault.First) {
|
||||
selItem = source.Cast<object>().First();
|
||||
}
|
||||
}
|
||||
if (handler != null && selItem != null) dataGrid.SelectionChanged -= handler;
|
||||
dataGrid.ItemsSource = source;
|
||||
if (handler != null && selItem != null) dataGrid.SelectionChanged += handler;
|
||||
dataGrid.SelectedItem = selItem;
|
||||
if (keepSort) {
|
||||
for (int i = 0; i < dataGrid.Columns.Count; i++)
|
||||
dataGrid.Columns[i].SortDirection = sortColumns[i];
|
||||
foreach (var s in sort)
|
||||
dataGrid.Items.SortDescriptions.Add(s);
|
||||
}
|
||||
if (dataGrid.SelectedItem != null && column != null)
|
||||
dataGrid.CurrentCell = new(dataGrid.SelectedItem, column);
|
||||
}
|
||||
|
||||
public static void RenewItemsSource(ListBox listBox, IEnumerable? source, Func<object?, object?> getId, SelectionChangedEventHandler? handler = null, RenewSourceDefault def = RenewSourceDefault.None) {
|
||||
if (listBox.ItemsSource == source)
|
||||
return;
|
||||
var selectedId = getId(listBox.SelectedItem);
|
||||
object? selItem = null;
|
||||
if (selectedId != null && source != null)
|
||||
selItem = source.Cast<object>().FirstOrDefault(i => selectedId.Equals(getId(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;
|
||||
}
|
||||
|
||||
public static object? GetItemFromSource(IEnumerable source, Func<object?, object?> getId, object? id) {
|
||||
if (source == null)
|
||||
return null;
|
||||
var items = source.Cast<object>();
|
||||
var item = items.Where(i => getId(i)?.Equals(id) ?? false).FirstOrDefault();
|
||||
if (item == null && items.Any(i => i is NullItem))
|
||||
return items.Where(i => i is NullItem).First();
|
||||
return item;
|
||||
}
|
||||
|
||||
public static object? GetItemFromSource(IEnumerable source, object? item, Func<object?, object?> getId) {
|
||||
return GetItemFromSource(source, getId, getId(item));
|
||||
}
|
||||
|
||||
public static void SelectComboBoxItem(ComboBox cb, Func<object?, object?> getId, object? id) {
|
||||
cb.SelectedItem = GetItemFromSource(cb.ItemsSource, getId, id);
|
||||
}
|
||||
|
||||
public static void SelectComboBoxItem(ComboBox cb, object? item, Func<object?, object?> getId) {
|
||||
SelectComboBoxItem(cb, getId, getId(item));
|
||||
}
|
||||
|
||||
public static IEnumerable<object?> GetItemsFromSource(IEnumerable source, Func<object?, object?> getId, IEnumerable<object?> ids) {
|
||||
if (source == null)
|
||||
return Array.Empty<object>();
|
||||
return source.Cast<object>().Where(i => ids.Any(c => c?.Equals(getId(i)) ?? false));
|
||||
}
|
||||
|
||||
public static IEnumerable<object?> GetItemsFromSource(IEnumerable source, IEnumerable<object?>? items, Func<object?, object?> getId) {
|
||||
if (items == null)
|
||||
return Array.Empty<object>();
|
||||
return GetItemsFromSource(source, getId, items.Select(i => getId(i)));
|
||||
}
|
||||
|
||||
public static void SelectCheckComboBoxItems(Xceed.Wpf.Toolkit.CheckComboBox ccb, Func<object?, object?> getId, IEnumerable<object?>? ids) {
|
||||
ccb.SelectedItems.Clear();
|
||||
if (ids == null) return;
|
||||
foreach (var id in ids)
|
||||
ccb.SelectedItems.Add(GetItemFromSource(ccb.ItemsSource, getId, id));
|
||||
}
|
||||
|
||||
public static void SelectCheckComboBoxItems(Xceed.Wpf.Toolkit.CheckComboBox ccb, IEnumerable<object>? items, Func<object?, object?> getId) {
|
||||
SelectCheckComboBoxItems(ccb, getId, items?.Select(i => getId(i)));
|
||||
}
|
||||
|
||||
public static object? GetInputValue(Control input) {
|
||||
if (input is TextBox tb) {
|
||||
return tb.Text;
|
||||
} else if (input is ComboBox sb) {
|
||||
return sb.SelectedItem;
|
||||
} else if (input is Xceed.Wpf.Toolkit.CheckComboBox ccb) {
|
||||
return ccb.SelectedItems.Cast<object>().ToArray();
|
||||
} else if (input is CheckBox cb) {
|
||||
return cb.IsChecked?.ToString();
|
||||
} else if (input is RadioButton rb) {
|
||||
return rb.IsChecked?.ToString();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
67
Elwig/Helpers/Export/Bki.cs
Normal file
67
Elwig/Helpers/Export/Bki.cs
Normal file
@@ -0,0 +1,67 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
|
||||
namespace Elwig.Helpers.Export {
|
||||
|
||||
using Row = Tuple<(string?, string?, string?, string?, string, int, string, int), (string, int, string, string, string, int, string, double, double)>;
|
||||
|
||||
public class Bki : Csv<Row> {
|
||||
|
||||
private readonly string _clientData;
|
||||
|
||||
public Bki(string filename) : base(filename, ';', Encoding.Latin1) {
|
||||
Header = """
|
||||
EDV-Liste zum automatischen Einlesen in die Weindatenbank;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
Stammdaten;;;;;;;;;;;;;;Transportschein;;;;;;;;;;;;;;;;
|
||||
Empfänger:;;;;;;;Versender:;;;;;;;;;;;;;;;;;;;;;;;
|
||||
Betriebsnr;Name od. Firmenname;Vorname;Straße;Hausnr;Plz;Ort;Betriebsnr;Name od. Firmenname;Vorname;Straße;Hausnr;Plz;Ort;Datum der Lieferung;Menge in kg;Art;Weiß;Rot;Sorte1;Sorte2;Sorte3;Qualitätsstufe;Jahrgang;Herkunft;°KMW;°Oe;Vollablieferer;Ha Gesamt;Ha Ertragsfähig;Flächenbindung in Ha für AMA
|
||||
""";
|
||||
var c = App.Client;
|
||||
var (a1, a2) = Utils.SplitAddress(c.Address);
|
||||
_clientData = $"{c.LfbisNr};{c.NameFull};;{a1};{a2};{c.Plz};{c.Ort}";
|
||||
}
|
||||
|
||||
public async Task ExportAsync(int year) {
|
||||
using var cnx = await AppDbContext.ConnectAsync();
|
||||
using var cmd = cnx.CreateCommand();
|
||||
cmd.CommandText = $"""
|
||||
SELECT lfbis_nr, family_name, name, billing_name, address, plz, ort, area,
|
||||
date, weight, type, sortid, qualid, year, hkid, kmw, oe
|
||||
FROM v_bki_delivery
|
||||
WHERE year = {year}
|
||||
""";
|
||||
var r = await cmd.ExecuteReaderAsync();
|
||||
List<Row> rows = new();
|
||||
while (await r.ReadAsync()) {
|
||||
rows.Add(new(
|
||||
(r.IsDBNull(0) ? null : r.GetString(0), r.IsDBNull(1) ? null : r.GetString(1), r.IsDBNull(2) ? null : r.GetString(2), r.IsDBNull(3) ? null : r.GetString(3), r.GetString(4), r.GetInt32(5), r.GetString(6), r.GetInt32(7)),
|
||||
(r.GetString(8), r.GetInt32(9), r.GetString(10), r.GetString(11), r.GetString(12), r.GetInt32(13), r.GetString(14), r.GetDouble(15), r.GetDouble(16))
|
||||
));
|
||||
}
|
||||
|
||||
await ExportAsync(rows);
|
||||
}
|
||||
|
||||
public void Export(int year) {
|
||||
ExportAsync(year).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
public override string FormatRow(Row row) {
|
||||
var (member, delivery) = row;
|
||||
var (lfBisNr, familyName, name, billingName, address, plz, ort, area) = member;
|
||||
var (date, weight, type, sortid, qualid, year, hkid, kmw, oe) = delivery;
|
||||
|
||||
var (n1, n2) = billingName == null ? (familyName, name) : Utils.SplitName(billingName, familyName);
|
||||
var (a1, a2) = Utils.SplitAddress(address);
|
||||
var memberData = $"{lfBisNr};{n1};{n2};{a1};{a2};{plz};{ort}";
|
||||
var deliveryData = $"{string.Join(".", date.Split("-").Reverse())};{weight};TB;{(type == "W" ? "J" : "")};{(type == "R" ? "J" : "")};{sortid};;;{qualid};{year};{hkid};{kmw:0.0};{oe:0}";
|
||||
var vollData = $"N;;;{area / 10_000.0}";
|
||||
|
||||
return $"{_clientData};{memberData};{deliveryData};{vollData}";
|
||||
}
|
||||
}
|
||||
}
|
61
Elwig/Helpers/Export/Csv.cs
Normal file
61
Elwig/Helpers/Export/Csv.cs
Normal file
@@ -0,0 +1,61 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Elwig.Helpers.Export {
|
||||
public abstract class Csv<T> : IExporter<T> {
|
||||
|
||||
public static string FileExtension => "csv";
|
||||
|
||||
private readonly StreamWriter _writer;
|
||||
protected readonly char Separator;
|
||||
protected string? Header;
|
||||
|
||||
public Csv(string filename, char separator = ';') : this(filename, separator, Utils.UTF8) { }
|
||||
|
||||
public Csv(string filename, char separator, Encoding encoding) {
|
||||
_writer = new StreamWriter(filename, false, encoding);
|
||||
Separator = separator;
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
GC.SuppressFinalize(this);
|
||||
_writer.Dispose();
|
||||
}
|
||||
|
||||
public ValueTask DisposeAsync() {
|
||||
GC.SuppressFinalize(this);
|
||||
return _writer.DisposeAsync();
|
||||
}
|
||||
|
||||
public async Task ExportAsync(IEnumerable<T> data, IProgress<double>? progress = null) {
|
||||
progress?.Report(0.0);
|
||||
int count = data.Count() + 2, i = 0;
|
||||
|
||||
if (Header != null) await _writer.WriteLineAsync(Header);
|
||||
progress?.Report(100.0 * ++i / count);
|
||||
|
||||
foreach (var row in data) {
|
||||
await _writer.WriteLineAsync(FormatRow(row));
|
||||
progress?.Report(100.0 * ++i / count);
|
||||
}
|
||||
|
||||
await _writer.FlushAsync();
|
||||
progress?.Report(100.0);
|
||||
}
|
||||
|
||||
public void Export(IEnumerable<T> data, IProgress<double>? progress = null) {
|
||||
ExportAsync(data, progress).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
public string FormatRow(IEnumerable row) {
|
||||
return string.Join(Separator, row);
|
||||
}
|
||||
|
||||
public abstract string FormatRow(T row);
|
||||
}
|
||||
}
|
109
Elwig/Helpers/Export/Ebics.cs
Normal file
109
Elwig/Helpers/Export/Ebics.cs
Normal file
@@ -0,0 +1,109 @@
|
||||
using Elwig.Helpers.Billing;
|
||||
using Elwig.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Elwig.Helpers.Export {
|
||||
public class Ebics : IBankingExporter {
|
||||
|
||||
public static string FileExtension => "xml";
|
||||
|
||||
private readonly StreamWriter _writer;
|
||||
private readonly DateOnly _date;
|
||||
private readonly int _year;
|
||||
private readonly string _name;
|
||||
private readonly int _nr;
|
||||
|
||||
public Ebics(PaymentVar variant, string filename) {
|
||||
_writer = new(filename, false, Utils.UTF8);
|
||||
_date = variant.TransferDate ?? DateOnly.Parse("2021-01-10"); //throw new ArgumentException("TransferDate has to be set in PaymentVar");
|
||||
_year = variant.Year;
|
||||
_name = variant.Name;
|
||||
_nr = variant.AvNr;
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
GC.SuppressFinalize(this);
|
||||
_writer.Dispose();
|
||||
}
|
||||
|
||||
public ValueTask DisposeAsync() {
|
||||
GC.SuppressFinalize(this);
|
||||
return _writer.DisposeAsync();
|
||||
}
|
||||
|
||||
public void Export(IEnumerable<Transaction> transactions, IProgress<double>? progress = null) {
|
||||
ExportAsync(transactions, progress).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
public async Task ExportAsync(IEnumerable<Transaction> transactions, IProgress<double>? progress = null) {
|
||||
progress?.Report(0.0);
|
||||
var nbOfTxs = transactions.Count();
|
||||
int count = nbOfTxs + 2, i = 0;
|
||||
var ctrlSum = Transaction.FormatAmountCent(transactions.Sum(tx => tx.AmountCent));
|
||||
var msgId = $"ELWIG-{App.Client.NameToken}-{_year}-AV{_nr:00}";
|
||||
var pmtInfId = $"{msgId}-1";
|
||||
|
||||
await _writer.WriteLineAsync($"""
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.001.001.09"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="urn:iso:std:iso:20022:tech:xsd:pain.001.001.09 pain.001.001.09.xsd">
|
||||
<CstmrCdtTrfInitn>
|
||||
<GrpHdr>
|
||||
<MsgId>{msgId}</MsgId>
|
||||
<CreDtTm>{DateTime.UtcNow:o}</CreDtTm>
|
||||
<NbOfTxs>{nbOfTxs}</NbOfTxs>
|
||||
<CtrlSum>{ctrlSum}</CtrlSum>
|
||||
<InitgPty><Nm>{App.Client.NameFull}</Nm></InitgPty>
|
||||
</GrpHdr>
|
||||
<PmtInf>
|
||||
<PmtInfId>{pmtInfId}</PmtInfId>
|
||||
<PmtMtd>TRF</PmtMtd>
|
||||
<NbOfTxs>{nbOfTxs}</NbOfTxs>
|
||||
<CtrlSum>{ctrlSum}</CtrlSum>
|
||||
<ReqdExctnDt><Dt>{_date:yyyy-MM-dd}</Dt></ReqdExctnDt>
|
||||
<Dbtr><Nm>{App.Client.NameFull}</Nm></Dbtr>
|
||||
<DbtrAcct><Id><IBAN>{App.Client.Iban?.Replace(" ", "")}</IBAN></Id></DbtrAcct>
|
||||
<DbtrAgt><FinInstnId><BICFI>{App.Client.Bic ?? "NOTPROVIDED"}</BICFI></FinInstnId></DbtrAgt>
|
||||
""");
|
||||
progress?.Report(100.0 * ++i / count);
|
||||
|
||||
foreach (var tx in transactions) {
|
||||
var a = (IAddress?)tx.Member.BillingAddress ?? tx.Member;
|
||||
var (a1, a2) = Utils.SplitAddress(a.Address);
|
||||
var id = $"ELWIG-{App.Client.NameToken}-{_year}-TG{tx.Nr:0000}";
|
||||
var info = $"{_name} - Traubengutschrift {_year}/{tx.Nr:000}";
|
||||
await _writer.WriteLineAsync($"""
|
||||
<CdtTrfTxInf>
|
||||
<PmtId><EndToEndId>{id}</EndToEndId></PmtId>
|
||||
<Amt><InstdAmt Ccy="{tx.Currency}">{Transaction.FormatAmountCent(tx.AmountCent)}</InstdAmt></Amt>
|
||||
<Cdtr>
|
||||
<Nm>{a.Name}</Nm>
|
||||
<PstlAdr>
|
||||
<StrtNm>{a1}</StrtNm><BldgNb>{a2}</BldgNb>
|
||||
<PstCd>{a.PostalDest.AtPlz?.Plz}</PstCd><TwnNm>{a.PostalDest.AtPlz?.Ort.Name}</TwnNm>
|
||||
<Ctry>{a.PostalDest.Country.Alpha2}</Ctry>
|
||||
</PstlAdr>
|
||||
</Cdtr>
|
||||
<CdtrAcct><Id><IBAN>{tx.Member.Iban}</IBAN></Id><CdtrAcct>
|
||||
<CdtrAgt><FinInstnId><BICFI>{tx.Member.Bic ?? "NOTPROVIDED"}</BICFI></FinInstnId></CdtrAgt>
|
||||
<RmtInf><Ustrd>{info}</Ustrd></RmtInf>
|
||||
</CdtTrfTxInf>
|
||||
""");
|
||||
progress?.Report(100.0 * ++i / count);
|
||||
}
|
||||
|
||||
await _writer.WriteLineAsync("""
|
||||
</PmtInf>
|
||||
</CstmrCdtTrfInitn>
|
||||
</Document>
|
||||
""");
|
||||
await _writer.FlushAsync();
|
||||
progress?.Report(100.0);
|
||||
}
|
||||
}
|
||||
}
|
15
Elwig/Helpers/Export/Elba.cs
Normal file
15
Elwig/Helpers/Export/Elba.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using Elwig.Helpers.Billing;
|
||||
using System;
|
||||
|
||||
namespace Elwig.Helpers.Export {
|
||||
public class Elba : Csv<Transaction>, IBankingExporter {
|
||||
|
||||
public static new string FileExtension => "elba";
|
||||
|
||||
public Elba(string filename) : base(filename) { }
|
||||
|
||||
public override string FormatRow(Transaction row) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
8
Elwig/Helpers/Export/IBankingExporter.cs
Normal file
8
Elwig/Helpers/Export/IBankingExporter.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using Elwig.Helpers.Billing;
|
||||
|
||||
namespace Elwig.Helpers.Export {
|
||||
/// <summary>
|
||||
/// Interface for exporting banking data
|
||||
/// </summary>
|
||||
public interface IBankingExporter : IExporter<Transaction> { }
|
||||
}
|
26
Elwig/Helpers/Export/IExporter.cs
Normal file
26
Elwig/Helpers/Export/IExporter.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Elwig.Helpers.Export {
|
||||
public interface IExporter<T> : IDisposable, IAsyncDisposable {
|
||||
/// <summary>
|
||||
/// The default file extension of the exported files to be used (whithout a preceding ".")
|
||||
/// </summary>
|
||||
static abstract string FileExtension { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Export the given data to the given file.
|
||||
/// </summary>
|
||||
/// <param name="data">The data to be exported</param>
|
||||
/// <param name="progress">The progress object to report to</param>
|
||||
void Export(IEnumerable<T> data, IProgress<double>? progress = null);
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronosly export the given data to the given file.
|
||||
/// </summary>
|
||||
/// <param name="data">The data to be exported</param>
|
||||
/// <param name="progress">The progress object to report to</param>
|
||||
Task ExportAsync(IEnumerable<T> data, IProgress<double>? progress = null);
|
||||
}
|
||||
}
|
9
Elwig/Helpers/IAddress.cs
Normal file
9
Elwig/Helpers/IAddress.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using Elwig.Models;
|
||||
|
||||
namespace Elwig.Helpers {
|
||||
public interface IAddress {
|
||||
string Name { get; }
|
||||
string Address { get; }
|
||||
PostalDest PostalDest { get; }
|
||||
}
|
||||
}
|
5
Elwig/Helpers/NullItem.cs
Normal file
5
Elwig/Helpers/NullItem.cs
Normal file
@@ -0,0 +1,5 @@
|
||||
namespace Elwig.Helpers {
|
||||
public class NullItem {
|
||||
public static string Name => "- Keine Angabe -";
|
||||
}
|
||||
}
|
@@ -8,7 +8,7 @@ namespace Elwig.Helpers {
|
||||
|
||||
public TempFile() : this(null) { }
|
||||
|
||||
public TempFile(string? ext) : this(Path.Combine(Path.GetTempPath(), "Elwig"), ext) { }
|
||||
public TempFile(string? ext) : this(App.TempPath, ext) { }
|
||||
|
||||
public TempFile(string dir, string? ext) {
|
||||
FilePath = Path.Combine(dir, Path.GetRandomFileName().Replace(".", "") + (ext != null ? $".{ext}" : ""));
|
||||
|
@@ -2,32 +2,88 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Media;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Diagnostics;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.IO.Ports;
|
||||
using PdfSharp.Charting;
|
||||
using System.Net.Sockets;
|
||||
using Elwig.Dialogs;
|
||||
using System.Text;
|
||||
using System.Numerics;
|
||||
using Elwig.Models;
|
||||
|
||||
namespace Elwig.Helpers {
|
||||
public static partial class Utils {
|
||||
|
||||
public static int CurrentSeason => DateTime.Now.Year - (DateTime.Now.Month <= 3 ? 1 : 0);
|
||||
public static readonly Encoding UTF8 = new UTF8Encoding(false, true);
|
||||
|
||||
public static int CurrentYear => DateTime.Now.Year;
|
||||
public static int CurrentNextSeason => DateTime.Now.Year - (DateTime.Now.Month <= 3 ? 1 : 0);
|
||||
public static int CurrentLastSeason => DateTime.Now.Year - (DateTime.Now.Month <= 7 ? 1 : 0);
|
||||
public static DateTime Today => (DateTime.Now.Hour >= 3) ? DateTime.Today : DateTime.Today.AddDays(-1);
|
||||
|
||||
public static readonly Regex SerialRegex = GeneratedSerialRegex();
|
||||
public static readonly Regex TcpRegex = GeneratedTcpRegex();
|
||||
public static readonly Regex PartialDateRegex = GeneratedPartialDateRegex();
|
||||
public static readonly Regex FromToRegex = GeneratedFromToRegex();
|
||||
public static readonly Regex FromToTimeRegex = GeneratedFromToTimeRegex();
|
||||
public static readonly Regex AddressRegex = GeneratedAddressRegex();
|
||||
|
||||
[GeneratedRegex("^serial://([A-Za-z0-9]+):([0-9]+)(,([5-9]),([NOEMSnoems]),(0|1|1\\.5|2|))?$", RegexOptions.Compiled)]
|
||||
private static partial Regex GeneratedSerialRegex();
|
||||
|
||||
[GeneratedRegex("^tcp://[A-Za-z0-9:._-]+(:[0-9]+)?$", RegexOptions.Compiled)]
|
||||
[GeneratedRegex("^tcp://([A-Za-z0-9._-]+):([0-9]+)$", RegexOptions.Compiled)]
|
||||
private static partial Regex GeneratedTcpRegex();
|
||||
|
||||
[GeneratedRegex(@"^(0?[1-9]|[12][0-9]|3[01])\.(0?[1-9]|1[0-2])\.$", RegexOptions.Compiled)]
|
||||
private static partial Regex GeneratedPartialDateRegex();
|
||||
|
||||
[GeneratedRegex(@"^([0-9]+([\.,][0-9]+)?)?-([0-9]+([\.,][0-9]+)?)?$", RegexOptions.Compiled)]
|
||||
private static partial Regex GeneratedFromToRegex();
|
||||
|
||||
[GeneratedRegex(@"^([0-9]{1,2}:[0-9]{2})?-([0-9]{1,2}:[0-9]{2})?$", RegexOptions.Compiled)]
|
||||
private static partial Regex GeneratedFromToTimeRegex();
|
||||
|
||||
[GeneratedRegex(@"^(.*?) +([0-9].*)$", RegexOptions.Compiled)]
|
||||
private static partial Regex GeneratedAddressRegex();
|
||||
|
||||
private static readonly ushort[] Crc16ModbusTable = {
|
||||
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
|
||||
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
|
||||
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
|
||||
0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
|
||||
0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
|
||||
0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
|
||||
0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
|
||||
0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
|
||||
0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
|
||||
0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
|
||||
0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
|
||||
0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
|
||||
0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
|
||||
0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
|
||||
0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
|
||||
0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
|
||||
0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
|
||||
0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
|
||||
0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
|
||||
0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
|
||||
0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
|
||||
0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
|
||||
0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
|
||||
0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
|
||||
0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
|
||||
0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
|
||||
0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
|
||||
0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
|
||||
0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
|
||||
0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
|
||||
0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
|
||||
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040,
|
||||
};
|
||||
|
||||
public static SerialPort OpenSerialConnection(string connection) {
|
||||
var m = Utils.SerialRegex.Match(connection);
|
||||
var m = SerialRegex.Match(connection);
|
||||
if (!m.Success)
|
||||
throw new ArgumentException("Invalid connection string for scheme \"serial\"");
|
||||
|
||||
@@ -45,93 +101,28 @@ namespace Elwig.Helpers {
|
||||
DataBits = data == "" ? 8 : int.Parse(data),
|
||||
StopBits = (StopBits)(stop == "" ? 1 : stop == "1.5" ? 3 : stop[0] - '0'),
|
||||
Handshake = Handshake.None,
|
||||
WriteTimeout = 250,
|
||||
ReadTimeout = 11000,
|
||||
};
|
||||
port.Open();
|
||||
return port;
|
||||
}
|
||||
|
||||
public static TcpClient OpenTcpConnection(string connection) {
|
||||
var m = Utils.TcpRegex.Match(connection);
|
||||
var m = TcpRegex.Match(connection);
|
||||
if (!m.Success)
|
||||
throw new ArgumentException("Invalid connection string for scheme \"tcp\"");
|
||||
|
||||
var client = new TcpClient() {
|
||||
SendTimeout = 250,
|
||||
ReceiveTimeout = 250,
|
||||
ReceiveTimeout = 11000,
|
||||
};
|
||||
client.Connect(m.Groups[1].Value, int.Parse(m.Groups[2].Value));
|
||||
return client;
|
||||
}
|
||||
|
||||
public static void SetInputChanged(Control input) {
|
||||
var brush = Brushes.Orange;
|
||||
if (input is ComboBox cb) {
|
||||
var border = GetComboBoxBorder(cb);
|
||||
if (border != null)
|
||||
border.BorderBrush = brush;
|
||||
} else {
|
||||
input.BorderBrush = brush;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetInputInvalid(Control input) {
|
||||
var brush = Brushes.Red;
|
||||
if (input is ComboBox cb) {
|
||||
var border = GetComboBoxBorder(cb);
|
||||
if (border != null)
|
||||
border.BorderBrush = brush;
|
||||
} else {
|
||||
input.BorderBrush = brush;
|
||||
}
|
||||
}
|
||||
|
||||
public static void ClearInputState(Control input) {
|
||||
if (input is ComboBox cb) {
|
||||
GetComboBoxBorder(cb)?.ClearValue(Border.BorderBrushProperty);
|
||||
} else {
|
||||
input.ClearValue(Control.BorderBrushProperty);
|
||||
}
|
||||
}
|
||||
|
||||
private static Border? GetComboBoxBorder(ComboBox cb) {
|
||||
var toggleButton = cb.Template.FindName("toggleButton", cb) as ToggleButton;
|
||||
return toggleButton?.Template.FindName("templateRoot", toggleButton) as Border;
|
||||
}
|
||||
|
||||
public static IEnumerable<T> FindAllChildren<T>(DependencyObject depObj) where T : DependencyObject {
|
||||
if (depObj == null)
|
||||
yield return (T)Enumerable.Empty<T>();
|
||||
foreach (var child in LogicalTreeHelper.GetChildren(depObj)) {
|
||||
if (child == null) {
|
||||
continue;
|
||||
} else if (child is T t) {
|
||||
yield return t;
|
||||
} else if (child is DependencyObject childDepOpj) {
|
||||
foreach (T childOfChild in FindAllChildren<T>(childDepOpj)) {
|
||||
yield return childOfChild;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<T> FindAllChildren<T>(DependencyObject depObj, IEnumerable<DependencyObject> exempt) where T : DependencyObject {
|
||||
return FindAllChildren<T>(depObj).Where(c => !exempt.Contains(c));
|
||||
}
|
||||
|
||||
public static T? FindNextSibling<T>(Control me) where T : DependencyObject {
|
||||
var found = false;
|
||||
foreach (var child in LogicalTreeHelper.GetChildren(me.Parent)) {
|
||||
if (found && child is T c) {
|
||||
return c;
|
||||
} else if (child == me) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static int Modulo(string a, int b) {
|
||||
if (a.Length == 0 || !a.All(char.IsDigit)) {
|
||||
if (a.Length == 0 || !a.All(char.IsAsciiDigit)) {
|
||||
throw new ArgumentException("First argument has to be a decimal string");
|
||||
} else if (b < 2) {
|
||||
throw new ArgumentException("Second argument has to be greater than 1");
|
||||
@@ -139,6 +130,22 @@ namespace Elwig.Helpers {
|
||||
return a.Select(ch => ch - '0').Aggregate((sum, n) => (sum * 10 + n) % b);
|
||||
}
|
||||
|
||||
public static ushort CalcCrc16Modbus(byte[] data) {
|
||||
// https://www.modbustools.com/modbus_crc16.htm
|
||||
byte temp;
|
||||
ushort crc = 0xFFFF;
|
||||
foreach (byte b in data) {
|
||||
temp = (byte)(b ^ crc);
|
||||
crc >>= 8;
|
||||
crc ^= Crc16ModbusTable[temp];
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
public static ushort CalcCrc16Modbus(string data) {
|
||||
return CalcCrc16Modbus(Encoding.ASCII.GetBytes(data));
|
||||
}
|
||||
|
||||
public static void RunBackground(string title, Func<Task> a) {
|
||||
Task.Run(async () => {
|
||||
try {
|
||||
@@ -173,5 +180,148 @@ namespace Elwig.Helpers {
|
||||
public static long DecToDb(decimal value, byte precision) {
|
||||
return (long)decimal.Round(value * (decimal)Math.Pow(10, precision), 0);
|
||||
}
|
||||
|
||||
public static int GetAge(DateOnly birthday) {
|
||||
var today = DateTime.Today;
|
||||
var a = (today.Year * 100 + today.Month) * 100 + today.Day;
|
||||
var b = (birthday.Year * 100 + birthday.Month) * 100 + birthday.Day;
|
||||
return (a - b) / 10000;
|
||||
}
|
||||
|
||||
public static int GetSearchScore(IEnumerable<string?> words, IEnumerable<string> searchKeywords) {
|
||||
searchKeywords = searchKeywords.Where(s => s.Length >= 2 || (s.Length > 0 && s.All(c => char.IsAsciiDigit(c))));
|
||||
if (!searchKeywords.Any())
|
||||
return 0;
|
||||
|
||||
return words
|
||||
.Select(w => {
|
||||
w = w?.ToLower();
|
||||
var p = w?.ToLower()?.Split(" ");
|
||||
if (w == null || p == null)
|
||||
return 0;
|
||||
|
||||
var t1 = searchKeywords.Where(f => w == f).Select(f => f.Length).OrderDescending().FirstOrDefault(0);
|
||||
var t2 = searchKeywords.Where(f => p.Any(a => a == f)).Select(f => f.Length).OrderDescending().FirstOrDefault(0);
|
||||
var t3 = searchKeywords.Where(f => p.Any(a => a.StartsWith(f))).Select(f => f.Length).OrderDescending().FirstOrDefault(0);
|
||||
var t4 = searchKeywords.Where(f => w.Contains(f)).Select(f => f.Length).OrderDescending().FirstOrDefault(0);
|
||||
if (t1 > 0) {
|
||||
return 4 + t1;
|
||||
} else if (t2 > 0) {
|
||||
return 3 + t2;
|
||||
} else if (t3 > 0) {
|
||||
return 2 + t3;
|
||||
} else if (t4 > 0) {
|
||||
return 1 + t4;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
})
|
||||
.Sum();
|
||||
}
|
||||
|
||||
public static (int, string?)? ShowManualWeighingDialog() {
|
||||
var d = new ManualWeighingDialog();
|
||||
return d.ShowDialog() == true ? (d.Weight, d.Reason) : null;
|
||||
}
|
||||
|
||||
public static int? ShowAbwertenDialog(string lsnr, string name, int weight) {
|
||||
var d = new AbwertenDialog(lsnr, name, weight);
|
||||
return d.ShowDialog() == true ? d.Weight : null;
|
||||
}
|
||||
|
||||
public static double? ShowLinearPriceIncreaseDialog() {
|
||||
var d = new LinearPriceIncreaseDialog();
|
||||
return d.ShowDialog() == true ? d.Price : null;
|
||||
}
|
||||
|
||||
public static string? ShowDeliveryExtractionDialog(string lsnr, string name, bool single, IEnumerable<string> lsnrs) {
|
||||
var d = new DeliveryExtractionDialog(lsnr, name, single, lsnrs);
|
||||
return d.ShowDialog() == true ? d.AddTo : null;
|
||||
}
|
||||
|
||||
public static Footer GenerateFooter(string lineBreak, string seperator) {
|
||||
return new Footer(lineBreak, seperator);
|
||||
}
|
||||
|
||||
public class Footer {
|
||||
private string Text = "";
|
||||
private readonly string LineBreak;
|
||||
private readonly string Seperator;
|
||||
private bool FirstLine = true;
|
||||
private bool FirstItemInLine = true;
|
||||
|
||||
public Footer(string lineBreak, string seperator) {
|
||||
LineBreak = lineBreak;
|
||||
Seperator = seperator;
|
||||
}
|
||||
|
||||
public Footer Item(string? text) {
|
||||
if (text == null) return this;
|
||||
Text += FirstItemInLine ? (FirstLine ? "" : LineBreak) : Seperator;
|
||||
Text += text;
|
||||
FirstLine = false;
|
||||
FirstItemInLine = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Footer Item(string name, string? text) {
|
||||
return text == null ? this : Item($"{name}: {text}");
|
||||
}
|
||||
|
||||
public Footer NextLine() {
|
||||
FirstItemInLine = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return Text;
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetSign<T>(T number) where T : INumber<T>
|
||||
=> T.Sign(number) switch {
|
||||
< 0 => "\u2212", // minus
|
||||
0 => "\u00b1", // plus minus
|
||||
> 0 => "+",
|
||||
};
|
||||
|
||||
public static double AggregateDeliveryPartsKmw(IEnumerable<DeliveryPart> parts)
|
||||
=> parts.Aggregate(
|
||||
(Weight: 0, Kmw: 0.0),
|
||||
(sum, item) => (
|
||||
sum.Weight + item.Weight,
|
||||
(sum.Kmw * sum.Weight + item.Kmw * item.Weight) / (sum.Weight + item.Weight)
|
||||
),
|
||||
sum => sum.Kmw
|
||||
);
|
||||
|
||||
public static string GenerateLsNr(Delivery d) => GenerateLsNr(d.Date, d.ZwstId, d.LNr);
|
||||
|
||||
public static string GenerateLsNr(DateOnly date, string zwstid, int lnr) => $"{date:yyyyMMdd}{zwstid}{lnr:000}";
|
||||
|
||||
public static (string, string?) SplitAddress(string address) {
|
||||
var m = AddressRegex.Match(address);
|
||||
return (m.Groups[1].Value, m.Groups[2].Value);
|
||||
}
|
||||
|
||||
public static (string, string?) SplitName(string fullName, string? familyName) {
|
||||
if (familyName == null || familyName == "") return (fullName, null);
|
||||
var p0 = fullName.ToLower().IndexOf(familyName.ToLower());
|
||||
if (p0 == -1) return (fullName, null);
|
||||
var p1 = fullName.IndexOf(" und ");
|
||||
var p2 = fullName.ToLower().LastIndexOf(" und ");
|
||||
if (p1 != p2) {
|
||||
if (p0 > p1) {
|
||||
// A und B familyName [und ...]
|
||||
return (fullName[p0..^0], fullName[0..(p0 - 1)]);
|
||||
} else {
|
||||
// familyName und ... A und B
|
||||
var p3 = fullName.LastIndexOf(' ', p2 - 1);
|
||||
return (fullName[0..p3], fullName[(p3 + 1)..^0]);
|
||||
}
|
||||
} else {
|
||||
return (familyName, fullName.Replace(familyName, "").Replace(" ", " ").Trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -5,7 +5,7 @@ using System.Windows.Controls;
|
||||
using Elwig.Models;
|
||||
|
||||
namespace Elwig.Helpers {
|
||||
static class Validator {
|
||||
public static class Validator {
|
||||
|
||||
private static readonly Dictionary<string, string[][]> PHONE_NRS = new() {
|
||||
{ "43", new string[][] {
|
||||
@@ -31,15 +31,15 @@ namespace Elwig.Helpers {
|
||||
};
|
||||
|
||||
public static ValidationResult CheckInteger(TextBox input, bool required) {
|
||||
return CheckNumeric(input, required, -1);
|
||||
return CheckInteger(input, required, -1);
|
||||
}
|
||||
|
||||
private static ValidationResult CheckNumeric(TextBox input, bool required, int maxLen) {
|
||||
public static ValidationResult CheckInteger(TextBox input, bool required, int maxLen) {
|
||||
string text = "";
|
||||
int pos = input.CaretIndex;
|
||||
for (int i = 0; i < input.Text.Length; i++) {
|
||||
char ch = input.Text[i];
|
||||
if (char.IsDigit(ch))
|
||||
if (char.IsAsciiDigit(ch))
|
||||
text += ch;
|
||||
if (i == input.CaretIndex - 1)
|
||||
pos = text.Length;
|
||||
@@ -59,15 +59,80 @@ namespace Elwig.Helpers {
|
||||
return new(true, null);
|
||||
}
|
||||
|
||||
public static ValidationResult CheckDecimal(TextBox input, bool required) {
|
||||
return CheckDecimal(input, required, -1, -1);
|
||||
}
|
||||
|
||||
public static ValidationResult CheckDecimal(TextBox input, bool required, int maxLen, int maxDecimal) {
|
||||
string text = "";
|
||||
int pos = input.CaretIndex;
|
||||
int v1 = 0, v2 = -1;
|
||||
for (int i = 0; i < input.Text.Length; i++) {
|
||||
char ch = input.Text[i];
|
||||
if (char.IsAsciiDigit(ch)) {
|
||||
if (v2 == -1 && v1 < maxLen) {
|
||||
text += ch; v1++;
|
||||
} else if (v2 != -1 && v2 < maxDecimal) {
|
||||
text += ch; v2++;
|
||||
}
|
||||
} else if (v2 == 0-1 && ch == ',' || ch == '.') {
|
||||
if (v1 == 0) { text += '0'; v1++; }
|
||||
text += ',';
|
||||
v2 = 0;
|
||||
}
|
||||
if (i == input.CaretIndex - 1)
|
||||
pos = text.Length;
|
||||
}
|
||||
input.Text = text;
|
||||
input.CaretIndex = pos;
|
||||
|
||||
if (text.Length == 0) {
|
||||
return required ? new(false, "Wert ist nicht optional") : new(true, null);
|
||||
} else if (v2 == 0) {
|
||||
return new(false, "Ungültige Kommazahl");
|
||||
}
|
||||
|
||||
return new(true, null);
|
||||
}
|
||||
|
||||
public static ValidationResult CheckUpperCase(TextBox input, bool required) {
|
||||
return CheckUpperCase(input, required, -1);
|
||||
}
|
||||
|
||||
public static ValidationResult CheckUpperCase(TextBox input, bool required, int maxLen) {
|
||||
string text = "";
|
||||
int pos = input.CaretIndex;
|
||||
for (int i = 0; i < input.Text.Length; i++) {
|
||||
char ch = input.Text[i];
|
||||
if (char.IsAsciiLetter(ch))
|
||||
text += char.ToUpper(ch);
|
||||
if (i == input.CaretIndex - 1)
|
||||
pos = text.Length;
|
||||
}
|
||||
input.Text = text;
|
||||
input.CaretIndex = pos;
|
||||
|
||||
if (text.Length == 0) {
|
||||
return required ? new(false, "Wert ist nicht optional") : new(true, null);
|
||||
}
|
||||
|
||||
if (maxLen >= 0 && input.Text.Length > maxLen) {
|
||||
input.Text = input.Text[..maxLen];
|
||||
input.CaretIndex = Math.Min(pos, maxLen);
|
||||
}
|
||||
|
||||
return new(true, null);
|
||||
}
|
||||
|
||||
public static ValidationResult CheckPlz(TextBox input, bool required, AppDbContext ctx) {
|
||||
CheckNumeric(input, false, 4);
|
||||
CheckInteger(input, false, 4);
|
||||
if (!required && input.Text.Length == 0) {
|
||||
return new(true, null);
|
||||
} else if (input.Text.Length != 4) {
|
||||
return new(false, "PLZ zu kurz");
|
||||
}
|
||||
int plz = int.Parse(input.Text);
|
||||
if (!ctx.Postleitzahlen.Any(p => p.Plz == plz)) {
|
||||
if (ctx.Postleitzahlen.Find(plz) == null) {
|
||||
return new(false, "Ungültige PLZ");
|
||||
}
|
||||
return new(true, null);
|
||||
@@ -76,7 +141,7 @@ namespace Elwig.Helpers {
|
||||
public static ValidationResult CheckPhoneNumber(TextBox input, bool required) {
|
||||
string text = "";
|
||||
int pos = input.CaretIndex;
|
||||
for (int i = 0, v = 0; i < input.Text.Length && v < 30; i++) {
|
||||
for (int i = 0, v = 0; i < input.Text.Length && v <= 15; i++) {
|
||||
char ch = input.Text[i];
|
||||
if (v == 0 && input.Text.Length - i >= 2 && ch == '0' && input.Text[i + 1] == '0') {
|
||||
v++; i++;
|
||||
@@ -89,21 +154,30 @@ namespace Elwig.Helpers {
|
||||
} else if (v == 0 && ch == '+') {
|
||||
v++;
|
||||
text += ch;
|
||||
} else if (v > 0 && char.IsDigit(ch)) {
|
||||
} else if (v > 0 && (char.IsAsciiDigit(ch) || ch == ' ' || ch == '-')) {
|
||||
if (PHONE_NRS.Any(kv => text == "+" + kv.Key))
|
||||
text += ' ';
|
||||
if (text.StartsWith("+43 ")) {
|
||||
var nr = text[4..];
|
||||
var vws = PHONE_NRS["43"];
|
||||
if (v >= 4 && v - 4 < vws.Length && vws[v - 4].Any(vw => nr.StartsWith(vw)))
|
||||
if (!text.EndsWith(" ") && v >= 4 && v - 4 < vws.Length && vws[v - 4].Any(vw => nr.StartsWith(vw))) {
|
||||
text += ' ';
|
||||
else if (nr == "1")
|
||||
} else if (nr == "1") {
|
||||
text += ' ';
|
||||
else if (v == 7 && nr.Length == 4)
|
||||
} else if (v == 7 && nr.Length == 4) {
|
||||
text += ' ';
|
||||
}
|
||||
var vw = text.Split(" ");
|
||||
if (char.IsAsciiDigit(ch)) {
|
||||
v++;
|
||||
text += ch;
|
||||
} else if (char.IsAsciiDigit(text[^1]) && vw.Length > 2 && v >= 10 && (vw[1].Length - 1 >= vws.Length || !vws[vw[1].Length - 1].Any(v => vw[1].StartsWith(v)))) {
|
||||
text += ch;
|
||||
}
|
||||
} else {
|
||||
v++;
|
||||
text += ch;
|
||||
}
|
||||
v++;
|
||||
text += ch;
|
||||
}
|
||||
if (i == input.CaretIndex - 1)
|
||||
pos = text.Length;
|
||||
@@ -117,7 +191,7 @@ namespace Elwig.Helpers {
|
||||
return new(false, "Telefonnummer zu kurz");
|
||||
}
|
||||
|
||||
return new(true, null);
|
||||
return new(char.IsAsciiDigit(text[^1]), null);
|
||||
}
|
||||
|
||||
public static ValidationResult CheckEmailAddress(TextBox input, bool required) {
|
||||
@@ -127,7 +201,7 @@ namespace Elwig.Helpers {
|
||||
for (int i = 0; i < input.Text.Length && text.Length < 256; i++) {
|
||||
char ch = input.Text[i];
|
||||
if (domain) {
|
||||
if ((char.IsAscii(ch) && char.IsLetterOrDigit(ch)) || ".-_öäüßÖÄÜẞ".Any(c => c == ch)) {
|
||||
if ((char.IsAsciiLetterOrDigit(ch)) || ".-_öäüßÖÄÜẞ".Any(c => c == ch)) {
|
||||
if (!(text.Last() == '.' && ch == '.'))
|
||||
text += char.ToLower(ch);
|
||||
}
|
||||
@@ -145,13 +219,13 @@ namespace Elwig.Helpers {
|
||||
input.CaretIndex = pos;
|
||||
|
||||
if (text.Length == 0) {
|
||||
return required ? new(false, "E-Mail_Adresse ist nicht optional") : new(true, null);
|
||||
return required ? new(false, "E-Mail-Adresse ist nicht optional") : new(true, null);
|
||||
} else if (text[0] == '@' || !domain) {
|
||||
return new(false, "E-Mail-Adresse ungültig");
|
||||
}
|
||||
|
||||
var last = text.Split(".").Last();
|
||||
if (last.Length < 2 || !last.All(ch => char.IsAscii(ch) && char.IsLower(ch)))
|
||||
if (last.Length < 2 || !last.All(ch => char.IsAsciiLetterLower(ch)))
|
||||
return new(false, "E-Mail-Adresse ungültig");
|
||||
|
||||
return new(true, null);
|
||||
@@ -163,9 +237,9 @@ namespace Elwig.Helpers {
|
||||
int v = 0;
|
||||
for (int i = 0; i < input.Text.Length && v < 34; i++) {
|
||||
char ch = input.Text[i];
|
||||
if (char.IsLetterOrDigit(ch) && char.IsAscii(ch)) {
|
||||
if (((v < 2 && char.IsLetter(ch)) || (v >= 2 && v < 4 && char.IsDigit(ch)) || v >= 4) &&
|
||||
((!text.StartsWith("AT") && !text.StartsWith("DE")) || char.IsDigit(ch)))
|
||||
if (char.IsAsciiLetterOrDigit(ch)) {
|
||||
if (((v < 2 && char.IsAsciiLetter(ch)) || (v >= 2 && v < 4 && char.IsAsciiDigit(ch)) || v >= 4) &&
|
||||
((!text.StartsWith("AT") && !text.StartsWith("DE")) || char.IsAsciiDigit(ch)))
|
||||
{
|
||||
if (v != 0 && v % 4 == 0)
|
||||
text += ' ';
|
||||
@@ -190,7 +264,7 @@ namespace Elwig.Helpers {
|
||||
}
|
||||
|
||||
var validation = (text[4..] + text[..4]).Replace(" ", "")
|
||||
.Select(ch => char.IsDigit(ch) ? ch.ToString() : (ch - 'A' + 10).ToString())
|
||||
.Select(ch => char.IsAsciiDigit(ch) ? ch.ToString() : (ch - 'A' + 10).ToString())
|
||||
.Aggregate((a, b) => a + b);
|
||||
if (Utils.Modulo(validation, 97) != 1)
|
||||
return new(false, "Prüfsumme der IBAN ist falsch");
|
||||
@@ -203,10 +277,10 @@ namespace Elwig.Helpers {
|
||||
int pos = input.CaretIndex;
|
||||
for (int i = 0, v = 0; i < input.Text.Length; i++) {
|
||||
char ch = input.Text[i];
|
||||
if ((v < 4 || v >= 6) && char.IsAscii(ch) && char.IsLetterOrDigit(ch)) {
|
||||
if ((v < 4 || v >= 6) && char.IsAsciiLetterOrDigit(ch)) {
|
||||
v++;
|
||||
text += char.ToUpper(ch);
|
||||
} else if (v >= 4 && v < 6 && char.IsAscii(ch) && char.IsLetter(ch)) {
|
||||
} else if (v >= 4 && v < 6 && char.IsAsciiLetter(ch)) {
|
||||
v++;
|
||||
text += char.ToUpper(ch);
|
||||
}
|
||||
@@ -237,7 +311,7 @@ namespace Elwig.Helpers {
|
||||
}
|
||||
|
||||
public static ValidationResult CheckLfbisNr(TextBox input, bool required) {
|
||||
var res = CheckNumeric(input, false, 7);
|
||||
var res = CheckInteger(input, false, 7);
|
||||
if (!res.IsValid) {
|
||||
return res;
|
||||
} else if (!required && input.Text.Length == 0) {
|
||||
@@ -247,7 +321,7 @@ namespace Elwig.Helpers {
|
||||
}
|
||||
|
||||
// https://statistik.at/fileadmin/shared/QM/Standarddokumentationen/RW/std_r_land-forstw_register.pdf#page=41
|
||||
int s = 0, v = 0;
|
||||
int s = 0, v;
|
||||
for (int i = 0; i < 6; i++)
|
||||
s += (input.Text[i] - '0') * (7 - i);
|
||||
v = (11 - (s % 11)) % 10;
|
||||
@@ -258,20 +332,20 @@ namespace Elwig.Helpers {
|
||||
return new(true, null);
|
||||
}
|
||||
|
||||
public static ValidationResult CheckUstId(TextBox input, bool required) {
|
||||
public static ValidationResult CheckUstIdNr(TextBox input, bool required) {
|
||||
string text = "";
|
||||
int pos = input.CaretIndex;
|
||||
for (int i = 0, v = 0; i < input.Text.Length; i++) {
|
||||
char ch = input.Text[i];
|
||||
if (v < 2 && char.IsAscii(ch) && char.IsLetter(ch)) {
|
||||
if (v < 2 && char.IsAsciiLetter(ch)) {
|
||||
v++;
|
||||
text += char.ToUpper(ch);
|
||||
} else if (v >= 2 && char.IsAscii(ch) && char.IsLetterOrDigit(ch)) {
|
||||
} else if (v >= 2 && char.IsAsciiLetterOrDigit(ch)) {
|
||||
if (text.StartsWith("AT")) {
|
||||
if (v == 2 && (ch == 'u' || ch == 'U')) {
|
||||
v++;
|
||||
text += 'U';
|
||||
} else if (v > 2 && char.IsDigit(ch)) {
|
||||
} else if (v > 2 && char.IsAsciiDigit(ch)) {
|
||||
v++;
|
||||
text += ch;
|
||||
}
|
||||
@@ -302,7 +376,7 @@ namespace Elwig.Helpers {
|
||||
|
||||
// http://www.pruefziffernberechnung.de/U/USt-IdNr.shtml
|
||||
int s = 0, v = 0;
|
||||
for (int i = 0; i < 8; i++)
|
||||
for (int i = 0; i < 7; i++)
|
||||
s += ((text[i + 3] - '0') * (i % 2 + 1)).ToString().Select(ch => ch - '0').Sum();
|
||||
v = (96 - s) % 10;
|
||||
|
||||
@@ -315,7 +389,23 @@ namespace Elwig.Helpers {
|
||||
return new(true, null);
|
||||
}
|
||||
|
||||
public static ValidationResult CheckMgNr(TextBox input, bool required, AppDbContext ctx, Member? m) {
|
||||
public static ValidationResult CheckMgNr(TextBox input, bool required, AppDbContext ctx) {
|
||||
var res = CheckInteger(input, required);
|
||||
if (!res.IsValid) {
|
||||
return res;
|
||||
} else if (!required && input.Text.Length == 0) {
|
||||
return new(true, null);
|
||||
}
|
||||
|
||||
int nr = int.Parse(input.Text);
|
||||
if (!ctx.MgNrExists(nr).GetAwaiter().GetResult()) {
|
||||
return new(false, "Ungültige Mitgliedsnummer");
|
||||
}
|
||||
|
||||
return new(true, null);
|
||||
}
|
||||
|
||||
public static ValidationResult CheckNewMgNr(TextBox input, bool required, AppDbContext ctx, Member? m) {
|
||||
var res = CheckInteger(input, required);
|
||||
if (!res.IsValid) {
|
||||
return res;
|
||||
@@ -331,6 +421,26 @@ namespace Elwig.Helpers {
|
||||
return new(true, null);
|
||||
}
|
||||
|
||||
public static ValidationResult CheckSortId(TextBox input, bool required, AppDbContext ctx) {
|
||||
var res = CheckUpperCase(input, required, 3);
|
||||
if (!res.IsValid) {
|
||||
return res;
|
||||
} else if (!required && input.Text.Length == 0) {
|
||||
return new(true, null);
|
||||
}
|
||||
|
||||
if (input.Text.Length < 2 || !ctx.SortIdExists(input.Text[0..2]).GetAwaiter().GetResult()) {
|
||||
return new(false, "Ungültige Sorte");
|
||||
} else if (input.Text.Length >= 3) {
|
||||
var attr = input.Text[2..];
|
||||
if (!ctx.AttrIdExists(attr).GetAwaiter().GetResult()) {
|
||||
return new(false, "Ungültiges Attribut");
|
||||
}
|
||||
}
|
||||
|
||||
return new(true, null);
|
||||
}
|
||||
|
||||
public static ValidationResult CheckPredecessorMgNr(TextBox input, bool required, AppDbContext ctx) {
|
||||
var res = CheckInteger(input, required);
|
||||
if (!res.IsValid) {
|
||||
@@ -345,16 +455,73 @@ namespace Elwig.Helpers {
|
||||
}
|
||||
|
||||
public static ValidationResult CheckDate(TextBox input, bool required) {
|
||||
// TODO
|
||||
return new(true, "Not implemented yet");
|
||||
return CheckDate(input, required, false);
|
||||
}
|
||||
|
||||
public static ValidationResult CheckPartialDate(TextBox input, bool required) {
|
||||
// TODO
|
||||
return new(true, "Not implemented yet");
|
||||
return CheckDate(input, required, true);
|
||||
}
|
||||
|
||||
public static ValidationResult CheckVNr(TextBox input, bool required, AppDbContext ctx, Contract? c) {
|
||||
private static ValidationResult CheckDate(TextBox input, bool required, bool partial) {
|
||||
string text = "";
|
||||
int pos = input.CaretIndex;
|
||||
int p = 0;
|
||||
var parts = new string?[3];
|
||||
parts[0] = "";
|
||||
for (int i = 0; i < input.Text.Length; i++) {
|
||||
char ch = input.Text[i];
|
||||
if (ch == '.') {
|
||||
if (p < 2 && (parts[p]?.Length > 0 || pos == text.Length)) {
|
||||
if (parts[p]?.Length == 1 && ((pos != text.Length && pos != text.Length - 1) || !input.IsFocused)) {
|
||||
parts[p] = "0" + parts[p];
|
||||
text = text[..(text.Length - 1)] + "0" + text[^1];
|
||||
}
|
||||
parts[++p] = "";
|
||||
text += '.';
|
||||
}
|
||||
} else if (char.IsAsciiDigit(ch)) {
|
||||
if ((partial && parts[p]?.Length < 4) || (!partial && ((p < 2 && parts[p]?.Length < 2) || (p == 2 && parts[2]?.Length < 4)))) {
|
||||
parts[p] += ch;
|
||||
text += ch;
|
||||
}
|
||||
if (p == 0 && pos == 1 && input.Text.Length >= 4 && input.Text.Length <= 9) {
|
||||
parts[++p] = "";
|
||||
text += '.';
|
||||
continue; // skip caret update
|
||||
}
|
||||
}
|
||||
|
||||
if (i == input.CaretIndex - 1) {
|
||||
pos = text.Length;
|
||||
}
|
||||
}
|
||||
|
||||
input.Text = text;
|
||||
input.CaretIndex = pos;
|
||||
|
||||
if (text.Length == 0)
|
||||
return required ? new(false, "Datum ist nicht optional") : new(true, null);
|
||||
|
||||
if (partial) {
|
||||
if (p == 0) {
|
||||
// only year provided
|
||||
return (parts[0]?.Length == 4) ? new(true, null) : new(false, "Datum ist ungültig");
|
||||
} else if (p == 1) {
|
||||
// only month and year provided
|
||||
int m = parts[0] != null && parts[0] != "" ? int.Parse(parts[0] ?? "0") : 0;
|
||||
if (parts[1]?.Length != 4 || parts[0]?.Length != 2 || m < 1 || m > 12)
|
||||
return new(false, "Datum ist ungültig");
|
||||
return new(true, null);
|
||||
}
|
||||
}
|
||||
|
||||
if (!DateOnly.TryParseExact(text, "dd.MM.yyyy", out _))
|
||||
return new(false, "Datum ist ungültig");
|
||||
|
||||
return new(true, null);
|
||||
}
|
||||
|
||||
public static ValidationResult CheckFbNr(TextBox input, bool required, AppDbContext ctx, AreaCom? c) {
|
||||
var res = CheckInteger(input, required);
|
||||
if (!res.IsValid) {
|
||||
return res;
|
||||
@@ -363,8 +530,8 @@ namespace Elwig.Helpers {
|
||||
}
|
||||
|
||||
int nr = int.Parse(input.Text);
|
||||
if (nr != c?.VNr && ctx.VNrExists(nr).GetAwaiter().GetResult()) {
|
||||
return new(false, "Vertragsnummer wird bereits verwendet");
|
||||
if (nr != c?.FbNr && ctx.FbNrExists(nr).GetAwaiter().GetResult()) {
|
||||
return new(false, "Flächenbindungsnummer wird bereits verwendet");
|
||||
}
|
||||
|
||||
return new(true, null);
|
||||
@@ -374,5 +541,37 @@ namespace Elwig.Helpers {
|
||||
// TODO
|
||||
return new(true, "Not implemented yet");
|
||||
}
|
||||
|
||||
public static ValidationResult CheckGradatoinOe(TextBox input, bool required) {
|
||||
var res = CheckInteger(input, required, 3);
|
||||
if (!res.IsValid) {
|
||||
return res;
|
||||
} else if (!required && input.Text.Length == 0) {
|
||||
return new(true, null);
|
||||
}
|
||||
|
||||
var oe = double.Parse(input.Text);
|
||||
if (oe < 10 || oe >= 300) {
|
||||
return new(false, "Ungültiger Oechsle-Wert");
|
||||
}
|
||||
|
||||
return new(true, null);
|
||||
}
|
||||
|
||||
public static ValidationResult CheckGradationKmw(TextBox input, bool required) {
|
||||
var res = CheckDecimal(input, required, 2, 1);
|
||||
if (!res.IsValid) {
|
||||
return res;
|
||||
} else if (!required && input.Text.Length == 0) {
|
||||
return new(true, null);
|
||||
}
|
||||
|
||||
var kmw = double.Parse(input.Text);
|
||||
if (kmw < 5 || kmw >= 50) {
|
||||
return new(false, "Ungültiger KMW-Wert");
|
||||
}
|
||||
|
||||
return new(true, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -14,13 +14,14 @@ namespace Elwig.Helpers.Weighing {
|
||||
public string Manufacturer => "Gassner";
|
||||
public int InternalScaleNr => 1;
|
||||
public string Model { get; private set; }
|
||||
public int ScaleNr { get; private set; }
|
||||
public string ScaleId { get; private set; }
|
||||
public bool IsReady { get; private set; }
|
||||
public bool HasFillingClearance { get; private set; }
|
||||
public int? WeightLimit { get; private set; }
|
||||
public string? LogPath { get; private set; }
|
||||
|
||||
public GassnerScale(int scaleNr, string model, string connection) {
|
||||
ScaleNr = scaleNr;
|
||||
public GassnerScale(string id, string model, string connection) {
|
||||
ScaleId = id;
|
||||
Model = model;
|
||||
IsReady = true;
|
||||
HasFillingClearance = false;
|
||||
|
@@ -17,9 +17,9 @@ namespace Elwig.Helpers.Weighing {
|
||||
string Model { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Unique number of the scale
|
||||
/// Unique identificator of the scale
|
||||
/// </summary>
|
||||
int ScaleNr { get; }
|
||||
string ScaleId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Internal identifying number of the scale in its system
|
||||
@@ -41,6 +41,11 @@ namespace Elwig.Helpers.Weighing {
|
||||
/// </summary>
|
||||
int? WeightLimit { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Where to log the requests and responses from the scale to
|
||||
/// </summary>
|
||||
string? LogPath { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Get the current weight on the scale without performing a weighing process
|
||||
/// </summary>
|
||||
|
44
Elwig/Helpers/Weighing/InvalidScale.cs
Normal file
44
Elwig/Helpers/Weighing/InvalidScale.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Elwig.Helpers.Weighing {
|
||||
public class InvalidScale : IScale {
|
||||
|
||||
public string Manufacturer => "NONE";
|
||||
public string Model => "NONE";
|
||||
public string ScaleId { get; private set; }
|
||||
public int InternalScaleNr => 0;
|
||||
public bool IsReady => false;
|
||||
public bool HasFillingClearance => false;
|
||||
public int? WeightLimit => null;
|
||||
public string? LogPath => null;
|
||||
|
||||
public InvalidScale(string id) {
|
||||
ScaleId = id;
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
public Task<WeighingResult> Weigh() {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<WeighingResult> GetCurrentWeight() {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task Empty() {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task GrantFillingClearance() {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task RevokeFillingClearance() {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
@@ -7,11 +7,12 @@ namespace Elwig.Helpers.Weighing {
|
||||
|
||||
public string Manufacturer => "Schember";
|
||||
public string Model => throw new NotImplementedException();
|
||||
public int ScaleNr => throw new NotImplementedException();
|
||||
public string ScaleId => throw new NotImplementedException();
|
||||
public int InternalScaleNr => throw new NotImplementedException();
|
||||
public bool IsReady => throw new NotImplementedException();
|
||||
public bool HasFillingClearance => throw new NotImplementedException();
|
||||
public int? WeightLimit => throw new NotImplementedException();
|
||||
public string? LogPath => throw new NotImplementedException();
|
||||
|
||||
public void Dispose() {
|
||||
throw new NotImplementedException();
|
||||
|
@@ -11,9 +11,9 @@ namespace Elwig.Helpers.Weighing {
|
||||
protected enum Output { RTS, DTR, OUT1, OUT2 };
|
||||
|
||||
protected SerialPort? Serial = null;
|
||||
protected SerialPort? ControlSerialEmpty = null, ControlSerialFilling = null;
|
||||
protected TcpClient? Tcp = null;
|
||||
protected StreamReader Reader;
|
||||
protected StreamWriter Writer;
|
||||
protected Stream Stream;
|
||||
|
||||
protected readonly Output? EmptyMode = null;
|
||||
protected readonly Output? FillingClearanceMode = null;
|
||||
@@ -22,71 +22,89 @@ namespace Elwig.Helpers.Weighing {
|
||||
public string Manufacturer => "SysTec";
|
||||
public int InternalScaleNr => 1;
|
||||
public string Model { get; private set; }
|
||||
public int ScaleNr { get; private set; }
|
||||
public string ScaleId { get; private set; }
|
||||
public bool IsReady { get; private set; }
|
||||
public bool HasFillingClearance { get; private set; }
|
||||
public int? WeightLimit { get; private set; }
|
||||
public string? LogPath { get; private set; }
|
||||
|
||||
public SystecScale(int scaleNr, string model, string connection, string? empty = null, string? fill = null, int? limit = null) {
|
||||
ScaleNr = scaleNr;
|
||||
public SystecScale(string id, string model, string connection, string? empty = null, string? filling = null, int? limit = null, string? log = null) {
|
||||
ScaleId = id;
|
||||
Model = model;
|
||||
IsReady = true;
|
||||
HasFillingClearance = false;
|
||||
LogPath = log;
|
||||
|
||||
Stream stream;
|
||||
if (connection.StartsWith("serial:")) {
|
||||
Serial = Utils.OpenSerialConnection(connection);
|
||||
stream = Serial.BaseStream;
|
||||
Stream = Serial.BaseStream;
|
||||
} else if (connection.StartsWith("tcp:")) {
|
||||
Tcp = Utils.OpenTcpConnection(connection);
|
||||
stream = Tcp.GetStream();
|
||||
Stream = Tcp.GetStream();
|
||||
} else {
|
||||
throw new ArgumentException("Unsupported scheme");
|
||||
}
|
||||
|
||||
if (empty != null) {
|
||||
var parts = empty.Split(':');
|
||||
EmptyMode = ConvertOutput(parts[0]);
|
||||
EmptyDelay = int.Parse(parts[1]);
|
||||
if (parts.Length == 3) {
|
||||
if (parts[0] != Serial?.PortName)
|
||||
ControlSerialEmpty = Utils.OpenSerialConnection($"serial://{parts[0]}:9600");
|
||||
} else if (parts.Length != 2) {
|
||||
throw new ArgumentException("Invalid value for 'empty'");
|
||||
}
|
||||
EmptyMode = ConvertOutput(parts[^2]);
|
||||
EmptyDelay = int.Parse(parts[^1]);
|
||||
}
|
||||
FillingClearanceMode = ConvertOutput(fill);
|
||||
WeightLimit = limit;
|
||||
if (FillingClearanceMode != null && WeightLimit == null)
|
||||
throw new ArgumentException("Weight limit has to be set, if filling clearance supervision is enalbed");
|
||||
|
||||
Writer = new(stream, Encoding.ASCII, -1, true);
|
||||
Reader = new(stream, Encoding.ASCII, false, -1, true);
|
||||
WeightLimit = limit;
|
||||
if (filling != null) {
|
||||
var parts = filling.Split(':');
|
||||
if (parts.Length == 2) {
|
||||
if (parts[0] != Serial?.PortName)
|
||||
ControlSerialFilling = parts[0] != ControlSerialEmpty?.PortName ? Utils.OpenSerialConnection($"serial://{parts[0]}:9600") : ControlSerialEmpty;
|
||||
} else if (parts.Length != 1) {
|
||||
throw new ArgumentException("Invalid value for 'filling'");
|
||||
}
|
||||
FillingClearanceMode = ConvertOutput(parts[^1]);
|
||||
}
|
||||
|
||||
if (FillingClearanceMode != null && WeightLimit == null)
|
||||
throw new ArgumentException("Weight limit has to be set, if filling clearance supervision is enabled");
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
Writer.Close();
|
||||
Reader.Close();
|
||||
Stream.Close();
|
||||
Serial?.Close();
|
||||
ControlSerialEmpty?.Close();
|
||||
ControlSerialFilling?.Close();
|
||||
Tcp?.Close();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected static Output? ConvertOutput(string? value) {
|
||||
if (value == null) return null;
|
||||
value = value.ToUpper();
|
||||
if (value == "RTS") {
|
||||
return Output.RTS;
|
||||
} else if (value == "DTR") {
|
||||
return Output.DTR;
|
||||
} else if (value == "OUT1") {
|
||||
return Output.OUT1;
|
||||
} else if (value == "OUT2") {
|
||||
return Output.OUT2;
|
||||
return value switch {
|
||||
null => null,
|
||||
"RTS" => Output.RTS,
|
||||
"DTR" => Output.DTR,
|
||||
"OUT1" => Output.OUT1,
|
||||
"OUT2" => Output.OUT2,
|
||||
_ => throw new ArgumentException($"Invalid value for argument: '{value}'"),
|
||||
};
|
||||
}
|
||||
|
||||
protected async Task SendCommand(string command) {
|
||||
byte[] bytes = Encoding.ASCII.GetBytes($"<{command}>");
|
||||
await Stream.WriteAsync(bytes);
|
||||
if (LogPath != null) await File.AppendAllTextAsync(LogPath, $"<{command}>");
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
throw new ArgumentException("Invalid value for argument empty");
|
||||
}
|
||||
|
||||
public async Task SendCommand(string command) {
|
||||
await Writer.WriteAsync($"<{command}>");
|
||||
}
|
||||
|
||||
public async Task<string> ReceiveResponse() {
|
||||
var line = await Reader.ReadLineAsync();
|
||||
if (line == null || line.Length < 4 || !line.StartsWith("<") || !line.EndsWith(">")) {
|
||||
throw new IOException("Invalid response from scale");
|
||||
}
|
||||
@@ -94,7 +112,7 @@ namespace Elwig.Helpers.Weighing {
|
||||
var error = line[1..3];
|
||||
if (error[0] == '0') {
|
||||
if (error[1] != '0') {
|
||||
throw new IOException($"Invalid response from scale (error code {error}");
|
||||
throw new IOException($"Invalid response from scale (error code {error})");
|
||||
}
|
||||
} else if (error[0] == '1') {
|
||||
string msg = $"Unbekannter Fehler (Fehler code {error})";
|
||||
@@ -119,32 +137,44 @@ namespace Elwig.Helpers.Weighing {
|
||||
throw new IOException($"Invalid response from scale (error code {error})");
|
||||
}
|
||||
|
||||
return line[3..(line.Length - 1)];
|
||||
return line[1..^1];
|
||||
}
|
||||
|
||||
protected async Task<WeighingResult> Weigh(bool incIdentNr) {
|
||||
await SendCommand(incIdentNr ? $"RM{InternalScaleNr}" : $"RN{InternalScaleNr}");
|
||||
string line = await ReceiveResponse();
|
||||
await SendCommand(incIdentNr ? $"RN{InternalScaleNr}" : $"RM{InternalScaleNr}");
|
||||
string record = await ReceiveResponse();
|
||||
if (record.Length != 62)
|
||||
throw new IOException("Invalid response from scale: Received record has invalid size");
|
||||
var line = record[2..];
|
||||
|
||||
var status = line[ 0.. 2];
|
||||
var date = line[ 2..10];
|
||||
var time = line[10..15];
|
||||
var identNr = line[15..19];
|
||||
var identNr = line[15..19].Trim();
|
||||
var scaleNr = line[19..20];
|
||||
var brutto = line[20..28];
|
||||
var tara = line[28..36];
|
||||
var netto = line[36..44];
|
||||
var brutto = line[20..28].Trim();
|
||||
var tara = line[28..36].Trim();
|
||||
var netto = line[36..44].Trim();
|
||||
var unit = line[44..46];
|
||||
var taraCode = line[46..48];
|
||||
var zone = line[48..49];
|
||||
var terminalNr = line[49..52];
|
||||
var crc16 = line[52..60];
|
||||
var zone = line[48..49].Trim();
|
||||
var terminalNr = line[49..52].Trim();
|
||||
var crc16 = line[52..60].Trim();
|
||||
|
||||
if (Utils.CalcCrc16Modbus(record[..54]) != ushort.Parse(crc16)) {
|
||||
throw new IOException($"Invalid response from scale: Invalid CRC16 checksum ({crc16} != {Utils.CalcCrc16Modbus(record[..54]).ToString()})");
|
||||
} else if (unit != "kg") {
|
||||
throw new IOException($"Unsupported unit in weighing response: '{unit}'");
|
||||
}
|
||||
|
||||
identNr = identNr.Length > 0 && identNr != "0" ? identNr : null;
|
||||
var parsedDate = DateOnly.Parse(date);
|
||||
return new() {
|
||||
Weight = int.TryParse(netto.Trim(), out int w) ? w : null,
|
||||
WeighingId = identNr.Trim().Length > 0 ? identNr.Trim() : null,
|
||||
Date = date,
|
||||
Time = time,
|
||||
Weight = int.Parse(netto),
|
||||
WeighingId = identNr,
|
||||
FullWeighingId = identNr != null ? $"{parsedDate:yyyy-MM-dd}/{identNr}" : null,
|
||||
Date = parsedDate,
|
||||
Time = TimeOnly.Parse(time),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -157,33 +187,35 @@ namespace Elwig.Helpers.Weighing {
|
||||
}
|
||||
|
||||
public async Task Empty() {
|
||||
if (EmptyMode == Output.RTS && Serial != null) {
|
||||
Serial.RtsEnable = true;
|
||||
SerialPort? p = ControlSerialEmpty ?? Serial;
|
||||
if (EmptyMode == Output.RTS && p != null) {
|
||||
p.RtsEnable = true;
|
||||
await Task.Delay(EmptyDelay);
|
||||
Serial.RtsEnable = false;
|
||||
} else if (EmptyMode == Output.DTR && Serial != null) {
|
||||
Serial.DtrEnable = true;
|
||||
p.RtsEnable = false;
|
||||
} else if (EmptyMode == Output.DTR && p != null) {
|
||||
p.DtrEnable = true;
|
||||
await Task.Delay(EmptyDelay);
|
||||
Serial.DtrEnable = false;
|
||||
p.DtrEnable = false;
|
||||
} else if (EmptyMode == Output.OUT1 || EmptyMode == Output.OUT2) {
|
||||
int output = EmptyMode == Output.OUT1 ? 1 : 2;
|
||||
await SendCommand($"OS{output:02i}");
|
||||
await SendCommand($"OS{output:00}");
|
||||
await ReceiveResponse();
|
||||
await Task.Delay(EmptyDelay);
|
||||
await SendCommand($"OC{output:02i}");
|
||||
await SendCommand($"OC{output:00}");
|
||||
await ReceiveResponse();
|
||||
}
|
||||
}
|
||||
|
||||
protected async Task SetFillingClearance(bool status) {
|
||||
if (FillingClearanceMode == Output.RTS && Serial != null) {
|
||||
Serial.RtsEnable = status;
|
||||
} else if (FillingClearanceMode == Output.DTR && Serial != null) {
|
||||
Serial.DtrEnable = status;
|
||||
SerialPort? p = ControlSerialFilling ?? Serial;
|
||||
if (FillingClearanceMode == Output.RTS && p != null) {
|
||||
p.RtsEnable = status;
|
||||
} else if (FillingClearanceMode == Output.DTR && p != null) {
|
||||
p.DtrEnable = status;
|
||||
} else if (FillingClearanceMode == Output.OUT1 || FillingClearanceMode == Output.OUT2) {
|
||||
string cmd = status ? "OS" : "OC";
|
||||
int output = FillingClearanceMode == Output.OUT1 ? 1 : 2;
|
||||
await SendCommand($"{cmd}{output:02i}");
|
||||
await SendCommand($"{cmd}{output:00}");
|
||||
await ReceiveResponse();
|
||||
}
|
||||
}
|
||||
|
@@ -1,3 +1,5 @@
|
||||
using System;
|
||||
|
||||
namespace Elwig.Helpers.Weighing {
|
||||
/// <summary>
|
||||
/// Result of a weighing process on an industrial scale
|
||||
@@ -13,14 +15,25 @@ namespace Elwig.Helpers.Weighing {
|
||||
/// </summary>
|
||||
public string? WeighingId = null;
|
||||
|
||||
/// <summary>
|
||||
/// Wheighing id (or IdentNr) provided by the scale optionally combined with the current date
|
||||
/// </summary>
|
||||
public string? FullWeighingId = null;
|
||||
|
||||
/// <summary>
|
||||
/// Date string provided by the scale
|
||||
/// </summary>
|
||||
public string? Date = null;
|
||||
public DateOnly? Date = null;
|
||||
|
||||
/// <summary>
|
||||
/// Time string provided by the scale
|
||||
/// </summary>
|
||||
public string? Time = null;
|
||||
public TimeOnly? Time = null;
|
||||
|
||||
/// <returns><Weight/WeighingId/Date/Time></returns>
|
||||
override public string ToString() {
|
||||
var w = Weight != null ? $"{Weight}kg" : "";
|
||||
return $"<{w}/{WeighingId}/{Date:yyyy-MM-dd}/{Time:HH:mm}>";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Elwig.Models {
|
||||
@@ -9,5 +10,11 @@ namespace Elwig.Models {
|
||||
|
||||
[Column("name")]
|
||||
public string Name { get; private set; }
|
||||
|
||||
[InverseProperty("Gem")]
|
||||
public virtual ISet<AT_Kg> Kgs { get; private set; }
|
||||
|
||||
[InverseProperty("AtGem")]
|
||||
public virtual WbGem? WbGem { get; private set; }
|
||||
}
|
||||
}
|
||||
|
@@ -15,5 +15,8 @@ namespace Elwig.Models {
|
||||
|
||||
[ForeignKey("Gkz")]
|
||||
public virtual AT_Gem Gem { get; private set; }
|
||||
|
||||
[InverseProperty("AtKg")]
|
||||
public virtual WbKg WbKg { get; private set; }
|
||||
}
|
||||
}
|
||||
|
@@ -11,7 +11,7 @@ namespace Elwig.Models {
|
||||
public int Okz { get; private set; }
|
||||
|
||||
[Column("country")]
|
||||
public string CountryCode { get; private set; }
|
||||
public int CountryNum { get; private set; }
|
||||
|
||||
[Column("id")]
|
||||
public string Id { get; private set; }
|
||||
@@ -25,7 +25,7 @@ namespace Elwig.Models {
|
||||
[ForeignKey("Okz")]
|
||||
public virtual AT_Ort Ort { get; private set; }
|
||||
|
||||
[ForeignKey("CountryCode")]
|
||||
[ForeignKey("CountryNum")]
|
||||
public virtual Country Country { get; private set; }
|
||||
}
|
||||
}
|
||||
|
@@ -1,39 +1,55 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
|
||||
namespace Elwig.Models {
|
||||
[Table("area_commitment"), PrimaryKey("VNr")]
|
||||
[Table("area_commitment"), PrimaryKey("FbNr")]
|
||||
public class AreaCom {
|
||||
[Column("vnr")]
|
||||
public int VNr { get; set; }
|
||||
[Column("fbnr")]
|
||||
public int FbNr { get; set; }
|
||||
|
||||
[Column("area")]
|
||||
public int Area { get; set; }
|
||||
[Column("mgnr")]
|
||||
public int MgNr { get; set; }
|
||||
|
||||
[Column("sortid")]
|
||||
public string SortId { get; set; }
|
||||
[Column("vtrgid")]
|
||||
public string VtrgId { get; set; }
|
||||
|
||||
[Column("cultid")]
|
||||
public string CultId { get; set; }
|
||||
|
||||
[ForeignKey("VNr")]
|
||||
public virtual Contract Contract { get; private set; }
|
||||
[Column("area")]
|
||||
public int Area { get; set; }
|
||||
|
||||
[ForeignKey("SortId")]
|
||||
public virtual WineVar WineVar { get; private set; }
|
||||
[Column("kgnr")]
|
||||
public int KgNr { get; set; }
|
||||
|
||||
[Column("gstnr")]
|
||||
public string GstNr { get; set; }
|
||||
|
||||
[Column("rdnr")]
|
||||
public int? RdNr { get; set; }
|
||||
|
||||
[Column("year_from")]
|
||||
public int YearFrom { get; set; }
|
||||
|
||||
[Column("year_to")]
|
||||
public int? YearTo { get; set; }
|
||||
|
||||
[Column("comment")]
|
||||
public string? Comment { get; set; }
|
||||
|
||||
[ForeignKey("MgNr")]
|
||||
public virtual Member Member { get; private set; }
|
||||
|
||||
[ForeignKey("VtrgId")]
|
||||
public virtual AreaComType AreaComType { get; private set; }
|
||||
|
||||
[ForeignKey("CultId")]
|
||||
public virtual WineCult WineCult { get; private set; }
|
||||
|
||||
[InverseProperty("AreaCom")]
|
||||
public virtual ISet<AreaComParcel> Parcels { get; private set; }
|
||||
[ForeignKey("KgNr")]
|
||||
public virtual WbKg Kg { get; private set; }
|
||||
|
||||
[InverseProperty("AreaCom")]
|
||||
public virtual ISet<AreaComAttr> AttributeEntries { get; private set; }
|
||||
|
||||
[NotMapped]
|
||||
public IEnumerable<WineAttr> Attributes => AttributeEntries.Select(e => e.WineAttr);
|
||||
[ForeignKey("KgNr, RdNr")]
|
||||
public virtual WbRd? Rd { get; private set; }
|
||||
}
|
||||
}
|
||||
|
@@ -1,19 +0,0 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Elwig.Models {
|
||||
[Table("area_commitment_attribute"), PrimaryKey("VNr", "AttrId")]
|
||||
public class AreaComAttr {
|
||||
[Column("vnr")]
|
||||
public int VNr { get; set; }
|
||||
|
||||
[Column("attrid")]
|
||||
public string AttrId { get; set; }
|
||||
|
||||
[ForeignKey("VNr")]
|
||||
public virtual AreaCom AreaCom { get; private set; }
|
||||
|
||||
[ForeignKey("AttrId")]
|
||||
public virtual WineAttr WineAttr { get; private set; }
|
||||
}
|
||||
}
|
@@ -1,31 +0,0 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Elwig.Models {
|
||||
[Table("area_commitment_parcel"), PrimaryKey("VNr", "KgNr", "GstNr")]
|
||||
public class AreaComParcel {
|
||||
[Column("vnr")]
|
||||
public int VNr { get; set; }
|
||||
|
||||
[Column("kgnr")]
|
||||
public int KgNr { get; set; }
|
||||
|
||||
[Column("gstnr")]
|
||||
public string? GstNr { get; set; }
|
||||
|
||||
[Column("rdnr")]
|
||||
public int? RdNr { get; set; }
|
||||
|
||||
[Column("area")]
|
||||
public int? Area { get; set; }
|
||||
|
||||
[ForeignKey("KgNr")]
|
||||
public virtual WbKg Kg { get; private set; }
|
||||
|
||||
[ForeignKey("KgNr, RdNr")]
|
||||
public virtual WbRd? Rd { get; private set; }
|
||||
|
||||
[ForeignKey("VNr")]
|
||||
public virtual AreaCom AreaCom { get; private set; }
|
||||
}
|
||||
}
|
51
Elwig/Models/AreaComType.cs
Normal file
51
Elwig/Models/AreaComType.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using Elwig.Helpers;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Elwig.Models {
|
||||
[Table("area_commitment_type"), PrimaryKey("VtrgId"), Index("SortId", "AttrId1", "AttrId2", "Discriminator")]
|
||||
public class AreaComType {
|
||||
[Column("vtrgid")]
|
||||
public string VtrgId { get; set; }
|
||||
|
||||
[Column("sortid")]
|
||||
public string SortId { get; set; }
|
||||
|
||||
[Column("attrid_1")]
|
||||
public string? AttrId1 { get; set; }
|
||||
|
||||
[Column("attrid_2")]
|
||||
public string? AttrId2 { get; set; }
|
||||
|
||||
[Column("disc")]
|
||||
public string? Discriminator { get; set; }
|
||||
|
||||
[Column("min_kg_per_ha")]
|
||||
public int? MinKgPerHa { get; set; }
|
||||
|
||||
[Column("max_kg_per_ha")]
|
||||
public int? MaxKgPerHa { get; set; }
|
||||
|
||||
[Column("penalty_amount")]
|
||||
public long? PenaltyAmoutValue { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public decimal? PenaltyAmount {
|
||||
get => PenaltyAmoutValue != null ? Utils.DecFromDb(PenaltyAmoutValue.Value, 4) : null;
|
||||
set => PenaltyAmoutValue = value != null ? Utils.DecToDb(value.Value, 4) : null;
|
||||
}
|
||||
|
||||
[ForeignKey("SortId")]
|
||||
public virtual WineVar WineVar { get; private set; }
|
||||
|
||||
[ForeignKey("AttrId1")]
|
||||
public virtual WineAttr? WineAttr1 { get; private set; }
|
||||
|
||||
[ForeignKey("AttrId2")]
|
||||
public virtual WineAttr? WineAttr2 { get; private set; }
|
||||
|
||||
[NotMapped]
|
||||
public string DisplayName => WineVar.Name + (WineAttr1 != null ? $" {WineAttr1.Name}" : "") +
|
||||
(WineAttr2 != null ? $" {WineAttr2.Name}" : "") + (Discriminator != null ? $" ({Discriminator})" : "");
|
||||
}
|
||||
}
|
@@ -1,9 +1,10 @@
|
||||
using Elwig.Helpers;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Elwig.Models {
|
||||
[Table("member_billing_address"), PrimaryKey("MgNr")]
|
||||
public class BillingAddr {
|
||||
public class BillingAddr : IAddress {
|
||||
[Column("mgnr")]
|
||||
public int MgNr { get; set; }
|
||||
|
||||
@@ -11,7 +12,7 @@ namespace Elwig.Models {
|
||||
public string Name { get; set; }
|
||||
|
||||
[Column("country")]
|
||||
public string CountryCode { get; set; }
|
||||
public int CountryNum { get; set; }
|
||||
|
||||
[Column("postal_dest")]
|
||||
public string PostalDestId { get; set; }
|
||||
@@ -22,10 +23,10 @@ namespace Elwig.Models {
|
||||
[ForeignKey("MgNr")]
|
||||
public virtual Member Member { get; private set; }
|
||||
|
||||
[ForeignKey("CountryCode")]
|
||||
[ForeignKey("CountryNum")]
|
||||
public virtual Country Country { get; private set; }
|
||||
|
||||
[ForeignKey("CountryCode, PostalDestId")]
|
||||
[ForeignKey("CountryNum, PostalDestId")]
|
||||
public virtual PostalDest PostalDest { get; private set; }
|
||||
}
|
||||
}
|
||||
|
@@ -11,6 +11,30 @@ namespace Elwig.Models {
|
||||
[Column("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[Column("country")]
|
||||
public int? CountryNum { get; set; }
|
||||
|
||||
[Column("postal_dest")]
|
||||
public string? PostalDestId { get; set; }
|
||||
|
||||
[Column("address")]
|
||||
public string? Address { get; set; }
|
||||
|
||||
[ForeignKey("CountryNum")]
|
||||
public virtual Country? Country { get; private set; }
|
||||
|
||||
[ForeignKey("CountryNum, PostalDestId")]
|
||||
public virtual PostalDest? PostalDest { get; private set; }
|
||||
|
||||
[Column("phone_nr")]
|
||||
public string? PhoneNr { get; set; }
|
||||
|
||||
[Column("fax_nr")]
|
||||
public string? FaxNr { get; set; }
|
||||
|
||||
[Column("mobile_nr")]
|
||||
public string? MobileNr { get; set; }
|
||||
|
||||
[InverseProperty("Branch")]
|
||||
public virtual ISet<Member> Members { get; private set; }
|
||||
}
|
||||
|
13
Elwig/Models/ClientParam.cs
Normal file
13
Elwig/Models/ClientParam.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Elwig.Models {
|
||||
[Table("client_parameter"), PrimaryKey("Param")]
|
||||
public class ClientParam {
|
||||
[Column("param")]
|
||||
public string Param { get; set; }
|
||||
|
||||
[Column("value")]
|
||||
public string? Value { get; set; }
|
||||
}
|
||||
}
|
@@ -1,45 +0,0 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Elwig.Models {
|
||||
[Table("contract"), PrimaryKey("VNr")]
|
||||
public class Contract {
|
||||
[Column("vnr")]
|
||||
public int VNr { get; set; }
|
||||
|
||||
[Column("mgnr")]
|
||||
public int MgNr { get; set; }
|
||||
|
||||
[Column("date")]
|
||||
public string? DateString { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public DateOnly? Date {
|
||||
get {
|
||||
return DateString != null ? DateOnly.ParseExact(DateString, "yyyy-MM-dd") : null;
|
||||
}
|
||||
set {
|
||||
DateString = value?.ToString("yyyy-MM-dd");
|
||||
}
|
||||
}
|
||||
|
||||
[Column("year_from")]
|
||||
public int YearFrom { get; set; }
|
||||
|
||||
[Column("year_to")]
|
||||
public int? YearTo { get; set; }
|
||||
|
||||
[Column("comment")]
|
||||
public string? Comment { get; set; }
|
||||
|
||||
[ForeignKey("MgNr")]
|
||||
public virtual Member Member { get; private set; }
|
||||
|
||||
[InverseProperty("Contract")]
|
||||
public virtual AreaCom? AreaCom { get; private set; }
|
||||
|
||||
[NotMapped]
|
||||
public int? Area => AreaCom?.Area;
|
||||
}
|
||||
}
|
@@ -2,17 +2,17 @@ using Microsoft.EntityFrameworkCore;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Elwig.Models {
|
||||
[Table("country"), PrimaryKey("Alpha2")]
|
||||
[Table("country"), PrimaryKey("Num"), Index("Alpha2", IsUnique = true), Index("Alpha3", IsUnique = true)]
|
||||
public class Country {
|
||||
[Column("num")]
|
||||
public int Num { get; private set; }
|
||||
|
||||
[Column("alpha2")]
|
||||
public string Alpha2 { get; private set; }
|
||||
|
||||
[Column("alpha3")]
|
||||
public string Alpha3 { get; private set; }
|
||||
|
||||
[Column("num")]
|
||||
public int Num { get; private set; }
|
||||
|
||||
[Column("name")]
|
||||
public string Name { get; private set; }
|
||||
|
||||
|
104
Elwig/Models/Credit.cs
Normal file
104
Elwig/Models/Credit.cs
Normal file
@@ -0,0 +1,104 @@
|
||||
using Elwig.Helpers;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Elwig.Models {
|
||||
[Table("credit"), PrimaryKey("Year", "TgNr"), Index("Year", "AvNr", "MgNr", IsUnique = true)]
|
||||
public class Credit {
|
||||
[Column("year")]
|
||||
public int Year { get; set; }
|
||||
|
||||
[Column("tgnr")]
|
||||
public int TgNr { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public string TgId => $"{Year}/{TgNr:000}";
|
||||
|
||||
[Column("mgnr")]
|
||||
public int MgNr { get; set; }
|
||||
|
||||
[Column("avnr")]
|
||||
public int AvNr { get; set; }
|
||||
|
||||
[Column("net_amount")]
|
||||
public long NetAmountValue { get; set; }
|
||||
[NotMapped]
|
||||
public decimal NetAmount {
|
||||
get => Utils.DecFromDb(NetAmountValue, 2);
|
||||
set => NetAmountValue = Utils.DecToDb(value, 2);
|
||||
}
|
||||
|
||||
[Column("prev_net_amount")]
|
||||
public long? PrevNetAmountValue { get; set; }
|
||||
[NotMapped]
|
||||
public decimal? PrevNetAmount {
|
||||
get => PrevNetAmountValue != null ? Utils.DecFromDb(PrevNetAmountValue.Value, 2) : null;
|
||||
set => PrevNetAmountValue = value != null ? Utils.DecToDb(value.Value, 2) : null;
|
||||
}
|
||||
|
||||
[Column("vat")]
|
||||
public double VatValue { get; set; }
|
||||
[NotMapped]
|
||||
public decimal Vat {
|
||||
get => (decimal)VatValue;
|
||||
set => VatValue = (double)value;
|
||||
}
|
||||
|
||||
[Column("vat_amount")]
|
||||
public long VatAmountValue { get; private set; }
|
||||
[NotMapped]
|
||||
public decimal VatAmount {
|
||||
get => Utils.DecFromDb(VatAmountValue, 2);
|
||||
}
|
||||
|
||||
[Column("gross_amount")]
|
||||
public long GrossAmountValue { get; private set; }
|
||||
[NotMapped]
|
||||
public decimal GrossAmount {
|
||||
get => Utils.DecFromDb(GrossAmountValue, 2);
|
||||
}
|
||||
|
||||
[Column("modifiers")]
|
||||
public long? ModifiersValue { get; set; }
|
||||
[NotMapped]
|
||||
public decimal? Modifiers {
|
||||
get => ModifiersValue != null ? Utils.DecFromDb(ModifiersValue.Value, 2) : null;
|
||||
set => ModifiersValue = value != null ? Utils.DecToDb(value.Value, 2) : null;
|
||||
}
|
||||
|
||||
[Column("prev_modifiers")]
|
||||
public long? PrevModifiersValue { get; set; }
|
||||
[NotMapped]
|
||||
public decimal? PrevModifiers {
|
||||
get => PrevModifiersValue != null ? Utils.DecFromDb(PrevModifiersValue.Value, 2) : null;
|
||||
set => PrevModifiersValue = value != null ? Utils.DecToDb(value.Value, 2) : null;
|
||||
}
|
||||
|
||||
[Column("amount")]
|
||||
public long AmountValue { get; private set; }
|
||||
[NotMapped]
|
||||
public decimal Amount {
|
||||
get => Utils.DecFromDb(AmountValue, 2);
|
||||
}
|
||||
|
||||
[Column("ctime")]
|
||||
public long CTime { get; private set; }
|
||||
[NotMapped]
|
||||
public DateTime CreatedTimestamp => DateTimeOffset.FromUnixTimeSeconds(CTime).LocalDateTime;
|
||||
|
||||
[Column("mtime")]
|
||||
public long MTime { get; private set; }
|
||||
[NotMapped]
|
||||
public DateTime ModifiedTimestamp => DateTimeOffset.FromUnixTimeSeconds(CTime).LocalDateTime;
|
||||
|
||||
[ForeignKey("Year, AvNr, MgNr")]
|
||||
public virtual PaymentMember Payment { get; private set; }
|
||||
|
||||
[ForeignKey("Year, AvNr")]
|
||||
public virtual PaymentVar Variant { get; private set; }
|
||||
|
||||
[ForeignKey("MgNr")]
|
||||
public virtual Member Member { get; private set; }
|
||||
}
|
||||
}
|
@@ -18,6 +18,6 @@ namespace Elwig.Models {
|
||||
public long? OneEuroValue { get; private set; }
|
||||
|
||||
[NotMapped]
|
||||
public decimal? OneEuro => OneEuroValue != null ? Utils.DecFromDb((long)OneEuroValue, 6) : null;
|
||||
public decimal? OneEuro => OneEuroValue != null ? Utils.DecFromDb(OneEuroValue.Value, 6) : null;
|
||||
}
|
||||
}
|
||||
|
94
Elwig/Models/Delivery.cs
Normal file
94
Elwig/Models/Delivery.cs
Normal file
@@ -0,0 +1,94 @@
|
||||
using Elwig.Helpers;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
|
||||
namespace Elwig.Models {
|
||||
[Table("delivery"), PrimaryKey("Year", "DId"), Index("DateString", "ZwstId", "LNr", IsUnique = true), Index("LsNr", IsUnique = true)]
|
||||
public class Delivery {
|
||||
[Column("year")]
|
||||
public int Year { get; set; }
|
||||
|
||||
[Column("did")]
|
||||
public int DId { get; set; }
|
||||
|
||||
[Column("date")]
|
||||
public string DateString { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public DateOnly Date {
|
||||
get => DateOnly.ParseExact(DateString, "yyyy-MM-dd");
|
||||
set => DateString = value.ToString("yyyy-MM-dd");
|
||||
}
|
||||
|
||||
[Column("time")]
|
||||
public string? TimeString { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public TimeOnly? Time {
|
||||
get => (TimeString == null) ? null : TimeOnly.ParseExact(TimeString, "HH:mm:ss");
|
||||
set => TimeString = value?.ToString("HH:mm:ss");
|
||||
}
|
||||
|
||||
[NotMapped]
|
||||
public DateTime DateTime {
|
||||
get => Date.ToDateTime(Time ?? TimeOnly.MinValue);
|
||||
set {
|
||||
Date = DateOnly.FromDateTime(value);
|
||||
Time = TimeOnly.FromDateTime(value);
|
||||
}
|
||||
}
|
||||
|
||||
[Column("zwstid")]
|
||||
public string ZwstId { get; set; }
|
||||
|
||||
[ForeignKey("ZwstId")]
|
||||
public virtual Branch Branch { get; private set; }
|
||||
|
||||
[Column("lnr")]
|
||||
public int LNr { get; set; }
|
||||
|
||||
[Column("lsnr")]
|
||||
public string LsNr { get; set; }
|
||||
|
||||
[Column("mgnr")]
|
||||
public int MgNr { get; set; }
|
||||
|
||||
[ForeignKey("MgNr")]
|
||||
public virtual Member Member { get; private set; }
|
||||
|
||||
[Column("comment")]
|
||||
public string? Comment { get; set; }
|
||||
|
||||
[ForeignKey("Year")]
|
||||
public virtual Season Season { get; private set; }
|
||||
|
||||
[InverseProperty("Delivery")]
|
||||
public virtual ISet<DeliveryPart> Parts { get; private set; }
|
||||
|
||||
public int Weight => Parts.Select(p => p.Weight).Sum();
|
||||
|
||||
public IEnumerable<string> SortIds => Parts
|
||||
.GroupBy(p => p.SortId)
|
||||
.OrderByDescending(g => g.Select(p => p.Weight).Sum())
|
||||
.Select(g => g.Select(p => p.SortId).First());
|
||||
|
||||
public string SortIdString => string.Join(", ", SortIds);
|
||||
|
||||
public double Kmw => Utils.AggregateDeliveryPartsKmw(Parts);
|
||||
|
||||
public double Oe => Utils.KmwToOe(Kmw);
|
||||
|
||||
public int SearchScore(IEnumerable<string> keywords) {
|
||||
var list = new string?[] {
|
||||
LsNr, Time?.ToString("HH:mm"),
|
||||
Member.FamilyName, Member.MiddleName, Member.GivenName, Member.BillingAddress?.Name,
|
||||
Comment
|
||||
}.ToList();
|
||||
list.AddRange(Parts.Select(p => p.Comment).Distinct());
|
||||
return Utils.GetSearchScore(list, keywords);
|
||||
}
|
||||
}
|
||||
}
|
111
Elwig/Models/DeliveryPart.cs
Normal file
111
Elwig/Models/DeliveryPart.cs
Normal file
@@ -0,0 +1,111 @@
|
||||
using Elwig.Helpers;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
|
||||
namespace Elwig.Models {
|
||||
[Table("delivery_part"), PrimaryKey("Year", "DId", "DPNr")]
|
||||
public class DeliveryPart {
|
||||
[Column("year")]
|
||||
public int Year { get; set; }
|
||||
|
||||
[Column("did")]
|
||||
public int DId { get; set; }
|
||||
|
||||
[ForeignKey("Year, DId")]
|
||||
public virtual Delivery Delivery { get; private set; }
|
||||
|
||||
[Column("dpnr")]
|
||||
public int DPNr { get; set; }
|
||||
|
||||
[Column("sortid")]
|
||||
public string SortId { get; set; }
|
||||
|
||||
[ForeignKey("SortId")]
|
||||
public virtual WineVar Variant { get; private set; }
|
||||
|
||||
[Column("weight")]
|
||||
public int Weight { get; set; }
|
||||
|
||||
[Column("kmw")]
|
||||
public double Kmw { get; set; }
|
||||
[NotMapped]
|
||||
public double Oe {
|
||||
get => Utils.KmwToOe(Kmw);
|
||||
set => Kmw = Utils.OeToKmw(value);
|
||||
}
|
||||
|
||||
[Column("qualid")]
|
||||
public string QualId { get; set; }
|
||||
|
||||
[ForeignKey("QualId")]
|
||||
public virtual WineQualLevel Quality { get; private set; }
|
||||
|
||||
[Column("hkid")]
|
||||
public string HkId { get; set; }
|
||||
|
||||
[ForeignKey("HkId")]
|
||||
public virtual WineOrigin Origin { get; private set; }
|
||||
|
||||
[Column("kgnr")]
|
||||
public int? KgNr { get; set; }
|
||||
|
||||
[ForeignKey("KgNr")]
|
||||
public virtual WbKg? Kg { get; private set; }
|
||||
|
||||
[Column("rdnr")]
|
||||
public int? RdNr { get; set; }
|
||||
|
||||
[ForeignKey("KgNr, RdNr")]
|
||||
public virtual WbRd? Rd { get; private set; }
|
||||
|
||||
[Column("gerebelt")]
|
||||
public bool IsGerebelt { get; set; }
|
||||
|
||||
[Column("manual_weighing")]
|
||||
public bool ManualWeighing { get; set; }
|
||||
|
||||
[Column("spl_check")]
|
||||
public bool SplCheck { get; set; }
|
||||
|
||||
[Column("hand_picked")]
|
||||
public bool? IsHandPicked { get; set; }
|
||||
|
||||
[Column("lesewagen")]
|
||||
public bool? IsLesewagen { get; set; }
|
||||
|
||||
[Column("temperature")]
|
||||
public double? Temperature { get; set; }
|
||||
|
||||
[Column("acid")]
|
||||
public double? Acid { get; set; }
|
||||
|
||||
[Column("scale_id")]
|
||||
public string? ScaleId { get; set; }
|
||||
|
||||
[Column("weighing_id")]
|
||||
public string? WeighingId { get; set; }
|
||||
|
||||
[Column("comment")]
|
||||
public string? Comment { get; set; }
|
||||
|
||||
[InverseProperty("Part")]
|
||||
public virtual ISet<DeliveryPartAttr> PartAttributes { get; private set; }
|
||||
|
||||
[NotMapped]
|
||||
public IEnumerable<WineAttr> Attributes => PartAttributes.Select(a => a.Attr);
|
||||
|
||||
[InverseProperty("Part")]
|
||||
public virtual ISet<DeliveryPartModifier> PartModifiers { get; private set; }
|
||||
|
||||
[NotMapped]
|
||||
public IEnumerable<Modifier> Modifiers => PartModifiers.Select(m => m.Modifier).OrderBy(m => m.Ordering);
|
||||
|
||||
[InverseProperty("DeliveryPart")]
|
||||
public virtual PaymentDeliveryPart? Payment { get; private set; }
|
||||
|
||||
[NotMapped]
|
||||
public string OriginString => Origin.OriginString + "\n" + (Kg?.Gl != null ? $" / {Kg.Gl.Name}" : "") + (Kg != null ? $" / {Kg.AtKg.Gem.Name} / KG {Kg.AtKg.Name}" : "") + (Rd != null ? $" / Ried {Rd.Name}" : "");
|
||||
}
|
||||
}
|
25
Elwig/Models/DeliveryPartAttr.cs
Normal file
25
Elwig/Models/DeliveryPartAttr.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Elwig.Models {
|
||||
[Table("delivery_part_attribute"), PrimaryKey("Year", "DId", "DPNr", "AttrId")]
|
||||
public class DeliveryPartAttr {
|
||||
[Column("year")]
|
||||
public int Year { get; set; }
|
||||
|
||||
[Column("did")]
|
||||
public int DId { get; set; }
|
||||
|
||||
[Column("dpnr")]
|
||||
public int DPNr { get; set; }
|
||||
|
||||
[ForeignKey("Year, DId, DPNr")]
|
||||
public virtual DeliveryPart Part { get; private set; }
|
||||
|
||||
[Column("attrid")]
|
||||
public string AttrId { get; set; }
|
||||
|
||||
[ForeignKey("AttrId")]
|
||||
public virtual WineAttr Attr { get; private set; }
|
||||
}
|
||||
}
|
25
Elwig/Models/DeliveryPartModifier.cs
Normal file
25
Elwig/Models/DeliveryPartModifier.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Elwig.Models {
|
||||
[Table("delivery_part_modifier"), PrimaryKey("Year", "DId", "DPNr", "ModId")]
|
||||
public class DeliveryPartModifier {
|
||||
[Column("year")]
|
||||
public int Year { get; set; }
|
||||
|
||||
[Column("did")]
|
||||
public int DId { get; set; }
|
||||
|
||||
[Column("dpnr")]
|
||||
public int DPNr { get; set; }
|
||||
|
||||
[ForeignKey("Year, DId, DPNr")]
|
||||
public virtual DeliveryPart Part { get; private set; }
|
||||
|
||||
[Column("modid")]
|
||||
public string ModId { get; set; }
|
||||
|
||||
[ForeignKey("Year, ModId")]
|
||||
public virtual Modifier Modifier { get; private set; }
|
||||
}
|
||||
}
|
@@ -7,7 +7,7 @@ using System.Linq;
|
||||
|
||||
namespace Elwig.Models {
|
||||
[Table("member"), PrimaryKey("MgNr")]
|
||||
public class Member {
|
||||
public class Member : IAddress {
|
||||
[Column("mgnr")]
|
||||
public int MgNr { get; set; }
|
||||
|
||||
@@ -35,6 +35,25 @@ namespace Elwig.Models {
|
||||
[Column("suffix")]
|
||||
public string? Suffix { get; set; }
|
||||
|
||||
public string Name =>
|
||||
(Prefix != null ? Prefix + " " : "") +
|
||||
GivenName + " " +
|
||||
(MiddleName != null ? MiddleName + " " : "") +
|
||||
FamilyName +
|
||||
(Suffix != null ? " " + Suffix : "");
|
||||
|
||||
public string ShortName => GivenName + " " + FamilyName;
|
||||
|
||||
public string AdministrativeName => AdministrativeName1 + " " + AdministrativeName2;
|
||||
|
||||
public string AdministrativeName1 => FamilyName.ToUpper();
|
||||
|
||||
public string AdministrativeName2 =>
|
||||
(Prefix != null ? Prefix + " " : "") +
|
||||
GivenName +
|
||||
(MiddleName != null ? " " + MiddleName : "") +
|
||||
(Suffix != null ? " " + Suffix : "");
|
||||
|
||||
[Column("birthday")]
|
||||
public string? Birthday { get; set; }
|
||||
|
||||
@@ -76,8 +95,8 @@ namespace Elwig.Models {
|
||||
[Column("lfbis_nr")]
|
||||
public string? LfbisNr { get; set; }
|
||||
|
||||
[Column("ustid")]
|
||||
public string? UstId { get; set; }
|
||||
[Column("ustid_nr")]
|
||||
public string? UstIdNr { get; set; }
|
||||
|
||||
[Column("volllieferant")]
|
||||
public bool IsVollLieferant { get; set; }
|
||||
@@ -91,6 +110,9 @@ namespace Elwig.Models {
|
||||
[Column("active")]
|
||||
public bool IsActive { get; set; }
|
||||
|
||||
[Column("deceased")]
|
||||
public bool IsDeceased { get; set; }
|
||||
|
||||
[Column("iban")]
|
||||
public string? Iban { get; set; }
|
||||
|
||||
@@ -98,7 +120,7 @@ namespace Elwig.Models {
|
||||
public string? Bic { get; set; }
|
||||
|
||||
[Column("country")]
|
||||
public string CountryCode { get; set; }
|
||||
public int CountryNum { get; set; }
|
||||
|
||||
[Column("postal_dest")]
|
||||
public string PostalDestId { get; set; }
|
||||
@@ -109,20 +131,14 @@ namespace Elwig.Models {
|
||||
[Column("email")]
|
||||
public string? Email { get; set; }
|
||||
|
||||
[Column("phone_landline")]
|
||||
public string? PhoneLandline { get; set; }
|
||||
|
||||
[Column("phone_mobile_1")]
|
||||
public string? PhoneMobile1 { get; set; }
|
||||
|
||||
[Column("phone_mobile_2")]
|
||||
public string? PhoneMobile2 { get; set; }
|
||||
|
||||
[Column("default_kgnr")]
|
||||
public int? DefaultKgNr { get; set; }
|
||||
|
||||
[Column("default_contact")]
|
||||
public string DefaultContact { get; set; }
|
||||
[Column("contact_postal")]
|
||||
public bool ContactViaPost { get; set; }
|
||||
|
||||
[Column("contact_email")]
|
||||
public bool ContactViaEmail { get; set; }
|
||||
|
||||
[Column("comment")]
|
||||
public string? Comment { get; set; }
|
||||
@@ -130,10 +146,10 @@ namespace Elwig.Models {
|
||||
[ForeignKey("PredecessorMgNr")]
|
||||
public virtual Member? Predecessor { get; private set; }
|
||||
|
||||
[ForeignKey("CountryCode")]
|
||||
[ForeignKey("CountryNum")]
|
||||
public virtual Country Country { get; private set; }
|
||||
|
||||
[ForeignKey("CountryCode, PostalDestId")]
|
||||
[ForeignKey("CountryNum, PostalDestId")]
|
||||
public virtual PostalDest PostalDest { get; private set; }
|
||||
|
||||
[ForeignKey("DefaultKgNr")]
|
||||
@@ -143,41 +159,33 @@ namespace Elwig.Models {
|
||||
public virtual Branch? Branch { get; private set; }
|
||||
|
||||
[InverseProperty("Member")]
|
||||
public virtual ISet<Contract> Contracts { get; private set; }
|
||||
public virtual ISet<AreaCom> AreaCommitments { get; private set; }
|
||||
|
||||
[NotMapped]
|
||||
public virtual ISet<Contract> ActiveContracts => Contracts
|
||||
.Where(c => c.YearFrom <= Utils.CurrentSeason && (c.YearTo ?? int.MaxValue) >= Utils.CurrentSeason)
|
||||
.ToHashSet();
|
||||
public IEnumerable<AreaCom> ActiveAreaCommitments => AreaCommitments
|
||||
.Where(c => c.YearFrom <= Utils.CurrentNextSeason && (c.YearTo ?? int.MaxValue) >= Utils.CurrentNextSeason);
|
||||
|
||||
[InverseProperty("Member")]
|
||||
public virtual BillingAddr BillingAddress { get; private set; }
|
||||
public virtual BillingAddr? BillingAddress { get; private set; }
|
||||
|
||||
[InverseProperty("Member")]
|
||||
public virtual ISet<Delivery> Deliveries { get; private set; }
|
||||
|
||||
[InverseProperty("Member")]
|
||||
public virtual ISet<MemberTelNr> TelephoneNumbers { get; private set; }
|
||||
|
||||
public string FullAddress => $"{Address}, {PostalDest.AtPlz.Plz} {PostalDest.AtPlz.Ort.Name}";
|
||||
|
||||
public int DeliveryRight => BusinessShares * App.Client.DeliveryRight;
|
||||
public int DeliveryObligation => BusinessShares * App.Client.DeliveryObligation;
|
||||
|
||||
public int SearchScore(IEnumerable<string> keywords) {
|
||||
keywords = keywords.Where(s => s.Length >= 2 || (s.Length > 0 && s.All(c => char.IsDigit(c))));
|
||||
if (!keywords.Any())
|
||||
return 0;
|
||||
|
||||
string?[] check = new string?[] {
|
||||
return Utils.GetSearchScore(new string?[] {
|
||||
MgNr.ToString(),
|
||||
FamilyName.ToLower(), MiddleName?.ToLower(), GivenName.ToLower(),
|
||||
BillingAddress?.Name.ToLower(),
|
||||
Comment?.ToLower(),
|
||||
};
|
||||
|
||||
int i = 0;
|
||||
foreach (string? c in check) {
|
||||
if (c == null) {
|
||||
continue;
|
||||
} else if (keywords.Any(f => c == f)) {
|
||||
i += 100;
|
||||
} else if (keywords.Any(f => c.Split(" ").Any(a => a == f))) {
|
||||
i += 99;
|
||||
} else if (keywords.Any(f => f != null && c.Contains(f))) {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
FamilyName, MiddleName, GivenName,
|
||||
BillingAddress?.Name,
|
||||
Comment,
|
||||
}, keywords);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
25
Elwig/Models/MemberTelNr.cs
Normal file
25
Elwig/Models/MemberTelNr.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Elwig.Models {
|
||||
[Table("member_telephone_number"), PrimaryKey("MgNr", "Nr")]
|
||||
public class MemberTelNr {
|
||||
[Column("mgnr")]
|
||||
public int MgNr { get; set; }
|
||||
|
||||
[Column("nr")]
|
||||
public int Nr { get; set; }
|
||||
|
||||
[Column("type")]
|
||||
public string Type { get; set; }
|
||||
|
||||
[Column("number")]
|
||||
public string Number { get; set; }
|
||||
|
||||
[Column("comment")]
|
||||
public string? Comment { get; set; }
|
||||
|
||||
[ForeignKey("MgNr")]
|
||||
public virtual Member Member { get; private set; }
|
||||
}
|
||||
}
|
@@ -1,5 +1,8 @@
|
||||
using Elwig.Helpers;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
|
||||
namespace Elwig.Models {
|
||||
[Table("modifier"), PrimaryKey("Year", "ModId")]
|
||||
@@ -10,6 +13,9 @@ namespace Elwig.Models {
|
||||
[Column("modid")]
|
||||
public string ModId { get; set; }
|
||||
|
||||
[Column("ordering")]
|
||||
public int Ordering { get; set; }
|
||||
|
||||
[Column("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
@@ -18,16 +24,18 @@ namespace Elwig.Models {
|
||||
|
||||
[NotMapped]
|
||||
public decimal? Abs {
|
||||
get {
|
||||
return AbsValue != null ? Season.DecFromDb((long)AbsValue) : null;
|
||||
}
|
||||
set {
|
||||
AbsValue = value != null ? Season.DecToDb((decimal)value) : null;
|
||||
}
|
||||
get => AbsValue != null ? Season.DecFromDb(AbsValue.Value) : null;
|
||||
set => AbsValue = value != null ? Season.DecToDb(value.Value) : null;
|
||||
}
|
||||
|
||||
[Column("rel")]
|
||||
public double? Rel { get; set; }
|
||||
public double? RelValue { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public decimal? Rel {
|
||||
get => (decimal?)RelValue;
|
||||
set => RelValue = (double?)value;
|
||||
}
|
||||
|
||||
[Column("standard")]
|
||||
public bool IsStandard { get; set; }
|
||||
@@ -38,5 +46,13 @@ namespace Elwig.Models {
|
||||
[ForeignKey("Year")]
|
||||
public virtual Season Season { get; private set; }
|
||||
|
||||
public string ValueStr =>
|
||||
(Abs != null) ? $"{Utils.GetSign(Abs.Value)}{Math.Abs(Abs.Value).ToString("0." + string.Concat(Enumerable.Repeat('0', Season.Precision)))}\u00a0{Season.Currency.Symbol}/kg" :
|
||||
(Rel != null) ? $"{Utils.GetSign(Rel.Value)}{(Math.Abs(Rel.Value) < 0.1m ? "\u2007" : "")}{Math.Abs(Rel.Value):0.00##\u00a0%}" :
|
||||
"";
|
||||
|
||||
public override string ToString() {
|
||||
return Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
158
Elwig/Models/PaymentDeliveryPart.cs
Normal file
158
Elwig/Models/PaymentDeliveryPart.cs
Normal file
@@ -0,0 +1,158 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
|
||||
namespace Elwig.Models {
|
||||
[Table("payment_delivery_part"), PrimaryKey("Year", "DId", "DPNr", "AvNr")]
|
||||
public class PaymentDeliveryPart {
|
||||
[Column("year")]
|
||||
public int Year { get; set; }
|
||||
|
||||
[Column("did")]
|
||||
public int DId { get; set; }
|
||||
|
||||
[Column("dpnr")]
|
||||
public int DPNr { get; set; }
|
||||
|
||||
[Column("avnr")]
|
||||
public int AvNr { get; set; }
|
||||
|
||||
[Column("mod_abs")]
|
||||
public long ModAbsValue { get; set; }
|
||||
[NotMapped]
|
||||
public decimal ModAbs {
|
||||
get => Variant.Season.DecFromDb(ModAbsValue);
|
||||
set => ModAbsValue = Variant.Season.DecToDb(value);
|
||||
}
|
||||
|
||||
[Column("mod_rel")]
|
||||
public double ModRelValue { get; set; }
|
||||
[NotMapped]
|
||||
public decimal ModRel {
|
||||
get => (decimal)ModRelValue;
|
||||
set => ModRelValue = (double)value;
|
||||
}
|
||||
|
||||
[Column("bucket_1")]
|
||||
public int? Bucket1 { get; set; }
|
||||
|
||||
[Column("bucket_2")]
|
||||
public int? Bucket2 { get; set; }
|
||||
|
||||
[Column("bucket_3")]
|
||||
public int? Bucket3 { get; set; }
|
||||
|
||||
[Column("bucket_4")]
|
||||
public int? Bucket4 { get; set; }
|
||||
|
||||
[Column("bucket_5")]
|
||||
public int? Bucket5 { get; set; }
|
||||
|
||||
[Column("bucket_6")]
|
||||
public int? Bucket6 { get; set; }
|
||||
|
||||
[Column("bucket_7")]
|
||||
public int? Bucket7 { get; set; }
|
||||
|
||||
[Column("bucket_8")]
|
||||
public int? Bucket8 { get; set; }
|
||||
|
||||
[Column("bucket_9")]
|
||||
public int? Bucket9 { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public int[] Buckets => (new int?[] { Bucket1, Bucket2, Bucket3, Bucket4, Bucket5, Bucket6, Bucket7, Bucket8, Bucket9 })
|
||||
.Where(b => b != null).Select(b => b.Value).ToArray();
|
||||
|
||||
[Column("price_1")]
|
||||
public long? Price1Value { get; set; }
|
||||
[NotMapped]
|
||||
public decimal? Price1 {
|
||||
get => Price1Value != null ? Variant.Season.DecFromDb(Price1Value.Value) : null;
|
||||
set => Price1Value = value != null ? Variant.Season.DecToDb(value.Value) : null;
|
||||
}
|
||||
|
||||
[Column("price_2")]
|
||||
public long? Price2Value { get; set; }
|
||||
[NotMapped]
|
||||
public decimal? Price2 {
|
||||
get => Price2Value != null ? Variant.Season.DecFromDb(Price2Value.Value) : null;
|
||||
set => Price2Value = value != null ? Variant.Season.DecToDb(value.Value) : null;
|
||||
}
|
||||
|
||||
[Column("price_3")]
|
||||
public long? Price3Value { get; set; }
|
||||
[NotMapped]
|
||||
public decimal? Price3 {
|
||||
get => Price3Value != null ? Variant.Season.DecFromDb(Price3Value.Value) : null;
|
||||
set => Price3Value = value != null ? Variant.Season.DecToDb(value.Value) : null;
|
||||
}
|
||||
|
||||
[Column("price_4")]
|
||||
public long? Price4Value { get; set; }
|
||||
[NotMapped]
|
||||
public decimal? Price4 {
|
||||
get => Price4Value != null ? Variant.Season.DecFromDb(Price4Value.Value) : null;
|
||||
set => Price4Value = value != null ? Variant.Season.DecToDb(value.Value) : null;
|
||||
}
|
||||
|
||||
[Column("price_5")]
|
||||
public long? Price5Value { get; set; }
|
||||
[NotMapped]
|
||||
public decimal? Price5 {
|
||||
get => Price5Value != null ? Variant.Season.DecFromDb(Price5Value.Value) : null;
|
||||
set => Price5Value = value != null ? Variant.Season.DecToDb(value.Value) : null;
|
||||
}
|
||||
|
||||
[Column("price_6")]
|
||||
public long? Price6Value { get; set; }
|
||||
[NotMapped]
|
||||
public decimal? Price6 {
|
||||
get => Price6Value != null ? Variant.Season.DecFromDb(Price6Value.Value) : null;
|
||||
set => Price6Value = value != null ? Variant.Season.DecToDb(value.Value) : null;
|
||||
}
|
||||
|
||||
[Column("price_7")]
|
||||
public long? Price7Value { get; set; }
|
||||
[NotMapped]
|
||||
public decimal? Price7 {
|
||||
get => Price7Value != null ? Variant.Season.DecFromDb(Price7Value.Value) : null;
|
||||
set => Price7Value = value != null ? Variant.Season.DecToDb(value.Value) : null;
|
||||
}
|
||||
|
||||
[Column("price_8")]
|
||||
public long? Price8Value { get; set; }
|
||||
[NotMapped]
|
||||
public decimal? Price8 {
|
||||
get => Price8Value != null ? Variant.Season.DecFromDb(Price8Value.Value) : null;
|
||||
set => Price8Value = value != null ? Variant.Season.DecToDb(value.Value) : null;
|
||||
}
|
||||
|
||||
[Column("price_9")]
|
||||
public long? Price9Value { get; set; }
|
||||
[NotMapped]
|
||||
public decimal? Price9 {
|
||||
get => Price9Value != null ? Variant.Season.DecFromDb(Price9Value.Value) : null;
|
||||
set => Price9Value = value != null ? Variant.Season.DecToDb(value.Value) : null;
|
||||
}
|
||||
|
||||
[Column("amount")]
|
||||
public long? AmountValue { get; set; }
|
||||
[NotMapped]
|
||||
public decimal? Amount {
|
||||
get => AmountValue != null ? Variant.Season.DecFromDb(AmountValue.Value) : null;
|
||||
set => AmountValue = value != null ? Variant.Season.DecToDb(value.Value) : null;
|
||||
}
|
||||
|
||||
[NotMapped]
|
||||
public decimal[] Prices => (new decimal?[] { Price1, Price2, Price3, Price4, Price5, Price6, Price7, Price8, Price9 })
|
||||
.Where(p => p != null).Select(p => p.Value).ToArray();
|
||||
|
||||
[ForeignKey("Year, AvNr")]
|
||||
public virtual PaymentVar Variant { get; private set; }
|
||||
|
||||
[ForeignKey("Year, DId, DPNr")]
|
||||
public virtual DeliveryPart DeliveryPart { get; private set; }
|
||||
}
|
||||
}
|
34
Elwig/Models/PaymentMember.cs
Normal file
34
Elwig/Models/PaymentMember.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Elwig.Models {
|
||||
[Table("payment_member"), PrimaryKey("Year", "AvNr", "MgNr")]
|
||||
public class PaymentMember {
|
||||
[Column("year")]
|
||||
public int Year { get; set; }
|
||||
|
||||
[Column("avnr")]
|
||||
public int AvNr { get; set; }
|
||||
|
||||
[Column("mgnr")]
|
||||
public int MgNr { get; set; }
|
||||
|
||||
[Column("amount")]
|
||||
public long AmountValue { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public decimal Amount {
|
||||
get => Variant.Season.DecFromDb(AmountValue);
|
||||
set => AmountValue = Variant.Season.DecToDb(value);
|
||||
}
|
||||
|
||||
[ForeignKey("Year, AvNr")]
|
||||
public virtual PaymentVar Variant { get; private set; }
|
||||
|
||||
[ForeignKey("MgNr")]
|
||||
public virtual Member Member { get; private set; }
|
||||
|
||||
[InverseProperty("Payment")]
|
||||
public virtual Credit? Credit { get; private set; }
|
||||
}
|
||||
}
|
89
Elwig/Models/PaymentVar.cs
Normal file
89
Elwig/Models/PaymentVar.cs
Normal file
@@ -0,0 +1,89 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
|
||||
namespace Elwig.Models {
|
||||
[Table("payment_variant"), PrimaryKey("Year", "AvNr")]
|
||||
public class PaymentVar {
|
||||
[Column("year")]
|
||||
public int Year { get; set; }
|
||||
|
||||
[Column("avnr")]
|
||||
public int AvNr { get; set; }
|
||||
|
||||
[Column("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[Column("date")]
|
||||
public string DateString { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public DateOnly Date {
|
||||
get => DateOnly.ParseExact(DateString, "yyyy-MM-dd");
|
||||
set => DateString = value.ToString("yyyy-MM-dd");
|
||||
}
|
||||
|
||||
[Column("transfer_date")]
|
||||
public string? TransferDateString { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public DateOnly? TransferDate {
|
||||
get => TransferDateString != null ? DateOnly.ParseExact(TransferDateString, "yyyy-MM-dd") : null;
|
||||
set => TransferDateString = value?.ToString("yyyy-MM-dd");
|
||||
}
|
||||
|
||||
[Column("test_variant")]
|
||||
public bool TestVariant { get; set; }
|
||||
|
||||
[Column("calc_time")]
|
||||
public int? CalcTime { get; set; }
|
||||
|
||||
[Column("bucket_1_name")]
|
||||
public string? Bucket1Name { get; set; }
|
||||
|
||||
[Column("bucket_2_name")]
|
||||
public string? Bucket2Name { get; set; }
|
||||
|
||||
[Column("bucket_3_name")]
|
||||
public string? Bucket3Name { get; set; }
|
||||
|
||||
[Column("bucket_4_name")]
|
||||
public string? Bucket4Name { get; set; }
|
||||
|
||||
[Column("bucket_5_name")]
|
||||
public string? Bucket5Name { get; set; }
|
||||
|
||||
[Column("bucket_6_name")]
|
||||
public string? Bucket6Name { get; set; }
|
||||
|
||||
[Column("bucket_7_name")]
|
||||
public string? Bucket7Name { get; set; }
|
||||
|
||||
[Column("bucket_8_name")]
|
||||
public string? Bucket8Name { get; set; }
|
||||
|
||||
[Column("bucket_9_name")]
|
||||
public string? Bucket9Name { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public string[] BucketNames => (new string?[] { Bucket1Name, Bucket2Name, Bucket3Name, Bucket4Name, Bucket5Name, Bucket6Name, Bucket7Name, Bucket8Name, Bucket9Name })
|
||||
.Where(n => n != null).Select(n => n ?? "").ToArray();
|
||||
|
||||
[Column("comment")]
|
||||
public string? Comment { get; set; }
|
||||
|
||||
[Column("data")]
|
||||
public string Data { get; set; }
|
||||
|
||||
[ForeignKey("Year")]
|
||||
public virtual Season Season { get; private set; }
|
||||
|
||||
[InverseProperty("Variant")]
|
||||
public virtual ISet<PaymentMember> MemberPayments { get; private set; }
|
||||
|
||||
[InverseProperty("Variant")]
|
||||
public virtual ISet<Credit> Credits { get; private set; }
|
||||
}
|
||||
}
|
@@ -2,15 +2,15 @@ using Microsoft.EntityFrameworkCore;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Elwig.Models {
|
||||
[Table("postal_dest"), PrimaryKey("CountryCode", "Id")]
|
||||
[Table("postal_dest"), PrimaryKey("CountryNum", "Id")]
|
||||
public class PostalDest {
|
||||
[Column("country")]
|
||||
public string CountryCode { get; private set; }
|
||||
public int CountryNum { get; private set; }
|
||||
|
||||
[Column("id")]
|
||||
public string Id { get; private set; }
|
||||
|
||||
[ForeignKey("CountryCode")]
|
||||
[ForeignKey("CountryNum")]
|
||||
public virtual Country Country { get; private set; }
|
||||
|
||||
[ForeignKey("Id")]
|
||||
|
@@ -48,6 +48,12 @@ namespace Elwig.Models {
|
||||
[InverseProperty("Season")]
|
||||
public virtual ISet<Modifier> Modifiers { get; private set; }
|
||||
|
||||
[InverseProperty("Season")]
|
||||
public virtual ISet<PaymentVar> PaymentVariants { get; private set; }
|
||||
|
||||
[InverseProperty("Season")]
|
||||
public virtual ISet<Delivery> Deliveries { get; private set; }
|
||||
|
||||
public decimal DecFromDb(long value) {
|
||||
return Utils.DecFromDb(value, Precision);
|
||||
}
|
||||
|
19
Elwig/Models/WbGem.cs
Normal file
19
Elwig/Models/WbGem.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Elwig.Models {
|
||||
[Table("wb_gem"), PrimaryKey("Gkz")]
|
||||
public class WbGem {
|
||||
[Column("gkz")]
|
||||
public int Gkz { get; private set; }
|
||||
|
||||
[Column("hkid")]
|
||||
public string HkId { get; private set; }
|
||||
|
||||
[ForeignKey("Gkz")]
|
||||
public virtual AT_Gem AtGem { get; private set; }
|
||||
|
||||
[ForeignKey("HkId")]
|
||||
public virtual WineOrigin Origin { get; private set; }
|
||||
}
|
||||
}
|
17
Elwig/Models/WbGl.cs
Normal file
17
Elwig/Models/WbGl.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Elwig.Models {
|
||||
[Table("wb_gl"), PrimaryKey("GlNr")]
|
||||
public class WbGl {
|
||||
[Column("glnr")]
|
||||
public int GlNr { get; private set; }
|
||||
|
||||
[Column("name")]
|
||||
public string Name { get; private set; }
|
||||
|
||||
[InverseProperty("Gl")]
|
||||
public virtual ISet<WbKg> Kgs { get; private set; }
|
||||
}
|
||||
}
|
@@ -1,4 +1,5 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Elwig.Models {
|
||||
@@ -11,6 +12,18 @@ namespace Elwig.Models {
|
||||
public int? GlNr { get; set; }
|
||||
|
||||
[ForeignKey("KgNr")]
|
||||
public virtual AT_Kg Kg { get; private set; }
|
||||
public virtual AT_Kg AtKg { get; private set; }
|
||||
|
||||
[ForeignKey("GlNr")]
|
||||
public virtual WbGl Gl { get; private set; }
|
||||
|
||||
[InverseProperty("Kg")]
|
||||
public virtual ISet<WbRd> Rds { get; private set; }
|
||||
|
||||
[NotMapped]
|
||||
public WbGem Gem => AtKg.Gem.WbGem;
|
||||
|
||||
[NotMapped]
|
||||
public WineOrigin Origin => Gem.Origin;
|
||||
}
|
||||
}
|
||||
|
@@ -14,6 +14,6 @@ namespace Elwig.Models {
|
||||
public string Name { get; set; }
|
||||
|
||||
[ForeignKey("KgNr")]
|
||||
public virtual WbKg WbKg { get; private set; }
|
||||
public virtual WbKg Kg { get; private set; }
|
||||
}
|
||||
}
|
||||
|
@@ -10,7 +10,13 @@ namespace Elwig.Models {
|
||||
[Column("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[Column("kg_per_ha")]
|
||||
public int KgPerHa { get; set; }
|
||||
[Column("max_kg_per_ha")]
|
||||
public int? MaxKgPerHa { get; set; }
|
||||
|
||||
[Column("active")]
|
||||
public bool IsActive { get; set; }
|
||||
public override string ToString() {
|
||||
return Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
46
Elwig/Models/WineOrigin.cs
Normal file
46
Elwig/Models/WineOrigin.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
|
||||
namespace Elwig.Models {
|
||||
[Table("wine_origin"), PrimaryKey("HkId"), Index("Name", IsUnique = true)]
|
||||
public class WineOrigin {
|
||||
[Column("hkid")]
|
||||
public string HkId { get; private set; }
|
||||
|
||||
[Column("parent_hkid")]
|
||||
public string? ParentHkId { get; private set; }
|
||||
|
||||
[ForeignKey("ParentHkId")]
|
||||
public virtual WineOrigin? Parent { get; private set; }
|
||||
|
||||
[Column("name")]
|
||||
public string Name { get; private set; }
|
||||
|
||||
[Column("blnr")]
|
||||
public int? BlNr { get; private set; }
|
||||
|
||||
[InverseProperty("Origin")]
|
||||
public virtual ISet<WbGem> Gems { get; private set; }
|
||||
|
||||
[InverseProperty("Parent")]
|
||||
public virtual ISet<WineOrigin> Children { get; private set; }
|
||||
|
||||
public int Level => (Parent?.Level + 1) ?? 0;
|
||||
|
||||
public string HkIdLevel => $"{new string(' ', Level * 2)}{HkId}";
|
||||
|
||||
public int TotalChildNum => 1 + Children.Select(c => c.TotalChildNum).Sum();
|
||||
|
||||
private int SortKey1 => (Parent?.SortKey1 ?? 0) | (TotalChildNum << ((3 - Level) * 8));
|
||||
public int SortKey => SortKey1 | ((Level < 3) ? (-1 >>> (Level * 8 + 8)) : 0);
|
||||
|
||||
public override string ToString() {
|
||||
return Name;
|
||||
}
|
||||
|
||||
public string OriginString => (Parent != null ? $"{Parent.OriginString} / " : "") + Name;
|
||||
}
|
||||
}
|
@@ -1,26 +0,0 @@
|
||||
using Elwig.Helpers;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Elwig.Models {
|
||||
[Table("wine_quality"), PrimaryKey("QualId")]
|
||||
public class WineQual {
|
||||
[Column("qualid")]
|
||||
public string QualId { get; private set; }
|
||||
|
||||
[Column("origin_level")]
|
||||
public int? OriginLevel { get; private set; }
|
||||
|
||||
[Column("predicate")]
|
||||
public bool IsPredicate { get; private set; }
|
||||
|
||||
[Column("min_kmw")]
|
||||
public double? MinKmw { get; private set; }
|
||||
|
||||
[NotMapped]
|
||||
public double? MinOe => MinKmw != null ? Utils.KmwToOe((double)MinKmw) : null;
|
||||
|
||||
[Column("name")]
|
||||
public string Name { get; private set; }
|
||||
}
|
||||
}
|
47
Elwig/Models/WineQualLevel.cs
Normal file
47
Elwig/Models/WineQualLevel.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using Elwig.Helpers;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Configuration;
|
||||
using System.Security.Cryptography.Pkcs;
|
||||
|
||||
namespace Elwig.Models {
|
||||
[Table("wine_quality_level"), PrimaryKey("QualId")]
|
||||
public class WineQualLevel : IEquatable<WineQualLevel> {
|
||||
[Column("qualid")]
|
||||
public string QualId { get; private set; }
|
||||
|
||||
[Column("origin_level")]
|
||||
public int? OriginLevel { get; private set; }
|
||||
|
||||
[Column("predicate")]
|
||||
public bool IsPredicate { get; private set; }
|
||||
|
||||
[Column("min_kmw")]
|
||||
public double? MinKmw { get; private set; }
|
||||
|
||||
[NotMapped]
|
||||
public double? MinOe => MinKmw != null ? Utils.KmwToOe((double)MinKmw) : null;
|
||||
|
||||
[Column("name")]
|
||||
public string Name { get; private set; }
|
||||
|
||||
public string MinKmwStr => (MinKmw == null) ? "" : $"(mind. {MinKmw:#.0}°)";
|
||||
|
||||
public override bool Equals(object? obj) {
|
||||
return Equals(obj as WineQualLevel);
|
||||
}
|
||||
|
||||
public bool Equals(WineQualLevel? obj) {
|
||||
return QualId == obj?.QualId;
|
||||
}
|
||||
|
||||
public static bool operator ==(WineQualLevel? q1, WineQualLevel? q2) {
|
||||
return q1?.Equals(q2) ?? Equals(q1, q2);
|
||||
}
|
||||
|
||||
public static bool operator !=(WineQualLevel? q1, WineQualLevel? q2) {
|
||||
return !(q1?.Equals(q2) ?? Equals(q1, q2));
|
||||
}
|
||||
}
|
||||
}
|
@@ -15,5 +15,14 @@ namespace Elwig.Models {
|
||||
|
||||
[Column("comment")]
|
||||
public string? Comment { get; private set; }
|
||||
|
||||
public string CommentFormat => (Comment != null) ? $" ({Comment})" : "";
|
||||
|
||||
public bool IsRed => Type == "R";
|
||||
public bool IsWhite => Type == "W";
|
||||
|
||||
public override string ToString() {
|
||||
return Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
https://go.microsoft.com/fwlink/?LinkID=208121.
|
||||
-->
|
||||
|
@@ -1,45 +1,109 @@
|
||||
using Elwig.Helpers;
|
||||
using Elwig.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Threading;
|
||||
using Xceed.Wpf.Toolkit;
|
||||
|
||||
namespace Elwig.Windows {
|
||||
public abstract class AdministrationWindow : ContextWindow {
|
||||
|
||||
protected Control[] ExemptInputs { private get; set; }
|
||||
protected Control[] RequiredInputs { private get; set; }
|
||||
|
||||
private bool _IsEditing;
|
||||
private bool _IsCreating;
|
||||
protected bool IsEditing {
|
||||
get { return _IsEditing; }
|
||||
set {
|
||||
_IsEditing = value;
|
||||
LockContext = IsEditing;
|
||||
}
|
||||
}
|
||||
protected bool IsCreating {
|
||||
get { return _IsCreating; }
|
||||
set {
|
||||
_IsCreating = value;
|
||||
LockContext = IsEditing;
|
||||
}
|
||||
}
|
||||
protected bool DoShowWarningWindows = true;
|
||||
protected bool IsClosing { get; private set; }
|
||||
|
||||
private TextBox[] TextBoxInputs;
|
||||
private TextBox[] PlzInputs;
|
||||
private ComboBox[] ComboBoxInputs;
|
||||
private ComboBox[] PlzOrtInputs;
|
||||
private CheckComboBox[] CheckComboBoxInputs;
|
||||
private CheckBox[] CheckBoxInputs;
|
||||
private RadioButton[] RadioButtonInputs;
|
||||
private readonly Dictionary<Control, bool> Valid;
|
||||
private readonly Dictionary<Control, object?> OriginalValues;
|
||||
private readonly Dictionary<Control, object?> DefaultValues;
|
||||
|
||||
public AdministrationWindow() : base() {
|
||||
IsEditing = false;
|
||||
IsCreating = false;
|
||||
ExemptInputs = Array.Empty<Control>();
|
||||
RequiredInputs = Array.Empty<Control>();
|
||||
TextBoxInputs = Array.Empty<TextBox>();
|
||||
PlzInputs = Array.Empty<TextBox>();
|
||||
ComboBoxInputs = Array.Empty<ComboBox>();
|
||||
CheckComboBoxInputs = Array.Empty<CheckComboBox>();
|
||||
PlzOrtInputs = Array.Empty<ComboBox>();
|
||||
CheckBoxInputs = Array.Empty<CheckBox>();
|
||||
RadioButtonInputs = Array.Empty<RadioButton>();
|
||||
Valid = new();
|
||||
OriginalValues = new();
|
||||
DefaultValues = new();
|
||||
Closing += OnClosing;
|
||||
Loaded += OnLoaded;
|
||||
}
|
||||
|
||||
private void OnLoaded(object sender, RoutedEventArgs evt) {
|
||||
TextBoxInputs = Utils.FindAllChildren<TextBox>(this, ExemptInputs).ToArray();
|
||||
ComboBoxInputs = Utils.FindAllChildren<ComboBox>(this, ExemptInputs).ToArray();
|
||||
CheckBoxInputs = Utils.FindAllChildren<CheckBox>(this, ExemptInputs).ToArray();
|
||||
RadioButtonInputs = Utils.FindAllChildren<RadioButton>(this, ExemptInputs).ToArray();
|
||||
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();
|
||||
RadioButtonInputs = ControlUtils.FindAllChildren<RadioButton>(this, ExemptInputs).ToArray();
|
||||
PlzInputs = TextBoxInputs.Where(tb => "PLZ".Equals(tb.Tag)).ToArray();
|
||||
PlzOrtInputs = PlzInputs.Select(tb => ControlUtils.FindNextSibling<ComboBox>(tb) ?? throw new MissingMemberException()).ToArray();
|
||||
foreach (var tb in TextBoxInputs)
|
||||
Valid[tb] = true;
|
||||
foreach (var cb in ComboBoxInputs)
|
||||
cb.SelectionChanged += ComboBox_SelectionChanged;
|
||||
foreach (var cb in CheckComboBoxInputs)
|
||||
cb.ItemSelectionChanged += ComboBox_SelectionChanged;
|
||||
}
|
||||
|
||||
private void OnClosing(object? sender, CancelEventArgs evt) {
|
||||
if ((IsCreating || IsEditing) && HasChanged) {
|
||||
var r = System.Windows.MessageBox.Show("Soll das Fenster wirklich geschlossen werden?", "Schlie<69>en best<73>tigen",
|
||||
MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No);
|
||||
if (r != MessageBoxResult.Yes) {
|
||||
evt.Cancel = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
IsClosing = true;
|
||||
}
|
||||
|
||||
private ComboBox GetPlzOrtInput(TextBox input) {
|
||||
return PlzOrtInputs[Array.IndexOf(PlzInputs, input)];
|
||||
}
|
||||
|
||||
abstract protected void UpdateButtons();
|
||||
|
||||
protected override async Task RenewContext() {
|
||||
for (int i = 0; i < PlzInputs.Length; i++)
|
||||
UpdatePlz(PlzInputs[i], PlzOrtInputs[i]);
|
||||
}
|
||||
|
||||
protected void ValidateInput(Control input, bool valid) {
|
||||
Valid[input] = valid;
|
||||
}
|
||||
@@ -48,33 +112,58 @@ namespace Elwig.Windows {
|
||||
return (sender is Control c) && RequiredInputs.Contains(c);
|
||||
}
|
||||
|
||||
protected void FinishInputFilling() {
|
||||
FillOriginalValues();
|
||||
ValidateDefaultValues();
|
||||
ValidateRequiredInputs();
|
||||
}
|
||||
|
||||
protected void ClearInputStates() {
|
||||
foreach (var tb in TextBoxInputs)
|
||||
Utils.ClearInputState(tb);
|
||||
ControlUtils.ClearInputState(tb);
|
||||
foreach (var cb in ComboBoxInputs)
|
||||
Utils.ClearInputState(cb);
|
||||
ControlUtils.ClearInputState(cb);
|
||||
foreach (var ccb in CheckComboBoxInputs)
|
||||
ControlUtils.ClearInputState(ccb);
|
||||
foreach (var cb in CheckBoxInputs)
|
||||
Utils.ClearInputState(cb);
|
||||
ControlUtils.ClearInputState(cb);
|
||||
foreach (var rb in RadioButtonInputs)
|
||||
Utils.ClearInputState(rb);
|
||||
ControlUtils.ClearInputState(rb);
|
||||
}
|
||||
|
||||
protected void ValidateRequiredInputs() {
|
||||
foreach (var input in RequiredInputs) {
|
||||
if (input is TextBox tb && tb.Text.Length == 0) {
|
||||
Utils.SetInputInvalid(input);
|
||||
ControlUtils.SetInputInvalid(input);
|
||||
Valid[input] = false;
|
||||
} else if (input is ComboBox cb && cb.SelectedItem == null && cb.ItemsSource != null) {
|
||||
Utils.SetInputInvalid(input);
|
||||
ControlUtils.SetInputInvalid(input);
|
||||
} else if (input is CheckComboBox ccb && ccb.SelectedItem == null && ccb.ItemsSource != null) {
|
||||
ControlUtils.SetInputInvalid(input);
|
||||
} else if (input is CheckBox ckb && ckb.IsChecked != true) {
|
||||
ControlUtils.SetInputInvalid(input);
|
||||
Valid[input] = false;
|
||||
} else if (input is RadioButton rb && rb.IsChecked != true) {
|
||||
ControlUtils.SetInputInvalid(input);
|
||||
Valid[input] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void ValidateDefaultValues() {
|
||||
foreach (var input in DefaultValues.Keys) {
|
||||
if (InputIsNotDefault(input))
|
||||
ControlUtils.SetInputNotDefault(input);
|
||||
}
|
||||
}
|
||||
|
||||
protected void LockInputs() {
|
||||
foreach (var tb in TextBoxInputs)
|
||||
tb.IsReadOnly = true;
|
||||
foreach (var cb in ComboBoxInputs)
|
||||
cb.IsEnabled = false;
|
||||
foreach (var ccb in CheckComboBoxInputs)
|
||||
ccb.IsEnabled = false;
|
||||
foreach (var cb in CheckBoxInputs)
|
||||
cb.IsEnabled = false;
|
||||
foreach (var rb in RadioButtonInputs)
|
||||
@@ -86,6 +175,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 cb in CheckBoxInputs)
|
||||
cb.IsEnabled = true;
|
||||
foreach (var rb in RadioButtonInputs)
|
||||
@@ -96,31 +187,81 @@ namespace Elwig.Windows {
|
||||
OriginalValues.Clear();
|
||||
}
|
||||
|
||||
protected void ClearDefaultValues() {
|
||||
DefaultValues.Clear();
|
||||
}
|
||||
|
||||
protected void FillOriginalValues() {
|
||||
foreach (var tb in TextBoxInputs)
|
||||
OriginalValues[tb] = tb.Text;
|
||||
foreach (var cb in ComboBoxInputs)
|
||||
OriginalValues[cb] = cb.SelectedItem;
|
||||
foreach (var ccb in CheckComboBoxInputs)
|
||||
OriginalValues[ccb] = ccb.SelectedItems.Cast<object>().ToArray();
|
||||
foreach (var cb in CheckBoxInputs)
|
||||
OriginalValues[cb] = (cb.IsChecked ?? false) ? bool.TrueString : null;
|
||||
OriginalValues[cb] = cb.IsChecked?.ToString();
|
||||
foreach (var rb in RadioButtonInputs)
|
||||
OriginalValues[rb] = (rb.IsChecked ?? false) ? bool.TrueString : null;
|
||||
OriginalValues[rb] = rb.IsChecked?.ToString();
|
||||
}
|
||||
|
||||
protected void ClearInputs() {
|
||||
protected void SetOriginalValue(Control input, object? value) {
|
||||
OriginalValues[input] = value is bool b ? b.ToString() : value;
|
||||
if (InputHasChanged(input)) {
|
||||
ControlUtils.SetInputChanged(input);
|
||||
} else {
|
||||
ControlUtils.ClearInputState(input);
|
||||
}
|
||||
}
|
||||
|
||||
protected void SetOriginalValue(Control input) {
|
||||
SetOriginalValue(input, ControlUtils.GetInputValue(input));
|
||||
}
|
||||
|
||||
protected void UnsetOriginalValue(Control input) {
|
||||
OriginalValues.Remove(input);
|
||||
ControlUtils.ClearInputState(input);
|
||||
}
|
||||
|
||||
protected void SetDefaultValue(Control input, object? value) {
|
||||
DefaultValues[input] = value is bool b ? b.ToString() : value;
|
||||
if (!InputHasChanged(input)) {
|
||||
if (InputIsNotDefault(input)) {
|
||||
ControlUtils.SetInputNotDefault(input);
|
||||
} else {
|
||||
ControlUtils.ClearInputState(input);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void SetDefaultValue(Control input) {
|
||||
SetDefaultValue(input, ControlUtils.GetInputValue(input));
|
||||
}
|
||||
|
||||
protected void UnsetDefaultValue(Control input) {
|
||||
DefaultValues.Remove(input);
|
||||
if (!InputHasChanged(input)) {
|
||||
ControlUtils.ClearInputState(input);
|
||||
}
|
||||
}
|
||||
|
||||
protected void ClearInputs(bool validate = true) {
|
||||
foreach (var tb in TextBoxInputs)
|
||||
tb.Text = "";
|
||||
foreach (var cb in ComboBoxInputs)
|
||||
cb.SelectedItem = null;
|
||||
foreach (var ccb in CheckComboBoxInputs)
|
||||
ccb.SelectedItems.Clear();
|
||||
foreach (var cb in CheckBoxInputs)
|
||||
cb.IsChecked = false;
|
||||
foreach (var rb in RadioButtonInputs)
|
||||
rb.IsChecked = false;
|
||||
ValidateRequiredInputs();
|
||||
if (validate) ValidateRequiredInputs();
|
||||
}
|
||||
|
||||
protected bool IsValid() {
|
||||
return Valid.All(kv => kv.Value) && ComboBoxInputs.All(cb => cb.ItemsSource == null || cb.SelectedItem != null);
|
||||
protected bool IsValid => Valid.All(kv => kv.Value);
|
||||
|
||||
protected bool GetInputValid(Control input) {
|
||||
return Valid[input];
|
||||
}
|
||||
|
||||
protected bool InputHasChanged(Control input) {
|
||||
@@ -130,82 +271,130 @@ namespace Elwig.Windows {
|
||||
return OriginalValues[tb]?.ToString() != tb.Text;
|
||||
} else if (input is ComboBox sb) {
|
||||
return OriginalValues[sb] != sb.SelectedItem;
|
||||
} else if (input is CheckComboBox ccb) {
|
||||
return !ccb.SelectedItems.Cast<object>().ToArray().SequenceEqual(((object[]?)OriginalValues[ccb]) ?? Array.Empty<object>());
|
||||
} else if (input is CheckBox cb) {
|
||||
return (OriginalValues[cb] != null) != (cb.IsChecked ?? false);
|
||||
return (string?)OriginalValues[cb] != cb.IsChecked?.ToString();
|
||||
} else if (input is RadioButton rb) {
|
||||
return (OriginalValues[rb] != null) != (rb.IsChecked ?? false);
|
||||
return (string?)OriginalValues[rb] != rb.IsChecked?.ToString();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected bool HasChanged() {
|
||||
return !IsValid() ||
|
||||
protected bool InputIsNotDefault(Control input) {
|
||||
if (!DefaultValues.ContainsKey(input)) {
|
||||
return false;
|
||||
} else if (input is TextBox tb) {
|
||||
return DefaultValues[tb]?.ToString() != tb.Text;
|
||||
} else if (input is ComboBox sb) {
|
||||
return DefaultValues[sb] != sb.SelectedItem;
|
||||
} else if (input is CheckComboBox ccb) {
|
||||
return !ccb.SelectedItems.Cast<object>().ToArray().SequenceEqual(((object[]?)DefaultValues[ccb]) ?? Array.Empty<object>());
|
||||
} else if (input is CheckBox cb) {
|
||||
return (string?)DefaultValues[cb] != cb.IsChecked?.ToString();
|
||||
} else if (input is RadioButton rb) {
|
||||
return (string?)DefaultValues[rb] != rb.IsChecked?.ToString();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected bool HasChanged =>
|
||||
IsEditing && (
|
||||
!IsValid ||
|
||||
TextBoxInputs.Any(InputHasChanged) ||
|
||||
ComboBoxInputs.Any(InputHasChanged) ||
|
||||
CheckComboBoxInputs.Any(InputHasChanged) ||
|
||||
CheckBoxInputs.Any(InputHasChanged) ||
|
||||
RadioButtonInputs.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) ||
|
||||
CheckBoxInputs.Any(InputIsNotDefault) ||
|
||||
RadioButtonInputs.Any(InputIsNotDefault)
|
||||
);
|
||||
|
||||
protected void UpdatePlz(TextBox plzInput, ComboBox ortInput) {
|
||||
if (plzInput.Text.Length == 4) {
|
||||
ortInput.ItemsSource = Context.Postleitzahlen.Find(int.Parse(plzInput.Text))?.Orte.ToList();
|
||||
} else {
|
||||
ortInput.ItemsSource = null;
|
||||
}
|
||||
ortInput.SelectedItem = null;
|
||||
if (ortInput.ItemsSource != null) {
|
||||
Utils.SetInputInvalid(ortInput);
|
||||
} else {
|
||||
Utils.ClearInputState(ortInput);
|
||||
}
|
||||
ValidateInput(plzInput, SenderIsRequired(plzInput) || (ortInput.ItemsSource != null));
|
||||
UpdateButtons();
|
||||
var plzInputValid = GetInputValid(plzInput);
|
||||
var item = ortInput.SelectedItem;
|
||||
var list = plzInputValid && plzInput.Text.Length == 4 ? Context.Postleitzahlen.Find(int.Parse(plzInput.Text))?.Orte.ToList() : null;
|
||||
ControlUtils.RenewItemsSource(ortInput, list, i => (i as AT_PlzDest)?.Id);
|
||||
if (list != null && ortInput.SelectedItem == null && list.Count == 1)
|
||||
ortInput.SelectedItem = list[0];
|
||||
UpdateComboBox(ortInput);
|
||||
}
|
||||
|
||||
protected void InputTextChanged(TextBox input, Func<TextBox, bool, ValidationResult> checker) {
|
||||
InputTextChanged(input, (tb, required, ctx) => checker(tb, required));
|
||||
protected static void InitializeDelayTimer(TextBox tb, Action<object, TextChangedEventArgs> handler) {
|
||||
var timer = new DispatcherTimer {
|
||||
Interval = TimeSpan.FromMilliseconds(250)
|
||||
};
|
||||
timer.Tick += (object? sender, EventArgs evt) => {
|
||||
timer.Stop();
|
||||
var (oSender, oEvent) = ((object, TextChangedEventArgs))timer.Tag;
|
||||
handler(oSender, oEvent);
|
||||
};
|
||||
tb.TextChanged += (object sender, TextChangedEventArgs evt) => {
|
||||
timer.Stop();
|
||||
timer.Tag = (sender, evt);
|
||||
timer.Start();
|
||||
};
|
||||
}
|
||||
|
||||
protected void InputTextChanged(TextBox input, Func<TextBox, bool, AppDbContext, ValidationResult> checker) {
|
||||
InputTextChanged(input, checker(input, SenderIsRequired(input), Context));
|
||||
protected bool InputTextChanged(TextBox input) {
|
||||
return InputTextChanged(input, new ValidationResult(true, null));
|
||||
}
|
||||
|
||||
protected void InputTextChanged(TextBox input, ValidationResult res) {
|
||||
protected bool InputTextChanged(TextBox input, Func<TextBox, bool, ValidationResult> checker) {
|
||||
return InputTextChanged(input, (tb, required, ctx) => checker(tb, required));
|
||||
}
|
||||
|
||||
protected bool InputTextChanged(TextBox input, Func<TextBox, bool, AppDbContext, ValidationResult> checker) {
|
||||
return InputTextChanged(input, checker(input, SenderIsRequired(input), Context));
|
||||
}
|
||||
|
||||
protected bool InputTextChanged(TextBox input, ValidationResult res) {
|
||||
ValidateInput(input, res.IsValid);
|
||||
if (res.IsValid) {
|
||||
if (InputHasChanged(input)) {
|
||||
Utils.SetInputChanged(input);
|
||||
ControlUtils.SetInputChanged(input);
|
||||
} else if (InputIsNotDefault(input)) {
|
||||
ControlUtils.SetInputNotDefault(input);
|
||||
} else {
|
||||
Utils.ClearInputState(input);
|
||||
ControlUtils.ClearInputState(input);
|
||||
}
|
||||
} else {
|
||||
Utils.SetInputInvalid(input);
|
||||
ControlUtils.SetInputInvalid(input);
|
||||
}
|
||||
UpdateButtons();
|
||||
return res.IsValid;
|
||||
}
|
||||
|
||||
protected void InputLostFocus(TextBox input, Func<TextBox, bool, ValidationResult> checker, string? msg = null) {
|
||||
InputLostFocus(input, (tb, requiered, ctx) => checker(tb, requiered), msg);
|
||||
protected bool InputLostFocus(TextBox input, Func<TextBox, bool, ValidationResult> checker, string? msg = null) {
|
||||
return InputLostFocus(input, (tb, requiered, ctx) => checker(tb, requiered), msg);
|
||||
}
|
||||
|
||||
protected void InputLostFocus(TextBox input, Func<TextBox, bool, AppDbContext, ValidationResult> checker, string? msg = null) {
|
||||
InputLostFocus(input, checker(input, SenderIsRequired(input), Context), msg);
|
||||
protected bool InputLostFocus(TextBox input, Func<TextBox, bool, AppDbContext, ValidationResult> checker, string? msg = null) {
|
||||
return InputLostFocus(input, checker(input, SenderIsRequired(input), Context), msg);
|
||||
}
|
||||
|
||||
protected void InputLostFocus(TextBox input, ValidationResult res, string? msg = null) {
|
||||
if (!res.IsValid)
|
||||
MessageBox.Show(res.ErrorContent.ToString(), msg ?? res.ErrorContent.ToString(), MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
protected bool InputLostFocus(TextBox input, ValidationResult res, string? msg = null) {
|
||||
if (DoShowWarningWindows && !res.IsValid && !IsClosing && (IsEditing || IsCreating))
|
||||
System.Windows.MessageBox.Show(res.ErrorContent.ToString(), msg ?? res.ErrorContent.ToString(), MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
return res.IsValid;
|
||||
}
|
||||
|
||||
protected void CheckBox_Changed(object sender, RoutedEventArgs evt) {
|
||||
var input = (CheckBox)sender;
|
||||
if (SenderIsRequired(input) && input.IsChecked != true) {
|
||||
Utils.SetInputInvalid(input);
|
||||
ControlUtils.SetInputInvalid(input);
|
||||
} else if (InputHasChanged(input)) {
|
||||
Utils.SetInputChanged(input);
|
||||
ControlUtils.SetInputChanged(input);
|
||||
} else if (InputIsNotDefault(input)) {
|
||||
ControlUtils.SetInputNotDefault(input);
|
||||
} else {
|
||||
Utils.ClearInputState(input);
|
||||
ControlUtils.ClearInputState(input);
|
||||
}
|
||||
UpdateButtons();
|
||||
}
|
||||
@@ -213,11 +402,13 @@ namespace Elwig.Windows {
|
||||
protected void RadioButton_Changed(object sender, RoutedEventArgs evt) {
|
||||
var input = (RadioButton)sender;
|
||||
if (SenderIsRequired(input) && input.IsChecked != true) {
|
||||
Utils.SetInputInvalid(input);
|
||||
ControlUtils.SetInputInvalid(input);
|
||||
} else if (InputHasChanged(input)) {
|
||||
Utils.SetInputChanged(input);
|
||||
ControlUtils.SetInputChanged(input);
|
||||
} else if (InputIsNotDefault(input)) {
|
||||
ControlUtils.SetInputNotDefault(input);
|
||||
} else {
|
||||
Utils.ClearInputState(input);
|
||||
ControlUtils.ClearInputState(input);
|
||||
}
|
||||
UpdateButtons();
|
||||
}
|
||||
@@ -226,30 +417,47 @@ namespace Elwig.Windows {
|
||||
var input = (TextBox)sender;
|
||||
if (SenderIsRequired(input) && input.Text.Length == 0) {
|
||||
ValidateInput(input, false);
|
||||
Utils.SetInputInvalid(input);
|
||||
ControlUtils.SetInputInvalid(input);
|
||||
} else {
|
||||
ValidateInput(input, true);
|
||||
if (InputHasChanged(input)) {
|
||||
Utils.SetInputChanged(input);
|
||||
ControlUtils.SetInputChanged(input);
|
||||
} else if (InputIsNotDefault(input)) {
|
||||
ControlUtils.SetInputNotDefault(input);
|
||||
} else {
|
||||
Utils.ClearInputState(input);
|
||||
ControlUtils.ClearInputState(input);
|
||||
}
|
||||
}
|
||||
UpdateButtons();
|
||||
}
|
||||
|
||||
protected void ComboBox_SelectionChanged(object sender, RoutedEventArgs evt) {
|
||||
var input = (ComboBox)sender;
|
||||
if (input.ItemsSource != null && input.SelectedItem == null) {
|
||||
Utils.SetInputInvalid(input);
|
||||
} else if (InputHasChanged(input)) {
|
||||
Utils.SetInputChanged(input);
|
||||
private void UpdateComboBox(Control input) {
|
||||
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);
|
||||
}
|
||||
if (valid) {
|
||||
ValidateInput(input, true);
|
||||
if (InputHasChanged(input)) {
|
||||
ControlUtils.SetInputChanged(input);
|
||||
} else if (InputIsNotDefault(input)) {
|
||||
ControlUtils.SetInputNotDefault(input);
|
||||
} else {
|
||||
ControlUtils.ClearInputState(input);
|
||||
}
|
||||
} else {
|
||||
Utils.ClearInputState(input);
|
||||
ValidateInput(input, false);
|
||||
ControlUtils.SetInputInvalid(input);
|
||||
}
|
||||
UpdateButtons();
|
||||
}
|
||||
|
||||
protected void ComboBox_SelectionChanged(object sender, RoutedEventArgs evt) {
|
||||
UpdateComboBox((Control)sender);
|
||||
}
|
||||
|
||||
protected void IntegerInput_TextChanged(object sender, RoutedEventArgs evt) {
|
||||
InputTextChanged((TextBox)sender, Validator.CheckInteger);
|
||||
}
|
||||
@@ -258,27 +466,37 @@ namespace Elwig.Windows {
|
||||
InputTextChanged((TextBox)sender, Validator.CheckPartialDate);
|
||||
}
|
||||
|
||||
protected void PartialDateInput_LostFocus(object sender, RoutedEventArgs evt) {
|
||||
InputLostFocus((TextBox)sender, Validator.CheckPartialDate);
|
||||
}
|
||||
|
||||
protected void DateInput_TextChanged(object sender, RoutedEventArgs evt) {
|
||||
InputTextChanged((TextBox)sender, Validator.CheckDate);
|
||||
}
|
||||
|
||||
protected void DateInput_LostFocus(object sender, RoutedEventArgs evt) {
|
||||
InputLostFocus((TextBox)sender, Validator.CheckDate);
|
||||
}
|
||||
|
||||
protected void PlzInput_TextChanged(object sender, RoutedEventArgs evt) {
|
||||
var plz = (TextBox)sender;
|
||||
InputTextChanged(plz, Validator.CheckPlz);
|
||||
UpdatePlz(plz, Utils.FindNextSibling<ComboBox>(plz));
|
||||
if ("PLZ".Equals(plz.Tag))
|
||||
UpdatePlz(plz, GetPlzOrtInput(plz));
|
||||
}
|
||||
|
||||
protected void PlzInput_LostFocus(object sender, RoutedEventArgs evt) {
|
||||
var plz = (TextBox)sender;
|
||||
InputLostFocus(plz, Validator.CheckPlz);
|
||||
UpdatePlz(plz, Utils.FindNextSibling<ComboBox>(plz));
|
||||
if ("PLZ".Equals(plz.Tag))
|
||||
UpdatePlz(plz, GetPlzOrtInput(plz));
|
||||
}
|
||||
|
||||
protected void EmailInput_TextChanged(object sender, RoutedEventArgs evt) {
|
||||
protected void EmailAddressInput_TextChanged(object sender, RoutedEventArgs evt) {
|
||||
InputTextChanged((TextBox)sender, Validator.CheckEmailAddress);
|
||||
}
|
||||
|
||||
protected void EmailInput_LostFocus(object sender, RoutedEventArgs evt) {
|
||||
protected void EmailAddressInput_LostFocus(object sender, RoutedEventArgs evt) {
|
||||
InputLostFocus((TextBox)sender, Validator.CheckEmailAddress);
|
||||
}
|
||||
|
||||
@@ -306,12 +524,12 @@ namespace Elwig.Windows {
|
||||
InputLostFocus((TextBox)sender, Validator.CheckBic);
|
||||
}
|
||||
|
||||
protected void UstIdInput_TextChanged(object sender, RoutedEventArgs evt) {
|
||||
InputTextChanged((TextBox)sender, Validator.CheckUstId);
|
||||
protected void UstIdNrInput_TextChanged(object sender, RoutedEventArgs evt) {
|
||||
InputTextChanged((TextBox)sender, Validator.CheckUstIdNr);
|
||||
}
|
||||
|
||||
protected void UstIdInput_LostFocus(object sender, RoutedEventArgs evt) {
|
||||
InputLostFocus((TextBox)sender, Validator.CheckUstId);
|
||||
protected void UstIdNrInput_LostFocus(object sender, RoutedEventArgs evt) {
|
||||
InputLostFocus((TextBox)sender, Validator.CheckUstIdNr);
|
||||
}
|
||||
|
||||
protected void LfbisNrInput_TextChanged(object sender, RoutedEventArgs evt) {
|
||||
|
@@ -5,7 +5,8 @@
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:Elwig.Windows"
|
||||
mc:Ignorable="d"
|
||||
Title="Flächenbindugen - Elwig" Height="500" Width="950"
|
||||
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
|
||||
Title="Flächenbindungen - Elwig" Height="480" Width="850"
|
||||
Loaded="Window_Loaded">
|
||||
<Window.Resources>
|
||||
<Style TargetType="Label">
|
||||
@@ -30,6 +31,13 @@
|
||||
<Setter Property="HorizontalAlignment" Value="Stretch"/>
|
||||
<Setter Property="VerticalAlignment" Value="Top"/>
|
||||
</Style>
|
||||
<Style TargetType="xctk:CheckComboBox">
|
||||
<Setter Property="IsEnabled" Value="False"/>
|
||||
<Setter Property="Height" Value="25"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="HorizontalAlignment" Value="Stretch"/>
|
||||
<Setter Property="VerticalAlignment" Value="Top"/>
|
||||
</Style>
|
||||
<Style TargetType="Button">
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="Padding" Value="9,3"/>
|
||||
@@ -39,153 +47,116 @@
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="19"/>
|
||||
<RowDefinition Height="120"/>
|
||||
<RowDefinition Height="190"/>
|
||||
<RowDefinition Height="1*"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="620"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="330"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Menu Grid.ColumnSpan="3" BorderThickness="0,0,0,1" BorderBrush="LightGray" Background="White">
|
||||
<Menu Grid.ColumnSpan="2" BorderThickness="0,0,0,1" BorderBrush="LightGray" Background="White">
|
||||
<MenuItem Header="Flächenbindugen"/>
|
||||
</Menu>
|
||||
|
||||
<Grid Grid.RowSpan="4" Grid.Row="1">
|
||||
<Grid Grid.RowSpan="2" Grid.Row="1" Grid.Column="0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="125"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="125"/>
|
||||
<ColumnDefinition Width="125"/>
|
||||
<ColumnDefinition Width="125"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<DataGrid x:Name="ContractList" AutoGenerateColumns="False" HeadersVisibility="Column" IsReadOnly="True" GridLinesVisibility="None" SelectionMode="Single"
|
||||
CanUserDeleteRows="False" CanUserResizeRows="False" CanUserAddRows="False" SelectionChanged="ContractList_SelectionChanged" Grid.Column="0" Grid.Row="1"
|
||||
Margin="10,10,5,47" FontSize="14" Grid.ColumnSpan="2" Background="#e2e2e2">
|
||||
<DataGrid x:Name="AreaCommitmentList" AutoGenerateColumns="False" HeadersVisibility="Column" IsReadOnly="True" GridLinesVisibility="None" SelectionMode="Single"
|
||||
CanUserDeleteRows="False" CanUserResizeRows="False" CanUserAddRows="False" SelectionChanged="AreaCommitmentList_SelectionChanged" Grid.Column="0" Grid.Row="1"
|
||||
Margin="5,10,5,42" FontSize="14" Grid.ColumnSpan="3" Background="#e2e2e2">
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="VNr." Binding="{Binding VNr}" Width="*"/>
|
||||
<DataGridTextColumn Header="Von" Binding="{Binding YearFrom}" Width="*"/>
|
||||
<DataGridTextColumn Header="Bis" Binding="{Binding YearTo}" Width="*"/>
|
||||
<DataGridTextColumn Header="FbNr." Binding="{Binding FbNr}" Width="2*"/>
|
||||
<DataGridTextColumn Header="Katastralgemeinde" Binding="{Binding Kg.AtKg.Name}" Width="6*"/>
|
||||
<DataGridTextColumn Header="Ried" Binding="{Binding Rd.Name}" Width="4*"/>
|
||||
<DataGridTextColumn Header="Parzelle" Binding="{Binding GstNr}" Width="4*"/>
|
||||
<DataGridTextColumn Header="Fläche" Binding="{Binding Area, StringFormat='{}{0:N0} m²'}" Width="4*">
|
||||
<DataGridTextColumn.CellStyle>
|
||||
<Style>
|
||||
<Setter Property="TextBlock.TextAlignment" Value="Right"/>
|
||||
</Style>
|
||||
</DataGridTextColumn.CellStyle>
|
||||
</DataGridTextColumn>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
|
||||
|
||||
<Button x:Name="NewContractButton" Content="Neu" Click="NewContractButton_Click"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="10,10,0,10" Width="110" Grid.Column="0"/>
|
||||
<Button x:Name="DeleteContractButton" Content="Löschen" Click="DeleteContractButton_Click" IsEnabled="False"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="5,10,0,10" Width="110" Grid.Column="1"/>
|
||||
|
||||
<Button x:Name="ContractSaveButton" Content="Speichern" Click="ContractSaveButton_Click" IsEnabled="False" Visibility="Hidden"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="10,10,0,10" Width="110" Grid.Column="0"/>
|
||||
<Button x:Name="ContractCancelButton" Content="Abbrechen" Click="ContractCancelButton_Click" IsEnabled="False" Visibility="Hidden" IsCancel="True"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="5,10,0,10" Width="110" Grid.Column="1"/>
|
||||
|
||||
|
||||
|
||||
<Button x:Name="NewAreaCommitmentButton" Content="Neu" Click="NewAreaCommitmentButton_Click" IsEnabled="False"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="5,10,0,10" Width="110" Grid.Column="2"/>
|
||||
<Button x:Name="NewAreaCommitmentButton" Content="Neu" Click="NewAreaCommitmentButton_Click"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="5,5,2.5,10" Grid.Column="0"/>
|
||||
<Button x:Name="EditAreaCommitmentButton" Content="Bearbeiten" Click="EditAreaCommitmentButton_Click" IsEnabled="False"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="-5,10,0,10" Width="110" Grid.Column="3"/>
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="2.5,5,2.5,10" Grid.Column="1"/>
|
||||
<Button x:Name="DeleteAreaCommitmentButton" Content="Löschen" Click="DeleteAreaCommitmentButton_Click" IsEnabled="False"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="0,10,10,10" Width="110" Grid.Column="4"/>
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="2.5,5,5,10" Grid.Column="2"/>
|
||||
|
||||
<Button x:Name="AreaCommitmentSaveButton" Content="Speichern" Click="AreaCommitmentSaveButton_Click" IsEnabled="False" Visibility="Hidden"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="10,10,0,10" Width="110" Grid.Column="2"/>
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="5,5,2.5,10" Grid.Column="0"/>
|
||||
<Button x:Name="AreaCommitmentResetButton" Content="Zurücksetzen" Click="AreaCommitmentResetButton_Click" IsEnabled="False" Visibility="Hidden"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="-5,10,0,10" Width="110" Grid.Column="3"/>
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="2.5,5,2.5,10" Grid.Column="1"/>
|
||||
<Button x:Name="AreaCommitmentCancelButton" Content="Abbrechen" Click="AreaCommitmentCancelButton_Click" IsEnabled="False" Visibility="Hidden" IsCancel="True"
|
||||
HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="0,10,10,10" Width="110" Grid.Column="4"/>
|
||||
|
||||
<DataGrid x:Name="AreaCommitmentList" AutoGenerateColumns="False" HeadersVisibility="Column" IsReadOnly="True" GridLinesVisibility="None" SelectionMode="Single"
|
||||
CanUserDeleteRows="False" CanUserResizeRows="False" CanUserAddRows="False" SelectionChanged="AreaCommitmentList_SelectionChanged" Grid.Column="2" Grid.Row="1"
|
||||
Margin="5,10,10,47" FontSize="14" Grid.ColumnSpan="3" Background="#e2e2e2">
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="Katastralgemeinde" Binding="{Binding Kg.Kg.Name}" Width="5*"/>
|
||||
<DataGridTextColumn Header="Ried" Binding="{Binding Rd.Name}" Width="4*"/>
|
||||
<DataGridTextColumn Header="Parzelle" Binding="{Binding GstNr}" Width="4*"/>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="2.5,5,5,10" Grid.Column="2"/>
|
||||
</Grid>
|
||||
|
||||
<GroupBox Header="Vertrag" Grid.Column="1" Grid.Row="1" Grid.RowSpan="1" Margin="5,5,5,5">
|
||||
<GroupBox Header="Vertrag" Grid.Column="2" Grid.Row="1" Grid.RowSpan="1" Margin="5,5,5,5">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="60"/>
|
||||
<ColumnDefinition Width="70"/>
|
||||
<ColumnDefinition Width="80"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="50"/>
|
||||
<ColumnDefinition Width="100"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label Content="VNr.:" Margin="10,10,0,0" Grid.Column="0"/>
|
||||
<TextBox x:Name="VNrInput" Margin="0,10,0,0" Width="48" Grid.Column="1" TextAlignment="Right" HorizontalAlignment="Left"
|
||||
TextChanged="VNrInput_TextChanged" LostFocus="VNrInput_LostFocus"/>
|
||||
|
||||
<Label Content="FbNr.:" Margin="10,10,0,0" Grid.Column="0"/>
|
||||
<TextBox x:Name="FbNrInput" Margin="0,10,0,0" Width="48" Grid.Column="1" TextAlignment="Right" HorizontalAlignment="Left"
|
||||
TextChanged="FbNrInput_TextChanged" LostFocus="FbNrInput_LostFocus"/>
|
||||
|
||||
<Label Content="MgNr.:" Margin="10,40,0,0" Grid.Column="0"/>
|
||||
<TextBox x:Name="MgNrInput" Margin="0,40,0,0" Width="48" Grid.Column="1" TextAlignment="Right" HorizontalAlignment="Left"/>
|
||||
|
||||
<TextBox x:Name="MgNrInput" IsEnabled="False"
|
||||
Margin="0,40,0,0" Width="48" Grid.Column="1" TextAlignment="Right" HorizontalAlignment="Left"/>
|
||||
|
||||
<Label Content="Von:" Margin="10,10,0,0" Grid.Column="2"/>
|
||||
<TextBox x:Name="YearFromInput" Margin="0,10,0,0" Width="100" Grid.Column="3" TextAlignment="Right" HorizontalAlignment="Left"
|
||||
TextChanged="YearFromInput_TextChanged"/>
|
||||
|
||||
<TextBox x:Name="YearFromInput" Margin="0,10,0,0" Width="41" Grid.Column="3" TextAlignment="Right" HorizontalAlignment="Left"
|
||||
TextChanged="IntegerInput_TextChanged"/>
|
||||
|
||||
<Label Content="Bis:" Margin="10,40,0,0" Grid.Column="2"/>
|
||||
<TextBox x:Name="YearToInput" Margin="0,40,0,0" Width="100" Grid.Column="3" TextAlignment="Right" HorizontalAlignment="Left"
|
||||
TextChanged="YearToInput_TextChanged"/>
|
||||
<TextBox x:Name="YearToInput" Margin="0,40,0,0" Width="41" Grid.Column="3" TextAlignment="Right" HorizontalAlignment="Left"
|
||||
TextChanged="IntegerInput_TextChanged"/>
|
||||
|
||||
<Label Content="Vertragsart:" Margin="10,70,0,0" Grid.Column="0" Grid.ColumnSpan="2"/>
|
||||
<ComboBox x:Name="AreaComTypeInput" DisplayMemberPath="DisplayName" TextSearch.TextPath="DisplayName"
|
||||
HorizontalAlignment="Stretch" Margin="0,70,10,0" Grid.Column="1" Grid.ColumnSpan="3"/>
|
||||
|
||||
<Label Content="Bewirt.-Art:" Margin="10,100,0,0" Grid.Column="0" Grid.ColumnSpan="2"/>
|
||||
<ComboBox x:Name="WineCultivationInput" DisplayMemberPath="Name" TextSearch.TextPath="Name"
|
||||
HorizontalAlignment="Stretch" Margin="0,100,10,0" Grid.Column="1" Grid.ColumnSpan="3"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Header="Lage" Grid.Column="1" Grid.Row="2" Grid.RowSpan="1" Margin="5,5,5,5">
|
||||
|
||||
<GroupBox Header="Lage" Grid.Column="2" Grid.Row="2" Grid.RowSpan="1" Margin="5,5,5,10">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="80"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label Content="Gemeinde:" Margin="10,10,0,0" Grid.Column="0"/>
|
||||
<ComboBox x:Name="KgInput" ItemTemplate="{StaticResource KgTemplate}" TextSearch.TextPath="Name"
|
||||
Width="200" HorizontalAlignment="Left" SelectionChanged="KgInput_SelectionChanged"
|
||||
Margin="0,10,10,0" Grid.Column="1"/>
|
||||
|
||||
<Label Content="KG:" Margin="10,10,0,0" Grid.Column="0"/>
|
||||
<ComboBox x:Name="KgInput" ItemTemplate="{StaticResource KgNrTemplate}" TextSearch.TextPath="Name"
|
||||
HorizontalAlignment="Stretch" Margin="0,10,10,0" Grid.Column="1"
|
||||
SelectionChanged="KgInput_SelectionChanged"/>
|
||||
|
||||
<Label Content="Ried:" Margin="10,40,0,0" Grid.Column="0"/>
|
||||
<ComboBox x:Name="RdInput" ItemTemplate="{StaticResource KgTemplate}" TextSearch.TextPath="Name"
|
||||
Width="200" HorizontalAlignment="Left" SelectionChanged="ComboBox_SelectionChanged"
|
||||
Margin="0,40,0,0" Grid.Column="1"/>
|
||||
|
||||
<Label Content="Parzelle:" Margin="10,70,0,0" Grid.Column="0"/>
|
||||
<TextBox x:Name="GstNrInput" Margin="0,70,0,0" Width="100" Grid.Column="1" TextAlignment="Right" HorizontalAlignment="Left"
|
||||
<ComboBox x:Name="RdInput" DisplayMemberPath="Name" TextSearch.TextPath="Name"
|
||||
HorizontalAlignment="Stretch" Margin="0,40,10,0" Grid.Column="1"/>
|
||||
|
||||
<Label Content="Parzelle(n):" Margin="10,70,0,0" Grid.Column="0"/>
|
||||
<TextBox x:Name="GstNrInput" Margin="0,70,10,0" Grid.Column="1" HorizontalAlignment="Stretch"
|
||||
TextChanged="GstNrInput_TextChanged" LostFocus="GstNrInput_LostFocus"/>
|
||||
|
||||
<Label Content="Fläche (m²):" Margin="10,100,0,0" Grid.Column="0"/>
|
||||
<Label Content="Fläche:" Margin="10,100,0,0" Grid.Column="0"/>
|
||||
<TextBox x:Name="AreaInput" Margin="0,100,0,0" Width="100" Grid.Column="1" TextAlignment="Right" HorizontalAlignment="Left"
|
||||
TextChanged="AreaInput_TextChanged"/>
|
||||
</Grid>
|
||||
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Header="Eigenschaften" Grid.Column="1" Grid.Row="3" Grid.RowSpan="1" Margin="5,5,5,5">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="80"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label Content="Sorte:" Margin="10,10,0,0" Grid.Column="0"/>
|
||||
<ComboBox x:Name="SortInput" ItemTemplate="{StaticResource KgTemplate}" TextSearch.TextPath="Name"
|
||||
Width="200" HorizontalAlignment="Left" SelectionChanged="ComboBox_SelectionChanged"
|
||||
Margin="0,10,10,0" Grid.Column="1"/>
|
||||
|
||||
<Label Content="Attribut:" Margin="10,40,0,0" Grid.Column="0"/>
|
||||
<ComboBox x:Name="AttrInput" ItemTemplate="{StaticResource KgTemplate}" TextSearch.TextPath="Name"
|
||||
Width="200" HorizontalAlignment="Left" SelectionChanged="ComboBox_SelectionChanged"
|
||||
Margin="0,40,10,0" Grid.Column="1"/>
|
||||
|
||||
<Label Content="Bewirt. Art:" Margin="10,70,0,0" Grid.Column="0"/>
|
||||
<ComboBox x:Name="CultInput" ItemTemplate="{StaticResource KgTemplate}" TextSearch.TextPath="Name"
|
||||
Width="200" HorizontalAlignment="Left" SelectionChanged="ComboBox_SelectionChanged"
|
||||
Margin="0,70,10,0" Grid.Column="1"/>
|
||||
|
||||
TextChanged="IntegerInput_TextChanged"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
</Grid>
|
||||
|
@@ -1,5 +1,4 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
@@ -7,41 +6,31 @@ using Elwig.Helpers;
|
||||
using Elwig.Models;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
||||
using Xceed.Wpf.Toolkit.Primitives;
|
||||
|
||||
namespace Elwig.Windows {
|
||||
public partial class AreaComAdminWindow : AdministrationWindow {
|
||||
private readonly Member member;
|
||||
private bool IsEditing = false;
|
||||
private bool IsCreating = false;
|
||||
private readonly Member Member;
|
||||
|
||||
public AreaComAdminWindow(Member member) {
|
||||
public AreaComAdminWindow(int mgnr) {
|
||||
InitializeComponent();
|
||||
this.member = member;
|
||||
Title = $"Flächenbindungen - {member.FamilyName} {member.GivenName} - Elwig";
|
||||
Member = Context.Members.Find(mgnr) ?? throw new ArgumentException("MgNr argument has invalid value");
|
||||
Title = $"Flächenbindungen - {Member.AdministrativeName} - Elwig";
|
||||
ExemptInputs = new Control[] {
|
||||
MgNrInput, ContractList, AreaCommitmentList, NewContractButton, DeleteContractButton,
|
||||
ContractSaveButton, ContractCancelButton, NewAreaCommitmentButton,
|
||||
MgNrInput, AreaCommitmentList, NewAreaCommitmentButton,
|
||||
EditAreaCommitmentButton, DeleteAreaCommitmentButton, AreaCommitmentSaveButton,
|
||||
AreaCommitmentResetButton, AreaCommitmentCancelButton
|
||||
};
|
||||
RequiredInputs = new Control[] {
|
||||
VNrInput, YearFromInput, KgInput,
|
||||
GstNrInput, AreaInput, SortInput, CultInput
|
||||
FbNrInput, YearFromInput, KgInput,
|
||||
GstNrInput, AreaInput, AreaComTypeInput, WineCultivationInput
|
||||
};
|
||||
}
|
||||
|
||||
private async void Window_Loaded(object sender, RoutedEventArgs e) {
|
||||
await RefreshContractList();
|
||||
KgInput.ItemsSource = Context.WbKgs.Select(k => k.Kg).OrderBy(k => k.Name).ToList();
|
||||
SortInput.ItemsSource = Context.WineVarieties.OrderBy(s => s.Name).ToList();
|
||||
AttrInput.ItemsSource = Context.WineAttributes.OrderBy(a => a.Name).ToList();
|
||||
CultInput.ItemsSource = Context.WineCultivations.OrderBy(c => c.Name).ToList();
|
||||
}
|
||||
|
||||
private async Task RefreshContractList() {
|
||||
await Context.Contracts.LoadAsync();
|
||||
await RefreshContractListQuery();
|
||||
private void Window_Loaded(object sender, RoutedEventArgs e) {
|
||||
LockInputs();
|
||||
}
|
||||
|
||||
private async Task RefreshAreaCommitmentList() {
|
||||
@@ -49,94 +38,79 @@ namespace Elwig.Windows {
|
||||
await RefreshAreaCommitmentListQuery();
|
||||
}
|
||||
|
||||
private async Task RefreshContractListQuery() {
|
||||
List<Contract> contracts = await Context.Contracts.Where(c => c.MgNr == member.MgNr).ToListAsync();
|
||||
|
||||
ContractList.ItemsSource = contracts;
|
||||
if (contracts.Count == 1)
|
||||
ContractList.SelectedIndex = 0;
|
||||
|
||||
// TODO notwendig?
|
||||
await RefreshAreaCommitmentList();
|
||||
RefreshInputs();
|
||||
}
|
||||
|
||||
private async Task RefreshAreaCommitmentListQuery() {
|
||||
Contract? contract = (Contract)ContractList.SelectedItem;
|
||||
|
||||
if (contract == null) {
|
||||
AreaCommitmentList.ItemsSource = null;
|
||||
return;
|
||||
}
|
||||
List<AreaCom> areaComs = await Context.AreaCommitments.Where(a => a.MgNr == Member.MgNr).OrderBy(a => a.FbNr).ToListAsync();
|
||||
|
||||
List<AreaComParcel> parcels = (await Context.AreaCommitments.FindAsync(contract.VNr)).Parcels.ToList();
|
||||
|
||||
AreaCommitmentList.ItemsSource = parcels;
|
||||
if (parcels.Count == 1)
|
||||
ControlUtils.RenewItemsSource(AreaCommitmentList, areaComs, i => (i as AreaCom)?.FbNr);
|
||||
if (areaComs.Count == 1)
|
||||
AreaCommitmentList.SelectedIndex = 0;
|
||||
|
||||
RefreshInputs();
|
||||
}
|
||||
|
||||
private void RefreshInputs(bool validate = false) {
|
||||
ClearInputStates();
|
||||
Contract? c = (Contract)ContractList.SelectedItem;
|
||||
AreaComParcel? a = (AreaComParcel)AreaCommitmentList.SelectedItem;
|
||||
|
||||
if (c != null) {
|
||||
DeleteContractButton.IsEnabled = true;
|
||||
NewAreaCommitmentButton.IsEnabled = true;
|
||||
} else {
|
||||
DeleteContractButton.IsEnabled = false;
|
||||
NewAreaCommitmentButton.IsEnabled = false;
|
||||
}
|
||||
|
||||
if (a != null) {
|
||||
if (AreaCommitmentList.SelectedItem is AreaCom a) {
|
||||
EditAreaCommitmentButton.IsEnabled = true;
|
||||
DeleteAreaCommitmentButton.IsEnabled = true;
|
||||
FillInputs(a);
|
||||
} else {
|
||||
EditAreaCommitmentButton.IsEnabled = false;
|
||||
DeleteAreaCommitmentButton.IsEnabled = false;
|
||||
ClearInputs();
|
||||
MgNrInput.Text = "";
|
||||
ClearOriginalValues();
|
||||
ClearDefaultValues();
|
||||
ClearInputs(validate);
|
||||
ClearInputStates();
|
||||
}
|
||||
if (!validate) ClearInputStates();
|
||||
GC.Collect();
|
||||
}
|
||||
|
||||
private void FillInputs(AreaComParcel a) {
|
||||
private void FillInputs(AreaCom a) {
|
||||
ClearOriginalValues();
|
||||
ClearDefaultValues();
|
||||
|
||||
VNrInput.Text = a.VNr.ToString();
|
||||
MgNrInput.Text = a.AreaCom.Contract.MgNr.ToString();
|
||||
YearFromInput.Text = a.AreaCom.Contract.YearFrom.ToString();
|
||||
YearToInput.Text = a.AreaCom.Contract.YearTo.ToString();
|
||||
FbNrInput.Text = a.FbNr.ToString();
|
||||
MgNrInput.Text = a.MgNr.ToString();
|
||||
YearFromInput.Text = a.YearFrom.ToString();
|
||||
YearToInput.Text = a.YearTo.ToString();
|
||||
|
||||
KgInput.SelectedItem = a.Kg.Kg;
|
||||
KgInput.SelectedItem = a.Kg.AtKg;
|
||||
RdInput.SelectedItem = a.Rd;
|
||||
GstNrInput.Text = a.GstNr;
|
||||
AreaInput.Text = a.Area.ToString();
|
||||
|
||||
SortInput.SelectedItem = a.AreaCom.WineVar;
|
||||
// FIXME
|
||||
//AttrInput.SelectedItem = a.WineAttr;
|
||||
CultInput.SelectedItem = a.AreaCom.WineCult;
|
||||
AreaComTypeInput.SelectedItem = a.AreaComType;
|
||||
WineCultivationInput.SelectedItem = a.WineCult;
|
||||
|
||||
FillOriginalValues();
|
||||
FinishInputFilling();
|
||||
}
|
||||
|
||||
private async void InitInputs() {
|
||||
ClearOriginalValues();
|
||||
ClearDefaultValues();
|
||||
|
||||
FbNrInput.Text = (await Context.NextFbNr()).ToString();
|
||||
MgNrInput.Text = Member.MgNr.ToString();
|
||||
|
||||
SetDefaultValue(FbNrInput);
|
||||
ValidateRequiredInputs();
|
||||
}
|
||||
|
||||
protected override async Task RenewContext() {
|
||||
await base.RenewContext();
|
||||
ControlUtils.RenewItemsSource(KgInput, await Context.WbKgs.Select(k => k.AtKg).OrderBy(k => k.Name).ToListAsync(), i => (i as AT_Kg)?.KgNr);
|
||||
ControlUtils.RenewItemsSource(AreaComTypeInput, await Context.AreaCommitmentTypes.OrderBy(v => v.VtrgId).ToListAsync(), i => (i as AreaComType)?.VtrgId);
|
||||
ControlUtils.RenewItemsSource(WineCultivationInput, await Context.WineCultivations.OrderBy(c => c.Name).ToListAsync(), i => (i as WineCult)?.CultId);
|
||||
await RefreshAreaCommitmentList();
|
||||
}
|
||||
|
||||
private void NewAreaCommitmentButton_Click(object sender, RoutedEventArgs evt) {
|
||||
IsCreating = true;
|
||||
AreaCommitmentList.IsEnabled = false;
|
||||
AreaCommitmentList.SelectedItem = null;
|
||||
ContractList.IsEnabled = false;
|
||||
HideAreaCommitmentNewEditDeleteButtons();
|
||||
ShowAreaCommitmentSaveResetCancelButtons();
|
||||
DisableContractNewDeleteButtons();
|
||||
UnlockInputs();
|
||||
VNrInput.IsReadOnly = true;
|
||||
YearFromInput.IsReadOnly = true;
|
||||
YearToInput.IsReadOnly = true;
|
||||
InitInputs();
|
||||
}
|
||||
|
||||
@@ -146,21 +120,19 @@ namespace Elwig.Windows {
|
||||
|
||||
IsEditing = true;
|
||||
AreaCommitmentList.IsEnabled = false;
|
||||
ContractList.IsEnabled = false;
|
||||
|
||||
HideAreaCommitmentNewEditDeleteButtons();
|
||||
ShowAreaCommitmentSaveResetCancelButtons();
|
||||
DisableContractNewDeleteButtons();
|
||||
UnlockInputs();
|
||||
}
|
||||
|
||||
private async void DeleteAreaCommitmentButton_Click(object sender, RoutedEventArgs evt) {
|
||||
AreaComParcel a = (AreaComParcel)AreaCommitmentList.SelectedItem;
|
||||
AreaCom a = (AreaCom)AreaCommitmentList.SelectedItem;
|
||||
if (a == null) return;
|
||||
|
||||
var r = MessageBox.Show(
|
||||
$"Soll die Parzelle {a.GstNr} ({a.Area} m²) wirklich unwiderruflich gelöscht werden?",
|
||||
"Parzelle löschen", MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No);
|
||||
$"Soll die Flächenbindung {a.GstNr} ({a.Area} m²) wirklich unwiderruflich gelöscht werden?",
|
||||
"Flächenbindung löschen", MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No);
|
||||
if (r == MessageBoxResult.Yes) {
|
||||
Context.Remove(a);
|
||||
Context.SaveChanges();
|
||||
@@ -168,86 +140,44 @@ namespace Elwig.Windows {
|
||||
}
|
||||
}
|
||||
|
||||
private void NewContractButton_Click(object sender, RoutedEventArgs evt) {
|
||||
IsCreating = true;
|
||||
ContractList.IsEnabled = false;
|
||||
ContractList.SelectedItem = null;
|
||||
AreaCommitmentList.IsEnabled = false;
|
||||
AreaCommitmentList.SelectedItem = null;
|
||||
HideContractNewDeleteButtons();
|
||||
ShowContractSaveCancelButtons();
|
||||
DisableAreaCommitmentNewEditDeleteButtons();
|
||||
UnlockInputs();
|
||||
InitInputs();
|
||||
}
|
||||
|
||||
private async void DeleteContractButton_Click(object sender, RoutedEventArgs evt) {
|
||||
Contract c = (Contract)ContractList.SelectedItem;
|
||||
if (c == null) return;
|
||||
|
||||
var r = MessageBox.Show(
|
||||
$"Soll der Vertrag {c.VNr} und alle enthaltenen Parzellen wirklich unwiderruflich gelöscht werden?",
|
||||
"Vertrag löschen", MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No);
|
||||
if (r == MessageBoxResult.Yes) {
|
||||
Context.Remove(c);
|
||||
Context.SaveChanges();
|
||||
await RefreshContractList();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<Contract> UpdateContract(Contract c) {
|
||||
int newVNr = int.Parse(VNrInput.Text);
|
||||
c.MgNr = int.Parse(MgNrInput.Text);
|
||||
c.YearFrom = int.Parse(YearFromInput.Text);
|
||||
c.YearTo = (YearToInput.Text == "") ? null : int.Parse(YearToInput.Text);
|
||||
|
||||
EntityEntry<Contract>? tr = null;
|
||||
try {
|
||||
if (IsEditing) {
|
||||
tr = Context.Update(c);
|
||||
} else if (IsCreating) {
|
||||
c.VNr = newVNr;
|
||||
tr = (await Context.AddAsync(c));
|
||||
}
|
||||
await Context.SaveChangesAsync();
|
||||
|
||||
if (newVNr != c.VNr) {
|
||||
await Context.Database.ExecuteSqlAsync($"UPDATE contract SET vnr = {newVNr} WHERE mgnr = {c.VNr}");
|
||||
await Context.Contracts.LoadAsync();
|
||||
c = await Context.Contracts.FindAsync(newVNr);
|
||||
}
|
||||
} catch (Exception exc) {
|
||||
if (tr != null) await tr.ReloadAsync();
|
||||
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, "Vertrag aktualisieren", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
private async Task<AreaComParcel> UpdateaAreaComParcel(AreaComParcel a) {
|
||||
a.VNr = int.Parse(VNrInput.Text);
|
||||
private async Task<AreaCom> UpdateAreaCom(AreaCom a) {
|
||||
int newFbNr = int.Parse(FbNrInput.Text);
|
||||
a.MgNr = int.Parse(MgNrInput.Text);
|
||||
a.YearFrom = int.Parse(YearFromInput.Text);
|
||||
a.YearTo = (YearToInput.Text == "") ? null : int.Parse(YearToInput.Text);
|
||||
a.KgNr = ((AT_Kg)KgInput.SelectedItem).KgNr;
|
||||
a.RdNr = ((WbRd)RdInput.SelectedItem).RdNr;
|
||||
a.RdNr = RdInput.SelectedItem.GetType() == typeof(NullItem) ? null : ((WbRd)RdInput.SelectedItem).RdNr;
|
||||
a.GstNr = GstNrInput.Text;
|
||||
a.Area = int.Parse(AreaInput.Text);
|
||||
a.AreaCom.SortId = ((WineVar)SortInput.SelectedItem).SortId;
|
||||
// FIXME
|
||||
//a.AttrId = ((WineAttr)AttrInput.SelectedItem).AttrId;
|
||||
a.AreaCom.CultId = ((WineCult)CultInput.SelectedItem).CultId;
|
||||
a.VtrgId = (AreaComTypeInput.SelectedItem as AreaComType)?.VtrgId;
|
||||
a.CultId = (WineCultivationInput.SelectedItem as WineCult)?.CultId;
|
||||
|
||||
EntityEntry<AreaComParcel>? tr = null;
|
||||
EntityEntry<AreaCom>? tr = null;
|
||||
try {
|
||||
if (IsEditing) {
|
||||
tr = Context.Update(a);
|
||||
} else if (IsCreating) {
|
||||
a.FbNr = newFbNr;
|
||||
tr = (await Context.AddAsync(a));
|
||||
} else {
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
await Context.SaveChangesAsync();
|
||||
|
||||
if (newFbNr != a.FbNr) {
|
||||
await Context.Database.ExecuteSqlAsync($"UPDATE area_commitment SET fbnr = {newFbNr} WHERE fbnr = {a.FbNr}");
|
||||
tr.State = EntityState.Detached;
|
||||
await Context.SaveChangesAsync();
|
||||
await tr.ReloadAsync();
|
||||
a = await Context.AreaCommitments.FindAsync(newFbNr);
|
||||
}
|
||||
|
||||
} catch (Exception exc) {
|
||||
if (tr != null) await tr.ReloadAsync();
|
||||
if (tr != null) {
|
||||
tr.State = EntityState.Detached;
|
||||
await tr.ReloadAsync();
|
||||
}
|
||||
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
|
||||
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
|
||||
MessageBox.Show(str, "Flächenbindung aktualisieren", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
@@ -257,20 +187,14 @@ namespace Elwig.Windows {
|
||||
}
|
||||
|
||||
private async void AreaCommitmentSaveButton_Click(object sender, RoutedEventArgs evt) {
|
||||
Contract c = await UpdateContract((Contract)ContractList.SelectedItem);
|
||||
AreaComParcel a = await UpdateaAreaComParcel(IsEditing ? (AreaComParcel)AreaCommitmentList.SelectedItem : Context.CreateProxy<AreaComParcel>());
|
||||
|
||||
AreaCom a = await UpdateAreaCom(IsEditing ? (AreaCom)AreaCommitmentList.SelectedItem : Context.CreateProxy<AreaCom>());
|
||||
IsEditing = false;
|
||||
IsCreating = false;
|
||||
AreaCommitmentList.IsEnabled = true;
|
||||
ContractList.IsEnabled = true;
|
||||
HideAreaCommitmentSaveResetCancelButtons();
|
||||
ShowAreaCommitmentNewEditDeleteButtons();
|
||||
EnableContractNewDeleteButtons();
|
||||
LockInputs();
|
||||
await RefreshContractList();
|
||||
await RefreshAreaCommitmentList();
|
||||
ContractList.SelectedItem = c;
|
||||
AreaCommitmentList.SelectedItem = a;
|
||||
}
|
||||
|
||||
@@ -287,41 +211,8 @@ namespace Elwig.Windows {
|
||||
IsEditing = false;
|
||||
IsCreating = false;
|
||||
AreaCommitmentList.IsEnabled = true;
|
||||
ContractList.IsEnabled = true;
|
||||
HideAreaCommitmentSaveResetCancelButtons();
|
||||
ShowAreaCommitmentNewEditDeleteButtons();
|
||||
EnableContractNewDeleteButtons();
|
||||
RefreshInputs();
|
||||
ClearInputStates();
|
||||
LockInputs();
|
||||
}
|
||||
|
||||
private async void ContractSaveButton_Click(object sender, RoutedEventArgs evt) {
|
||||
Contract c = await UpdateContract(Context.CreateProxy<Contract>());
|
||||
AreaComParcel a = await UpdateaAreaComParcel(Context.CreateProxy<AreaComParcel>());
|
||||
|
||||
IsEditing = false;
|
||||
IsCreating = false;
|
||||
AreaCommitmentList.IsEnabled = true;
|
||||
ContractList.IsEnabled = true;
|
||||
HideContractSaveCancelButtons();
|
||||
ShowContractNewDeleteButtons();
|
||||
EnableAreaCommitmentNewEditDeleteButtons();
|
||||
LockInputs();
|
||||
await RefreshContractList();
|
||||
await RefreshAreaCommitmentList();
|
||||
ContractList.SelectedItem = c;
|
||||
AreaCommitmentList.SelectedItem = a;
|
||||
}
|
||||
|
||||
private void ContractCancelButton_Click(object sender, RoutedEventArgs evt) {
|
||||
IsEditing = false;
|
||||
IsCreating = false;
|
||||
ContractList.IsEnabled = true;
|
||||
AreaCommitmentList.IsEnabled = true;
|
||||
HideContractSaveCancelButtons();
|
||||
ShowContractNewDeleteButtons();
|
||||
EnableAreaCommitmentNewEditDeleteButtons();
|
||||
RefreshInputs();
|
||||
ClearInputStates();
|
||||
LockInputs();
|
||||
@@ -329,27 +220,9 @@ namespace Elwig.Windows {
|
||||
|
||||
override protected void UpdateButtons() {
|
||||
if (!IsEditing && !IsCreating) return;
|
||||
bool ch = HasChanged(), v = IsValid();
|
||||
ContractSaveButton.IsEnabled = (v && ch);
|
||||
bool ch = HasChanged, v = IsValid;
|
||||
AreaCommitmentResetButton.IsEnabled = (ch);
|
||||
AreaCommitmentSaveButton.IsEnabled = (v && ch);
|
||||
}
|
||||
|
||||
private async void InitInputs() {
|
||||
VNrInput.Text = ContractList.SelectedItem == null ? (await Context.NextVNr()).ToString() : ((Contract)ContractList.SelectedItem).VNr.ToString();
|
||||
MgNrInput.Text = member.MgNr.ToString();
|
||||
FillOriginalValues();
|
||||
ValidateRequiredInputs();
|
||||
}
|
||||
|
||||
private void EnableContractNewDeleteButtons() {
|
||||
NewContractButton.IsEnabled = true;
|
||||
DeleteContractButton.IsEnabled = ContractList.SelectedItem != null;
|
||||
}
|
||||
|
||||
private void DisableContractNewDeleteButtons() {
|
||||
NewContractButton.IsEnabled = false;
|
||||
DeleteContractButton.IsEnabled = false;
|
||||
AreaCommitmentSaveButton.IsEnabled = (ch && v);
|
||||
}
|
||||
|
||||
private void DisableAreaCommitmentNewEditDeleteButtons() {
|
||||
@@ -359,37 +232,11 @@ namespace Elwig.Windows {
|
||||
}
|
||||
|
||||
private void EnableAreaCommitmentNewEditDeleteButtons() {
|
||||
NewAreaCommitmentButton.IsEnabled = ContractList.SelectedItem != null;
|
||||
NewAreaCommitmentButton.IsEnabled = true;
|
||||
EditAreaCommitmentButton.IsEnabled = AreaCommitmentList.SelectedItem != null;
|
||||
DeleteAreaCommitmentButton.IsEnabled = AreaCommitmentList.SelectedItem != null;
|
||||
}
|
||||
|
||||
private void ShowContractSaveCancelButtons() {
|
||||
ContractSaveButton.IsEnabled = false;
|
||||
ContractCancelButton.IsEnabled = true;
|
||||
ContractSaveButton.Visibility = Visibility.Visible;
|
||||
ContractCancelButton.Visibility = Visibility.Visible;
|
||||
}
|
||||
|
||||
private void HideContractSaveCancelButtons() {
|
||||
ContractSaveButton.IsEnabled = false;
|
||||
ContractCancelButton.IsEnabled = false;
|
||||
ContractSaveButton.Visibility = Visibility.Hidden;
|
||||
ContractCancelButton.Visibility = Visibility.Hidden;
|
||||
}
|
||||
|
||||
private void ShowContractNewDeleteButtons() {
|
||||
EnableContractNewDeleteButtons();
|
||||
NewContractButton.Visibility = Visibility.Visible;
|
||||
DeleteContractButton.Visibility = Visibility.Visible;
|
||||
}
|
||||
|
||||
private void HideContractNewDeleteButtons() {
|
||||
DisableContractNewDeleteButtons();
|
||||
NewContractButton.Visibility = Visibility.Hidden;
|
||||
DeleteContractButton.Visibility = Visibility.Hidden;
|
||||
}
|
||||
|
||||
private void ShowAreaCommitmentSaveResetCancelButtons() {
|
||||
AreaCommitmentSaveButton.IsEnabled = false;
|
||||
AreaCommitmentResetButton.IsEnabled = false;
|
||||
@@ -422,51 +269,42 @@ namespace Elwig.Windows {
|
||||
DeleteAreaCommitmentButton.Visibility = Visibility.Hidden;
|
||||
}
|
||||
|
||||
private async void ContractList_SelectionChanged(object sender, SelectionChangedEventArgs evt) {
|
||||
//await RefreshContractListQuery();
|
||||
await RefreshAreaCommitmentList();
|
||||
}
|
||||
|
||||
private void AreaCommitmentList_SelectionChanged(object sender, SelectionChangedEventArgs evt) {
|
||||
RefreshInputs();
|
||||
}
|
||||
|
||||
private void KgInput_SelectionChanged(object sender, SelectionChangedEventArgs evt) {
|
||||
AT_Kg? curr_kg = (AT_Kg)KgInput.SelectedItem;
|
||||
if (curr_kg != null) {
|
||||
RdInput.ItemsSource = Context.WbRde.Where(r => r.KgNr == curr_kg.KgNr).OrderBy(r => r.Name).ToList();
|
||||
private void AttributesInput_SelectionChanged(object sender, ItemSelectionChangedEventArgs evt) {
|
||||
|
||||
}
|
||||
|
||||
private async void KgInput_SelectionChanged(object sender, SelectionChangedEventArgs evt) {
|
||||
if (KgInput.SelectedItem is AT_Kg curr_kg) {
|
||||
var rdList = await Context.WbRde.Where(r => r.KgNr == curr_kg.KgNr).OrderBy(r => r.Name).Cast<object>().ToListAsync();
|
||||
rdList.Insert(0, new NullItem());
|
||||
ControlUtils.RenewItemsSource(RdInput, rdList, i => (i as WbRd)?.RdNr);
|
||||
} else {
|
||||
var rdList = new object[] { new NullItem() };
|
||||
ControlUtils.RenewItemsSource(RdInput, rdList, i => (i as WbRd)?.RdNr);
|
||||
}
|
||||
ComboBox_SelectionChanged(sender, evt);
|
||||
}
|
||||
|
||||
protected void InputTextChanged(TextBox input, Func<TextBox, bool, AppDbContext, Contract?, ValidationResult> checker) {
|
||||
InputTextChanged(input, checker(input, SenderIsRequired(input), Context, (Contract)ContractList.SelectedItem));
|
||||
protected void InputTextChanged(TextBox input, Func<TextBox, bool, AppDbContext, AreaCom?, ValidationResult> checker) {
|
||||
InputTextChanged(input, checker(input, SenderIsRequired(input), Context, (AreaCom)AreaCommitmentList.SelectedItem));
|
||||
}
|
||||
|
||||
protected void InputLostFocus(TextBox input, Func<TextBox, bool, AppDbContext, Contract?, ValidationResult> checker, string? msg = null) {
|
||||
InputLostFocus(input, checker(input, SenderIsRequired(input), Context, (Contract)ContractList.SelectedItem), msg);
|
||||
protected void InputLostFocus(TextBox input, Func<TextBox, bool, AppDbContext, AreaCom?, ValidationResult> checker, string? msg = null) {
|
||||
InputLostFocus(input, checker(input, SenderIsRequired(input), Context, (AreaCom)AreaCommitmentList.SelectedItem), msg);
|
||||
}
|
||||
|
||||
private void NumericInput_TextChanged(object sender, RoutedEventArgs evt) {
|
||||
InputTextChanged((TextBox)sender, Validator.CheckInteger);
|
||||
private void FbNrInput_TextChanged(object sender, RoutedEventArgs evt) {
|
||||
InputTextChanged((TextBox)sender, Validator.CheckFbNr);
|
||||
}
|
||||
|
||||
private void VNrInput_TextChanged(object sender, RoutedEventArgs evt) {
|
||||
InputTextChanged((TextBox)sender, Validator.CheckVNr);
|
||||
private void FbNrInput_LostFocus(object sender, RoutedEventArgs evt) {
|
||||
InputLostFocus((TextBox)sender, Validator.CheckFbNr);
|
||||
}
|
||||
|
||||
private void VNrInput_LostFocus(object sender, RoutedEventArgs evt) {
|
||||
InputLostFocus((TextBox)sender, Validator.CheckVNr);
|
||||
}
|
||||
|
||||
private void YearFromInput_TextChanged(object sender, RoutedEventArgs evt) {
|
||||
InputTextChanged((TextBox)sender, Validator.CheckInteger);
|
||||
}
|
||||
|
||||
private void YearToInput_TextChanged(object sender, RoutedEventArgs evt) {
|
||||
InputTextChanged((TextBox)sender, Validator.CheckInteger);
|
||||
}
|
||||
|
||||
|
||||
private void GstNrInput_TextChanged(object sender, RoutedEventArgs evt) {
|
||||
InputTextChanged((TextBox)sender, Validator.CheckGstNr);
|
||||
}
|
||||
@@ -474,9 +312,5 @@ namespace Elwig.Windows {
|
||||
private void GstNrInput_LostFocus(object sender, RoutedEventArgs evt) {
|
||||
InputLostFocus((TextBox)sender, Validator.CheckGstNr);
|
||||
}
|
||||
|
||||
private void AreaInput_TextChanged(object sender, RoutedEventArgs evt) {
|
||||
InputTextChanged((TextBox)sender, Validator.CheckInteger);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
235
Elwig/Windows/BaseDataWindow.xaml
Normal file
235
Elwig/Windows/BaseDataWindow.xaml
Normal file
@@ -0,0 +1,235 @@
|
||||
<local:AdministrationWindow x:Class="Elwig.Windows.BaseDataWindow"
|
||||
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"
|
||||
mc:Ignorable="d"
|
||||
Title="Stammdaten - Elwig" Height="500" MinHeight="400" Width="800" MinWidth="800"
|
||||
Loaded="Window_Loaded">
|
||||
<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="ComboBox">
|
||||
<Setter Property="Height" Value="25"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="HorizontalAlignment" Value="Stretch"/>
|
||||
<Setter Property="VerticalAlignment" Value="Top"/>
|
||||
</Style>
|
||||
<Style TargetType="Button">
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="Padding" Value="9,3"/>
|
||||
<Setter Property="Height" Value="27"/>
|
||||
</Style>
|
||||
</Window.Resources>
|
||||
<Grid>
|
||||
<TabControl Margin="10,10,10,42">
|
||||
<TabItem Header="Mandant">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="130"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="90"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label Content="Vollständiger Name:"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="0" Margin="10,10,0,10"/>
|
||||
<TextBox x:Name="ClientNameFull" IsEnabled="False"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Stretch" Grid.Column="1" Grid.ColumnSpan="3" Margin="0,10,10,10"/>
|
||||
|
||||
<Label Content="Name:"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="0" Margin="10,40,0,10"/>
|
||||
<TextBox x:Name="ClientNameInput"
|
||||
TextChanged="ClientNames_TextChanged"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Stretch" Grid.Column="1" Grid.ColumnSpan="3" Margin="0,40,10,10"/>
|
||||
|
||||
<Label Content="Namenszusatz:"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="0" Margin="10,70,0,10"/>
|
||||
<TextBox x:Name="ClientNameSuffixInput"
|
||||
TextChanged="ClientNames_TextChanged"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Stretch" Grid.Column="1" Grid.ColumnSpan="3" Margin="0,70,10,10"/>
|
||||
|
||||
<Label Content="Gesellschaftsform:"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="0" Margin="10,100,0,10"/>
|
||||
<TextBox x:Name="ClientNameTypeInput"
|
||||
TextChanged="ClientNames_TextChanged"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Stretch" Grid.Column="1" Margin="0,100,10,10"/>
|
||||
|
||||
<Label Content="Kürzel/Kurzform:"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="0" Margin="10,130,0,10"/>
|
||||
<TextBox x:Name="ClientNameTokenInput"
|
||||
TextChanged="TextBox_TextChanged"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="1" Margin="0,130,10,10" Width="70"/>
|
||||
<TextBox x:Name="ClientNameShortInput"
|
||||
TextChanged="TextBox_TextChanged"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Stretch" Grid.Column="1" Margin="75,130,10,10"/>
|
||||
|
||||
<Label Content="Adresse:"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="0" Margin="10,160,0,10"/>
|
||||
<TextBox x:Name="ClientAddressInput"
|
||||
TextChanged="TextBox_TextChanged"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Stretch" Grid.Column="1" Margin="0,160,10,10"/>
|
||||
|
||||
<Label Content="PLZ/Ort:"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="0" Margin="10,190,0,10"/>
|
||||
<TextBox x:Name="ClientPlzInput"
|
||||
Margin="0,190,0,0" Width="42" Grid.Column="1" HorizontalAlignment="Left"
|
||||
TextChanged="PlzInput_TextChanged" LostFocus="PlzInput_LostFocus"/>
|
||||
<TextBox x:Name="ClientOrtInput" Margin="47,190,10,0" Grid.Column="1"
|
||||
TextChanged="TextBox_TextChanged"/>
|
||||
|
||||
<Label Content="IBAN:" Margin="10,220,0,0" Grid.Column="0"/>
|
||||
<TextBox x:Name="ClientIbanInput" Margin="0,220,10,0" Grid.Column="1"
|
||||
TextChanged="IbanInput_TextChanged" LostFocus="IbanInput_LostFocus"/>
|
||||
|
||||
<Label Content="BIC:" Margin="10,250,0,0" Grid.Column="0"/>
|
||||
<TextBox x:Name="ClientBicInput" Margin="0,250,10,0" Grid.Column="1"
|
||||
TextChanged="BicInput_TextChanged" LostFocus="BicInput_LostFocus"/>
|
||||
|
||||
<Label Content="UID:"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="2" Margin="10,100,0,10"/>
|
||||
<TextBox x:Name="ClientUstIdNrInput"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="3" Margin="0,100,10,10" Width="96"
|
||||
TextChanged="UstIdNrInput_TextChanged" LostFocus="UstIdNrInput_LostFocus"/>
|
||||
|
||||
<Label Content="Betriebs-Nr.:"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="2" Margin="10,130,0,10"/>
|
||||
<TextBox x:Name="ClientLfbisNrInput"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="3" Margin="0,130,10,10" Width="64"
|
||||
TextChanged="LfbisNrInput_TextChanged" LostFocus="LfbisNrInput_LostFocus"/>
|
||||
|
||||
<Label Content="Telefon-Nr.:"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="2" Margin="10,160,0,10"/>
|
||||
<TextBox x:Name="ClientPhoneNrInput" Margin="0,160,10,10" Grid.Column="3"
|
||||
TextChanged="PhoneNrInput_TextChanged" LostFocus="PhoneNrInput_LostFocus"/>
|
||||
|
||||
<Label Content="Fax-Nr.:"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="2" Margin="10,190,0,10"/>
|
||||
<TextBox x:Name="ClientFaxNrInput" Margin="0,190,10,10" Grid.Column="3"
|
||||
TextChanged="PhoneNrInput_TextChanged" LostFocus="PhoneNrInput_LostFocus"/>
|
||||
|
||||
<Label Content="E-Mail-Adr.:"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="2" Margin="10,220,0,10"/>
|
||||
<TextBox x:Name="ClientEmailAddressInput" Margin="0,220,10,0" Grid.Column="3"
|
||||
TextChanged="EmailAddressInput_TextChanged" LostFocus="EmailAddressInput_LostFocus"/>
|
||||
|
||||
<Label Content="Website:"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="2" Margin="10,250,0,10"/>
|
||||
<TextBox x:Name="ClientWebsiteInput" Margin="0,250,10,0" Grid.Column="3"
|
||||
TextChanged="TextBox_TextChanged"/>
|
||||
</Grid>
|
||||
</TabItem>
|
||||
<TabItem Header="Zweigstellen">
|
||||
|
||||
</TabItem>
|
||||
<TabItem Header="Sortenattribute">
|
||||
|
||||
</TabItem>
|
||||
<TabItem Header="Bewirtschaftungsarten">
|
||||
|
||||
</TabItem>
|
||||
<TabItem Header="Flächenbindungsverträge">
|
||||
|
||||
</TabItem>
|
||||
|
||||
<TabItem Header="Saisons">
|
||||
<Grid>
|
||||
<ListBox x:Name="SeasonList" HorizontalAlignment="Left" VerticalAlignment="Stretch" Width="150" Margin="10,10,10,10"
|
||||
SelectionChanged="SeasonList_SelectionChanged">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding Year}" Width="40"/>
|
||||
<TextBlock Text="{Binding Currency.Name}" Width="60"/>
|
||||
<TextBlock Text="{Binding Precision}" Width="10"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
|
||||
<GroupBox Header="Zu-/Abschläge" Margin="170,150,10,10" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="400"/>
|
||||
<ColumnDefinition Width="70"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<ListBox x:Name="SeasonModifierList" SelectionChanged="SeasonModifierList_SelectionChanged"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Stretch" Width="350" Margin="10,10,10,10">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding ModId}" Width="30"/>
|
||||
<TextBlock Text="{Binding Name}" Width="200" Margin="0,0,10,0"/>
|
||||
<TextBlock Text="{Binding ValueStr}"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
<Button x:Name="SeasonModifierUpButton" Content="" FontFamily="Segoe MDL2 Assets" FontSize="10" Padding="0,0,0,0" IsEnabled="False"
|
||||
Click="SeasonModifierUpButton_Click"
|
||||
VerticalAlignment="Center" HorizontalAlignment="Left" Width="25" Height="25" Margin="365,0,0,90"/>
|
||||
<Button x:Name="SeasonModifierDownButton" Content="" FontFamily="Segoe MDL2 Assets" FontSize="10" Padding="0,2,0,0" IsEnabled="False"
|
||||
Click="SeasonModifierDownButton_Click"
|
||||
VerticalAlignment="Center" HorizontalAlignment="Left" Width="25" Height="25" Margin="365,0,0,30"/>
|
||||
<Button x:Name="SeasonModifierAddButton" Content="" FontFamily="Segoe MDL2 Assets" FontSize="11" Padding="0,1.5,0,0" IsEnabled="False"
|
||||
Click="SeasonModifierAddButton_Click"
|
||||
VerticalAlignment="Center" HorizontalAlignment="Left" Width="25" Height="25" Margin="365,30,0,0"/>
|
||||
<Button x:Name="SeasonModifierDeleteButton" Content="" FontFamily="Segoe MDL2 Assets" FontSize="11" Padding="0,1.5,0,0" IsEnabled="False"
|
||||
Click="SeasonModifierDeleteButton_Click"
|
||||
VerticalAlignment="Center" HorizontalAlignment="Left" Width="25" Height="25" Margin="365,90,0,0"/>
|
||||
|
||||
<Label Content="ID:" Grid.Column="1" Margin="10,10,10,10"/>
|
||||
<TextBox x:Name="SeasonModifierIdInput" Grid.Column="2" Margin="0,10,10,10" Width="50" HorizontalAlignment="Left"
|
||||
TextChanged="SeasonModifierIdInput_TextChanged"/>
|
||||
|
||||
<Label Content="Name:" Grid.Column="1" Margin="10,40,10,10"/>
|
||||
<TextBox x:Name="SeasonModifierNameInput" Grid.Column="2" Margin="0,40,10,10"
|
||||
TextChanged="SeasonModifierNameInput_TextChanged"/>
|
||||
|
||||
<Label Content="Relativ:" Grid.Column="1" Margin="10,70,10,10"/>
|
||||
<TextBox x:Name="SeasonModifierRelInput" Grid.Column="2" Margin="0,70,10,10"
|
||||
TextChanged="SeasonModifierRelInput_TextChanged"/>
|
||||
|
||||
<Label Content="Absolut:" Grid.Column="1" Margin="10,100,10,10"/>
|
||||
<TextBox x:Name="SeasonModifierAbsInput" Grid.Column="2" Margin="0,100,10,10"
|
||||
TextChanged="SeasonModifierAbsInput_TextChanged"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
</Grid>
|
||||
</TabItem>
|
||||
<TabItem Header="Parameter">
|
||||
|
||||
</TabItem>
|
||||
<TabItem Header="Textelemente">
|
||||
|
||||
</TabItem>
|
||||
</TabControl>
|
||||
|
||||
<Button x:Name="EditButton" Content="Bearbeiten"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="0,0,0,10" Width="120"
|
||||
Click="EditButton_Click"/>
|
||||
<Button x:Name="SaveButton" Content="Speichern" IsEnabled="False"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="0,0,250,10" Width="120"
|
||||
Click="SaveButton_Click"/>
|
||||
<Button x:Name="ResetButton" Content="Zurücksetzen" IsEnabled="False" Visibility="Hidden"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="0,0,0,10" Width="120"
|
||||
Click="ResetButton_Click"/>
|
||||
<Button x:Name="CancelButton" Content="Abbrechen" IsEnabled="False" IsCancel="True"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="250,0,0,10" Width="120"
|
||||
Click="CancelButton_Click"/>
|
||||
</Grid>
|
||||
</local:AdministrationWindow>
|
343
Elwig/Windows/BaseDataWindow.xaml.cs
Normal file
343
Elwig/Windows/BaseDataWindow.xaml.cs
Normal file
@@ -0,0 +1,343 @@
|
||||
using Elwig.Helpers;
|
||||
using Elwig.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Elwig.Windows {
|
||||
public partial class BaseDataWindow : AdministrationWindow {
|
||||
|
||||
private Dictionary<string, string?>? Modifiers = null;
|
||||
private Dictionary<Modifier, string>? ModifierIds = null;
|
||||
private ObservableCollection<Modifier>? ModifierList = null;
|
||||
private bool ModifiersChanged = false;
|
||||
private bool ModifierUpdate = false;
|
||||
|
||||
public BaseDataWindow() {
|
||||
InitializeComponent();
|
||||
RequiredInputs = new Control[] {
|
||||
ClientNameInput, ClientNameTypeInput, ClientNameTokenInput, ClientNameShortInput,
|
||||
ClientAddressInput, ClientPlzInput, ClientOrtInput,
|
||||
};
|
||||
ExemptInputs = new Control[] {
|
||||
ClientNameFull,
|
||||
SeasonModifierIdInput, SeasonModifierNameInput, SeasonModifierRelInput, SeasonModifierAbsInput,
|
||||
};
|
||||
}
|
||||
|
||||
new protected void LockInputs() {
|
||||
base.LockInputs();
|
||||
SeasonModifierIdInput.IsReadOnly = true;
|
||||
SeasonModifierNameInput.IsReadOnly = true;
|
||||
SeasonModifierRelInput.IsReadOnly = true;
|
||||
SeasonModifierAbsInput.IsReadOnly = true;
|
||||
}
|
||||
|
||||
new protected void UnlockInputs() {
|
||||
base.UnlockInputs();
|
||||
SeasonModifierIdInput.IsReadOnly = false;
|
||||
SeasonModifierNameInput.IsReadOnly = false;
|
||||
SeasonModifierRelInput.IsReadOnly = false;
|
||||
SeasonModifierAbsInput.IsReadOnly = false;
|
||||
}
|
||||
|
||||
private void Window_Loaded(object sender, RoutedEventArgs evt) {
|
||||
LockInputs();
|
||||
FillInputs(App.Client);
|
||||
}
|
||||
|
||||
protected override async Task RenewContext() {
|
||||
await base.RenewContext();
|
||||
ControlUtils.RenewItemsSource(SeasonList, await Context.Seasons.OrderByDescending(s => s.Year).ToListAsync(), s => (s as Season)?.Year, null, ControlUtils.RenewSourceDefault.First);
|
||||
var year = (SeasonList.SelectedItem as Season)?.Year;
|
||||
ControlUtils.RenewItemsSource(SeasonModifierList, await Context.Modifiers.Where(m => m.Year == year).OrderBy(m => m.Ordering).ToListAsync(), m => (m as Modifier)?.ModId);
|
||||
}
|
||||
|
||||
protected override void UpdateButtons() {
|
||||
if (!IsEditing && !IsCreating) return;
|
||||
bool ch = ModifiersChanged || HasChanged, v = IsValid;
|
||||
CancelButton.IsEnabled = true;
|
||||
ResetButton.IsEnabled = ch;
|
||||
SaveButton.IsEnabled = ch && v;
|
||||
SeasonModifierUpButton.IsEnabled = SeasonModifierList.SelectedIndex >= 1;
|
||||
SeasonModifierDownButton.IsEnabled = SeasonModifierList.SelectedIndex != -1 && SeasonModifierList.SelectedIndex < (ModifierList?.Count - 1 ?? 0);
|
||||
SeasonModifierAddButton.IsEnabled = true;
|
||||
SeasonModifierDeleteButton.IsEnabled = SeasonModifierList.SelectedIndex != -1;
|
||||
}
|
||||
|
||||
private void ModifiersInitEditing() {
|
||||
var year = (SeasonList.SelectedItem as Season)?.Year;
|
||||
Context.ChangeTracker.Clear();
|
||||
ModifierList = new(Context.Modifiers.Where(m => m.Year == year).OrderBy(m => m.Ordering).ToList());
|
||||
Modifiers = ModifierList.ToDictionary(m => m.ModId, m => m.ModId);
|
||||
ModifierIds = ModifierList.ToDictionary(m => m, m => m.ModId);
|
||||
ControlUtils.RenewItemsSource(SeasonModifierList, ModifierList, m => (m as Modifier)?.ModId);
|
||||
}
|
||||
|
||||
private void ModifiersFinishEditing() {
|
||||
var year = (SeasonList.SelectedItem as Season)?.Year;
|
||||
ControlUtils.RenewItemsSource(SeasonModifierList, Context.Modifiers.Where(m => m.Year == year).OrderBy(m => m.Ordering).ToList(), m => (m as Modifier)?.ModId);
|
||||
ModifierList = null;
|
||||
Modifiers = null;
|
||||
ModifierIds = null;
|
||||
ModifiersChanged = false;
|
||||
|
||||
SeasonModifierUpButton.IsEnabled = false;
|
||||
SeasonModifierDownButton.IsEnabled = false;
|
||||
SeasonModifierAddButton.IsEnabled = false;
|
||||
SeasonModifierDeleteButton.IsEnabled = false;
|
||||
}
|
||||
|
||||
private async Task ModifiersSave() {
|
||||
if (!ModifiersChanged || ModifierList == null || Modifiers == null || ModifierIds == null) return;
|
||||
int i = 0;
|
||||
foreach (var mod in ModifierList) mod.Ordering = ++i;
|
||||
|
||||
var year = (SeasonList.SelectedItem as Season)?.Year;
|
||||
foreach (var (modid, _) in Modifiers.Where(m => m.Value == null)) {
|
||||
Context.Remove(Context.Modifiers.Find(new object?[] { year, modid }));
|
||||
}
|
||||
foreach (var (mod, old) in ModifierIds) {
|
||||
mod.ModId = old;
|
||||
}
|
||||
foreach (var (old, modid) in Modifiers.Where(m => m.Value != null)) {
|
||||
Context.Update(Context.Modifiers.Find(new object?[] { year, old }));
|
||||
}
|
||||
await Context.SaveChangesAsync();
|
||||
|
||||
foreach (var (old, modid) in Modifiers.Where(m => m.Value != null)) {
|
||||
await Context.Database.ExecuteSqlAsync($"UPDATE modifier SET modid = {modid} WHERE (year, modid) = ({year}, {old})");
|
||||
}
|
||||
await Context.SaveChangesAsync();
|
||||
|
||||
foreach (var mod in ModifierList.Where(m => !ModifierIds.ContainsKey(m))) {
|
||||
await Context.AddAsync(mod);
|
||||
}
|
||||
await Context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
private void EditButton_Click(object sender, RoutedEventArgs evt) {
|
||||
IsEditing = true;
|
||||
EditButton.Visibility = Visibility.Hidden;
|
||||
ResetButton.Visibility = Visibility.Visible;
|
||||
|
||||
ModifiersInitEditing();
|
||||
UnlockInputs();
|
||||
UpdateButtons();
|
||||
}
|
||||
|
||||
private void CancelButton_Click(object sender, RoutedEventArgs evt) {
|
||||
IsEditing = false;
|
||||
IsCreating = false;
|
||||
EditButton.Visibility = Visibility.Visible;
|
||||
ResetButton.Visibility = Visibility.Hidden;
|
||||
CancelButton.IsEnabled = false;
|
||||
SaveButton.IsEnabled = false;
|
||||
ResetButton.IsEnabled = false;
|
||||
ModifiersFinishEditing();
|
||||
|
||||
ClearInputStates();
|
||||
FillInputs(App.Client);
|
||||
LockInputs();
|
||||
}
|
||||
|
||||
private void ResetButton_Click(object sender, RoutedEventArgs evt) {
|
||||
ModifiersChanged = false;
|
||||
ModifiersInitEditing();
|
||||
ClearInputStates();
|
||||
FillInputs(App.Client);
|
||||
UpdateButtons();
|
||||
}
|
||||
|
||||
private async void SaveButton_Click(object sender, RoutedEventArgs evt) {
|
||||
try {
|
||||
await UpdateClientParameters(App.Client);
|
||||
await ModifiersSave();
|
||||
} 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, "Stammdaten aktualisieren", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
|
||||
IsEditing = false;
|
||||
IsCreating = false;
|
||||
EditButton.Visibility = Visibility.Visible;
|
||||
ResetButton.Visibility = Visibility.Hidden;
|
||||
CancelButton.IsEnabled = false;
|
||||
SaveButton.IsEnabled = false;
|
||||
ResetButton.IsEnabled = false;
|
||||
ModifiersFinishEditing();
|
||||
|
||||
ClearInputStates();
|
||||
FillInputs(App.Client);
|
||||
LockInputs();
|
||||
}
|
||||
|
||||
private void FillInputs(ClientParameters p) {
|
||||
ClearOriginalValues();
|
||||
ClearDefaultValues();
|
||||
|
||||
ClientNameInput.Text = p.Name;
|
||||
ClientNameSuffixInput.Text = p.NameSuffix;
|
||||
ClientNameTypeInput.Text = p.NameType;
|
||||
ClientNameTokenInput.Text = p.NameToken;
|
||||
ClientNameShortInput.Text = p.NameShort;
|
||||
ClientAddressInput.Text = p.Address;
|
||||
ClientPlzInput.Text = p.Plz.ToString();
|
||||
ClientOrtInput.Text = p.Ort;
|
||||
ClientIbanInput.Text = p.Iban;
|
||||
ClientBicInput.Text = p.Bic;
|
||||
ClientUstIdNrInput.Text = p.UstIdNr;
|
||||
ClientLfbisNrInput.Text = p.LfbisNr;
|
||||
ClientPhoneNrInput.Text = p.PhoneNr;
|
||||
ClientFaxNrInput.Text = p.FaxNr;
|
||||
ClientEmailAddressInput.Text = p.EmailAddress;
|
||||
ClientWebsiteInput.Text = p.Website;
|
||||
|
||||
FinishInputFilling();
|
||||
}
|
||||
|
||||
private async Task UpdateClientParameters(ClientParameters p) {
|
||||
p.Name = ClientNameInput.Text;
|
||||
p.NameSuffix = ClientNameSuffixInput.Text.Length > 0 ? ClientNameSuffixInput.Text : null;
|
||||
p.NameType = ClientNameTypeInput.Text;
|
||||
p.NameToken = ClientNameTokenInput.Text;
|
||||
p.NameShort = ClientNameShortInput.Text;
|
||||
p.Address = ClientAddressInput.Text;
|
||||
p.Plz = int.Parse(ClientPlzInput.Text);
|
||||
p.Ort = ClientOrtInput.Text;
|
||||
p.Iban = ClientIbanInput.Text.Length > 0 ? ClientIbanInput.Text : null;
|
||||
p.Bic = ClientBicInput.Text.Length > 0 ? ClientBicInput.Text : null;
|
||||
p.UstIdNr = ClientUstIdNrInput.Text.Length > 0 ? ClientUstIdNrInput.Text : null;
|
||||
p.LfbisNr = ClientLfbisNrInput.Text.Length > 0 ? ClientLfbisNrInput.Text : null;
|
||||
p.PhoneNr = ClientPhoneNrInput.Text.Length > 0 ? ClientPhoneNrInput.Text : null;
|
||||
p.FaxNr = ClientFaxNrInput.Text.Length > 0 ? ClientFaxNrInput.Text : null;
|
||||
p.EmailAddress = ClientEmailAddressInput.Text.Length > 0 ? ClientEmailAddressInput.Text : null;
|
||||
p.Website = ClientWebsiteInput.Text.Length > 0 ? ClientWebsiteInput.Text : null;
|
||||
|
||||
await p.UpdateValues();
|
||||
}
|
||||
|
||||
private void SeasonModifierUpButton_Click(object sender, RoutedEventArgs evt) {
|
||||
if (ModifierList == null) return;
|
||||
ModifiersChanged = true;
|
||||
var idx = SeasonModifierList.SelectedIndex;
|
||||
var item = ModifierList[idx];
|
||||
ModifierList.RemoveAt(idx);
|
||||
idx--;
|
||||
ModifierList.Insert(idx, item);
|
||||
SeasonModifierList.SelectedIndex = idx;
|
||||
UpdateButtons();
|
||||
}
|
||||
|
||||
private void SeasonModifierDownButton_Click(object sender, RoutedEventArgs evt) {
|
||||
if (ModifierList == null) return;
|
||||
ModifiersChanged = true;
|
||||
var idx = SeasonModifierList.SelectedIndex;
|
||||
var item = ModifierList[idx];
|
||||
ModifierList.RemoveAt(idx);
|
||||
idx++;
|
||||
ModifierList.Insert(idx, item);
|
||||
SeasonModifierList.SelectedIndex = idx;
|
||||
UpdateButtons();
|
||||
}
|
||||
|
||||
private void SeasonModifierAddButton_Click(object sender, RoutedEventArgs evt) {
|
||||
if (ModifierList == null || SeasonList.SelectedItem is not Season s) return;
|
||||
ModifiersChanged = true;
|
||||
var idx = (SeasonModifierList.SelectedIndex != -1) ? SeasonModifierList.SelectedIndex + 1 : ModifierList.Count;
|
||||
var item = Context.CreateProxy<Modifier>();
|
||||
item.Year = s.Year;
|
||||
ModifierList.Insert(idx, item);
|
||||
SeasonModifierList.SelectedIndex = idx;
|
||||
UpdateButtons();
|
||||
}
|
||||
|
||||
private void SeasonModifierDeleteButton_Click(object sender, RoutedEventArgs evt) {
|
||||
if (ModifierList == null || Modifiers == null) return;
|
||||
ModifiersChanged = true;
|
||||
var idx = SeasonModifierList.SelectedIndex;
|
||||
var item = ModifierList[idx];
|
||||
Modifiers[item.ModId] = null;
|
||||
ModifierList.RemoveAt(idx);
|
||||
SeasonModifierList.SelectedIndex = idx < ModifierList.Count ? idx : idx - 1;
|
||||
UpdateButtons();
|
||||
}
|
||||
|
||||
|
||||
private void ClientNames_TextChanged(object sender, TextChangedEventArgs evt) {
|
||||
var suffix = ClientNameSuffixInput.Text.Length > 0 ? ClientNameSuffixInput.Text : null;
|
||||
ClientNameFull.Text = $"{ClientNameInput.Text}{(suffix != null ? $", {suffix}," : "")} {ClientNameTypeInput.Text}";
|
||||
TextBox_TextChanged(sender, evt);
|
||||
}
|
||||
|
||||
private async void SeasonList_SelectionChanged(object sender, SelectionChangedEventArgs evt) {
|
||||
var year = (SeasonList.SelectedItem as Season)?.Year;
|
||||
SeasonModifierList.ItemsSource = await Context.Modifiers.Where(m => m.Year == year).OrderBy(m => m.Ordering).ToListAsync();
|
||||
}
|
||||
|
||||
private void SeasonModifierList_SelectionChanged(object sender, SelectionChangedEventArgs evt) {
|
||||
UpdateButtons();
|
||||
ModifierUpdate = true;
|
||||
if (SeasonModifierList.SelectedItem is not Modifier mod) {
|
||||
SeasonModifierIdInput.Text = "";
|
||||
SeasonModifierNameInput.Text = "";
|
||||
SeasonModifierRelInput.Text = "";
|
||||
SeasonModifierAbsInput.Text = "";
|
||||
} else {
|
||||
SeasonModifierIdInput.Text = mod.ModId;
|
||||
SeasonModifierNameInput.Text = mod.Name;
|
||||
SeasonModifierRelInput.Text = (mod.Rel * 100)?.ToString();
|
||||
SeasonModifierAbsInput.Text = mod.Abs?.ToString();
|
||||
}
|
||||
ModifierUpdate = false;
|
||||
}
|
||||
|
||||
private void SeasonModifierIdInput_TextChanged(object sender, TextChangedEventArgs evt) {
|
||||
if ((!IsEditing && !IsCreating) || SeasonModifierList.SelectedItem is not Modifier mod || Modifiers == null || ModifierIds == null) return;
|
||||
ModifiersChanged = ModifiersChanged || (SeasonModifierIdInput.Text ?? "") != ((SeasonModifierList.SelectedItem as Modifier)?.ModId ?? "");
|
||||
if (ModifierUpdate) return;
|
||||
var old = ModifierIds.GetValueOrDefault(mod);
|
||||
var id = SeasonModifierIdInput.Text ?? "";
|
||||
if (old != null) Modifiers[old] = id;
|
||||
mod.ModId = id;
|
||||
CollectionViewSource.GetDefaultView(ModifierList).Refresh();
|
||||
UpdateButtons();
|
||||
}
|
||||
|
||||
private void SeasonModifierNameInput_TextChanged(object sender, TextChangedEventArgs evt) {
|
||||
if ((!IsEditing && !IsCreating) || SeasonModifierList.SelectedItem is not Modifier mod) return;
|
||||
ModifiersChanged = ModifiersChanged || (SeasonModifierNameInput.Text ?? "") != ((SeasonModifierList.SelectedItem as Modifier)?.Name ?? "");
|
||||
if (ModifierUpdate) return;
|
||||
mod.Name = SeasonModifierNameInput.Text ?? "";
|
||||
CollectionViewSource.GetDefaultView(ModifierList).Refresh();
|
||||
UpdateButtons();
|
||||
}
|
||||
|
||||
private void SeasonModifierRelInput_TextChanged(object sender, TextChangedEventArgs evt) {
|
||||
if ((!IsEditing && !IsCreating) || SeasonModifierList.SelectedItem is not Modifier mod) return;
|
||||
ModifiersChanged = ModifiersChanged || (SeasonModifierRelInput.Text ?? "") != ((SeasonModifierList.SelectedItem as Modifier)?.Rel?.ToString() ?? "");
|
||||
if (ModifierUpdate) return;
|
||||
mod.Rel = decimal.TryParse(SeasonModifierRelInput.Text, out var v) ? v / 100 : null;
|
||||
if (mod.Rel != null) SeasonModifierAbsInput.Text = "";
|
||||
CollectionViewSource.GetDefaultView(ModifierList).Refresh();
|
||||
UpdateButtons();
|
||||
}
|
||||
|
||||
private void SeasonModifierAbsInput_TextChanged(object sender, TextChangedEventArgs evt) {
|
||||
if ((!IsEditing && !IsCreating) || SeasonModifierList.SelectedItem is not Modifier mod) return;
|
||||
ModifiersChanged = ModifiersChanged || (SeasonModifierAbsInput.Text ?? "") != ((SeasonModifierList.SelectedItem as Modifier)?.Abs?.ToString() ?? "");
|
||||
if (ModifierUpdate) return;
|
||||
mod.Abs = decimal.TryParse(SeasonModifierAbsInput.Text, out var v) ? v : null;
|
||||
if (mod.Abs != null) SeasonModifierRelInput.Text = "";
|
||||
CollectionViewSource.GetDefaultView(ModifierList).Refresh();
|
||||
UpdateButtons();
|
||||
}
|
||||
}
|
||||
}
|
188
Elwig/Windows/ChartWindow.xaml
Normal file
188
Elwig/Windows/ChartWindow.xaml
Normal file
@@ -0,0 +1,188 @@
|
||||
<local:AdministrationWindow x:Class="Elwig.Windows.ChartWindow"
|
||||
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:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
|
||||
xmlns:ScottPlot="clr-namespace:ScottPlot;assembly=ScottPlot.WPF"
|
||||
mc:Ignorable="d"
|
||||
Title="Auszahlung - Elwig" Height="700" Width="1500"
|
||||
Loaded="Window_Loaded">
|
||||
|
||||
<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="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"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="HorizontalAlignment" Value="Stretch"/>
|
||||
<Setter Property="VerticalAlignment" Value="Top"/>
|
||||
</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="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="330"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="200"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Grid Grid.Row="1" Margin="5,0,0,0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="42"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<DataGrid x:Name="GraphList" AutoGenerateColumns="False" HeadersVisibility="Column" IsReadOnly="True" GridLinesVisibility="None" SelectionMode="Single"
|
||||
CanUserDeleteRows="False" CanUserResizeRows="False" CanUserAddRows="False"
|
||||
SelectionChanged="GraphList_SelectionChanged"
|
||||
Margin="5,15,5,0" Grid.Row="0" FontSize="14" Grid.ColumnSpan="3">
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="Nr." Binding="{Binding Num}" Width="40">
|
||||
<DataGridTextColumn.ElementStyle>
|
||||
<Style>
|
||||
<Setter Property="TextBlock.TextWrapping" Value="Wrap" />
|
||||
</Style>
|
||||
</DataGridTextColumn.ElementStyle>
|
||||
</DataGridTextColumn>
|
||||
<DataGridTextColumn Header="Typ" Binding="{Binding Type}" Width="40"/>
|
||||
<DataGridTextColumn Header="Angewandte Verträge" Binding="{Binding Contracts}" Width="4*"/>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
|
||||
<Button x:Name="NewButton" Content="Neu"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="5,5,2.5,10" Grid.Column="0" Grid.Row="2"
|
||||
Click="NewButton_Click"/>
|
||||
<Button x:Name="EditButton" Content="Bearbeiten" IsEnabled="False"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="2.5,5,2.5,10" Grid.Column="1" Grid.Row="2"
|
||||
Click="EditButton_Click"/>
|
||||
<Button x:Name="DeleteButton" Content="Löschen" IsEnabled="False"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="2.5,5,5,10" Grid.Column="2" Grid.Row="2"
|
||||
Click="DeleteButton_Click"/>
|
||||
|
||||
<Button x:Name="SaveButton" Content="Speichern" IsEnabled="False" Visibility="Hidden"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="5,5,2.5,10" Grid.Column="0" Grid.Row="2"
|
||||
Click="SaveButton_Click"/>
|
||||
<Button x:Name="ResetButton" Content="Zurücksetzen" IsEnabled="False" Visibility="Hidden"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="2.5,5,2.5,10" Grid.Column="1" Grid.Row="2"
|
||||
Click="ResetButton_Click"/>
|
||||
<Button x:Name="CancelButton" Content="Abbrechen" IsEnabled="False" Visibility="Hidden" IsCancel="True"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="2.5,5,5,10" Grid.Column="2" Grid.Row="2"
|
||||
Click="CancelButton_Click"/>
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Row="1" Grid.Column="1">
|
||||
<ScottPlot:WpfPlot x:Name="OechslePricePlot" MouseMove="OechslePricePlot_MouseMove" MouseDown="OechslePricePlot_MouseDown" IsEnabled="False"/>
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Row="1" Grid.Column="2" Margin="0,0,5,0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="120"/>
|
||||
<RowDefinition Height="120"/>
|
||||
<RowDefinition Height="210"/>
|
||||
<RowDefinition Height="110"/>
|
||||
<RowDefinition Height="42"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<GroupBox Header="Graph" Grid.Row="0" Margin="0,5,5,5">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="85"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label Content="Nummer:" Margin="10,10,0,0" Grid.Column="0"/>
|
||||
<TextBox x:Name="GraphNumberInput" Grid.Column="1" HorizontalAlignment="Left" Margin="0,10,0,0" Text="" Width="90" TextChanged="GraphNumberInput_TextChanged" LostFocus="GraphNumberInput_LostFocus"/>
|
||||
|
||||
<Label Content="Typ:" Margin="10,45,0,0" Grid.Column="0"/>
|
||||
<RadioButton x:Name="OechsleGraphType_Input" GroupName="GraphType" Grid.Column="1" Margin="0,45,0,0">Oechsle</RadioButton>
|
||||
<RadioButton x:Name="KmwGraphType_Input" GroupName="GraphType" Grid.Column="1" Margin="0,60,0,0">KMW</RadioButton>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Header="Datenpunkt" Grid.Row="1" Margin="0,5,5,5">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="85"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label Content="Oechsle:" Margin="10,10,0,0" Grid.Column="0"/>
|
||||
<TextBox x:Name="OechsleInput" Grid.Column="1" HorizontalAlignment="Left" Margin="0,10,0,0" Text="" Width="90" TextChanged="OechsleInput_TextChanged" LostFocus="OechsleInput_LostFocus"/>
|
||||
|
||||
<Label Content="Preis pro kg:" Margin="10,40,0,0" Grid.Column="0"/>
|
||||
<TextBox x:Name="PriceInput" Grid.Column="1" HorizontalAlignment="Left" Margin="0,40,0,0" Text="" Width="90" TextChanged="PriceInput_TextChanged" LostFocus="PriceInput_LostFocus"/>
|
||||
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Header="Aktionen" Grid.Row="2" Margin="0,5,5,5">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Button x:Name="LeftFlatButton" Content="Links flach" Click="LeftFlatButton_Click" IsEnabled="False"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Top" Margin="10,10,10,10"/>
|
||||
|
||||
<Button x:Name="RightFlatButton" Content="Rechts flach" Click="RightFlatButton_Click" IsEnabled="False"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Top" Margin="10,50,10,10"/>
|
||||
|
||||
<Button x:Name="InterpolateButton" Content="Interpolieren" Click="InterpolateButton_Click" IsEnabled="False"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Top" Margin="10,90,10,10"/>
|
||||
|
||||
<Button x:Name="LinearIncreaseButton" Content="Linear wachsen" Click="LinearIncreaseButton_Click" IsEnabled="False"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Top" Margin="10,130,10,10"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Header="Optionen" Grid.Row="3" Margin="0,5,5,5">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<CheckBox x:Name="FreeZoomInput" Content="Freier Zoom" IsEnabled="False"
|
||||
Checked="FreeZoomInput_Changed" Unchecked="FreeZoomInput_Changed"
|
||||
HorizontalAlignment="Left" Margin="10,10,10,0" VerticalAlignment="Top"/>
|
||||
|
||||
<CheckBox x:Name="GradationLinesInput" Content="Gradationslinien anzeigen" IsEnabled="False"
|
||||
Checked="GradationLinesInput_Changed" Unchecked="GradationLinesInput_Changed"
|
||||
HorizontalAlignment="Left" Margin="10,30,10,0" VerticalAlignment="Top" IsChecked="True"/>
|
||||
|
||||
<CheckBox x:Name="TooltipInput" Content="Tooltips anzeigen" IsEnabled="False"
|
||||
HorizontalAlignment="Left" Margin="10,50,10,0" VerticalAlignment="Top" IsChecked="True"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</local:AdministrationWindow>
|
749
Elwig/Windows/ChartWindow.xaml.cs
Normal file
749
Elwig/Windows/ChartWindow.xaml.cs
Normal file
@@ -0,0 +1,749 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using Elwig.Helpers;
|
||||
using Elwig.Helpers.Billing;
|
||||
using Elwig.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
||||
using ScottPlot;
|
||||
using ScottPlot.Plottable;
|
||||
|
||||
namespace Elwig.Windows {
|
||||
public partial class ChartWindow : AdministrationWindow {
|
||||
|
||||
private readonly int Year = 2021;
|
||||
private readonly int AvNr = 2;
|
||||
|
||||
private ScatterPlot OechslePricePlotScatter;
|
||||
private MarkerPlot HighlightedPoint;
|
||||
private MarkerPlot PrimaryMarkedPoint;
|
||||
private MarkerPlot SecondaryMarkedPoint;
|
||||
private Tooltip Tooltip;
|
||||
|
||||
private int LastHighlightedIndex = -1;
|
||||
private int HighlightedIndex = -1;
|
||||
private int PrimaryMarkedPointIndex = -1;
|
||||
private int SecondaryMarkedPointIndex = -1;
|
||||
private bool HoverChanged = false;
|
||||
private bool HoverActive = false;
|
||||
|
||||
private const int MinOechsle = 50;
|
||||
private const int MaxOechsle = 140;
|
||||
|
||||
private Graph? Graph;
|
||||
|
||||
public ChartWindow() {
|
||||
InitializeComponent();
|
||||
|
||||
ExemptInputs = new Control[] {
|
||||
GraphList, OechsleInput, PriceInput, FreeZoomInput, GradationLinesInput, TooltipInput
|
||||
};
|
||||
}
|
||||
|
||||
private void Window_Loaded(object sender, RoutedEventArgs evt) {
|
||||
LockInputs();
|
||||
OechslePricePlot.IsEnabled = false;
|
||||
}
|
||||
|
||||
private async Task RefreshGraphList() {
|
||||
await Context.PaymentVariants.LoadAsync();
|
||||
await RefreshGraphListQuery();
|
||||
}
|
||||
|
||||
private async Task RefreshGraphListQuery(bool updateSort = false) {
|
||||
List<PaymentVar> paymentVars = await Context.PaymentVariants.Where(p => p.Year == Year && p.AvNr == AvNr).ToListAsync();
|
||||
|
||||
if (paymentVars.Count != 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
PaymentVar paymentVar = paymentVars[0];
|
||||
var data = JsonNode.Parse(paymentVar.Data).AsObject();
|
||||
|
||||
var auszahlungsSorten = data["AuszahlungSorten"]?.AsObject();
|
||||
if (auszahlungsSorten == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var Graphs = auszahlungsSorten["Kurven"]?.AsArray();
|
||||
|
||||
if (Graphs == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<Graph> GraphsList = new();
|
||||
|
||||
int i = 1;
|
||||
foreach (var graph in Graphs) {
|
||||
GraphsList.Add(new Graph("Oe", i, graph?.AsObject(), ParseContracts(auszahlungsSorten, i - 1), 50, 140));
|
||||
i++;
|
||||
}
|
||||
|
||||
ControlUtils.RenewItemsSource(GraphList, GraphsList, g => (g as Graph)?.Num);
|
||||
if (GraphsList.Count == 1) {
|
||||
GraphList.SelectedIndex = 0;
|
||||
}
|
||||
|
||||
RefreshInputs();
|
||||
}
|
||||
|
||||
private String ParseContracts(JsonObject auszahlungsSorten, int num) {
|
||||
List<string> contracts = new();
|
||||
|
||||
foreach (var sorte in auszahlungsSorten) {
|
||||
if (sorte.Key == "Kurven") continue;
|
||||
foreach (var attribut in sorte.Value.AsObject()) {
|
||||
foreach (var bindung in attribut.Value.AsObject()) {
|
||||
if ((int)bindung.Value.AsValue() == num) {
|
||||
contracts.Add($"{sorte.Key}/{attribut.Key}/{bindung.Key}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return string.Join("\n", contracts.ToArray());
|
||||
}
|
||||
|
||||
private async Task<bool> RemoveGraph(int num) {
|
||||
List<PaymentVar> paymentVars = await Context.PaymentVariants.Where(p => p.Year == Year && p.AvNr == AvNr).ToListAsync();
|
||||
|
||||
if (paymentVars.Count != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PaymentVar paymentVar = paymentVars[0];
|
||||
var data = JsonNode.Parse(paymentVar.Data).AsObject();
|
||||
|
||||
var auszahlungsSorten = data["AuszahlungSorten"]?.AsObject();
|
||||
if (auszahlungsSorten == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var Graphs = auszahlungsSorten["Kurven"]?.AsObject();
|
||||
if (Graphs == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int i = 1;
|
||||
foreach (var graph in Graphs) {
|
||||
if (i == num) {
|
||||
Graphs.Remove(graph.Key);
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
foreach (var sorte in auszahlungsSorten) {
|
||||
if (sorte.Key == "Kurven") continue;
|
||||
foreach (var attribut in sorte.Value.AsObject()) {
|
||||
var bindungen = attribut.Value.AsObject();
|
||||
foreach (var bindung in bindungen) {
|
||||
int v = (int)bindung.Value;
|
||||
if (v == num - 1) {
|
||||
bindungen.Remove(bindung.Key);
|
||||
} else if (v > num - 1) {
|
||||
bindungen[bindung.Key] = v - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EntityEntry<PaymentVar>? tr = null;
|
||||
try {
|
||||
paymentVar.Data = data.ToString();
|
||||
tr = Context.Update(paymentVar);
|
||||
|
||||
await Context.SaveChangesAsync();
|
||||
} catch (Exception exc) {
|
||||
if (tr != null) await tr.ReloadAsync();
|
||||
var str = "Der Eintrag konnte nicht in der Datenbank gelöscht werden!\n\n" + exc.Message;
|
||||
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
|
||||
MessageBox.Show(str, "Graph löschen", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void RefreshInputs(bool validate = false) {
|
||||
ResetPlot();
|
||||
ClearInputStates();
|
||||
if (GraphList.SelectedItem is Graph g) {
|
||||
EditButton.IsEnabled = true;
|
||||
DeleteButton.IsEnabled = true;
|
||||
EnableOptionButtons();
|
||||
FillInputs(g);
|
||||
} else {
|
||||
EditButton.IsEnabled = false;
|
||||
DeleteButton.IsEnabled = false;
|
||||
DisableOptionButtons();
|
||||
ClearOriginalValues();
|
||||
ClearInputs(validate);
|
||||
ClearInputStates();
|
||||
}
|
||||
GC.Collect();
|
||||
}
|
||||
|
||||
private void FillInputs(Graph g) {
|
||||
ClearOriginalValues();
|
||||
|
||||
Graph = (Graph)g.Clone();
|
||||
|
||||
GraphNumberInput.Text = Graph.Num.ToString();
|
||||
if (Graph.Type == "oe") {
|
||||
OechsleGraphType_Input.IsChecked = true;
|
||||
} else if (Graph.Type == "kmw") {
|
||||
KmwGraphType_Input.IsChecked = true;
|
||||
}
|
||||
|
||||
InitPlot();
|
||||
OechslePricePlot.IsEnabled = true;
|
||||
|
||||
FinishInputFilling();
|
||||
}
|
||||
|
||||
private void InitInputs() {
|
||||
GraphNumberInput.Text = (GraphList.Items.Count + 1).ToString();
|
||||
OechsleGraphType_Input.IsChecked = true;
|
||||
FinishInputFilling();
|
||||
}
|
||||
|
||||
protected override async Task RenewContext() {
|
||||
await base.RenewContext();
|
||||
await RefreshGraphList();
|
||||
}
|
||||
|
||||
private void InitPlot() {
|
||||
OechslePricePlotScatter = OechslePricePlot.Plot.AddScatter(Graph.DataX, Graph.DataY);
|
||||
|
||||
OechslePricePlot.Configuration.DoubleClickBenchmark = false;
|
||||
OechslePricePlotScatter.LineColor = Color.Blue;
|
||||
OechslePricePlotScatter.MarkerColor = Color.Blue;
|
||||
OechslePricePlotScatter.MarkerSize = 9;
|
||||
|
||||
//OechslePricePlot.Plot.XAxis.ManualTickSpacing(1);
|
||||
OechslePricePlot.Plot.YAxis.ManualTickSpacing(0.1);
|
||||
OechslePricePlot.Plot.SetAxisLimits(MinOechsle - 1, MaxOechsle + 1, -0.1, 2);
|
||||
|
||||
OechslePricePlot.Plot.Layout(padding: 0);
|
||||
OechslePricePlot.Plot.XAxis2.Layout(padding: 0);
|
||||
OechslePricePlot.Plot.YAxis.Layout(padding: 0);
|
||||
OechslePricePlot.Plot.YAxis2.Layout(padding: 0);
|
||||
|
||||
HighlightedPoint = OechslePricePlot.Plot.AddPoint(0, 0);
|
||||
HighlightedPoint.Color = Color.Red;
|
||||
HighlightedPoint.MarkerSize = 10;
|
||||
HighlightedPoint.MarkerShape = MarkerShape.openCircle;
|
||||
HighlightedPoint.IsVisible = false;
|
||||
|
||||
PrimaryMarkedPoint = OechslePricePlot.Plot.AddPoint(0, 0);
|
||||
PrimaryMarkedPoint.Color = Color.Red;
|
||||
PrimaryMarkedPoint.MarkerSize = 6;
|
||||
PrimaryMarkedPoint.MarkerShape = MarkerShape.filledCircle;
|
||||
PrimaryMarkedPoint.IsVisible = false;
|
||||
|
||||
SecondaryMarkedPoint = OechslePricePlot.Plot.AddPoint(0, 0);
|
||||
SecondaryMarkedPoint.Color = Color.Red;
|
||||
SecondaryMarkedPoint.MarkerSize = 6;
|
||||
SecondaryMarkedPoint.MarkerShape = MarkerShape.filledCircle;
|
||||
SecondaryMarkedPoint.IsVisible = false;
|
||||
|
||||
OechslePricePlot.Refresh();
|
||||
|
||||
RefreshFreeZoom();
|
||||
RefreshGradationLines();
|
||||
}
|
||||
|
||||
private void ResetPlot() {
|
||||
Graph = null;
|
||||
PrimaryMarkedPointIndex = -1;
|
||||
OechslePricePlot.Plot.Remove(OechslePricePlotScatter);
|
||||
OechslePricePlot.Plot.Clear();
|
||||
OechslePricePlot.Reset();
|
||||
OechslePricePlot.Refresh();
|
||||
}
|
||||
|
||||
private void ChangeMarker(MarkerPlot point, bool visible, double x = 0, double y = 0) {
|
||||
point.X = x;
|
||||
point.Y = y;
|
||||
point.IsVisible = visible;
|
||||
}
|
||||
|
||||
private void FlattenGraph(int begin, int end, double value) {
|
||||
for (int i = begin; i <= end; i++) {
|
||||
Graph.DataY[i] = value;
|
||||
}
|
||||
OechslePricePlot.Render();
|
||||
}
|
||||
|
||||
private void LinearIncreaseGraph(int begin, int end, double inc) {
|
||||
for (int i = begin; i < end; i++) {
|
||||
Graph.DataY[i + 1] = Graph.DataY[i] + inc;
|
||||
}
|
||||
OechslePricePlot.Render();
|
||||
}
|
||||
|
||||
private void EnableActionButtons() {
|
||||
LeftFlatButton.IsEnabled = true;
|
||||
RightFlatButton.IsEnabled = true;
|
||||
LinearIncreaseButton.IsEnabled = true;
|
||||
}
|
||||
|
||||
private void DisableActionButtons() {
|
||||
LeftFlatButton.IsEnabled = false;
|
||||
RightFlatButton.IsEnabled = false;
|
||||
InterpolateButton.IsEnabled = false;
|
||||
LinearIncreaseButton.IsEnabled = false;
|
||||
}
|
||||
|
||||
private void FreeZoomInput_Changed(object sender, RoutedEventArgs evt) {
|
||||
RefreshFreeZoom();
|
||||
}
|
||||
|
||||
private void RefreshFreeZoom() {
|
||||
if (FreeZoomInput.IsChecked == true) {
|
||||
UnlockZoom();
|
||||
} else {
|
||||
LockZoom();
|
||||
}
|
||||
OechslePricePlot.Refresh();
|
||||
}
|
||||
|
||||
private void LockZoom() {
|
||||
OechslePricePlot.Plot.XAxis.SetBoundary(MinOechsle - 1, MaxOechsle + 1);
|
||||
OechslePricePlot.Plot.YAxis.SetBoundary(-0.1, 2);
|
||||
OechslePricePlot.Plot.XAxis.SetZoomOutLimit(MaxOechsle - MinOechsle + 2);
|
||||
OechslePricePlot.Plot.YAxis.SetZoomOutLimit(2.1);
|
||||
OechslePricePlot.Plot.SetAxisLimits(MinOechsle - 1, MaxOechsle + 1, -0.1, 2);
|
||||
}
|
||||
|
||||
private void UnlockZoom() {
|
||||
OechslePricePlot.Plot.XAxis.SetBoundary();
|
||||
OechslePricePlot.Plot.YAxis.SetBoundary();
|
||||
OechslePricePlot.Plot.XAxis.SetZoomOutLimit((MaxOechsle - MinOechsle) * 1.5);
|
||||
OechslePricePlot.Plot.YAxis.SetZoomOutLimit(3.5);
|
||||
}
|
||||
|
||||
private void EnableOptionButtons() {
|
||||
FreeZoomInput.IsEnabled = true;
|
||||
GradationLinesInput.IsEnabled = true;
|
||||
TooltipInput.IsEnabled = true;
|
||||
}
|
||||
|
||||
private void DisableOptionButtons() {
|
||||
FreeZoomInput.IsEnabled = false;
|
||||
GradationLinesInput.IsEnabled = false;
|
||||
TooltipInput.IsEnabled = false;
|
||||
}
|
||||
|
||||
private void GradationLinesInput_Changed(object sender, RoutedEventArgs evt) {
|
||||
RefreshGradationLines();
|
||||
}
|
||||
|
||||
private void RefreshGradationLines() {
|
||||
if (GradationLinesInput.IsChecked == true) {
|
||||
ShowGradationLines();
|
||||
ShowLegend();
|
||||
} else {
|
||||
HideGradationLines();
|
||||
HideLegend();
|
||||
}
|
||||
OechslePricePlot.Refresh();
|
||||
}
|
||||
|
||||
private void ShowGradationLines() {
|
||||
OechslePricePlot.Plot.AddVerticalLine(68, Color.Red, 2, label: "68 Oechsle (LDW)");
|
||||
OechslePricePlot.Plot.AddVerticalLine(73, Color.Orange, 2, label: "73 Oechsle (QUW)");
|
||||
OechslePricePlot.Plot.AddVerticalLine(84, Color.Green, 2, label: "84 Oechsle (KAB)");
|
||||
}
|
||||
|
||||
private void HideGradationLines() {
|
||||
OechslePricePlot.Plot.Clear(typeof(VLine));
|
||||
}
|
||||
|
||||
private void ShowLegend() {
|
||||
OechslePricePlot.Plot.Legend(true, Alignment.UpperRight);
|
||||
}
|
||||
|
||||
private void HideLegend() {
|
||||
OechslePricePlot.Plot.Legend(false, Alignment.UpperRight);
|
||||
}
|
||||
|
||||
private void OechsleInput_TextChanged(object sender, RoutedEventArgs evt) {
|
||||
IntegerInput_TextChanged(sender, evt);
|
||||
|
||||
bool success = int.TryParse(OechsleInput.Text, out int oechsle);
|
||||
|
||||
SecondaryMarkedPointIndex = -1;
|
||||
ChangeMarker(SecondaryMarkedPoint, false);
|
||||
|
||||
if (success) {
|
||||
if (oechsle >= MinOechsle && oechsle <= MaxOechsle) {
|
||||
PrimaryMarkedPointIndex = oechsle - MinOechsle;
|
||||
ChangeMarker(PrimaryMarkedPoint, true, Graph.DataX[PrimaryMarkedPointIndex], Graph.DataY[PrimaryMarkedPointIndex]);
|
||||
|
||||
PriceInput.Text = Graph.DataY[PrimaryMarkedPointIndex].ToString();
|
||||
|
||||
if (IsEditing || IsCreating) EnableActionButtons();
|
||||
OechslePricePlot.Render();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
PrimaryMarkedPointIndex = -1;
|
||||
ChangeMarker(PrimaryMarkedPoint, false);
|
||||
DisableActionButtons();
|
||||
PriceInput.Text = "";
|
||||
OechslePricePlot.Render();
|
||||
}
|
||||
|
||||
private void PriceInput_TextChanged(object sender, RoutedEventArgs evt) {
|
||||
if (PrimaryMarkedPointIndex != -1) {
|
||||
bool success = Double.TryParse(PriceInput.Text, out double price);
|
||||
|
||||
if (success) {
|
||||
Graph.DataY[PrimaryMarkedPointIndex] = price;
|
||||
PrimaryMarkedPoint.Y = price;
|
||||
SaveButton.IsEnabled = true;
|
||||
ResetButton.IsEnabled = true;
|
||||
OechslePricePlot.Refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void LeftFlatButton_Click(object sender, RoutedEventArgs evt) {
|
||||
if (PrimaryMarkedPointIndex == -1) {
|
||||
return;
|
||||
}
|
||||
FlattenGraph(0, PrimaryMarkedPointIndex, Graph.DataY[PrimaryMarkedPointIndex]);
|
||||
SaveButton.IsEnabled = true;
|
||||
ResetButton.IsEnabled = true;
|
||||
}
|
||||
|
||||
private void RightFlatButton_Click(object sender, RoutedEventArgs evt) {
|
||||
if (PrimaryMarkedPointIndex == -1) {
|
||||
return;
|
||||
}
|
||||
FlattenGraph(PrimaryMarkedPointIndex, Graph.DataY.Length - 1, Graph.DataY[PrimaryMarkedPointIndex]);
|
||||
SaveButton.IsEnabled = true;
|
||||
ResetButton.IsEnabled = true;
|
||||
}
|
||||
|
||||
private void InterpolateButton_Click(object sender, RoutedEventArgs evt) {
|
||||
int steps = Math.Abs(PrimaryMarkedPointIndex - SecondaryMarkedPointIndex);
|
||||
if (PrimaryMarkedPointIndex == -1 || SecondaryMarkedPointIndex == -1 || steps < 2) {
|
||||
return;
|
||||
}
|
||||
var (lowIndex, highIndex) = PrimaryMarkedPointIndex < SecondaryMarkedPointIndex ? (PrimaryMarkedPointIndex, SecondaryMarkedPointIndex): (SecondaryMarkedPointIndex, PrimaryMarkedPointIndex);
|
||||
|
||||
double step = (Graph.DataY[highIndex] - Graph.DataY[lowIndex]) / steps;
|
||||
|
||||
for (int i = lowIndex; i < highIndex - 1; i++) {
|
||||
Graph.DataY[i + 1] = Math.Round(Graph.DataY[i] + step, 4); // TODO richtig runden
|
||||
}
|
||||
SaveButton.IsEnabled = true;
|
||||
ResetButton.IsEnabled = true;
|
||||
}
|
||||
|
||||
private void LinearIncreaseButton_Click(object sender, RoutedEventArgs e) {
|
||||
if (PrimaryMarkedPointIndex == -1) {
|
||||
return;
|
||||
}
|
||||
double? priceIncrease = Utils.ShowLinearPriceIncreaseDialog();
|
||||
if (priceIncrease == null) {
|
||||
return;
|
||||
}
|
||||
LinearIncreaseGraph(PrimaryMarkedPointIndex, Graph.DataY.Length - 1, priceIncrease.Value);
|
||||
SaveButton.IsEnabled = true;
|
||||
ResetButton.IsEnabled = true;
|
||||
}
|
||||
|
||||
private void OechslePricePlot_MouseDown(object sender, MouseEventArgs e) {
|
||||
if (!IsCreating && GraphList.SelectedItem == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (HoverActive) {
|
||||
if ((IsEditing || IsCreating) && Keyboard.IsKeyDown(Key.LeftCtrl)) {
|
||||
if (PrimaryMarkedPointIndex == -1) {
|
||||
return;
|
||||
}
|
||||
SecondaryMarkedPointIndex = HighlightedIndex;
|
||||
ChangeMarker(SecondaryMarkedPoint, true, Graph.DataX[SecondaryMarkedPointIndex], Graph.DataY[SecondaryMarkedPointIndex]);
|
||||
|
||||
InterpolateButton.IsEnabled = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
PrimaryMarkedPointIndex = HighlightedIndex;
|
||||
ChangeMarker(PrimaryMarkedPoint, true, Graph.DataX[PrimaryMarkedPointIndex], Graph.DataY[PrimaryMarkedPointIndex]);
|
||||
|
||||
OechsleInput.Text = Graph.DataX[HighlightedIndex].ToString();
|
||||
PriceInput.Text = Graph.DataY[HighlightedIndex].ToString();
|
||||
|
||||
if (IsEditing || IsCreating) {
|
||||
EnableActionButtons();
|
||||
}
|
||||
} else {
|
||||
PrimaryMarkedPointIndex = -1;
|
||||
SecondaryMarkedPointIndex = -1;
|
||||
ChangeMarker(PrimaryMarkedPoint, false);
|
||||
ChangeMarker(SecondaryMarkedPoint, false);
|
||||
|
||||
OechsleInput.Text = "";
|
||||
PriceInput.Text = "";
|
||||
|
||||
DisableActionButtons();
|
||||
}
|
||||
}
|
||||
|
||||
private void OechslePricePlot_MouseMove(object sender, MouseEventArgs e) {
|
||||
if (!IsCreating && GraphList.SelectedItem == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
(double mouseCoordX, double mouseCoordY) = OechslePricePlot.GetMouseCoordinates();
|
||||
double xyRatio = OechslePricePlot.Plot.XAxis.Dims.PxPerUnit / OechslePricePlot.Plot.YAxis.Dims.PxPerUnit;
|
||||
(double pointX, double pointY, int pointIndex) = OechslePricePlotScatter.GetPointNearest(mouseCoordX, mouseCoordY, xyRatio);
|
||||
|
||||
(double mousePixelX, double mousePixelY) = OechslePricePlot.GetMousePixel();
|
||||
(double pointPixelX, double pointPixelY) = OechslePricePlot.Plot.GetPixel(pointX, pointY);
|
||||
|
||||
HighlightedIndex = LastHighlightedIndex;
|
||||
|
||||
if (Math.Abs(mousePixelX - pointPixelX) < 3 && Math.Abs(mousePixelY - pointPixelY) < 3) {
|
||||
ChangeMarker(HighlightedPoint, true, pointX, pointY);
|
||||
HighlightedPoint.IsVisible = true;
|
||||
HoverChanged = true ^ HoverActive;
|
||||
HoverActive = true;
|
||||
} else {
|
||||
ChangeMarker(HighlightedPoint, false);
|
||||
HoverChanged= false ^ HoverActive;
|
||||
HoverActive= false;
|
||||
OechslePricePlot.Plot.Remove(Tooltip);
|
||||
OechslePricePlot.Render();
|
||||
}
|
||||
|
||||
if (LastHighlightedIndex != HighlightedIndex || HoverChanged) {
|
||||
OechslePricePlot.Plot.Remove(Tooltip);
|
||||
if (TooltipInput.IsChecked == true) {
|
||||
Tooltip = OechslePricePlot.Plot.AddTooltip($"Oechsle: {pointX:N2}, Preis: {Math.Round(pointY, 4)})", pointX, pointY);
|
||||
}
|
||||
LastHighlightedIndex = pointIndex;
|
||||
HoverChanged = false;
|
||||
OechslePricePlot.Render();
|
||||
}
|
||||
}
|
||||
|
||||
override protected void UpdateButtons() {
|
||||
if (!IsEditing && !IsCreating) return;
|
||||
bool ch = HasChanged, v = IsValid;
|
||||
}
|
||||
|
||||
private void DisableNewEditDeleteButtons() {
|
||||
NewButton.IsEnabled = false;
|
||||
EditButton.IsEnabled = false;
|
||||
DeleteButton.IsEnabled = false;
|
||||
}
|
||||
|
||||
private void EnableNewEditDeleteButtons() {
|
||||
NewButton.IsEnabled = true;
|
||||
EditButton.IsEnabled = GraphList.SelectedItem != null;
|
||||
DeleteButton.IsEnabled = GraphList.SelectedItem != null;
|
||||
}
|
||||
|
||||
private void ShowSaveResetCancelButtons() {
|
||||
SaveButton.IsEnabled = false;
|
||||
ResetButton.IsEnabled = false;
|
||||
CancelButton.IsEnabled = true;
|
||||
SaveButton.Visibility = Visibility.Visible;
|
||||
ResetButton.Visibility = Visibility.Visible;
|
||||
CancelButton.Visibility = Visibility.Visible;
|
||||
}
|
||||
|
||||
private void HideSaveResetCancelButtons() {
|
||||
SaveButton.IsEnabled = false;
|
||||
ResetButton.IsEnabled = false;
|
||||
CancelButton.IsEnabled = false;
|
||||
SaveButton.Visibility = Visibility.Hidden;
|
||||
ResetButton.Visibility = Visibility.Hidden;
|
||||
CancelButton.Visibility = Visibility.Hidden;
|
||||
}
|
||||
private void ShowNewEditDeleteButtons() {
|
||||
EnableNewEditDeleteButtons();
|
||||
NewButton.Visibility = Visibility.Visible;
|
||||
EditButton.Visibility = Visibility.Visible;
|
||||
DeleteButton.Visibility = Visibility.Visible;
|
||||
}
|
||||
|
||||
private void HideNewEditDeleteButtons() {
|
||||
DisableNewEditDeleteButtons();
|
||||
NewButton.Visibility = Visibility.Hidden;
|
||||
EditButton.Visibility = Visibility.Hidden;
|
||||
DeleteButton.Visibility = Visibility.Hidden;
|
||||
}
|
||||
|
||||
private void NewButton_Click(object sender, RoutedEventArgs e) {
|
||||
IsCreating = true;
|
||||
GraphList.IsEnabled = false;
|
||||
GraphList.SelectedItem = null;
|
||||
HideNewEditDeleteButtons();
|
||||
ShowSaveResetCancelButtons();
|
||||
UnlockInputs();
|
||||
PriceInput.IsReadOnly = false;
|
||||
OechsleInput.IsReadOnly = false;
|
||||
InitInputs();
|
||||
FillInputs(new Graph(GraphList.Items.Count + 1, MinOechsle, MaxOechsle));
|
||||
EnableOptionButtons();
|
||||
}
|
||||
|
||||
private void EditButton_Click(object sender, RoutedEventArgs e) {
|
||||
if (GraphList.SelectedItem == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
IsEditing = true;
|
||||
GraphList.IsEnabled = false;
|
||||
|
||||
HideNewEditDeleteButtons();
|
||||
ShowSaveResetCancelButtons();
|
||||
UnlockInputs();
|
||||
PriceInput.IsReadOnly = false;
|
||||
OechsleInput.IsReadOnly = false;
|
||||
if (PrimaryMarkedPointIndex != -1) EnableActionButtons();
|
||||
}
|
||||
|
||||
private async void DeleteButton_Click(object sender, RoutedEventArgs e) {
|
||||
Graph g = (Graph)GraphList.SelectedItem;
|
||||
if (g == null) return;
|
||||
|
||||
var r = MessageBox.Show(
|
||||
$"Soll der Graph {g.Num} (verwendet in folgenden Verträgen: {g.Contracts}) wirklich unwiderruflich gelöscht werden?",
|
||||
"Graph löschen", MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No);
|
||||
if (r == MessageBoxResult.Yes) {
|
||||
bool success = await RemoveGraph(g.Num);
|
||||
if (!success) {
|
||||
MessageBox.Show("Der Graph konnte nicht gelöscht werden", "Graph löschen", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
await RefreshGraphList();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private async void SaveButton_Click(object sender, RoutedEventArgs e) {
|
||||
int? index = await UpdateGraph(Graph);
|
||||
if (index == null) {
|
||||
MessageBox.Show("Der Graph konnte nicht gespeichert werden", "Graph speichern", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
IsEditing = false;
|
||||
IsCreating = false;
|
||||
GraphList.IsEnabled = true;
|
||||
HideSaveResetCancelButtons();
|
||||
ShowNewEditDeleteButtons();
|
||||
LockInputs();
|
||||
PriceInput.IsReadOnly = true;
|
||||
OechsleInput.IsReadOnly = true;
|
||||
await RefreshGraphList();
|
||||
GraphList.SelectedIndex = index.Value;
|
||||
}
|
||||
|
||||
private async Task<int?> UpdateGraph(Graph g) {
|
||||
List<PaymentVar> paymentVars = await Context.PaymentVariants.Where(p => p.Year == Year && p.AvNr == AvNr).ToListAsync();
|
||||
|
||||
if (paymentVars.Count != 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
PaymentVar paymentVar = paymentVars[0];
|
||||
var data = JsonNode.Parse(paymentVar.Data).AsObject();
|
||||
|
||||
var auszahlungsSorten = data["AuszahlungSorten"];
|
||||
if (auszahlungsSorten == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var Graphs = auszahlungsSorten["Kurven"].AsArray();
|
||||
if (Graphs == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (IsEditing) {
|
||||
Graphs[g.Num - 1] = g.ToJson();
|
||||
} else if(IsCreating) {
|
||||
Graphs.Add(g.ToJson());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
EntityEntry<PaymentVar>? tr = null;
|
||||
try {
|
||||
paymentVar.Data = data.ToString();
|
||||
tr = Context.Update(paymentVar);
|
||||
|
||||
await Context.SaveChangesAsync();
|
||||
} catch (Exception exc) {
|
||||
if (tr != null) await tr.ReloadAsync();
|
||||
var str = "Der Eintrag konnte nicht in der Datenbank gelöscht werden!\n\n" + exc.Message;
|
||||
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
|
||||
MessageBox.Show(str, "Graph löschen", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
|
||||
return g.Num - 1;
|
||||
}
|
||||
|
||||
private void ResetButton_Click(object sender, RoutedEventArgs e) {
|
||||
if (IsEditing) {
|
||||
RefreshInputs();
|
||||
} else if (IsCreating) {
|
||||
InitInputs();
|
||||
}
|
||||
UpdateButtons();
|
||||
}
|
||||
|
||||
private void CancelButton_Click(object sender, RoutedEventArgs e) {
|
||||
IsEditing = false;
|
||||
IsCreating = false;
|
||||
GraphList.IsEnabled = true;
|
||||
HideSaveResetCancelButtons();
|
||||
ShowNewEditDeleteButtons();
|
||||
DisableActionButtons();
|
||||
RefreshInputs();
|
||||
PriceInput.Text = "";
|
||||
OechsleInput.Text = "";
|
||||
ClearInputStates();
|
||||
LockInputs();
|
||||
PriceInput.IsReadOnly = true;
|
||||
OechsleInput.IsReadOnly = true;
|
||||
}
|
||||
|
||||
private void GraphList_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e) {
|
||||
RefreshInputs();
|
||||
|
||||
//var x = OechslePricePlot.Plot.GetPlottables().OfType<ScatterPlot>();
|
||||
//MessageBox.Show($"SelectionChanged\nLength: {x.ToList().Count}, Ys: {string.Join(", ", ((ScatterPlot)x.First()).Ys)}");
|
||||
}
|
||||
|
||||
private void PriceInput_LostFocus(object sender, RoutedEventArgs e) {
|
||||
|
||||
}
|
||||
|
||||
private void OechsleInput_LostFocus(object sender, RoutedEventArgs e) {
|
||||
|
||||
}
|
||||
|
||||
private void GraphNumberInput_TextChanged(object sender, TextChangedEventArgs e) {
|
||||
|
||||
}
|
||||
|
||||
private void GraphNumberInput_LostFocus(object sender, RoutedEventArgs e) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,19 +1,43 @@
|
||||
using Elwig.Helpers;
|
||||
using System.ComponentModel;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace Elwig.Windows {
|
||||
public abstract class ContextWindow : Window {
|
||||
|
||||
protected readonly AppDbContext Context;
|
||||
protected AppDbContext Context { get; private set; }
|
||||
protected bool LockContext { get; set; } = false;
|
||||
|
||||
private readonly DispatcherTimer ContextRenewTimer;
|
||||
private static readonly int ContextRenewSec = 10;
|
||||
|
||||
public ContextWindow() : base() {
|
||||
ContextRenewTimer = new DispatcherTimer();
|
||||
ContextRenewTimer.Tick += new EventHandler(OnRenewContext);
|
||||
ContextRenewTimer.Interval = new TimeSpan(0, 0, ContextRenewSec);
|
||||
ContextRenewTimer.Start();
|
||||
Context = new();
|
||||
Loaded += OnLoaded;
|
||||
}
|
||||
|
||||
protected override void OnClosing(CancelEventArgs evt) {
|
||||
private void OnRenewContext(object? sender, EventArgs evt) {
|
||||
if (LockContext || !Context.HasBackendChanged) return;
|
||||
Context.Dispose();
|
||||
base.OnClosing(evt);
|
||||
Context = new();
|
||||
RenewContext().GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
private void OnLoaded(object sender, RoutedEventArgs evt) {
|
||||
RenewContext().GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
protected override void OnClosed(EventArgs evt) {
|
||||
base.OnClosed(evt);
|
||||
Context.Dispose();
|
||||
}
|
||||
|
||||
abstract protected Task RenewContext();
|
||||
}
|
||||
}
|
||||
|
426
Elwig/Windows/DeliveryAdminWindow.xaml
Normal file
426
Elwig/Windows/DeliveryAdminWindow.xaml
Normal file
@@ -0,0 +1,426 @@
|
||||
<local:AdministrationWindow x:Class="Elwig.Windows.DeliveryAdminWindow"
|
||||
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:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
|
||||
Title="Lieferungen - Elwig" Height="720" Width="1100" MinHeight="700" MinWidth="1000"
|
||||
Loaded="Window_Loaded">
|
||||
<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="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">
|
||||
<Setter Property="Height" Value="25"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="HorizontalAlignment" Value="Stretch"/>
|
||||
<Setter Property="VerticalAlignment" Value="Top"/>
|
||||
</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="0.625*"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="24"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*" MinWidth="400"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Menu Grid.ColumnSpan="3" BorderThickness="0,0,0,1" BorderBrush="LightGray" Background="White">
|
||||
<MenuItem Header="Lieferung">
|
||||
</MenuItem>
|
||||
<MenuItem Header="Drucken">
|
||||
<MenuItem x:Name="Menu_Print_ShowDeliveryNote" Header="Lieferschein anzeigen" IsEnabled="False"
|
||||
Click="Menu_Print_ShowDeliveryNote_Click"/>
|
||||
<MenuItem x:Name="Menu_Print_PrintDeliveryNote" Header="Lieferschein drucken" IsEnabled="False"
|
||||
Click="Menu_Print_PrintDeliveryNote_Click"/>
|
||||
</MenuItem>
|
||||
<MenuItem Header="Exportieren">
|
||||
<MenuItem x:Name="Menu_Export_Bki" Header="Traubentransportscheinliste (BKI)"/>
|
||||
</MenuItem>
|
||||
<MenuItem Header="Werkzeuge">
|
||||
<MenuItem Header="Alle Lieferscheine überprüfen"/>
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
|
||||
<Grid Grid.RowSpan="4" Grid.Row="1" Margin="5,0,5,0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="42"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="42"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBox x:Name="SearchInput" Grid.ColumnSpan="3" Margin="5,10,161,0" IsReadOnly="False"
|
||||
TextChanged="SearchInput_TextChanged"/>
|
||||
<xctk:IntegerUpDown 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"/>
|
||||
<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"/>
|
||||
<CheckBox x:Name="AllSeasonsInput" Content="Jede Saison" IsEnabled="False"
|
||||
HorizontalAlignment="Right" Margin="0,24,10,0" VerticalAlignment="Top" Grid.Column="1" Grid.ColumnSpan="2"
|
||||
Checked="AllSeasonsInput_Changed" Unchecked="AllSeasonsInput_Changed"/>
|
||||
<DataGrid x:Name="DeliveryList" AutoGenerateColumns="False" HeadersVisibility="Column" IsReadOnly="True" GridLinesVisibility="None" SelectionMode="Single"
|
||||
SelectionChanged="DeliveryList_SelectionChanged"
|
||||
CanUserDeleteRows="False" CanUserResizeRows="False" CanUserAddRows="False"
|
||||
Margin="5,0,5,0" Grid.Row="1" FontSize="14" Grid.ColumnSpan="3">
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="MgNr." Binding="{Binding MgNr}" Width="70"/>
|
||||
<DataGridTextColumn Header="Datum" Binding="{Binding Date, StringFormat='dd.MM.yy'}" Width="70"/>
|
||||
<DataGridTextColumn Header="Zeit" Binding="{Binding Time, StringFormat='HH:mm'}" Width="70"/>
|
||||
<DataGridTextColumn Header="Sorte" Binding="{Binding SortIdString}" Width="60"/>
|
||||
<DataGridTextColumn Header="Gewicht" Binding="{Binding Weight, StringFormat='{}{0:N0} kg'}" Width="70">
|
||||
<DataGridTextColumn.CellStyle>
|
||||
<Style>
|
||||
<Setter Property="TextBlock.TextAlignment" Value="Right"/>
|
||||
</Style>
|
||||
</DataGridTextColumn.CellStyle>
|
||||
</DataGridTextColumn>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
|
||||
<Button x:Name="FinishButton" Content="Abschließen" IsEnabled="False" Visibility="Hidden"
|
||||
ToolTip="Übernahme abschließen und Lieferschein drucken"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="5,5,2.5,10" Grid.Column="0" Grid.Row="2"
|
||||
Click="FinishButton_Click"/>
|
||||
<Button x:Name="NewDeliveryPartButton" Content="Neue Teil-Lfrg." IsEnabled="False" Visibility="Hidden"
|
||||
ToolTip="Neue Teillieferung auf selben Lieferschein hinzufügen"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="2.5,5,2.5,10" Grid.Column="1" Grid.Row="2"
|
||||
Click="NewDeliveryPartButton_Click"/>
|
||||
<Button x:Name="CancelCreatingButton" Content="Abbrechen" IsEnabled="False" Visibility="Hidden"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="2.5,5,5,10" Grid.Column="2" Grid.Row="2"
|
||||
Click="CancelCreatingButton_Click"/>
|
||||
|
||||
<Button x:Name="NewDeliveryButton" Content="Neu" IsEnabled="False" Visibility="Hidden"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="5,5,2.5,10" Grid.Column="0" Grid.Row="2"
|
||||
Click="NewDeliveryButton_Click"/>
|
||||
<Button x:Name="AbwertenButton" Content="Abwerten" IsEnabled="False"
|
||||
ToolTip="Ausgewählte Teillieferung vollständig oder teilweise abwerten"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="5,5,2.5,10" Grid.Column="0" Grid.Row="2"
|
||||
Click="AbwertenButton_Click"/>
|
||||
<Button x:Name="EditDeliveryButton" Content="Bearbeiten" IsEnabled="False"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="2.5,5,2.5,10" Grid.Column="1" Grid.Row="2"
|
||||
Click="EditDeliveryButton_Click"/>
|
||||
<Button x:Name="DeleteDeliveryButton" Content="Löschen" IsEnabled="False"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="2.5,5,5,10" Grid.Column="2" Grid.Row="2"
|
||||
Click="DeleteDeliveryButton_Click"/>
|
||||
|
||||
<Button x:Name="SaveButton" Content="Speichern" IsEnabled="False" Visibility="Hidden"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="5,5,2.5,10" Grid.Column="0" Grid.Row="2"
|
||||
Click="SaveButton_Click"/>
|
||||
<Button x:Name="ResetButton" Content="Zurücksetzen" IsEnabled="False" Visibility="Hidden"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="2.5,5,2.5,10" Grid.Column="1" Grid.Row="2"
|
||||
Click="ResetButton_Click"/>
|
||||
<Button x:Name="CancelButton" Content="Abbrechen" IsEnabled="False" Visibility="Hidden" IsCancel="True"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="2.5,5,5,10" Grid.Column="2" Grid.Row="2"
|
||||
Click="CancelButton_Click"/>
|
||||
</Grid>
|
||||
|
||||
<GroupBox Header="Mitglied" Grid.Column="1" Grid.Row="1" Margin="5,5,5,5">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="70"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label Content="Mitglied:" Margin="10,10,0,0" Grid.Column="0"/>
|
||||
<TextBox x:Name="MgNrInput" Width="48" Grid.Row="1" Grid.Column="1" Margin="0,10,0,0" HorizontalAlignment="Left" TextAlignment="Right"
|
||||
TextChanged="MgNrInput_TextChanged" LostFocus="MgNrInput_LostFocus" KeyUp="Input_KeyUp"/>
|
||||
<ComboBox x:Name="MemberInput" Grid.Column="1" Margin="53,10,10,10" IsEditable="True"
|
||||
ItemTemplate="{StaticResource MemberAdminNameTemplate}" TextSearch.TextPath="AdministrativeName"
|
||||
SelectionChanged="MemberInput_SelectionChanged" KeyUp="Input_KeyUp"/>
|
||||
|
||||
<Label Content="Wohnort:" Margin="10,38,0,0" Grid.Column="0"/>
|
||||
<TextBox x:Name="MemberAddressField" Grid.Column="1" Margin="0,40,10,10" FontSize="12" Height="22"
|
||||
IsReadOnly="True" IsTabStop="False"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Header="Lieferung" Grid.Column="1" Grid.Row="2" Margin="5,5,5,5">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="100"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label Content="LieferscheinNr.:" Margin="10,10,0,0" Grid.Column="0"/>
|
||||
<TextBox x:Name="LsNrInput" Width="126" Grid.Column="1" HorizontalAlignment="Left" Margin="0,10,0,0"
|
||||
IsReadOnly="True" IsTabStop="False"/>
|
||||
|
||||
<Label Content="Datum/Uhrzeit:" Margin="10,40,0,0" Grid.Column="0"/>
|
||||
<TextBox x:Name="DateInput" Width="77" Grid.Column="1" HorizontalAlignment="Left" Margin="0,40,0,0"
|
||||
IsReadOnly="True" IsTabStop="False"
|
||||
TextChanged="DateInput_TextChanged"/>
|
||||
<TextBox x:Name="TimeInput" Width="44" Grid.Column="1" HorizontalAlignment="Left" Margin="82,40,0,0"
|
||||
IsReadOnly="True" IsTabStop="False"/>
|
||||
|
||||
<Label Content="Zweigstelle:" Margin="10,70,0,0" Grid.Column="0"/>
|
||||
<ComboBox x:Name="BranchInput" Width="126" Margin="0,70,10,0" Grid.Column="1" HorizontalAlignment="Left"
|
||||
IsEnabled="False"
|
||||
DisplayMemberPath="Name" TextSearch.TextPath="Name"/>
|
||||
|
||||
<Label Content="Anmerkung:" Margin="10,100,0,10"/>
|
||||
<TextBox x:Name="CommentInput" Grid.Column="1" Margin="0,100,10,10"
|
||||
TextChanged="TextBox_TextChanged"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Header="Sorte" Grid.Column="2" Grid.Row="1" Margin="5,5,5,5">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="70"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label Content="Sorte:" Margin="10,10,0,0" Grid.Column="0"/>
|
||||
<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" Margin="41,10,10,10"
|
||||
ItemTemplate="{StaticResource WineVarietyTemplate}" TextSearch.TextPath="Name"
|
||||
SelectionChanged="WineVarietyInput_SelectionChanged" KeyUp="Input_KeyUp"/>
|
||||
|
||||
<Label Content="Attribute:" Margin="10,40,0,0" Grid.Column="0"/>
|
||||
<xctk:CheckComboBox x:Name="AttributesInput" Grid.Row="1" Grid.Column="1" Margin="0,40,10,10"
|
||||
DisplayMemberPath="Name" Delimiter=", " AllItemsSelectedContent="Alle"
|
||||
ItemSelectionChanged="AttributesInput_SelectionChanged" KeyUp="Input_KeyUp"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Header="Gradation" Grid.Column="2" Grid.Row="2" Margin="5,5,5,5">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="100"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="Gradation:" Margin="10,10,10,10"/>
|
||||
<Grid Grid.Column="1" Width="54" Height="25" Margin="0,10,10,10" HorizontalAlignment="Left" VerticalAlignment="Top">
|
||||
<TextBox x:Name="GradationOeInput" TextAlignment="Right" Padding="2,2,23,2"
|
||||
TextChanged="GradationOeInput_TextChanged" LostFocus="GradationOeInput_LostFocus"/>
|
||||
<Label Content="°Oe" Margin="0,4,3,0" HorizontalAlignment="Right" FontSize="10"/>
|
||||
</Grid>
|
||||
<Label Content="=" Margin="60,10,10,10" Grid.Column="1"/>
|
||||
<Grid Grid.Column="1" Width="68" Height="25" Margin="78,10,10,10" HorizontalAlignment="Left" VerticalAlignment="Top">
|
||||
<TextBox x:Name="GradationKmwInput" TextAlignment="Right" Padding="2,2,34,2" SnapsToDevicePixels="True"
|
||||
TextChanged="GradationKmwInput_TextChanged" LostFocus="GradationKmwInput_LostFocus"/>
|
||||
<Label Content="°KMW" Margin="0,4,3,0" HorizontalAlignment="Right" FontSize="10"/>
|
||||
</Grid>
|
||||
|
||||
<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"/>
|
||||
|
||||
<CheckBox x:Name="AbgewertetInput" Content="Abgewertet" IsEnabled="False"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Left" Margin="10,75,10,10" Grid.Column="0" Grid.ColumnSpan="2"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Header="Gewicht" Grid.Column="2" Grid.Row="3" Margin="5,5,5,5">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="70"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label Content="Gewicht:" Margin="10,10,10,10"/>
|
||||
<Grid Grid.Column="1" Width="70" Height="25" Margin="0,10,10,10" HorizontalAlignment="Left" VerticalAlignment="Top">
|
||||
<TextBox x:Name="WeightInput" TextAlignment="Right" Padding="2,2,17,2" IsReadOnly="True"
|
||||
TextChanged="WeightInput_TextChanged"/>
|
||||
<Label Content="kg" Margin="0,4,3,0" HorizontalAlignment="Right" FontSize="10"/>
|
||||
</Grid>
|
||||
|
||||
<CheckBox x:Name="ManualWeighingInput" Content="Handwiegung" IsEnabled="False"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Left" Margin="10,45,10,10" Grid.Column="0" Grid.ColumnSpan="2"
|
||||
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"/>
|
||||
|
||||
<CheckBox x:Name="GerebeltGewogenInput" Content="Gerebelt gewogen"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Left" Margin="10,75,10,10" Grid.Column="0" Grid.ColumnSpan="2"
|
||||
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"/>
|
||||
|
||||
<Button x:Name="WeighingManualButton" Content="Handwiegung" Width="120"
|
||||
Click="WeighingManualButton_Click"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Right" Margin="10,10,10,10" Grid.Column="2"/>
|
||||
<Button x:Name="WeighingAButton" Content="Wiegen A" Width="120"
|
||||
Click="WeighingButton_Click"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Right" Margin="10,42,10,10" Grid.Column="2"/>
|
||||
<Button x:Name="WeighingBButton" Content="Wiegen B" Width="120"
|
||||
Click="WeighingButton_Click"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Right" Margin="10,74,10,10" Grid.Column="2"/>
|
||||
<Button x:Name="WeighingCButton" Content="Wiegen C" Width="120"
|
||||
Click="WeighingButton_Click"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Right" Margin="10,106,10,10" Grid.Column="2"/>
|
||||
<Button x:Name="WeighingDButton" Content="Wiegen D" Width="120"
|
||||
Click="WeighingButton_Click"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Right" Margin="10,138,10,10" Grid.Column="2"/>
|
||||
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Header="Sonstiges" Grid.Column="2" Grid.Row="4" Margin="5,5,5,10">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="100"/>
|
||||
<ColumnDefinition Width="65"/>
|
||||
<ColumnDefinition/>
|
||||
</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"
|
||||
ItemTemplate="{StaticResource ModifierTemplate}" Delimiter=", " AllItemsSelectedContent="Alle"
|
||||
ItemSelectionChanged="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"
|
||||
TextChanged="TextBox_TextChanged"/>
|
||||
|
||||
<Label Content="Temperatur:" Margin="10,70,0,10"/>
|
||||
<Grid Grid.Column="1" Height="25" Margin="0,70,10,10" VerticalAlignment="Top">
|
||||
<TextBox x:Name="TemperatureInput" TextAlignment="Right" Padding="2,2,16,2"
|
||||
TextChanged="TemperatureAcidInput_TextChanged" LostFocus="TemperatureAcidInput_LostFocus"/>
|
||||
<Label Content="°C" Margin="0,4,3,0" HorizontalAlignment="Right" FontSize="10"/>
|
||||
</Grid>
|
||||
|
||||
<Label Content="Säure:" Margin="10,100,0,10"/>
|
||||
<Grid Grid.Column="1" Height="25" Margin="0,100,10,10" VerticalAlignment="Top">
|
||||
<TextBox x:Name="AcidInput" TextAlignment="Right" Padding="2,2,19,2"
|
||||
TextChanged="TemperatureAcidInput_TextChanged" LostFocus="TemperatureAcidInput_LostFocus"/>
|
||||
<Label Content="g/l" Margin="0,4,3,0" HorizontalAlignment="Right" FontSize="10"/>
|
||||
</Grid>
|
||||
|
||||
<CheckBox x:Name="LesewagenInput" Content="Lesewagen" Margin="10,75,0,0" Grid.Column="2"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Left"
|
||||
Checked="LesewagenInput_Changed" Unchecked="LesewagenInput_Changed"/>
|
||||
<CheckBox x:Name="HandPickedInput" Content="Handlese" Margin="10,105,0,0" Grid.Column="2" IsThreeState="True"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Left"
|
||||
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Header="Teillieferungen" Grid.Column="1" Grid.Row="3" Margin="5,5,5,5">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<ListBox x:Name="DeliveryPartList" Margin="5,5,5,38" Grid.ColumnSpan="2"
|
||||
SelectionChanged="DeliveryPartList_SelectionChanged">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding DPNr}" Width="20"/>
|
||||
<TextBlock Text="{Binding SortId}" Width="30"/>
|
||||
<TextBlock Text="{Binding Kmw, StringFormat='{}{0:0.0}°'}" Width="40" TextAlignment="Right" Padding="0,0,10,0"/>
|
||||
<TextBlock Text="{Binding QualId}" Width="30"/>
|
||||
<TextBlock Text="{Binding Weight, StringFormat='{}{0:N0} kg'}" Width="60" TextAlignment="Right"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
|
||||
<Button x:Name="ExtractDeliveryPartButton" Content="Extrahieren" IsEnabled="False"
|
||||
ToolTip="Ausgewählte Teillieferung aus aktueller Lieferung entfernen und entweder anderer oder neuer Lieferung zuordnen"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="5,10,2.5,5" Grid.Column="0" Grid.Row="2"
|
||||
Click="ExtractDeliveryPartButton_Click"/>
|
||||
<Button x:Name="DeleteDeliveryPartButton" Content="Löschen" IsEnabled="False"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="2.5,10,5,5" Grid.Column="1" Grid.Row="2"
|
||||
Click="DeleteDeliveryPartButton_Click"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Header="Herkunft" Grid.Column="1" Grid.Row="4" Margin="5,5,5,10">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="100"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<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 WineOriginTemplate}"/>
|
||||
|
||||
<Label Content="Weinbau-KG:" Margin="10,40,0,10" Grid.Column="0"/>
|
||||
<ComboBox x:Name="WineKgInput" Margin="0,40,10,10" Grid.Column="1"
|
||||
DisplayMemberPath="Name"
|
||||
SelectionChanged="WineKgInput_SelectionChanged"/>
|
||||
|
||||
<Label Content="Ried:" Margin="10,70,0,10" Grid.Column="0"/>
|
||||
<ComboBox x:Name="WineRdInput" Margin="0,70,10,10" Grid.Column="1"
|
||||
DisplayMemberPath="Name"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<StatusBar Grid.Row="5" Grid.ColumnSpan="3" BorderThickness="0,1,0,0" BorderBrush="Gray">
|
||||
<StatusBar.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="2*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="150"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="2*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="3*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="3*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
</Grid>
|
||||
</ItemsPanelTemplate>
|
||||
</StatusBar.ItemsPanel>
|
||||
<StatusBarItem>
|
||||
<TextBlock Name="StatusMembers" Text="Mitglieder: -"/>
|
||||
</StatusBarItem>
|
||||
<Separator Grid.Column="1"/>
|
||||
<StatusBarItem Grid.Column="2">
|
||||
<TextBlock Name="StatusDeliveries" Text="Lieferungen: -"/>
|
||||
</StatusBarItem>
|
||||
<Separator Grid.Column="3"/>
|
||||
<StatusBarItem Grid.Column="4">
|
||||
<TextBlock Name="StatusVarieties" Text="Sorten: -"/>
|
||||
</StatusBarItem>
|
||||
<Separator Grid.Column="5"/>
|
||||
<StatusBarItem Grid.Column="6">
|
||||
<TextBlock Name="StatusWeight" Text="Gewicht: -"/>
|
||||
</StatusBarItem>
|
||||
<Separator Grid.Column="7"/>
|
||||
<StatusBarItem Grid.Column="8">
|
||||
<TextBlock Name="StatusGradation" Text="Gradation: -"/>
|
||||
</StatusBarItem>
|
||||
</StatusBar>
|
||||
</Grid>
|
||||
</local:AdministrationWindow>
|
1368
Elwig/Windows/DeliveryAdminWindow.xaml.cs
Normal file
1368
Elwig/Windows/DeliveryAdminWindow.xaml.cs
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user