Compare commits
	
		
			24 Commits
		
	
	
		
			ff2968c989
			...
			v0.4.2
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| a2f49e1b8b | |||
| 99c3474fb6 | |||
| 9924795888 | |||
| 733ab0d208 | |||
| 6e2ba56a7c | |||
| 2507a2695f | |||
| ddd83bf63d | |||
| 685793f0fb | |||
| f6712704ee | |||
| de500854c4 | |||
| d992b6a206 | |||
| d2b96736bb | |||
| 50b9f4e207 | |||
| 45fc0893b1 | |||
| c4dd56075d | |||
| f1084c716a | |||
| 2f8e4ca812 | |||
| 450f5d8109 | |||
| 62d6707d10 | |||
| 2bcf26cc8d | |||
| daddd069a3 | |||
| 3b3489b492 | |||
| 505ee0ad24 | |||
| 0b79fa192e | 
@@ -127,7 +127,7 @@ namespace Elwig {
 | 
				
			|||||||
                    ZwstId = entry.Item1;
 | 
					                    ZwstId = entry.Item1;
 | 
				
			||||||
                    BranchName = entry.Item2;
 | 
					                    BranchName = entry.Item2;
 | 
				
			||||||
                    BranchPlz = entry.Item3;
 | 
					                    BranchPlz = entry.Item3;
 | 
				
			||||||
                    BranchLocation = entry.Item4;
 | 
					                    BranchLocation = entry.Item4?.Split(" im ")[0];  // FIXME
 | 
				
			||||||
                    BranchAddress = entry.Item5;
 | 
					                    BranchAddress = entry.Item5;
 | 
				
			||||||
                    BranchPhoneNr = entry.Item6;
 | 
					                    BranchPhoneNr = entry.Item6;
 | 
				
			||||||
                    BranchFaxNr = entry.Item7;
 | 
					                    BranchFaxNr = entry.Item7;
 | 
				
			||||||
@@ -138,7 +138,7 @@ namespace Elwig {
 | 
				
			|||||||
                ZwstId = entry.Item1;
 | 
					                ZwstId = entry.Item1;
 | 
				
			||||||
                BranchName = entry.Item2;
 | 
					                BranchName = entry.Item2;
 | 
				
			||||||
                BranchPlz = entry.Item3;
 | 
					                BranchPlz = entry.Item3;
 | 
				
			||||||
                BranchLocation = entry.Item4;
 | 
					                BranchLocation = entry.Item4?.Split(" im ")[0];  // FIXME
 | 
				
			||||||
                BranchAddress = entry.Item5;
 | 
					                BranchAddress = entry.Item5;
 | 
				
			||||||
                BranchPhoneNr = entry.Item6;
 | 
					                BranchPhoneNr = entry.Item6;
 | 
				
			||||||
                BranchFaxNr = entry.Item7;
 | 
					                BranchFaxNr = entry.Item7;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										37
									
								
								Elwig/Dialogs/DeliveryConfirmationsDialog.xaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								Elwig/Dialogs/DeliveryConfirmationsDialog.xaml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
				
			|||||||
 | 
					<local:ContextWindow x:Class="Elwig.Dialogs.DeliveryConfirmationsDialog"
 | 
				
			||||||
 | 
					                     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"
 | 
				
			||||||
 | 
					                     ResizeMode="NoResize"
 | 
				
			||||||
 | 
					                     Loaded="Window_Loaded"
 | 
				
			||||||
 | 
					                     Title="Anlieferungsbestätingungen - Elwig" Height="400" Width="600">
 | 
				
			||||||
 | 
					    <Grid>
 | 
				
			||||||
 | 
					        <GroupBox Header="Sortieren nach" Margin="10,10,10,10" Width="180" Height="80" VerticalAlignment="Top" HorizontalAlignment="Left">
 | 
				
			||||||
 | 
					            <StackPanel Margin="5,5,0,5">
 | 
				
			||||||
 | 
					                <RadioButton GroupName="Order" x:Name="OrderMgNrInput" Content="Mitgliedsnummer" IsChecked="True"/>
 | 
				
			||||||
 | 
					                <RadioButton GroupName="Order" x:Name="OrderNameInput" Content="Name"/>
 | 
				
			||||||
 | 
					                <RadioButton GroupName="Order" x:Name="OrderPlzInput" Content="PLZ, Ort, Name"/>
 | 
				
			||||||
 | 
					            </StackPanel>
 | 
				
			||||||
 | 
					        </GroupBox>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <CheckBox x:Name="AllMembersInput" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="10,100,10,10">
 | 
				
			||||||
 | 
					            <TextBlock>Auch Mitglieder ohne<LineBreak/>Lieferungen miteinbeziehen</TextBlock>
 | 
				
			||||||
 | 
					        </CheckBox>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <TextBox x:Name="TextElement" TextWrapping="Wrap" VerticalScrollBarVisibility="Visible" AcceptsReturn="True"
 | 
				
			||||||
 | 
					                 HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="200,10,10,10" Height="Auto"/>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <Button x:Name="TestButton" Content="Stichprobe" FontSize="14" Width="180" Margin="10,10,10,74" Height="27" Tag="Print" IsEnabled="False"
 | 
				
			||||||
 | 
					                Click="TestButton_Click"
 | 
				
			||||||
 | 
					                VerticalAlignment="Bottom" HorizontalAlignment="Left"/>
 | 
				
			||||||
 | 
					        <Button x:Name="ShowButton" Content="Vorschau" FontSize="14" Width="180" Margin="10,10,10,42" Height="27" Tag="Print" IsEnabled="False"
 | 
				
			||||||
 | 
					                Click="ShowButton_Click"
 | 
				
			||||||
 | 
					                VerticalAlignment="Bottom" HorizontalAlignment="Left"/>
 | 
				
			||||||
 | 
					        <Button x:Name="PrintButton" Content="Drucken" FontSize="14" Width="180" Margin="10,10,10,10" Height="27" Tag="Print" IsEnabled="False"
 | 
				
			||||||
 | 
					                Click="PrintButton_Click"
 | 
				
			||||||
 | 
					                VerticalAlignment="Bottom" HorizontalAlignment="Left"/>
 | 
				
			||||||
 | 
					    </Grid>
 | 
				
			||||||
 | 
					</local:ContextWindow>
 | 
				
			||||||
							
								
								
									
										113
									
								
								Elwig/Dialogs/DeliveryConfirmationsDialog.xaml.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								Elwig/Dialogs/DeliveryConfirmationsDialog.xaml.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,113 @@
 | 
				
			|||||||
 | 
					using Elwig.Documents;
 | 
				
			||||||
 | 
					using Elwig.Models;
 | 
				
			||||||
 | 
					using Elwig.Windows;
 | 
				
			||||||
 | 
					using Microsoft.EntityFrameworkCore;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
 | 
					using System.Windows;
 | 
				
			||||||
 | 
					using System.Windows.Input;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Elwig.Dialogs {
 | 
				
			||||||
 | 
					    public partial class DeliveryConfirmationsDialog : ContextWindow {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public readonly int Year;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public DeliveryConfirmationsDialog(int year) {
 | 
				
			||||||
 | 
					            InitializeComponent();
 | 
				
			||||||
 | 
					            Year = year;
 | 
				
			||||||
 | 
					            Title = $"Anlieferungsbestätigungen - Lese {Year} - Elwig";
 | 
				
			||||||
 | 
					            TextElement.Text = App.Client.TextDeliveryConfirmation;
 | 
				
			||||||
 | 
					            if (!App.Config.Debug) {
 | 
				
			||||||
 | 
					                TestButton.Visibility = Visibility.Hidden;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void Window_Loaded(object sender, RoutedEventArgs evt) {
 | 
				
			||||||
 | 
					            TestButton.IsEnabled = App.IsPrintingReady;
 | 
				
			||||||
 | 
					            ShowButton.IsEnabled = App.IsPrintingReady;
 | 
				
			||||||
 | 
					            PrintButton.IsEnabled = App.IsPrintingReady;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        protected override async Task OnRenewContext() { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private async Task UpdateTextParameter() {
 | 
				
			||||||
 | 
					            var text = TextElement.Text;
 | 
				
			||||||
 | 
					            if (text.Length == 0) text = null;
 | 
				
			||||||
 | 
					            if (text != App.Client.TextDeliveryConfirmation) {
 | 
				
			||||||
 | 
					                App.Client.TextDeliveryConfirmation = text;
 | 
				
			||||||
 | 
					                await App.Client.UpdateValues();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private async Task Generate(int mode) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Mouse.OverrideCursor = Cursors.AppStarting;
 | 
				
			||||||
 | 
					            await UpdateTextParameter();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            IQueryable<Member> members;
 | 
				
			||||||
 | 
					            if (AllMembersInput.IsChecked == true) {
 | 
				
			||||||
 | 
					                members = Context.Members.Where(m => m.IsActive);
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                members = Context.Members.FromSqlRaw($"""
 | 
				
			||||||
 | 
					                    SELECT m.*
 | 
				
			||||||
 | 
					                    FROM member m
 | 
				
			||||||
 | 
					                        INNER JOIN delivery d ON d.mgnr = m.mgnr
 | 
				
			||||||
 | 
					                    WHERE d.year = {Year}
 | 
				
			||||||
 | 
					                    GROUP BY m.mgnr
 | 
				
			||||||
 | 
					                    """);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (OrderMgNrInput.IsChecked == true) {
 | 
				
			||||||
 | 
					                members = members
 | 
				
			||||||
 | 
					                    .OrderBy(m => m.MgNr);
 | 
				
			||||||
 | 
					            } else if (OrderNameInput.IsChecked == true) {
 | 
				
			||||||
 | 
					                members = members
 | 
				
			||||||
 | 
					                    .OrderBy(m => m.FamilyName)
 | 
				
			||||||
 | 
					                    .ThenBy(m => m.GivenName)
 | 
				
			||||||
 | 
					                    .ThenBy(m => m.MgNr);
 | 
				
			||||||
 | 
					            } else if (OrderPlzInput.IsChecked == true) {
 | 
				
			||||||
 | 
					                members = members
 | 
				
			||||||
 | 
					                    .OrderBy(m => m.PostalDest.AtPlz.Plz)
 | 
				
			||||||
 | 
					                    .ThenBy(m => m.PostalDest.AtPlz.Ort.Name)
 | 
				
			||||||
 | 
					                    .ThenBy(m => m.FamilyName)
 | 
				
			||||||
 | 
					                    .ThenBy(m => m.GivenName)
 | 
				
			||||||
 | 
					                    .ThenBy(m => m.MgNr);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            IEnumerable<Member> list = await members.ToListAsync();
 | 
				
			||||||
 | 
					            if (mode == 0) {
 | 
				
			||||||
 | 
					                var r = new Random().Next(0, 10);
 | 
				
			||||||
 | 
					                list = list.Where((_, n) => n % 10 == r);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            using var doc = await Document.Merge(list.Select(m => new DeliveryConfirmation(Context, Year, m))); ;
 | 
				
			||||||
 | 
					            await doc.Generate();
 | 
				
			||||||
 | 
					            Mouse.OverrideCursor = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (mode < 2) {
 | 
				
			||||||
 | 
					                doc.Show();
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (App.Config.Debug) {
 | 
				
			||||||
 | 
					                doc.Show();
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                await doc.Print();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            Close();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private async void TestButton_Click(object sender, RoutedEventArgs evt) {
 | 
				
			||||||
 | 
					            await Generate(0);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private async void ShowButton_Click(object sender, RoutedEventArgs evt) {
 | 
				
			||||||
 | 
					            await Generate(1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private async void PrintButton_Click(object sender, RoutedEventArgs evt) {
 | 
				
			||||||
 | 
					            await Generate(2);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -109,41 +109,52 @@
 | 
				
			|||||||
                <th><b>Lese @Model.Year</b> per @($"{Model.Date:dd.MM.yyyy}") [kg]</th>
 | 
					                <th><b>Lese @Model.Year</b> per @($"{Model.Date:dd.MM.yyyy}") [kg]</th>
 | 
				
			||||||
                <th>Lieferpflicht</th>
 | 
					                <th>Lieferpflicht</th>
 | 
				
			||||||
                <th>Lieferrecht</th>
 | 
					                <th>Lieferrecht</th>
 | 
				
			||||||
                <th>Unterliefert<br/>(bzgl. Zuget.)</th>
 | 
					                <th>Unterliefert</th>
 | 
				
			||||||
                <th>Noch zu liefern<br/>(bzgl. Gelft.)</th>
 | 
					                <th>Noch lieferbar</th>
 | 
				
			||||||
                <th>Überliefert<br/>(bzgl. Gelft.)</th>
 | 
					                <th>Überliefert</th>
 | 
				
			||||||
                <th>Zugeteilt</th>
 | 
					                <th>Zugeteilt</th>
 | 
				
			||||||
                <th>Geliefert</th>
 | 
					                <th>Geliefert</th>
 | 
				
			||||||
            </tr>
 | 
					            </tr>
 | 
				
			||||||
        </thead>
 | 
					        </thead>
 | 
				
			||||||
        <tbody>
 | 
					        <tbody>
 | 
				
			||||||
            @{
 | 
					            @{
 | 
				
			||||||
                string FormatRow(int obligation, int right, int sum, int? payment = null) {
 | 
					                string FormatRow(int mode, int obligation, int right, int sum, int? payment = null) {
 | 
				
			||||||
                    var isGa = payment == null;
 | 
					                    var isGa = mode == 0;
 | 
				
			||||||
                    payment ??= sum;
 | 
					                    payment ??= sum;
 | 
				
			||||||
                    return $"<td>{obligation:N0}</td>" +
 | 
					                    return $"<td>{(mode == 1 ? "" : obligation == 0 ? "-" : $"{obligation:N0}")}</td>" +
 | 
				
			||||||
                        $"<td>{right:N0}</td>" +
 | 
					                        $"<td>{(mode == 1 ? "" : right == 0 ? "-" : $"{right:N0}")}</td>" +
 | 
				
			||||||
                        $"<td>{(payment < obligation ? $"<b>{obligation - payment:N0}\x3c/b>" : "-")}</td>" +
 | 
					                        $"<td>{(mode == 1 ? "" : payment < obligation ? $"<b>{obligation - payment:N0}\x3c/b>" : "-")}</td>" +
 | 
				
			||||||
                        $"<td>{(sum >= obligation && sum <= right ? $"{right - sum:N0}" : "-")}</td>" +
 | 
					                        $"<td>{(mode == 1 ? "" : payment >= obligation && sum <= right ? $"{right - sum:N0}" : "-")}</td>" +
 | 
				
			||||||
                        $"<td>{(obligation == 0 && right == 0 ? "-" : (sum > right ? ((isGa ? "<b>" : "") + $"{sum - right:N0}" + (isGa ? "</b>" : "")) : "-"))}</td>" +
 | 
					                        $"<td>{(mode == 1 ? "" : obligation == 0 && right == 0 ? "-" : (sum > right ? ((isGa ? "<b>" : "") + $"{sum - right:N0}" + (isGa ? "</b>" : "")) : "-"))}</td>" +
 | 
				
			||||||
                        $"<td>{(obligation == 0 && right == 0 ? "-" : $"{payment:N0}")}</td>" +
 | 
					                        $"<td>{(mode != 2 ? "" : obligation == 0 && right == 0 ? "-" : $"{payment:N0}")}</td>" +
 | 
				
			||||||
                        $"<td>{sum:N0}</td>";
 | 
					                        $"<td>{sum:N0}</td>";
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					                var mBins = Model.MemberBins.Where(b => b.Value.Item2 > 0 || b.Value.Item3 > 0 || b.Value.Item4 > 0).ToList();
 | 
				
			||||||
 | 
					                var fbVars = mBins.Where(b => b.Value.Item2 > 0 || b.Value.Item3 > 0).Select(b => b.Key.Replace("_", "")).Order().ToArray();
 | 
				
			||||||
 | 
					                var fbs = mBins.Where(b => fbVars.Contains(b.Key)).OrderBy(b => b.Value.Item1);
 | 
				
			||||||
 | 
					                var rem = mBins.Where(b => !fbVars.Contains(b.Key)).OrderBy(b => b.Value.Item1);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            <tr>
 | 
					            <tr>
 | 
				
			||||||
                <th>Gesamtlieferung lt. gez. GA</th>
 | 
					                <th>Gesamtlieferung lt. gez. GA</th>
 | 
				
			||||||
                @Raw(FormatRow(Model.Member.DeliveryObligation, Model.Member.DeliveryRight, Model.Member.Deliveries.Where(d => d.Year == Model.Year).Sum(d => d.Weight)))
 | 
					                @Raw(FormatRow(0, Model.Member.DeliveryObligation, Model.Member.DeliveryRight, Model.Member.Deliveries.Where(d => d.Year == Model.Year).Sum(d => d.Weight)))
 | 
				
			||||||
            </tr>
 | 
					            </tr>
 | 
				
			||||||
            <tr class="subheading">
 | 
					            @if (rem.Any()) {
 | 
				
			||||||
                <th>Flächenbindungen:</th>
 | 
					                <tr class="subheading"><th colspan="8">Sortenaufteilung:</th></tr>
 | 
				
			||||||
            </tr>
 | 
					            }
 | 
				
			||||||
            @foreach (var (id, (name, right, obligation, sum, payment)) in Model.MemberBins.OrderBy(b => b.Key)) {
 | 
					            @foreach (var (id, (name, right, obligation, sum, payment)) in rem) {
 | 
				
			||||||
                if (right > 0 || obligation > 0 || sum > 0) {
 | 
					 | 
				
			||||||
                <tr>
 | 
					                <tr>
 | 
				
			||||||
                    <th>@name</th>
 | 
					                    <th>@name</th>
 | 
				
			||||||
                        @Raw(FormatRow(obligation, right, sum, payment))
 | 
					                    @Raw(FormatRow(1, obligation, right, sum, payment))
 | 
				
			||||||
                </tr>
 | 
					                </tr>
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            @if (fbs.Any()){
 | 
				
			||||||
 | 
					                <tr class="subheading"><th colspan="8">Flächenbindungen:</th></tr>
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            @foreach (var (id, (name, right, obligation, sum, payment)) in fbs) {
 | 
				
			||||||
 | 
					                <tr>
 | 
				
			||||||
 | 
					                    <th>@name</th>
 | 
				
			||||||
 | 
					                    @Raw(FormatRow(2, obligation, right, sum, payment))
 | 
				
			||||||
 | 
					                </tr>
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        </tbody>
 | 
					        </tbody>
 | 
				
			||||||
    </table>
 | 
					    </table>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,7 +13,7 @@ namespace Elwig.Documents {
 | 
				
			|||||||
        public Dictionary<string, (string, int, int, int, int)> MemberBins;
 | 
					        public Dictionary<string, (string, int, int, int, int)> MemberBins;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public DeliveryConfirmation(AppDbContext ctx, int year, Member m) :
 | 
					        public DeliveryConfirmation(AppDbContext ctx, int year, Member m) :
 | 
				
			||||||
            base($"Anlieferungsbestätigung {year} – {((IAddress?)m.BillingAddress ?? m).Name}", m) {
 | 
					            base($"Anlieferungsbestätigung {year}", m) {
 | 
				
			||||||
            Year = year;
 | 
					            Year = year;
 | 
				
			||||||
            ShowDateAndLocation = true;
 | 
					            ShowDateAndLocation = true;
 | 
				
			||||||
            UseBillingAddress = true;
 | 
					            UseBillingAddress = true;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -92,7 +92,7 @@
 | 
				
			|||||||
                <th>Lieferpflicht</th>
 | 
					                <th>Lieferpflicht</th>
 | 
				
			||||||
                <th>Lieferrecht</th>
 | 
					                <th>Lieferrecht</th>
 | 
				
			||||||
                <th>Unterliefert</th>
 | 
					                <th>Unterliefert</th>
 | 
				
			||||||
                <th>Noch zu liefern</th>
 | 
					                <th>Noch lieferbar</th>
 | 
				
			||||||
                <th>Überliefert</th>
 | 
					                <th>Überliefert</th>
 | 
				
			||||||
                <th>Geliefert</th>
 | 
					                <th>Geliefert</th>
 | 
				
			||||||
            </tr>
 | 
					            </tr>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -134,7 +134,7 @@ namespace Elwig.Documents {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        public void Show() {
 | 
					        public void Show() {
 | 
				
			||||||
            if (_pdfFile == null) throw new InvalidOperationException("Pdf file has not been generated yet");
 | 
					            if (_pdfFile == null) throw new InvalidOperationException("Pdf file has not been generated yet");
 | 
				
			||||||
            Pdf.Show(_pdfFile.NewReference(), Title);
 | 
					            Pdf.Show(_pdfFile.NewReference(), Title + (this is BusinessDocument b ? $" - {b.Member.Name}" : ""));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private class InternalDocument : Document {
 | 
					        private class InternalDocument : Document {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -78,6 +78,8 @@ table.delivery-confirmation-stats {
 | 
				
			|||||||
table.delivery-confirmation-stats th,
 | 
					table.delivery-confirmation-stats th,
 | 
				
			||||||
table.delivery-confirmation-stats td {
 | 
					table.delivery-confirmation-stats td {
 | 
				
			||||||
    padding: 0.125mm 0;
 | 
					    padding: 0.125mm 0;
 | 
				
			||||||
 | 
					    overflow: hidden;
 | 
				
			||||||
 | 
					    white-space: nowrap;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
table.delivery-confirmation-stats tr.subheading th {
 | 
					table.delivery-confirmation-stats tr.subheading th {
 | 
				
			||||||
@@ -104,3 +106,8 @@ table.delivery-confirmation-stats tbody th {
 | 
				
			|||||||
    font-style: italic;
 | 
					    font-style: italic;
 | 
				
			||||||
    text-align: left;
 | 
					    text-align: left;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					table.delivery-confirmation-stats tr.subheading th {
 | 
				
			||||||
 | 
					    font-weight: bold;
 | 
				
			||||||
 | 
					    border-top: 0.5pt solid black;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@
 | 
				
			|||||||
    <UseWPF>true</UseWPF>
 | 
					    <UseWPF>true</UseWPF>
 | 
				
			||||||
    <PreserveCompilationContext>true</PreserveCompilationContext>
 | 
					    <PreserveCompilationContext>true</PreserveCompilationContext>
 | 
				
			||||||
    <ApplicationIcon>elwig.ico</ApplicationIcon>
 | 
					    <ApplicationIcon>elwig.ico</ApplicationIcon>
 | 
				
			||||||
    <Version>0.3.7</Version>
 | 
					    <Version>0.4.2</Version>
 | 
				
			||||||
    <SatelliteResourceLanguages>de-AT</SatelliteResourceLanguages>
 | 
					    <SatelliteResourceLanguages>de-AT</SatelliteResourceLanguages>
 | 
				
			||||||
  </PropertyGroup>
 | 
					  </PropertyGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -215,17 +215,7 @@ namespace Elwig.Helpers {
 | 
				
			|||||||
            cnx ??= await ConnectAsync();
 | 
					            cnx ??= await ConnectAsync();
 | 
				
			||||||
            var bins = new Dictionary<int, Dictionary<string, (int, int)>>();
 | 
					            var bins = new Dictionary<int, Dictionary<string, (int, int)>>();
 | 
				
			||||||
            using (var cmd = cnx.CreateCommand()) {
 | 
					            using (var cmd = cnx.CreateCommand()) {
 | 
				
			||||||
                cmd.CommandText = $"""
 | 
					                cmd.CommandText = $"SELECT mgnr, bin, min_kg, max_kg FROM v_area_commitment_bin WHERE year = {year}";
 | 
				
			||||||
                    SELECT mgnr, t.vtrgid,
 | 
					 | 
				
			||||||
                           ROUND(SUM(COALESCE(area * min_kg_per_ha, 0)) / 10000.0) AS min_kg,
 | 
					 | 
				
			||||||
                           ROUND(SUM(COALESCE(area * max_kg_per_ha, 0)) / 10000.0) AS max_kg
 | 
					 | 
				
			||||||
                    FROM area_commitment c
 | 
					 | 
				
			||||||
                    JOIN area_commitment_type t ON t.vtrgid = c.vtrgid
 | 
					 | 
				
			||||||
                    WHERE (year_from IS NULL OR year_from <= {year}) AND
 | 
					 | 
				
			||||||
                          (year_to IS NULL OR year_to >= {year})
 | 
					 | 
				
			||||||
                    GROUP BY mgnr, t.vtrgid
 | 
					 | 
				
			||||||
                    ORDER BY LENGTH(t.vtrgid) DESC, t.vtrgid
 | 
					 | 
				
			||||||
                    """;
 | 
					 | 
				
			||||||
                using var reader = await cmd.ExecuteReaderAsync();
 | 
					                using var reader = await cmd.ExecuteReaderAsync();
 | 
				
			||||||
                while (await reader.ReadAsync()) {
 | 
					                while (await reader.ReadAsync()) {
 | 
				
			||||||
                    var mgnr = reader.GetInt32(0);
 | 
					                    var mgnr = reader.GetInt32(0);
 | 
				
			||||||
@@ -305,7 +295,7 @@ namespace Elwig.Helpers {
 | 
				
			|||||||
                var variety = await WineVarieties.FindAsync(id[..2]);
 | 
					                var variety = await WineVarieties.FindAsync(id[..2]);
 | 
				
			||||||
                var attrIds = id[2..];
 | 
					                var attrIds = id[2..];
 | 
				
			||||||
                var attrs = await WineAttributes.Where(a => attrIds.Contains(a.AttrId)).ToListAsync();
 | 
					                var attrs = await WineAttributes.Where(a => attrIds.Contains(a.AttrId)).ToListAsync();
 | 
				
			||||||
                var name = (variety?.Name ?? "") + (attrs.Count > 0 ? $" ({string.Join(" / ", attrs.Select(a => a.Name))})" : "");
 | 
					                var name = (variety?.Name ?? "") + (attrIds == "_" ? " (kein Qual.Wein)" : attrs.Count > 0 ? $" ({string.Join(" / ", attrs.Select(a => a.Name))})" : "");
 | 
				
			||||||
                bins[id] = (
 | 
					                bins[id] = (
 | 
				
			||||||
                    name,
 | 
					                    name,
 | 
				
			||||||
                    rightsAndObligations.GetValueOrDefault(id).Item1,
 | 
					                    rightsAndObligations.GetValueOrDefault(id).Item1,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,11 +4,11 @@ using System;
 | 
				
			|||||||
namespace Elwig.Helpers {
 | 
					namespace Elwig.Helpers {
 | 
				
			||||||
    public static class AppDbUpdater {
 | 
					    public static class AppDbUpdater {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public static readonly int RequiredSchemaVersion = 3;
 | 
					        public static readonly int RequiredSchemaVersion = 4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private static int _versionOffset = 0;
 | 
					        private static int _versionOffset = 0;
 | 
				
			||||||
        private static readonly Action<SqliteConnection>[] _updaters = new[] {
 | 
					        private static readonly Action<SqliteConnection>[] _updaters = new[] {
 | 
				
			||||||
            UpdateDbSchema_1_To_2, UpdateDbSchema_2_To_3
 | 
					            UpdateDbSchema_1_To_2, UpdateDbSchema_2_To_3, UpdateDbSchema_3_To_4
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private static void ExecuteNonQuery(SqliteConnection cnx, string sql) {
 | 
					        private static void ExecuteNonQuery(SqliteConnection cnx, string sql) {
 | 
				
			||||||
@@ -184,5 +184,34 @@ namespace Elwig.Helpers {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            ExecuteNonQuery(cnx, "ALTER TABLE wine_attribute ADD COLUMN fill_lower_bins INTEGER NOT NULL CHECK (fill_lower_bins IN (0, 1, 2)) DEFAULT 0");
 | 
					            ExecuteNonQuery(cnx, "ALTER TABLE wine_attribute ADD COLUMN fill_lower_bins INTEGER NOT NULL CHECK (fill_lower_bins IN (0, 1, 2)) DEFAULT 0");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private static void UpdateDbSchema_3_To_4(SqliteConnection cnx) {
 | 
				
			||||||
 | 
					            ExecuteNonQuery(cnx, "DROP VIEW v_payment_bin");
 | 
				
			||||||
 | 
					            ExecuteNonQuery(cnx, """
 | 
				
			||||||
 | 
					                CREATE VIEW v_payment_bin AS
 | 
				
			||||||
 | 
					                SELECT d.year, d.mgnr,
 | 
				
			||||||
 | 
					                       sortid || discr AS bin,
 | 
				
			||||||
 | 
					                       SUM(value) AS weight
 | 
				
			||||||
 | 
					                FROM v_delivery d
 | 
				
			||||||
 | 
					                    JOIN delivery_part_bin b ON (b.year, b.did, b.dpnr) = (d.year, d.did, d.dpnr)
 | 
				
			||||||
 | 
					                GROUP BY d.year, d.mgnr, bin
 | 
				
			||||||
 | 
					                HAVING SUM(value) > 0
 | 
				
			||||||
 | 
					                ORDER BY d.year, d.mgnr, LENGTH(bin) DESC, bin;
 | 
				
			||||||
 | 
					                """);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            ExecuteNonQuery(cnx, """
 | 
				
			||||||
 | 
					                CREATE VIEW v_area_commitment_bin AS
 | 
				
			||||||
 | 
					                SELECT s.year, c.mgnr,
 | 
				
			||||||
 | 
					                       c.vtrgid AS bin,
 | 
				
			||||||
 | 
					                       CAST(ROUND(SUM(COALESCE(area * min_kg_per_ha, 0)) / 10000.0, 0) AS INTEGER) AS min_kg,
 | 
				
			||||||
 | 
					                       CAST(ROUND(SUM(COALESCE(area * max_kg_per_ha, 0)) / 10000.0, 0) AS INTEGER) AS max_kg
 | 
				
			||||||
 | 
					                FROM area_commitment c, season s
 | 
				
			||||||
 | 
					                    JOIN area_commitment_type t ON t.vtrgid = c.vtrgid
 | 
				
			||||||
 | 
					                WHERE (year_from IS NULL OR year_from <= s.year) AND
 | 
				
			||||||
 | 
					                      (year_to IS NULL OR year_to >= s.year)
 | 
				
			||||||
 | 
					                GROUP BY s.year, c.mgnr, c.vtrgid
 | 
				
			||||||
 | 
					                ORDER BY s.year, c.mgnr, LENGTH(c.vtrgid) DESC, c.vtrgid;
 | 
				
			||||||
 | 
					                """);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -55,7 +55,7 @@ namespace Elwig.Helpers.Billing {
 | 
				
			|||||||
                             COALESCE(LENGTH(attributes), 0) ASC, attribute_prio DESC, COALESCE(attributes, '~'),
 | 
					                             COALESCE(LENGTH(attributes), 0) ASC, attribute_prio DESC, COALESCE(attributes, '~'),
 | 
				
			||||||
                             kmw DESC, lsnr, dpnr
 | 
					                             kmw DESC, lsnr, dpnr
 | 
				
			||||||
                    """;
 | 
					                    """;
 | 
				
			||||||
                var reader = await cmd.ExecuteReaderAsync();
 | 
					                using var reader = await cmd.ExecuteReaderAsync();
 | 
				
			||||||
                while (await reader.ReadAsync()) {
 | 
					                while (await reader.ReadAsync()) {
 | 
				
			||||||
                    deliveries.Add((
 | 
					                    deliveries.Add((
 | 
				
			||||||
                        reader.GetInt32(0), reader.GetInt32(1), reader.GetInt32(2), reader.GetString(3), reader.GetInt32(4),
 | 
					                        reader.GetInt32(0), reader.GetInt32(1), reader.GetInt32(2), reader.GetString(3), reader.GetInt32(4),
 | 
				
			||||||
@@ -104,7 +104,7 @@ namespace Elwig.Helpers.Billing {
 | 
				
			|||||||
                        var u = used.GetValueOrDefault(key, 0);
 | 
					                        var u = used.GetValueOrDefault(key, 0);
 | 
				
			||||||
                        var vr = Math.Max(0, Math.Min(rightsAndObligations[key].Item1 - u, w));
 | 
					                        var vr = Math.Max(0, Math.Min(rightsAndObligations[key].Item1 - u, w));
 | 
				
			||||||
                        var vo = Math.Max(0, Math.Min(rightsAndObligations[key].Item2 - u, w));
 | 
					                        var vo = Math.Max(0, Math.Min(rightsAndObligations[key].Item2 - u, w));
 | 
				
			||||||
                        var v = (c == 0 || p.Select(a => attrVals[a]).Min() == 2) ? vr : vo;
 | 
					                        var v = (attributes.Length == 0 || attributes.Select(a => attrVals[a]).Min() == 2) ? vr : vo;
 | 
				
			||||||
                        used[key] = u + v;
 | 
					                        used[key] = u + v;
 | 
				
			||||||
                        inserts.Add((did, dpnr, i, key[2..], v));
 | 
					                        inserts.Add((did, dpnr, i, key[2..], v));
 | 
				
			||||||
                        w -= v;
 | 
					                        w -= v;
 | 
				
			||||||
@@ -125,7 +125,81 @@ namespace Elwig.Helpers.Billing {
 | 
				
			|||||||
                await cmd.ExecuteNonQueryAsync();
 | 
					                await cmd.ExecuteNonQueryAsync();
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // TODO add second round to avoid under deliveries
 | 
					            if (!avoidUnderDeliveries)
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var underDeliveries = new Dictionary<(int, string), int>();
 | 
				
			||||||
 | 
					            using (var cmd = cnx.CreateCommand()) {
 | 
				
			||||||
 | 
					                cmd.CommandText = $"""
 | 
				
			||||||
 | 
					                    SELECT c.mgnr, c.bin, COALESCE(p.weight, 0) - c.min_kg AS diff
 | 
				
			||||||
 | 
					                    FROM v_area_commitment_bin c
 | 
				
			||||||
 | 
					                        LEFT JOIN v_payment_bin p ON (p.year, p.mgnr, p.bin) = (c.year, c.mgnr, c.bin)
 | 
				
			||||||
 | 
					                    WHERE c.year = {Year} AND LENGTH(c.bin) = 2 AND diff < 0
 | 
				
			||||||
 | 
					                    """;
 | 
				
			||||||
 | 
					                using var reader = await cmd.ExecuteReaderAsync();
 | 
				
			||||||
 | 
					                while (await reader.ReadAsync()) {
 | 
				
			||||||
 | 
					                    underDeliveries[(reader.GetInt32(0), reader.GetString(1))] = reader.GetInt32(2);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var fittingBins = new Dictionary<(int, string), int>();
 | 
				
			||||||
 | 
					            using (var cmd = cnx.CreateCommand()) {
 | 
				
			||||||
 | 
					                cmd.CommandText = $"""
 | 
				
			||||||
 | 
					                    SELECT c.mgnr, c.bin, COALESCE(p.weight, 0) - c.min_kg AS diff
 | 
				
			||||||
 | 
					                    FROM v_area_commitment_bin c
 | 
				
			||||||
 | 
					                        LEFT JOIN v_payment_bin p ON (p.year, p.mgnr, p.bin) = (c.year, c.mgnr, c.bin)
 | 
				
			||||||
 | 
					                    WHERE c.year = {Year} AND LENGTH(c.bin) = 3 AND diff > 0
 | 
				
			||||||
 | 
					                    """;
 | 
				
			||||||
 | 
					                using var reader = await cmd.ExecuteReaderAsync();
 | 
				
			||||||
 | 
					                while (await reader.ReadAsync()) {
 | 
				
			||||||
 | 
					                    fittingBins[(reader.GetInt32(0), reader.GetString(1))] = reader.GetInt32(2);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            foreach (var item in fittingBins) {
 | 
				
			||||||
 | 
					                var mgnr = item.Key.Item1;
 | 
				
			||||||
 | 
					                var id = item.Key.Item2[..2];
 | 
				
			||||||
 | 
					                var attr = item.Key.Item2[2..];
 | 
				
			||||||
 | 
					                var available = item.Value;
 | 
				
			||||||
 | 
					                var needed = -underDeliveries.GetValueOrDefault((mgnr, id), 0);
 | 
				
			||||||
 | 
					                if (needed <= 0) continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var fittingDeliveries = new List<(int, int, int, int)>();
 | 
				
			||||||
 | 
					                using (var cmd = cnx.CreateCommand()) {
 | 
				
			||||||
 | 
					                    cmd.CommandText = $"""
 | 
				
			||||||
 | 
					                        SELECT d.did, d.dpnr, d.weight, b.value
 | 
				
			||||||
 | 
					                        FROM v_delivery d
 | 
				
			||||||
 | 
					                            JOIN delivery_part_bin b ON (b.year, b.did, b.dpnr) = (d.year, d.did, d.dpnr) AND b.discr = '{attr}'
 | 
				
			||||||
 | 
					                        WHERE d.year = {Year} AND mgnr = {mgnr} AND sortid = '{id}' AND attributes = '{attr}'
 | 
				
			||||||
 | 
					                        ORDER BY kmw ASC, lsnr DESC, d.dpnr DESC
 | 
				
			||||||
 | 
					                        """;
 | 
				
			||||||
 | 
					                    using var reader = await cmd.ExecuteReaderAsync();
 | 
				
			||||||
 | 
					                    while (await reader.ReadAsync()) {
 | 
				
			||||||
 | 
					                        fittingDeliveries.Add((
 | 
				
			||||||
 | 
					                            reader.GetInt32(0), reader.GetInt32(1), reader.GetInt32(2), reader.GetInt32(3)
 | 
				
			||||||
 | 
					                        ));
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var changes = new List<(int, int, int, int)>();
 | 
				
			||||||
 | 
					                foreach (var (did, dpnr, _, w) in fittingDeliveries) {
 | 
				
			||||||
 | 
					                    int v = Math.Min(needed, w);
 | 
				
			||||||
 | 
					                    needed -= v;
 | 
				
			||||||
 | 
					                    changes.Add((did, dpnr, 1, v));
 | 
				
			||||||
 | 
					                    changes.Add((did, dpnr, 2, w - v));
 | 
				
			||||||
 | 
					                    if (needed == 0) break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                using (var cmd = cnx.CreateCommand()) {
 | 
				
			||||||
 | 
					                    cmd.CommandText = $"""
 | 
				
			||||||
 | 
					                        INSERT INTO delivery_part_bin (year, did, dpnr, binnr, discr, value)
 | 
				
			||||||
 | 
					                        VALUES {string.Join(",\n       ", changes.Select(i => $"({Year}, {i.Item1}, {i.Item2}, {i.Item3}, '', {i.Item4})"))}
 | 
				
			||||||
 | 
					                        ON CONFLICT DO UPDATE
 | 
				
			||||||
 | 
					                        SET value = excluded.value
 | 
				
			||||||
 | 
					                        """;
 | 
				
			||||||
 | 
					                    await cmd.ExecuteNonQueryAsync();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
        xmlns:local="clr-namespace:Elwig.Windows"
 | 
					        xmlns:local="clr-namespace:Elwig.Windows"
 | 
				
			||||||
        mc:Ignorable="d"
 | 
					        mc:Ignorable="d"
 | 
				
			||||||
        xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
 | 
					        xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
 | 
				
			||||||
        Title="Flächenbindungen - Elwig" Height="480" Width="850"
 | 
					        Title="Flächenbindungen - Elwig" Height="480" Width="1100"
 | 
				
			||||||
        Loaded="Window_Loaded">
 | 
					        Loaded="Window_Loaded">
 | 
				
			||||||
    <Window.Resources>
 | 
					    <Window.Resources>
 | 
				
			||||||
        <Style TargetType="Label">
 | 
					        <Style TargetType="Label">
 | 
				
			||||||
@@ -52,7 +52,7 @@
 | 
				
			|||||||
        </Grid.RowDefinitions>
 | 
					        </Grid.RowDefinitions>
 | 
				
			||||||
        <Grid.ColumnDefinitions>
 | 
					        <Grid.ColumnDefinitions>
 | 
				
			||||||
            <ColumnDefinition Width="*"/>
 | 
					            <ColumnDefinition Width="*"/>
 | 
				
			||||||
            <ColumnDefinition Width="330"/>
 | 
					            <ColumnDefinition Width="340"/>
 | 
				
			||||||
        </Grid.ColumnDefinitions>
 | 
					        </Grid.ColumnDefinitions>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <Menu Grid.ColumnSpan="2" BorderThickness="0,0,0,1" BorderBrush="LightGray" Background="White">
 | 
					        <Menu Grid.ColumnSpan="2" BorderThickness="0,0,0,1" BorderBrush="LightGray" Background="White">
 | 
				
			||||||
@@ -74,13 +74,15 @@
 | 
				
			|||||||
                    <DataGridTextColumn Header="Katastralgemeinde"  Binding="{Binding Kg.AtKg.Name}"  Width="6*"/>
 | 
					                    <DataGridTextColumn Header="Katastralgemeinde"  Binding="{Binding Kg.AtKg.Name}"  Width="6*"/>
 | 
				
			||||||
                    <DataGridTextColumn Header="Ried"               Binding="{Binding Rd.Name}"       Width="4*"/>
 | 
					                    <DataGridTextColumn Header="Ried"               Binding="{Binding Rd.Name}"       Width="4*"/>
 | 
				
			||||||
                    <DataGridTextColumn Header="Parzelle"           Binding="{Binding GstNr}"         Width="4*"/>
 | 
					                    <DataGridTextColumn Header="Parzelle"           Binding="{Binding GstNr}"         Width="4*"/>
 | 
				
			||||||
                    <DataGridTextColumn Header="Fläche"             Binding="{Binding Area, StringFormat='{}{0:N0} m²'}" Width="4*">
 | 
					                    <DataGridTextColumn Header="Fläche"             Binding="{Binding Area, StringFormat='{}{0:N0} m²'}" Width="3*">
 | 
				
			||||||
                        <DataGridTextColumn.CellStyle>
 | 
					                        <DataGridTextColumn.CellStyle>
 | 
				
			||||||
                            <Style>
 | 
					                            <Style>
 | 
				
			||||||
                                <Setter Property="TextBlock.TextAlignment" Value="Right"/>
 | 
					                                <Setter Property="TextBlock.TextAlignment" Value="Right"/>
 | 
				
			||||||
                            </Style>
 | 
					                            </Style>
 | 
				
			||||||
                        </DataGridTextColumn.CellStyle>
 | 
					                        </DataGridTextColumn.CellStyle>
 | 
				
			||||||
                    </DataGridTextColumn>
 | 
					                    </DataGridTextColumn>
 | 
				
			||||||
 | 
					                    <DataGridTextColumn Header="Sorte"           Binding="{Binding AreaComType.WineVar.Name}" Width="4*"/>
 | 
				
			||||||
 | 
					                    <DataGridTextColumn Header="Attribut"           Binding="{Binding AreaComType.WineAttr1.Name}" Width="3*"/>
 | 
				
			||||||
                </DataGrid.Columns>
 | 
					                </DataGrid.Columns>
 | 
				
			||||||
            </DataGrid>
 | 
					            </DataGrid>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -318,7 +318,7 @@ namespace Elwig.Windows {
 | 
				
			|||||||
            var filter = TextFilter.ToList();
 | 
					            var filter = TextFilter.ToList();
 | 
				
			||||||
            if (filter.Count > 0) {
 | 
					            if (filter.Count > 0) {
 | 
				
			||||||
                var var = await Context.WineVarieties.ToDictionaryAsync(v => v.SortId, v => v);
 | 
					                var var = await Context.WineVarieties.ToDictionaryAsync(v => v.SortId, v => v);
 | 
				
			||||||
                var qual = await Context.WineQualityLevels.ToDictionaryAsync(q => q.QualId, q => q);
 | 
					                var qual = await Context.WineQualityLevels.Where(q => !q.IsPredicate).ToDictionaryAsync(q => q.QualId, q => q);
 | 
				
			||||||
                var mgnr = await Context.Members.ToDictionaryAsync(m => m.MgNr.ToString(), m => m);
 | 
					                var mgnr = await Context.Members.ToDictionaryAsync(m => m.MgNr.ToString(), m => m);
 | 
				
			||||||
                var zwst = await Context.Branches.ToDictionaryAsync(b => b.Name.ToLower().Split(" ")[0], b => b);
 | 
					                var zwst = await Context.Branches.ToDictionaryAsync(b => b.Name.ToLower().Split(" ")[0], b => b);
 | 
				
			||||||
                var attr = await Context.WineAttributes.ToDictionaryAsync(a => a.Name.ToLower().Split(" ")[0], a => a);
 | 
					                var attr = await Context.WineAttributes.ToDictionaryAsync(a => a.Name.ToLower().Split(" ")[0], a => a);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,12 +32,16 @@
 | 
				
			|||||||
            </Grid.ColumnDefinitions>
 | 
					            </Grid.ColumnDefinitions>
 | 
				
			||||||
            <Image Source="/elwig.png" RenderOptions.BitmapScalingMode="HighQuality" Grid.Column="0"
 | 
					            <Image Source="/elwig.png" RenderOptions.BitmapScalingMode="HighQuality" Grid.Column="0"
 | 
				
			||||||
                   HorizontalAlignment="Left" Margin="5,5,5,5" VerticalAlignment="Top"/>
 | 
					                   HorizontalAlignment="Left" Margin="5,5,5,5" VerticalAlignment="Top"/>
 | 
				
			||||||
            <Label Grid.Column="1" Content="Elwig" FontSize="32"
 | 
					            <TextBlock Grid.Column="1" FontSize="32" HorizontalAlignment="Left" Margin="0,5,0,0" VerticalAlignment="Top">
 | 
				
			||||||
                   HorizontalAlignment="Left" Margin="0,10,0,0" VerticalAlignment="Top"/>
 | 
					                Elwig
 | 
				
			||||||
            <Label Grid.Column="1" Content="Elektonische Winzer-"
 | 
					            </TextBlock>
 | 
				
			||||||
                   HorizontalAlignment="Left" Margin="0,55,0,0" VerticalAlignment="Top"/>
 | 
					            <TextBlock Grid.Column="1" HorizontalAlignment="Left" Margin="0,50,0,0" VerticalAlignment="Top" LineHeight="14" LineStackingStrategy="BlockLineHeight">
 | 
				
			||||||
            <Label Grid.Column="1" Content="genossenschaftsverwaltung"
 | 
					                Elektonische Winzer-<LineBreak/>
 | 
				
			||||||
                   HorizontalAlignment="Left" Margin="0,70,0,0" VerticalAlignment="Top"/>
 | 
					                genossenschaftsverwaltung
 | 
				
			||||||
 | 
					            </TextBlock>
 | 
				
			||||||
 | 
					            <TextBlock x:Name="VersionField" Grid.Column="1" FontSize="10" HorizontalAlignment="Left" Margin="0,80,0,0" VerticalAlignment="Top">
 | 
				
			||||||
 | 
					                Version: ?
 | 
				
			||||||
 | 
					            </TextBlock>
 | 
				
			||||||
        </Grid>
 | 
					        </Grid>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <Button x:Name="MemberAdminButton" Content="Mitglieder" Click="MemberAdminButton_Click"
 | 
					        <Button x:Name="MemberAdminButton" Content="Mitglieder" Click="MemberAdminButton_Click"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,3 +1,4 @@
 | 
				
			|||||||
 | 
					using System.Reflection;
 | 
				
			||||||
using System.Windows;
 | 
					using System.Windows;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Elwig.Windows {
 | 
					namespace Elwig.Windows {
 | 
				
			||||||
@@ -5,6 +6,8 @@ namespace Elwig.Windows {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        public MainWindow() {
 | 
					        public MainWindow() {
 | 
				
			||||||
            InitializeComponent();
 | 
					            InitializeComponent();
 | 
				
			||||||
 | 
					            var v = Assembly.GetExecutingAssembly().GetName().Version;
 | 
				
			||||||
 | 
					            VersionField.Text = "Version: " + (v == null ? "?" : $"{v.Major}.{v.Minor}.{v.Build}");
 | 
				
			||||||
            if (!App.Config.Debug) {
 | 
					            if (!App.Config.Debug) {
 | 
				
			||||||
                TestWindowButton.Visibility = Visibility.Hidden;
 | 
					                TestWindowButton.Visibility = Visibility.Hidden;
 | 
				
			||||||
                //QueryWindowButton.Visibility = Visibility.Hidden;
 | 
					                //QueryWindowButton.Visibility = Visibility.Hidden;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -59,6 +59,8 @@
 | 
				
			|||||||
                              Click="Menu_Print_Letterheads_MgNr_Click"/>
 | 
					                              Click="Menu_Print_Letterheads_MgNr_Click"/>
 | 
				
			||||||
                    <MenuItem x:Name="Menu_Print_Letterheads_Name" Header="nach Name sortiert" IsEnabled="False" Tag="Print"
 | 
					                    <MenuItem x:Name="Menu_Print_Letterheads_Name" Header="nach Name sortiert" IsEnabled="False" Tag="Print"
 | 
				
			||||||
                              Click="Menu_Print_Letterheads_Name_Click"/>
 | 
					                              Click="Menu_Print_Letterheads_Name_Click"/>
 | 
				
			||||||
 | 
					                    <MenuItem x:Name="Menu_Print_Letterheads_Plz" Header="nach PLZ, Ort, Name sortiert" IsEnabled="False" Tag="Print"
 | 
				
			||||||
 | 
					                              Click="Menu_Print_Letterheads_Plz_Click"/>
 | 
				
			||||||
                </MenuItem>
 | 
					                </MenuItem>
 | 
				
			||||||
            </MenuItem>
 | 
					            </MenuItem>
 | 
				
			||||||
            <MenuItem Header="Rundschreiben">
 | 
					            <MenuItem Header="Rundschreiben">
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -291,7 +291,7 @@ namespace Elwig.Windows {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private async void Menu_Print_Letterheads_MgNr_Click(object sender, RoutedEventArgs evt) {
 | 
					        private async Task PrintLetterheads(int ordering) {
 | 
				
			||||||
            var n = await Context.Members.CountAsync(m => m.IsActive);
 | 
					            var n = await Context.Members.CountAsync(m => m.IsActive);
 | 
				
			||||||
            var res = MessageBox.Show(
 | 
					            var res = MessageBox.Show(
 | 
				
			||||||
                $"Sollen wirklich {n} Seiten gedruckt werden?", "Ausdruck Bestätigen",
 | 
					                $"Sollen wirklich {n} Seiten gedruckt werden?", "Ausdruck Bestätigen",
 | 
				
			||||||
@@ -299,10 +299,25 @@ namespace Elwig.Windows {
 | 
				
			|||||||
            if (res != MessageBoxResult.Yes)
 | 
					            if (res != MessageBoxResult.Yes)
 | 
				
			||||||
                return;
 | 
					                return;
 | 
				
			||||||
            Mouse.OverrideCursor = Cursors.AppStarting;
 | 
					            Mouse.OverrideCursor = Cursors.AppStarting;
 | 
				
			||||||
            using var doc = await Document.Merge(Context.Members
 | 
					            var members = Context.Members.Where(m => m.IsActive && m.ContactViaPost);
 | 
				
			||||||
                .Where(m => m.IsActive && m.ContactViaPost)
 | 
					            switch (ordering) {
 | 
				
			||||||
                .OrderBy(m => m.MgNr)
 | 
					                case 0: members = members
 | 
				
			||||||
                .Select(m => new Letterhead(m)));
 | 
					                        .OrderBy(m => m.MgNr);
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case 1: members = members
 | 
				
			||||||
 | 
					                        .OrderBy(m => m.FamilyName)
 | 
				
			||||||
 | 
					                        .ThenBy(m => m.GivenName)
 | 
				
			||||||
 | 
					                        .ThenBy(m => m.MgNr);
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case 2: members = members
 | 
				
			||||||
 | 
					                        .OrderBy(m => m.PostalDest.AtPlz.Plz)
 | 
				
			||||||
 | 
					                        .ThenBy(m => m.PostalDest.AtPlz.Ort.Name)
 | 
				
			||||||
 | 
					                        .ThenBy(m => m.FamilyName)
 | 
				
			||||||
 | 
					                        .ThenBy(m => m.GivenName)
 | 
				
			||||||
 | 
					                        .ThenBy(m => m.MgNr);
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            using var doc = await Document.Merge((await members.ToListAsync()).Select(m => new Letterhead(m)));
 | 
				
			||||||
            await doc.Generate();
 | 
					            await doc.Generate();
 | 
				
			||||||
            Mouse.OverrideCursor = null;
 | 
					            Mouse.OverrideCursor = null;
 | 
				
			||||||
            if (App.Config.Debug) {
 | 
					            if (App.Config.Debug) {
 | 
				
			||||||
@@ -312,26 +327,16 @@ namespace Elwig.Windows {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private async void Menu_Print_Letterheads_Name_Click(object sender, RoutedEventArgs evt) {
 | 
					        private async void Menu_Print_Letterheads_MgNr_Click(object sender, RoutedEventArgs evt) {
 | 
				
			||||||
            var n = await Context.Members.CountAsync(m => m.IsActive);
 | 
					            await PrintLetterheads(0);
 | 
				
			||||||
            var res = MessageBox.Show(
 | 
					 | 
				
			||||||
                $"Sollen wirklich {n} Seiten gedruckt werden?", "Ausdruck Bestätigen",
 | 
					 | 
				
			||||||
                MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No);
 | 
					 | 
				
			||||||
            if (res != MessageBoxResult.Yes)
 | 
					 | 
				
			||||||
                return;
 | 
					 | 
				
			||||||
            Mouse.OverrideCursor = Cursors.AppStarting;
 | 
					 | 
				
			||||||
            using var doc = await Document.Merge(Context.Members
 | 
					 | 
				
			||||||
                .Where(m => m.IsActive && m.ContactViaPost)
 | 
					 | 
				
			||||||
                .OrderBy(m => m.FamilyName)
 | 
					 | 
				
			||||||
                .ThenBy(m => m.GivenName)
 | 
					 | 
				
			||||||
                .Select(m => new Letterhead(m)));
 | 
					 | 
				
			||||||
            await doc.Generate();
 | 
					 | 
				
			||||||
            Mouse.OverrideCursor = null;
 | 
					 | 
				
			||||||
            if (App.Config.Debug) {
 | 
					 | 
				
			||||||
                doc.Show();
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                await doc.Print();
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private async void Menu_Print_Letterheads_Name_Click(object sender, RoutedEventArgs evt) {
 | 
				
			||||||
 | 
					            await PrintLetterheads(1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private async void Menu_Print_Letterheads_Plz_Click(object sender, RoutedEventArgs evt) {
 | 
				
			||||||
 | 
					            await PrintLetterheads(2);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private void FocusSearchInput(object sender, RoutedEventArgs evt) {
 | 
					        private void FocusSearchInput(object sender, RoutedEventArgs evt) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,29 +24,27 @@
 | 
				
			|||||||
                            Margin="110,40,0,0" VerticalAlignment="Top" HorizontalAlignment="Left"
 | 
					                            Margin="110,40,0,0" VerticalAlignment="Top" HorizontalAlignment="Left"
 | 
				
			||||||
                            ValueChanged="SeasonInput_ValueChanged"/>
 | 
					                            ValueChanged="SeasonInput_ValueChanged"/>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <Button x:Name="CalculateBinsButton"
 | 
					        <Button x:Name="CalculateBinsButton" Content="Aufteilung Berechnen"
 | 
				
			||||||
                Click="CalculateBinsButton_Click"
 | 
					                Click="CalculateBinsButton_Click"
 | 
				
			||||||
                Margin="50,80,0,0" FontSize="12" Height="40">
 | 
					                Margin="50,80,0,0"/>
 | 
				
			||||||
            <TextBlock TextAlignment="Center">Lieferungen auf Flächen-<LineBreak/>bindungen aufteilen</TextBlock>
 | 
					        <CheckBox x:Name="AllowAttrIntoLowerBinsInput" Content="Erlauben Lieferungen auch auf (konfigurierte) "schlechtere" Flächenbindungen aufzuteilen" IsChecked="True"
 | 
				
			||||||
        </Button>
 | 
					                  VerticalAlignment="Top" HorizontalAlignment="Left" Margin="255,68,0,0"/>
 | 
				
			||||||
        <CheckBox x:Name="AllowAttrIntoLowerBinsInput" Content="Lieferungen auch auf "schlechtere" Flächenbindungen aufteilen" IsChecked="True"
 | 
					        <CheckBox x:Name="AvoidUnderDeliveriesInput" Content="Unterlieferungen durch Abzug bei "besseren" Flächenbindungen vermeiden" IsChecked="True"
 | 
				
			||||||
                  VerticalAlignment="Top" HorizontalAlignment="Left" Margin="255,72,0,0"/>
 | 
					                  VerticalAlignment="Top" HorizontalAlignment="Left" Margin="255,88,0,0"/>
 | 
				
			||||||
        <CheckBox x:Name="AvoidUnderDeliveriesInput" Content="Unterlieferungen vermeiden" IsEnabled="False"
 | 
					        <CheckBox x:Name="HonorGebundenInput" Margin="255,108,0,0" VerticalAlignment="Top">
 | 
				
			||||||
                  VerticalAlignment="Top" HorizontalAlignment="Left" Margin="255,92,0,0"/>
 | 
					 | 
				
			||||||
        <CheckBox x:Name="HonorGebundenInput" Margin="255,112,0,0" VerticalAlignment="Top" HorizontalAlignment="Left">
 | 
					 | 
				
			||||||
            <TextBlock>Bei Lieferungen das Feld <Italic>Gebunden</Italic> berücksichtigen</TextBlock>
 | 
					            <TextBlock>Bei Lieferungen das Feld <Italic>Gebunden</Italic> berücksichtigen</TextBlock>
 | 
				
			||||||
        </CheckBox>
 | 
					        </CheckBox>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <Button x:Name="DeliveryConfirmationButton" Content="Anlieferungsbestätigungen"
 | 
					        <Button x:Name="DeliveryConfirmationButton" Content="Anlieferungsbestätigungen"
 | 
				
			||||||
                Click="DeliveryConfirmationButton_Click"
 | 
					                Click="DeliveryConfirmationButton_Click"
 | 
				
			||||||
                Margin="50,130,0,0"/>
 | 
					                Margin="50,122,0,0"/>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <Button x:Name="OverUnderDeliveryButton" Content="Über-/Unterlieferungen"
 | 
					        <Button x:Name="OverUnderDeliveryButton" Content="Über-/Unterlieferungen"
 | 
				
			||||||
                Click="OverUnderDeliveryButton_Click"
 | 
					                Click="OverUnderDeliveryButton_Click"
 | 
				
			||||||
                Margin="50,172,0,0"/>
 | 
					                Margin="50,164,0,0"/>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <Button x:Name="PaymentButton" Content="Auszahlung"
 | 
					        <Button x:Name="PaymentButton" Content="Auszahlung"
 | 
				
			||||||
                Click="PaymentButton_Click"
 | 
					                Click="PaymentButton_Click"
 | 
				
			||||||
                Margin="50,214,0,0"/>
 | 
					                Margin="50,206,0,0"/>
 | 
				
			||||||
    </Grid>
 | 
					    </Grid>
 | 
				
			||||||
</local:ContextWindow>
 | 
					</local:ContextWindow>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,10 @@
 | 
				
			|||||||
using Elwig.Documents;
 | 
					using Elwig.Dialogs;
 | 
				
			||||||
using Elwig.Helpers;
 | 
					using Elwig.Helpers;
 | 
				
			||||||
using Elwig.Helpers.Billing;
 | 
					using Elwig.Helpers.Billing;
 | 
				
			||||||
using Microsoft.EntityFrameworkCore;
 | 
					using Microsoft.Win32;
 | 
				
			||||||
using System.Linq;
 | 
					using System;
 | 
				
			||||||
 | 
					using System.IO;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
using System.Threading.Tasks;
 | 
					using System.Threading.Tasks;
 | 
				
			||||||
using System.Windows;
 | 
					using System.Windows;
 | 
				
			||||||
using System.Windows.Input;
 | 
					using System.Windows.Input;
 | 
				
			||||||
@@ -18,13 +20,15 @@ namespace Elwig.Windows {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        protected override async Task OnRenewContext() {
 | 
					        protected override async Task OnRenewContext() {
 | 
				
			||||||
 | 
					            SeasonInput_ValueChanged(null, null);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private async void SeasonInput_ValueChanged(object sender, RoutedEventArgs evt) {
 | 
					        private async void SeasonInput_ValueChanged(object? sender, RoutedEventArgs? evt) {
 | 
				
			||||||
            var s = await Context.Seasons.FindAsync(SeasonInput.Value);
 | 
					            var s0 = await Context.Seasons.FindAsync(SeasonInput.Value);
 | 
				
			||||||
            var valid = (s != null);
 | 
					            var s1 = await Context.Seasons.FindAsync(SeasonInput.Value + 1);
 | 
				
			||||||
            CalculateBinsButton.IsEnabled = valid;
 | 
					            var valid = (s0 != null);
 | 
				
			||||||
 | 
					            var last = (s1 == null);
 | 
				
			||||||
 | 
					            CalculateBinsButton.IsEnabled = valid && last;
 | 
				
			||||||
            DeliveryConfirmationButton.IsEnabled = valid;
 | 
					            DeliveryConfirmationButton.IsEnabled = valid;
 | 
				
			||||||
            OverUnderDeliveryButton.IsEnabled = valid;
 | 
					            OverUnderDeliveryButton.IsEnabled = valid;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -32,6 +36,7 @@ namespace Elwig.Windows {
 | 
				
			|||||||
        private async void CalculateBinsButton_Click(object sender, RoutedEventArgs evt) {
 | 
					        private async void CalculateBinsButton_Click(object sender, RoutedEventArgs evt) {
 | 
				
			||||||
            if (SeasonInput.Value is not int year)
 | 
					            if (SeasonInput.Value is not int year)
 | 
				
			||||||
                return;
 | 
					                return;
 | 
				
			||||||
 | 
					            CalculateBinsButton.IsEnabled = false;
 | 
				
			||||||
            Mouse.OverrideCursor = Cursors.AppStarting;
 | 
					            Mouse.OverrideCursor = Cursors.AppStarting;
 | 
				
			||||||
            var b = new Billing(year);
 | 
					            var b = new Billing(year);
 | 
				
			||||||
            await b.FinishSeason();
 | 
					            await b.FinishSeason();
 | 
				
			||||||
@@ -40,37 +45,106 @@ namespace Elwig.Windows {
 | 
				
			|||||||
                AvoidUnderDeliveriesInput.IsChecked ?? false,
 | 
					                AvoidUnderDeliveriesInput.IsChecked ?? false,
 | 
				
			||||||
                HonorGebundenInput.IsChecked ?? false);
 | 
					                HonorGebundenInput.IsChecked ?? false);
 | 
				
			||||||
            Mouse.OverrideCursor = null;
 | 
					            Mouse.OverrideCursor = null;
 | 
				
			||||||
 | 
					            CalculateBinsButton.IsEnabled = true;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private async void DeliveryConfirmationButton_Click(object sender, RoutedEventArgs evt) {
 | 
					        private void DeliveryConfirmationButton_Click(object sender, RoutedEventArgs evt) {
 | 
				
			||||||
            if (SeasonInput.Value is not int year)
 | 
					            if (SeasonInput.Value is not int year)
 | 
				
			||||||
                return;
 | 
					                return;
 | 
				
			||||||
            var res = MessageBox.Show(
 | 
					            var d = new DeliveryConfirmationsDialog(year);
 | 
				
			||||||
                $"Sollen wirklich alle Bestätigungen gedruckt werden?", "Ausdruck Bestätigen",
 | 
					            d.Show();
 | 
				
			||||||
                MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No);
 | 
					        }
 | 
				
			||||||
            if (res != MessageBoxResult.Yes)
 | 
					
 | 
				
			||||||
 | 
					        private async void OverUnderDeliveryButton_Click(object sender, RoutedEventArgs evt) {
 | 
				
			||||||
 | 
					            if (SeasonInput.Value is not int year)
 | 
				
			||||||
                return;
 | 
					                return;
 | 
				
			||||||
 | 
					            var d = new SaveFileDialog() {
 | 
				
			||||||
 | 
					                FileName = $"Über-Unterlieferungen-{year}.csv",
 | 
				
			||||||
 | 
					                DefaultExt = "csv",
 | 
				
			||||||
 | 
					                Filter = "CSV-Datei (*.csv)|*.csv",
 | 
				
			||||||
 | 
					                Title = $"Über-/Unterlieferungen {year} speichern unter - Elwig"
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            if (d.ShowDialog() == false)
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Mouse.OverrideCursor = Cursors.AppStarting;
 | 
					            Mouse.OverrideCursor = Cursors.AppStarting;
 | 
				
			||||||
            using var doc = await Document.Merge(Context.Members.FromSqlRaw($"""
 | 
					
 | 
				
			||||||
                SELECT m.*
 | 
					            try {
 | 
				
			||||||
 | 
					                using var file = new StreamWriter(d.FileName, false, Encoding.Latin1);
 | 
				
			||||||
 | 
					                using var cnx = await AppDbContext.ConnectAsync();
 | 
				
			||||||
 | 
					                await file.WriteLineAsync($"Auswertungen {year};;;;;;;;;;;");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                await file.WriteLineAsync($";;;;;;;;;;;");
 | 
				
			||||||
 | 
					                await file.WriteLineAsync($"Über-/Unterlieferungen lt. gez. GA;;;;;;;;;;;");
 | 
				
			||||||
 | 
					                await file.WriteLineAsync($"MgNr;Name;Vorname;Adresse;PLZ;Ort;GA;Lieferpflicht;Lieferrecht;Geliefert;Über-/Unterliefert;Prozent");
 | 
				
			||||||
 | 
					                using (var cmd = cnx.CreateCommand()) {
 | 
				
			||||||
 | 
					                    cmd.CommandText = $"""
 | 
				
			||||||
 | 
					                    SELECT m.mgnr, m.family_name, m.given_name, p.plz, o.name, m.address, m.business_shares,
 | 
				
			||||||
 | 
					                           m.business_shares * (SELECT value FROM client_parameter WHERE param = 'DELIVERY_OBLIGATION') AS min_kg,
 | 
				
			||||||
 | 
					                           m.business_shares * (SELECT value FROM client_parameter WHERE param = 'DELIVERY_RIGHT') AS max_kg,
 | 
				
			||||||
 | 
					                           COALESCE(SUM(d.weight), 0) AS sum
 | 
				
			||||||
                    FROM member m
 | 
					                    FROM member m
 | 
				
			||||||
                    JOIN delivery d ON d.mgnr = m.mgnr
 | 
					                        LEFT JOIN AT_plz_dest p ON p.id = m.postal_dest
 | 
				
			||||||
                WHERE m.active AND d.year = {year}
 | 
					                        LEFT JOIN AT_ort o ON o.okz = p.okz
 | 
				
			||||||
                GROUP BY m.mgnr
 | 
					                        LEFT JOIN v_delivery d ON d.mgnr = m.mgnr AND d.year = {year}
 | 
				
			||||||
                ORDER BY m.mgnr
 | 
					                    WHERE m.active = 1
 | 
				
			||||||
                """)
 | 
					                    GROUP BY d.year, m.mgnr
 | 
				
			||||||
                .ToList()
 | 
					                    ORDER BY sum = 0 DESC, 100.0 * sum / max_kg, m.mgnr;
 | 
				
			||||||
                .Select(m => new DeliveryConfirmation(Context, year, m)));
 | 
					                    """;
 | 
				
			||||||
            await doc.Generate();
 | 
					                    using var reader = await cmd.ExecuteReaderAsync();
 | 
				
			||||||
            Mouse.OverrideCursor = null;
 | 
					                    while (await reader.ReadAsync()) {
 | 
				
			||||||
            if (App.Config.Debug) {
 | 
					                        var mgnr = reader.GetInt32(0);
 | 
				
			||||||
                doc.Show();
 | 
					                        var familyName = reader.GetString(1);
 | 
				
			||||||
            } else {
 | 
					                        var givenName = reader.GetString(2);
 | 
				
			||||||
                await doc.Print();
 | 
					                        var plz = reader.GetInt32(3);
 | 
				
			||||||
 | 
					                        var ort = reader.GetString(4);
 | 
				
			||||||
 | 
					                        var addr = reader.GetString(5);
 | 
				
			||||||
 | 
					                        var ga = reader.GetInt32(6);
 | 
				
			||||||
 | 
					                        var minKg = reader.GetInt32(7);
 | 
				
			||||||
 | 
					                        var maxKg = reader.GetInt32(8);
 | 
				
			||||||
 | 
					                        var sum = reader.GetInt32(9);
 | 
				
			||||||
 | 
					                        var s1 = sum < minKg ? $"{sum - minKg}" : sum > maxKg ? $"{sum - maxKg}" : "";
 | 
				
			||||||
 | 
					                        var s2 = sum < minKg ? $"{sum * 100.0 / minKg - 100.0:0.0}" : sum > maxKg ? $"{sum * 100.0 / maxKg - 100:0.0}" : "";
 | 
				
			||||||
 | 
					                        await file.WriteLineAsync($"{mgnr};{familyName};{givenName};{addr};{plz};{ort};{ga};{minKg};{maxKg};{sum};{s1};{s2}");
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private void OverUnderDeliveryButton_Click(object sender, RoutedEventArgs evt) {
 | 
					                await file.WriteLineAsync($";;;;;;;;;;;");
 | 
				
			||||||
 | 
					                await file.WriteLineAsync($"Unterlieferungen lt. Flächenbindungen;;;;;;;;;;;");
 | 
				
			||||||
 | 
					                await file.WriteLineAsync($"MgNr;Name;Vorname;Adresse;PLZ;Ort;Vertrag;Lieferpflicht;Lieferrecht;Geliefert;Unterliefert;Prozent");
 | 
				
			||||||
 | 
					                using (var cmd = cnx.CreateCommand()) {
 | 
				
			||||||
 | 
					                    cmd.CommandText = $"""
 | 
				
			||||||
 | 
					                    SELECT m.mgnr, m.family_name, m.given_name, p.plz, o.name, m.address,
 | 
				
			||||||
 | 
					                           c.bin, c.min_kg, c.max_kg, b.weight
 | 
				
			||||||
 | 
					                    FROM member m
 | 
				
			||||||
 | 
					                        LEFT JOIN AT_plz_dest p ON p.id = m.postal_dest
 | 
				
			||||||
 | 
					                        LEFT JOIN AT_ort o ON o.okz = p.okz
 | 
				
			||||||
 | 
					                        JOIN v_area_commitment_bin c ON c.mgnr = m.mgnr AND c.year = {year}
 | 
				
			||||||
 | 
					                        LEFT JOIN v_payment_bin b ON (b.mgnr, b.bin) = (m.mgnr, c.bin) AND b.year = {year}
 | 
				
			||||||
 | 
					                    WHERE m.active = 1 AND b.weight < c.min_kg
 | 
				
			||||||
 | 
					                    ORDER BY m.mgnr, c.bin
 | 
				
			||||||
 | 
					                    """;
 | 
				
			||||||
 | 
					                    using var reader = await cmd.ExecuteReaderAsync();
 | 
				
			||||||
 | 
					                    while (await reader.ReadAsync()) {
 | 
				
			||||||
 | 
					                        var mgnr = reader.GetInt32(0);
 | 
				
			||||||
 | 
					                        var familyName = reader.GetString(1);
 | 
				
			||||||
 | 
					                        var givenName = reader.GetString(2);
 | 
				
			||||||
 | 
					                        var plz = reader.GetInt32(3);
 | 
				
			||||||
 | 
					                        var ort = reader.GetString(4);
 | 
				
			||||||
 | 
					                        var addr = reader.GetString(5);
 | 
				
			||||||
 | 
					                        var id = reader.GetString(6);
 | 
				
			||||||
 | 
					                        var minKg = reader.GetInt32(7);
 | 
				
			||||||
 | 
					                        var maxKg = reader.GetInt32(8);
 | 
				
			||||||
 | 
					                        var sum = reader.GetInt32(9);
 | 
				
			||||||
 | 
					                        await file.WriteLineAsync($"{mgnr};{familyName};{givenName};{addr};{plz};{ort};{id};{minKg};{maxKg};{sum};{sum - minKg};{sum * 100.0 / minKg - 100.0:0.0}");
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            } catch (Exception exc) {
 | 
				
			||||||
 | 
					                MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Mouse.OverrideCursor = null;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private void PaymentButton_Click(object sender, RoutedEventArgs evt) {
 | 
					        private void PaymentButton_Click(object sender, RoutedEventArgs evt) {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user