PaymentAdjustmentWindow: Improve DataGrid and add status bar
All checks were successful
Test / Run tests (push) Successful in 2m26s

This commit is contained in:
2024-06-26 19:04:43 +02:00
parent 9d9bb099e1
commit 5c76b8ec52
3 changed files with 239 additions and 43 deletions

View File

@ -0,0 +1,41 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace Elwig.Controls {
public class UnitConverter : DependencyObject, IValueConverter {
public static readonly DependencyProperty UnitProperty = DependencyProperty.Register("Unit", typeof(string), typeof(UnitConverter), new FrameworkPropertyMetadata(null));
public string Unit {
get => (string)GetValue(UnitProperty);
set => SetValue(UnitProperty, value);
}
public static readonly DependencyProperty PrecisionProperty = DependencyProperty.Register("Precision", typeof(byte), typeof(UnitConverter), new FrameworkPropertyMetadata((byte)0));
public byte Precision {
get => (byte)GetValue(PrecisionProperty);
set => SetValue(PrecisionProperty, value);
}
public object? Convert(object? value, Type targetType, object parameter, CultureInfo culture) {
if (value == null) {
return null;
}
var fmt = $"{{0:N{Precision}}}";
var unit = $"{(Unit != null ? " " : "")}{Unit}";
if (value is int i) {
return $"{string.Format(fmt, i)}{unit}";
} else if (value is decimal d) {
return $"{string.Format(fmt, d)}{unit}";
}
return Binding.DoNothing;
}
public object? ConvertBack(object? value, Type targetType, object parameter, CultureInfo culture) {
throw new NotImplementedException();
}
}
}

View File

