Compare commits

...

16 Commits

Author SHA1 Message Date
ddd83bf63d Bump version to 0.4.1 2023-10-18 01:31:22 +02:00
685793f0fb Billing: Implement feature 'avoid under deliveries' 2023-10-18 01:30:34 +02:00
f6712704ee DeliveryConfirmationsDialog: Fix button width 2023-10-18 01:22:17 +02:00
de500854c4 AppDbContext: Add v_area_commitment_bin 2023-10-17 23:48:16 +02:00
d992b6a206 Document: Add member name to pdf viewer window title 2023-10-17 23:10:19 +02:00
d2b96736bb DeliveryConfirmation: remove name from title 2023-10-17 23:02:28 +02:00
50b9f4e207 AppDbContext: add name for _ attribute 2023-10-17 22:58:22 +02:00
45fc0893b1 DeliveryConfirmation: fix tables 2023-10-17 22:56:21 +02:00
c4dd56075d DeliveryConfirmationsDialog: Use Print-Tag 2023-10-17 20:53:40 +02:00
f1084c716a DeliveryConfirmationsDialog: Add AllMemberInput checkbox 2023-10-17 20:50:16 +02:00
2f8e4ca812 Bump version to 0.4.0 2023-10-17 01:08:37 +02:00
450f5d8109 Dialogs: Add DeliveryConfirmationsDialog 2023-10-17 01:07:38 +02:00
62d6707d10 DeliveryConfirmation: no linebreaks in stat table 2023-10-17 00:58:01 +02:00
2bcf26cc8d MainWindow: Add version to header 2023-10-16 23:45:14 +02:00
daddd069a3 MemberAdminWindow: Add more letterhead sorting options 2023-10-16 23:25:22 +02:00
3b3489b492 SeasonFinishWindow: enhnace button handling 2023-10-16 22:53:04 +02:00
16 changed files with 357 additions and 101 deletions

View 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>

View 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);
}
}
}

View File

@@ -118,32 +118,43 @@
</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(1, obligation, right, sum, payment))
@Raw(FormatRow(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>

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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;
}

View File

@@ -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.1</Version>
<SatelliteResourceLanguages>de-AT</SatelliteResourceLanguages> <SatelliteResourceLanguages>de-AT</SatelliteResourceLanguages>
</PropertyGroup> </PropertyGroup>

View File

@@ -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,

View File

@@ -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;
""");
}
} }
} }

View File

@@ -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),
@@ -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();
}
}
} }
} }
} }

View File

@@ -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"

View File

@@ -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;

View File

@@ -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">

View File

@@ -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_MgNr_Click(object sender, RoutedEventArgs evt) {
await PrintLetterheads(0);
}
private async void Menu_Print_Letterheads_Name_Click(object sender, RoutedEventArgs evt) { private async void Menu_Print_Letterheads_Name_Click(object sender, RoutedEventArgs evt) {
var n = await Context.Members.CountAsync(m => m.IsActive); await PrintLetterheads(1);
var res = MessageBox.Show( }
$"Sollen wirklich {n} Seiten gedruckt werden?", "Ausdruck Bestätigen",
MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No); private async void Menu_Print_Letterheads_Plz_Click(object sender, RoutedEventArgs evt) {
if (res != MessageBoxResult.Yes) await PrintLetterheads(2);
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 void FocusSearchInput(object sender, RoutedEventArgs evt) { private void FocusSearchInput(object sender, RoutedEventArgs evt) {

View File

@@ -29,7 +29,7 @@
Margin="50,80,0,0"/> Margin="50,80,0,0"/>
<CheckBox x:Name="AllowAttrIntoLowerBinsInput" Content="Erlauben Lieferungen auch auf (konfigurierte) &quot;schlechtere&quot; Flächenbindungen aufzuteilen" IsChecked="True" <CheckBox x:Name="AllowAttrIntoLowerBinsInput" Content="Erlauben Lieferungen auch auf (konfigurierte) &quot;schlechtere&quot; Flächenbindungen aufzuteilen" IsChecked="True"
VerticalAlignment="Top" HorizontalAlignment="Left" Margin="255,68,0,0"/> VerticalAlignment="Top" HorizontalAlignment="Left" Margin="255,68,0,0"/>
<CheckBox x:Name="AvoidUnderDeliveriesInput" Content="Unterlieferungen durch Abzug bei &quot;besseren&quot; Flächenbindungen vermeiden" IsEnabled="False" <CheckBox x:Name="AvoidUnderDeliveriesInput" Content="Unterlieferungen durch Abzug bei &quot;besseren&quot; Flächenbindungen vermeiden" IsChecked="True"
VerticalAlignment="Top" HorizontalAlignment="Left" Margin="255,88,0,0"/> VerticalAlignment="Top" HorizontalAlignment="Left" Margin="255,88,0,0"/>
<CheckBox x:Name="HonorGebundenInput" Margin="255,108,0,0" VerticalAlignment="Top"> <CheckBox x:Name="HonorGebundenInput" Margin="255,108,0,0" VerticalAlignment="Top">
<TextBlock>Bei Lieferungen das Feld <Italic>Gebunden</Italic> berücksichtigen</TextBlock> <TextBlock>Bei Lieferungen das Feld <Italic>Gebunden</Italic> berücksichtigen</TextBlock>

View File

@@ -1,8 +1,6 @@
using Elwig.Documents; using Elwig.Dialogs;
using Elwig.Helpers; using Elwig.Helpers;
using Elwig.Helpers.Billing; using Elwig.Helpers.Billing;
using Microsoft.EntityFrameworkCore;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows; using System.Windows;
using System.Windows.Input; using System.Windows.Input;
@@ -18,13 +16,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 +32,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,34 +41,14 @@ 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)
return;
Mouse.OverrideCursor = Cursors.AppStarting;
using var doc = await Document.Merge(Context.Members.FromSqlRaw($"""
SELECT m.*
FROM member m
JOIN delivery d ON d.mgnr = m.mgnr
WHERE m.active AND d.year = {year}
GROUP BY m.mgnr
ORDER BY m.mgnr
""")
.ToList()
.Select(m => new DeliveryConfirmation(Context, year, m)));
await doc.Generate();
Mouse.OverrideCursor = null;
if (App.Config.Debug) {
doc.Show();
} else {
await doc.Print();
}
} }
private void OverUnderDeliveryButton_Click(object sender, RoutedEventArgs evt) { private void OverUnderDeliveryButton_Click(object sender, RoutedEventArgs evt) {