@ -6,8 +6,10 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Elwig.Windows"
xmlns:ctrl="clr-namespace:Elwig.Controls"
Title="Auszahlung anpassen - Elwig" Height="500" Width="850" MinHeight="400" MinWidth="850">
Title="Auszahlung anpassen - Elwig" Height="600" Width="1000" MinHeight="400" MinWidth="850">
<Window.Resources>
<ctrl:UnitConverter x:Key="CurrencyConverter" Precision="2" Unit="€"/>
<ctrl:UnitConverter x:Key="WeightConverter" Precision="0" Unit="kg"/>
<Style TargetType="Label">
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="VerticalAlignment" Value="Top"/>
@ -44,16 +46,25 @@
<RowDefinition Height="24"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="450"/>
<ColumnDefinition Width="2.5*"/>
<ColumnDefinition Width="2*" MinWidth="300"/>
<ColumnDefinition Width="5"/>
<ColumnDefinition Width="1*" MinWidth="380"/>
</Grid.ColumnDefinitions>
<Menu Grid.ColumnSpan="2" BorderThickness="0,0,0,1" BorderBrush="LightGray" Background="White">
<Menu Grid.ColumnSpan="3" BorderThickness="0,0,0,1" BorderBrush="LightGray" Background="White">
</Menu>
<Grid Grid.Row="1">
<DataGrid x:Name="MemberList" AutoGenerateColumns="False" HeadersVisibility="Column" IsReadOnly="True" GridLinesVisibility="None" SelectionMode="Single"
CanUserDeleteRows="False" CanUserResizeRows="False" CanUserAddRows="False" Margin="10,10,10,10">
CanUserDeleteRows="False" CanUserResizeRows="False" CanUserAddRows="False" Margin="10,10,5,10">
<DataGrid.Resources>
<Style TargetType="{x:Type DataGridRow}">
<Style.Setters>
<Setter Property="Background" Value="{Binding Path=Background}"></Setter>
<Setter Property="Foreground" Value="{Binding Path=Foreground}"></Setter>
</Style.Setters>
</Style>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn Header="MgNr." Binding="{Binding MgNr, StringFormat='{}{0} '}" Width="45">
<DataGridTextColumn.CellStyle>
@ -63,22 +74,50 @@
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Nachname" Binding="{Binding FamilyName}" Width="100"/>
<DataGridTextColumn Header="Vorname" Binding="{Binding GivenName}" Width="100"/>
<DataGridTextColumn Header="GA" Binding="{Binding BusinessShares, StringFormat='{}{0} '}" Width="35">
<DataGridTextColumn Header="Vorname" Binding="{Binding GivenName}" Width="90"/>
<DataGridTextColumn Header="GA" Binding="{Binding BusinessShares, StringFormat='{}{0:N0} '}" Width="35">
<DataGridTextColumn.CellStyle>
<Style>
<Setter Property="TextBlock.TextAlignment" Value="Right"/>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Ü.-/U.-Lfrg." Binding="{Binding OverUnder, StringFormat='{}{0} kg '}" Width="70">
<DataGridTextColumn Header="Ü.-/U.-Lfrg." Binding="{Binding OverUnder, Converter={StaticResource WeightConverter},StringFormat='{}{0} '}" Width="70">
<DataGridTextColumn.CellStyle>
<Style>
<Setter Property="TextBlock.TextAlignment" Value="Right"/>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Nachz." Binding="{Binding Adjust, StringFormat='{}{0} '}" Width="45">
<DataGridTextColumn Header="Strafe GA" Binding="{Binding PenaltyBs, Converter={StaticResource CurrencyConverter}, StringFormat='{}{0} '}" Width="65">
<DataGridTextColumn.CellStyle>
<Style>
<Setter Property="TextBlock.TextAlignment" Value="Right"/>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Pönale FB" Binding="{Binding PenaltyAc, Converter={StaticResource CurrencyConverter}, StringFormat='{}{0} '}" Width="65">
<DataGridTextColumn.CellStyle>
<Style>
<Setter Property="TextBlock.TextAlignment" Value="Right"/>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Nachz." Binding="{Binding Adjust, StringFormat='{}{0:N0} '}" Width="45">
<DataGridTextColumn.CellStyle>
<Style>
<Setter Property="TextBlock.TextAlignment" Value="Right"/>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Nachz.Betr." Binding="{Binding AdjustAmount, Converter={StaticResource CurrencyConverter}, StringFormat='{}{0} '}" Width="70">
<DataGridTextColumn.CellStyle>
<Style>
<Setter Property="TextBlock.TextAlignment" Value="Right"/>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Gesamt" Binding="{Binding Total, Converter={StaticResource CurrencyConverter}, StringFormat='{}{0} '}" Width="65">
<DataGridTextColumn.CellStyle>
<Style>
<Setter Property="TextBlock.TextAlignment" Value="Right"/>
@ -89,40 +128,106 @@
</DataGrid>
</Grid>
<Grid Grid.Column="1" Grid.Row="1">
<GroupBox Header="Automatische Nachzeichnung der Geschäftsanteile" Margin="10,10,10,10" Height="180" Width="360"
<GridSplitter Grid.Column="1" Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
<Grid Grid.Column="2" Grid.Row="1">
<GroupBox Header="Automatische Nachzeichnung der Geschäftsanteile" Margin="5,10,10,10" Height="180" Width="360"
VerticalAlignment="Top" HorizontalAlignment="Left">
<Grid>
<Label Content="Absoluter Freibetrag:" Margin="10,10,10,10"/>
<ctrl:UnitTextBox x:Name="AllowanceKgInput" Unit="kg" Margin="140,10,10,10" Width="70"
TextChanged="KgInput_TextChanged"/>
<ctrl:UnitTextBox x:Name="AllowanceBsInput" Unit="GA" Margin="215,10,10,10" Width="60"
TextChanged="PercentInput_TextChanged"/>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="28*"/>
</Grid.ColumnDefinitions>
<Label Content="Absoluter Freibetrag:" Margin="10,10,0,0" Grid.ColumnSpan="2"/>
<ctrl:UnitTextBox x:Name="AllowanceKgInput" Unit="kg" Margin="128,10,0,0" Width="70"
TextChanged="KgInput_TextChanged" Grid.Column="1"/>
<ctrl:UnitTextBox x:Name="AllowanceBsInput" Unit="GA" Margin="203,10,0,0" Width="60"
TextChanged="PercentInput_TextChanged" Grid.Column="1"/>
<Label Content="Relativer Freibetrag:" Margin="10,40,10,10"/>
<ctrl:UnitTextBox x:Name="AllowanceKgPerBsInput" Unit="kg/GA" Margin="140,40,10,10" Width="87"
TextChanged="KgInput_TextChanged"/>
<ctrl:UnitTextBox x:Name="AllowancePercentInput" Unit="%" Margin="232,40,10,10" Width="60"
TextChanged="PercentInput_TextChanged"/>
<Label Content="Relativer Freibetrag:" Margin="10,40,0,0" Grid.ColumnSpan="2"/>
<ctrl:UnitTextBox x:Name="AllowanceKgPerBsInput" Unit="kg/GA" Margin="128,40,0,0" Width="87"
TextChanged="KgInput_TextChanged" Grid.Column="1"/>
<ctrl:UnitTextBox x:Name="AllowancePercentInput" Unit="%" Margin="220,40,0,0" Width="60"
TextChanged="PercentInput_TextChanged" Grid.Column="1"/>
<Label Content="Nur mind. nachz.:" Margin="10,70,10,10"/>
<ctrl:UnitTextBox x:Name="MinBsInput" Unit="GA" Margin="140,70,10,10" Width="50"
TextChanged="BsInput_TextChanged"/>
<Label Content="Nur mind. nachz.:" Margin="10,70,0,0" Grid.ColumnSpan="2"/>
<ctrl:UnitTextBox x:Name="MinBsInput" Unit="GA" Margin="128,70,0,0" Width="50"
TextChanged="BsInput_TextChanged" Grid.Column="1"/>
<Button x:Name="SeasonButton" Content="GA-Wert" Margin="10,10,10,42" Width="120"
<Button x:Name="SeasonButton" Content="GA-Wert" Margin="0,0,10,42" Width="120"
HorizontalAlignment="Right" VerticalAlignment="Bottom"
Click="SeasonButton_Click"/>
<Button x:Name="AutoAdjustBsButton" Content="Nachzeichnen" Margin="10,10,135,10" Width="120"
Click="SeasonButton_Click" Grid.Column="1"/>
<Button x:Name="AutoAdjustBsButton" Content="Nachzeichnen" Margin="0,0,135,10" Width="120"
HorizontalAlignment="Right" VerticalAlignment="Bottom"
Click="AutoAdjustBsButton_Click"/>
<Button x:Name="UnAdjustBsButton" Content="Rückgängig" Margin="10,10,10,10" Width="120"
Click="AutoAdjustBsButton_Click" Grid.Column="1"/>
<Button x:Name="UnAdjustBsButton" Content="Rückgängig" Margin="0,0,10,10" Width="120"
HorizontalAlignment="Right" VerticalAlignment="Bottom"
Click="UnAdjustBsButton_Click"/>
Click="UnAdjustBsButton_Click" Grid.Column="1"/>
</Grid>
</GroupBox>
</Grid>
<StatusBar Grid.Row="2" Grid.ColumnSpan="2" BorderThickness="0,1,0,0" BorderBrush="Gray">
<StatusBar Grid.Row="2" Grid.ColumnSpan="3" BorderThickness="0,1,0,0" BorderBrush="Gray">
<StatusBar.ItemsPanel>
<ItemsPanelTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="1.25*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="130"/>
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
</StatusBar.ItemsPanel>
<StatusBarItem Grid.Column="0" HorizontalContentAlignment="Stretch">
<DockPanel>
<TextBlock Text="Strafe GA: "/>
<TextBlock x:Name="PenaltyBusinessShares" Text="-"/>
</DockPanel>
</StatusBarItem>
<Separator Grid.Column="1"/>
<StatusBarItem Grid.Column="2" HorizontalContentAlignment="Stretch">
<DockPanel>
<TextBlock Text="Pönale FB: "/>
<TextBlock x:Name="PenaltyAreaCommitments" Text="-"/>
</DockPanel>
</StatusBarItem>
<Separator Grid.Column="3"/>
<StatusBarItem Grid.Column="4" HorizontalContentAlignment="Stretch">
<DockPanel>
<TextBlock Text="Nachz.: "/>
<TextBlock x:Name="AutoBusinessShareAdjustment" Text="-"/>
</DockPanel>
</StatusBarItem>
<Separator Grid.Column="5"/>
<StatusBarItem Grid.Column="6" HorizontalContentAlignment="Stretch">
<DockPanel>
<TextBlock Text="Sonst.: "/>
<TextBlock x:Name="CustomModifiers" Text="-"/>
</DockPanel>
</StatusBarItem>
<Separator Grid.Column="7"/>
<StatusBarItem Grid.Column="8" HorizontalContentAlignment="Stretch">
<DockPanel>
<TextBlock Text="Gesamt: "/>
<TextBlock x:Name="TotalModifiers" Text="-"/>
</DockPanel>
</StatusBarItem>
<Separator Grid.Column="9"/>
<StatusBarItem Grid.Column="10" HorizontalContentAlignment="Stretch">
<DockPanel>
<TextBlock Text="Nicht-Lieferanten: "/>
<TextBlock x:Name="NonDeliveries" Text="-"/>
</DockPanel>
</StatusBarItem>
</StatusBar>
</Grid>
</local:ContextWindow>

View File

@ -9,6 +9,7 @@ using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
namespace Elwig.Windows {
public partial class PaymentAdjustmentWindow : ContextWindow {
@ -40,15 +41,19 @@ namespace Elwig.Windows {
m.FamilyName,
m.GivenName,
m.BusinessShares,
m.IsActive,
})
.OrderBy(m => m.FamilyName)
.ThenBy(m => m.GivenName)
.ThenBy(m => m.MgNr)
.ToListAsync();
var season = (await ctx.Seasons.FindAsync(Year))!;
var contracts = await ctx.AreaCommitmentTypes.ToDictionaryAsync(t => t.VtrgId, t => t);
var tbl = await OverUnderDeliveryData.ForSeason(ctx.OverUnderDeliveryRows, Year);
var weight = tbl.Rows.ToDictionary(r => r.MgNr, r => r.Weight);
var tbl1 = await OverUnderDeliveryData.ForSeason(ctx.OverUnderDeliveryRows, Year);
var tbl2 = await AreaComUnderDeliveryData.ForSeason(ctx.AreaComUnderDeliveryRows, Year);
var weight = tbl1.Rows.ToDictionary(r => r.MgNr, r => r.Weight);
var areaComs = tbl2.Rows.ToDictionary(r => r.MgNr, r => r.VtrgIds.Zip(r.UnderDeliveries).ToDictionary(r => r.First, r => r.Second));
var history = await ctx.MemberHistory
.Where(h => h.DateString.CompareTo($"{Year}-01-01") >= 0 && h.DateString.CompareTo($"{Year}-12-31") <= 0 && h.Type == "auto" && h.BusinessShares > 0)
@ -57,32 +62,77 @@ namespace Elwig.Windows {
var list = members
.Select(m => new {
m.MgNr,
m.FamilyName,
m.GivenName,
m.MgNr, m.FamilyName, m.GivenName,
m.IsActive,
BusinessShares = m.BusinessShares - history.GetValueOrDefault(m.MgNr, 0),
DeliveryObligation = (m.BusinessShares - history.GetValueOrDefault(m.MgNr, 0)) * season.MinKgPerBusinessShare,
DeliveryRight = (m.BusinessShares - history.GetValueOrDefault(m.MgNr, 0)) * season.MaxKgPerBusinessShare,
Adjust = history.TryGetValue(m.MgNr, out int v2) ? (int?)v2 : null,
})
.Select(m => new {
m.MgNr,
m.FamilyName,
m.GivenName,
m.MgNr, m.FamilyName, m.GivenName,
m.BusinessShares,
Weight = weight.GetValueOrDefault(m.MgNr, 0),
OverUnder = weight.TryGetValue(m.MgNr, out int v1) ?
(v1 < m.DeliveryObligation ? (int?)v1 - m.DeliveryObligation :
v1 > m.DeliveryRight ? (int?)v1 - m.DeliveryRight : null)
: null,
Adjust = history.TryGetValue(m.MgNr, out int v2) ? (int?)v2 : null
: (m.IsActive ? -m.DeliveryObligation : null),
m.Adjust,
AdjustAmount = m.Adjust * -season.BusinessShareValue,
})
.Where(m => m.OverUnder != null || m.Adjust != null)
.OrderByDescending(m => m.OverUnder)
.Select(m => new {
m.MgNr, m.FamilyName, m.GivenName,
m.BusinessShares, m.Weight, m.OverUnder,
PenaltyBs = m.OverUnder != null && m.OverUnder < 0 ?
(season.PenaltyPerKg * m.OverUnder ?? 0) +
(-season.PenaltyAmount ?? 0) +
(season.PenaltyPerBsAmount * Math.Floor(m.OverUnder / season.MinKgPerBusinessShare ?? 0m) ?? 0) +
(m.Weight == 0 ? (-season.PenaltyNone ?? 0) + (-season.PenaltyPerBsNone * m.BusinessShares ?? 0) : 0)
: (decimal?)null,
PenaltyAc = areaComs.TryGetValue(m.MgNr, out var c) ? c.Select(r => {
var con = contracts[r.Key];
return (r.Value.Kg * con.PenaltyPerKg ?? 0) + (r.Value.Kg < 0 ? con.PenaltyAmount ?? 0 : 0) + (r.Value.Percent == -100 ? con.PenaltyNone ?? 0 : 0);
}).Sum() : (decimal?)null,
m.Adjust,
m.AdjustAmount,
})
.Select(m => new {
m.MgNr, m.FamilyName, m.GivenName,
m.BusinessShares, m.Weight, m.OverUnder,
PenaltyBs = m.PenaltyBs == null || m.PenaltyBs == 0 ? (decimal?)null : Math.Round((decimal)m.PenaltyBs, 2),
PenaltyAc = m.PenaltyAc == null ? (decimal?)null : Math.Round((decimal)m.PenaltyAc, 2),
m.Adjust,
AdjustAmount = m.AdjustAmount == null ? (decimal?)null : Math.Round((decimal)m.AdjustAmount, 2),
})
.Select(m => new {
m.MgNr, m.FamilyName, m.GivenName,
m.BusinessShares, m.Weight, m.OverUnder,
m.PenaltyBs, m.PenaltyAc, m.Adjust, m.AdjustAmount,
Total = (m.PenaltyBs ?? 0) + (m.PenaltyAc ?? 0) + (m.AdjustAmount ?? 0),
})
.Select(m => new {
m.MgNr, m.FamilyName, m.GivenName,
m.BusinessShares, m.Weight, m.OverUnder,
m.PenaltyBs, m.PenaltyAc, m.Adjust, m.AdjustAmount,
m.Total,
Background = m.Weight == 0 ? Brushes.Orange : m.Weight / 2 < -m.Total ? Brushes.Red : Brushes.White,
Foreground = m.Total == 0 ? Brushes.Gray : Brushes.Black,
})
.Where(m => m.OverUnder != null || m.Adjust != null || m.PenaltyBs != null || m.PenaltyAc != null)
.OrderByDescending(m => m.OverUnder ?? 0)
.ThenBy(m => m.FamilyName)
.ThenBy(m => m.GivenName)
.ThenBy(m => m.MgNr)
.ToList();
MemberList.ItemsSource = list;
var sym = season.Currency.Symbol ?? season.Currency.Code;
PenaltyBusinessShares.Text = $"{list.Count(r => r.PenaltyBs != null && r.PenaltyBs != 0)} Mg. / {list.Sum(r => r.PenaltyBs):N2} {sym}";
PenaltyAreaCommitments.Text = $"{list.Count(r => r.PenaltyAc != null && r.PenaltyAc != 0)} Mg. / {list.Sum(r => r.PenaltyAc):N2} {sym}";
AutoBusinessShareAdjustment.Text = $"{list.Count(r => r.Adjust > 0)} Mg. / {list.Sum(r => r.Adjust)} GA / {list.Sum(r => r.AdjustAmount):N2} {sym}";
TotalModifiers.Text = $"{list.Count(r => r.Total != 0)} Mg. / {list.Sum(r => r.Total):N2} {sym}";
NonDeliveries.Text = $"{list.Count(r => r.Weight == 0):N0}";
}
private async void AutoAdjustBsButton_Click(object sender, RoutedEventArgs evt) {