[#48] Billing: Add custom modifiers for members
All checks were successful
Test / Run tests (push) Successful in 2m21s
All checks were successful
Test / Run tests (push) Successful in 2m21s
This commit is contained in:
@ -20,6 +20,7 @@ namespace Elwig.Documents {
|
|||||||
public decimal MemberTotalUnderDelivery;
|
public decimal MemberTotalUnderDelivery;
|
||||||
public int MemberAutoBusinessShares;
|
public int MemberAutoBusinessShares;
|
||||||
public decimal MemberAutoBusinessSharesAmount;
|
public decimal MemberAutoBusinessSharesAmount;
|
||||||
|
public PaymentCustom? CustomPayment;
|
||||||
|
|
||||||
public CreditNote(
|
public CreditNote(
|
||||||
AppDbContext ctx,
|
AppDbContext ctx,
|
||||||
@ -28,6 +29,7 @@ namespace Elwig.Documents {
|
|||||||
bool considerContractPenalties,
|
bool considerContractPenalties,
|
||||||
bool considerTotalPenalty,
|
bool considerTotalPenalty,
|
||||||
bool considerAutoBusinessShares,
|
bool considerAutoBusinessShares,
|
||||||
|
bool considerCustomModifiers,
|
||||||
Dictionary<string, UnderDelivery>? underDeliveries = null
|
Dictionary<string, UnderDelivery>? underDeliveries = null
|
||||||
) :
|
) :
|
||||||
base($"{Name} {(p.Credit != null ? $"Nr. {p.Credit.Year}/{p.Credit.TgNr:000}" : p.Member.Name)} – {p.Variant.Name}", p.Member) {
|
base($"{Name} {(p.Credit != null ? $"Nr. {p.Credit.Year}/{p.Credit.TgNr:000}" : p.Member.Name)} – {p.Variant.Name}", p.Member) {
|
||||||
@ -85,5 +87,8 @@ namespace Elwig.Documents {
|
|||||||
.Where(u => u.Item3 != 0)
|
.Where(u => u.Item3 != 0)
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
if (considerCustomModifiers) {
|
||||||
|
CustomPayment = ctx.CustomPayments.Find(p.Year, p.MgNr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
@ -157,13 +157,17 @@
|
|||||||
@Raw(FormatRow($"Autom. Nachz. von GA ({Model.MemberAutoBusinessShares})", Model.MemberAutoBusinessSharesAmount, add: true));
|
@Raw(FormatRow($"Autom. Nachz. von GA ({Model.MemberAutoBusinessShares})", Model.MemberAutoBusinessSharesAmount, add: true));
|
||||||
penalty += Model.MemberAutoBusinessSharesAmount;
|
penalty += Model.MemberAutoBusinessSharesAmount;
|
||||||
}
|
}
|
||||||
|
@if (Model.CustomPayment != null) {
|
||||||
|
@Raw(FormatRow(Model.CustomPayment.Comment ?? (Model.CustomPayment.Amount < 0 ? "Weitere Abzüge" : "Weitere Zuschläge"), Model.CustomPayment.Amount, add: true));
|
||||||
|
penalty += Model.CustomPayment.Amount;
|
||||||
|
}
|
||||||
|
|
||||||
@if (Model.Credit == null) {
|
@if (Model.Credit == null) {
|
||||||
@Raw(FormatRow("Auszahlungsbetrag", (Model.Payment?.Amount + penalty) ?? (sum + penalty), bold: true))
|
@Raw(FormatRow("Auszahlungsbetrag", (Model.Payment?.Amount + penalty) ?? (sum + penalty), bold: true))
|
||||||
} else {
|
} else {
|
||||||
var diff = Model.Credit.Modifiers - penalty;
|
var diff = Model.Credit.Modifiers - penalty;
|
||||||
if (diff != 0) {
|
if (diff != 0) {
|
||||||
@Raw(FormatRow(diff < 0 ? "Weitere Abzüge" : "Weitere Zuschläge", diff, add: true))
|
@Raw(FormatRow(diff < 0 ? "Sonstige Abzüge" : "Sonstige Zuschläge", diff, add: true))
|
||||||
}
|
}
|
||||||
if (Model.Credit.PrevModifiers != null && Model.Credit.PrevModifiers != 0) {
|
if (Model.Credit.PrevModifiers != null && Model.Credit.PrevModifiers != 0) {
|
||||||
@Raw(FormatRow("Bereits berücksichtigte Abzüge", -Model.Credit.PrevModifiers, add: true))
|
@Raw(FormatRow("Bereits berücksichtigte Abzüge", -Model.Credit.PrevModifiers, add: true))
|
||||||
|
@ -57,6 +57,7 @@ namespace Elwig.Helpers {
|
|||||||
public DbSet<PaymentVar> PaymentVariants { get; private set; }
|
public DbSet<PaymentVar> PaymentVariants { get; private set; }
|
||||||
public DbSet<PaymentMember> MemberPayments { get; private set; }
|
public DbSet<PaymentMember> MemberPayments { get; private set; }
|
||||||
public DbSet<PaymentDeliveryPart> PaymentDeliveryParts { get; private set; }
|
public DbSet<PaymentDeliveryPart> PaymentDeliveryParts { get; private set; }
|
||||||
|
public DbSet<PaymentCustom> CustomPayments { get; private set; }
|
||||||
public DbSet<Credit> Credits { get; private set; }
|
public DbSet<Credit> Credits { get; private set; }
|
||||||
|
|
||||||
public DbSet<OverUnderDeliveryRow> OverUnderDeliveryRows { get; private set; }
|
public DbSet<OverUnderDeliveryRow> OverUnderDeliveryRows { get; private set; }
|
||||||
|
@ -9,7 +9,7 @@ namespace Elwig.Helpers {
|
|||||||
public static class AppDbUpdater {
|
public static class AppDbUpdater {
|
||||||
|
|
||||||
// Don't forget to update value in Tests/fetch-resources.bat!
|
// Don't forget to update value in Tests/fetch-resources.bat!
|
||||||
public static readonly int RequiredSchemaVersion = 21;
|
public static readonly int RequiredSchemaVersion = 22;
|
||||||
|
|
||||||
private static int VersionOffset = 0;
|
private static int VersionOffset = 0;
|
||||||
|
|
||||||
|
@ -46,8 +46,10 @@ namespace Elwig.Helpers.Billing {
|
|||||||
ROUND(p.amount / POW(10, s.precision - 2)) AS net_amount,
|
ROUND(p.amount / POW(10, s.precision - 2)) AS net_amount,
|
||||||
ROUND(lp.amount / POW(10, s.precision - 2)) AS prev_amount,
|
ROUND(lp.amount / POW(10, s.precision - 2)) AS prev_amount,
|
||||||
IIF(m.buchführend, s.vat_normal, s.vat_flatrate) AS vat,
|
IIF(m.buchführend, s.vat_normal, s.vat_flatrate) AS vat,
|
||||||
|
ROUND(IIF({Data.ConsiderTotalPenalty}, COALESCE(b.total_penalty, 0), 0) / POW(10, s.precision - 2)) +
|
||||||
ROUND(IIF({Data.ConsiderContractPenalties}, COALESCE(u.total_penalty, 0), 0) / POW(10, 4 - 2)) +
|
ROUND(IIF({Data.ConsiderContractPenalties}, COALESCE(u.total_penalty, 0), 0) / POW(10, 4 - 2)) +
|
||||||
ROUND(IIF({Data.ConsiderAutoBusinessShares}, -COALESCE(a.total_amount, 0), 0) / POW(10, s.precision - 2))
|
ROUND(IIF({Data.ConsiderAutoBusinessShares}, -COALESCE(a.total_amount, 0), 0) / POW(10, s.precision - 2)) +
|
||||||
|
IIF({Data.ConsiderCustomModifiers}, COALESCE(x.amount, 0), 0)
|
||||||
AS modifiers,
|
AS modifiers,
|
||||||
lc.modifiers AS prev_modifiers
|
lc.modifiers AS prev_modifiers
|
||||||
FROM season s
|
FROM season s
|
||||||
@ -64,28 +66,12 @@ namespace Elwig.Helpers.Billing {
|
|||||||
LEFT JOIN payment_member lp ON (lp.year, lp.avnr, lp.mgnr) = (l.year, l.avnr, m.mgnr)
|
LEFT JOIN payment_member lp ON (lp.year, lp.avnr, lp.mgnr) = (l.year, l.avnr, m.mgnr)
|
||||||
LEFT JOIN payment_member p ON (p.year, p.avnr, p.mgnr) = (v.year, v.avnr, m.mgnr)
|
LEFT JOIN payment_member p ON (p.year, p.avnr, p.mgnr) = (v.year, v.avnr, m.mgnr)
|
||||||
LEFT JOIN credit lc ON (lc.year, lc.avnr, lc.mgnr) = (l.year, l.avnr, m.mgnr)
|
LEFT JOIN credit lc ON (lc.year, lc.avnr, lc.mgnr) = (l.year, l.avnr, m.mgnr)
|
||||||
|
LEFT JOIN v_penalty_business_shares b ON (b.year, b.mgnr) = (s.year, m.mgnr)
|
||||||
LEFT JOIN v_penalty_area_commitments u ON (u.year, u.mgnr) = (s.year, m.mgnr)
|
LEFT JOIN v_penalty_area_commitments u ON (u.year, u.mgnr) = (s.year, m.mgnr)
|
||||||
LEFT JOIN v_auto_business_shares a ON (a.year, a.mgnr) = (s.year, m.mgnr)
|
LEFT JOIN v_auto_business_shares a ON (a.year, a.mgnr) = (s.year, m.mgnr)
|
||||||
|
LEFT JOIN payment_custom x ON (x.year, x.mgnr) = (s.year, m.mgnr)
|
||||||
WHERE s.year = {Year} AND v.avnr = {AvNr};
|
WHERE s.year = {Year} AND v.avnr = {AvNr};
|
||||||
""");
|
""");
|
||||||
if (Data.ConsiderTotalPenalty) {
|
|
||||||
if (App.Client.IsWinzerkeller) {
|
|
||||||
// TODO
|
|
||||||
} else {
|
|
||||||
await AppDbContext.ExecuteBatch(cnx, $"""
|
|
||||||
UPDATE credit AS c
|
|
||||||
SET modifiers = modifiers + ROUND((
|
|
||||||
COALESCE(-s.penalty_amount, 0) +
|
|
||||||
COALESCE(-s.penalty_per_bs_amount * CEIL(CAST(-u.diff AS REAL) / s.min_kg_per_bs), 0) +
|
|
||||||
COALESCE(u.diff * s.penalty_per_kg, 0)
|
|
||||||
) / POW(10, s.precision - 2))
|
|
||||||
FROM v_total_under_delivery u
|
|
||||||
JOIN season s ON s.year = u.year
|
|
||||||
WHERE c.year = {Year} AND c.avnr = {AvNr} AND (u.year, u.mgnr) = (c.year, c.mgnr) AND
|
|
||||||
u.diff < 0
|
|
||||||
""");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await AppDbContext.ExecuteBatch(cnx, $"""
|
await AppDbContext.ExecuteBatch(cnx, $"""
|
||||||
UPDATE payment_variant SET test_variant = FALSE WHERE (year, avnr) = ({Year}, {AvNr});
|
UPDATE payment_variant SET test_variant = FALSE WHERE (year, avnr) = ({Year}, {AvNr});
|
||||||
""");
|
""");
|
||||||
|
31
Elwig/Models/Entities/PaymentCustom.cs
Normal file
31
Elwig/Models/Entities/PaymentCustom.cs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
using Elwig.Helpers;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
|
namespace Elwig.Models.Entities {
|
||||||
|
[Table("payment_custom"), PrimaryKey("Year", "MgNr")]
|
||||||
|
public class PaymentCustom {
|
||||||
|
[Column("year")]
|
||||||
|
public int Year { get; set; }
|
||||||
|
|
||||||
|
[Column("mgnr")]
|
||||||
|
public int MgNr { get; set; }
|
||||||
|
|
||||||
|
[Column("amount")]
|
||||||
|
public long AmountValue { get; set; }
|
||||||
|
[NotMapped]
|
||||||
|
public decimal Amount {
|
||||||
|
get => Utils.DecFromDb(AmountValue, 2);
|
||||||
|
set => AmountValue = Utils.DecToDb(value, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Column("comment")]
|
||||||
|
public string? Comment { get; set; }
|
||||||
|
|
||||||
|
[ForeignKey("Year")]
|
||||||
|
public virtual Season Season { get; private set; } = null!;
|
||||||
|
|
||||||
|
[ForeignKey("MgNr")]
|
||||||
|
public virtual Member Member { get; private set; } = null!;
|
||||||
|
}
|
||||||
|
}
|
45
Elwig/Resources/Sql/21-22.sql
Normal file
45
Elwig/Resources/Sql/21-22.sql
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
-- schema version 20 to 21
|
||||||
|
|
||||||
|
CREATE VIEW v_penalty_business_shares AS
|
||||||
|
SELECT u.year, u.mgnr,
|
||||||
|
SUM(IIF(u.weight = 0, COALESCE(-s.penalty_none, 0) + COALESCE(-u.business_shares * s.penalty_per_bs_none, 0), 0) +
|
||||||
|
IIF(u.diff < 0, COALESCE(-s.penalty_amount, 0), 0) +
|
||||||
|
COALESCE(u.diff * s.penalty_per_kg, 0) + COALESCE(CEIL(CAST(u.diff AS REAL) / s.min_kg_per_bs) * s.penalty_per_bs_amount, 0)
|
||||||
|
) AS total_penalty
|
||||||
|
FROM v_total_under_delivery u
|
||||||
|
JOIN season s ON u.year = s.year
|
||||||
|
JOIN member m ON m.mgnr = u.mgnr
|
||||||
|
WHERE m.active
|
||||||
|
GROUP BY u.year, u.mgnr
|
||||||
|
HAVING total_penalty < 0
|
||||||
|
ORDER BY u.year, u.mgnr;
|
||||||
|
|
||||||
|
DROP VIEW v_penalty_area_commitments;
|
||||||
|
CREATE VIEW v_penalty_area_commitments AS
|
||||||
|
SELECT u.year, u.mgnr,
|
||||||
|
SUM(COALESCE(IIF(u.weight = 0, -t.penalty_none, 0), 0) +
|
||||||
|
COALESCE(IIF(u.diff < 0, -t.penalty_amount, 0), 0) +
|
||||||
|
COALESCE(u.diff * t.penalty_per_kg, 0)
|
||||||
|
) AS total_penalty
|
||||||
|
FROM v_under_delivery u
|
||||||
|
JOIN area_commitment_type t ON t.vtrgid = u.bucket
|
||||||
|
GROUP BY year, mgnr
|
||||||
|
HAVING total_penalty < 0
|
||||||
|
ORDER BY year, mgnr;
|
||||||
|
|
||||||
|
-- all values in the table are stored with precision 2!
|
||||||
|
CREATE TABLE payment_custom (
|
||||||
|
year INTEGER NOT NULL,
|
||||||
|
mgnr INTEGER NOT NULL,
|
||||||
|
|
||||||
|
amount INTEGER NOT NULL,
|
||||||
|
comment TEXT,
|
||||||
|
|
||||||
|
CONSTRAINT pk_payment_custom PRIMARY KEY (year, mgnr),
|
||||||
|
CONSTRAINT fk_payment_custom_season FOREIGN KEY (year) REFERENCES season (year)
|
||||||
|
ON UPDATE CASCADE
|
||||||
|
ON DELETE CASCADE,
|
||||||
|
CONSTRAINT fk_payment_custom_member FOREIGN KEY (mgnr) REFERENCES member (mgnr)
|
||||||
|
ON UPDATE CASCADE
|
||||||
|
ON DELETE CASCADE
|
||||||
|
) STRICT;
|
@ -535,6 +535,7 @@ namespace Elwig.Windows {
|
|||||||
data.Item3.ConsiderContractPenalties,
|
data.Item3.ConsiderContractPenalties,
|
||||||
data.Item3.ConsiderTotalPenalty,
|
data.Item3.ConsiderTotalPenalty,
|
||||||
data.Item3.ConsiderAutoBusinessShares,
|
data.Item3.ConsiderAutoBusinessShares,
|
||||||
|
data.Item3.ConsiderCustomModifiers,
|
||||||
ctx.GetMemberUnderDelivery(year, m.MgNr).GetAwaiter().GetResult()
|
ctx.GetMemberUnderDelivery(year, m.MgNr).GetAwaiter().GetResult()
|
||||||
) { Date = postalDate })];
|
) { Date = postalDate })];
|
||||||
} catch (Exception) {
|
} catch (Exception) {
|
||||||
|
@ -56,7 +56,8 @@
|
|||||||
|
|
||||||
<Grid Grid.Row="1">
|
<Grid Grid.Row="1">
|
||||||
<DataGrid x:Name="MemberList" AutoGenerateColumns="False" HeadersVisibility="Column" IsReadOnly="True" GridLinesVisibility="None" SelectionMode="Single"
|
<DataGrid x:Name="MemberList" AutoGenerateColumns="False" HeadersVisibility="Column" IsReadOnly="True" GridLinesVisibility="None" SelectionMode="Single"
|
||||||
CanUserDeleteRows="False" CanUserResizeRows="False" CanUserAddRows="False" Margin="10,10,5,10">
|
CanUserDeleteRows="False" CanUserResizeRows="False" CanUserAddRows="False" Margin="10,10,5,10"
|
||||||
|
SelectionChanged="MemberList_SelectionChanged">
|
||||||
<DataGrid.Resources>
|
<DataGrid.Resources>
|
||||||
<Style TargetType="{x:Type DataGridRow}">
|
<Style TargetType="{x:Type DataGridRow}">
|
||||||
<Style.Setters>
|
<Style.Setters>
|
||||||
@ -117,6 +118,13 @@
|
|||||||
</Style>
|
</Style>
|
||||||
</DataGridTextColumn.CellStyle>
|
</DataGridTextColumn.CellStyle>
|
||||||
</DataGridTextColumn>
|
</DataGridTextColumn>
|
||||||
|
<DataGridTextColumn Header="Sonst." Binding="{Binding Custom, Converter={StaticResource CurrencyConverter}, StringFormat='{}{0} '}" Width="65">
|
||||||
|
<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 Header="Gesamt" Binding="{Binding Total, Converter={StaticResource CurrencyConverter}, StringFormat='{}{0} '}" Width="65">
|
||||||
<DataGridTextColumn.CellStyle>
|
<DataGridTextColumn.CellStyle>
|
||||||
<Style>
|
<Style>
|
||||||
@ -165,6 +173,36 @@
|
|||||||
Click="UnAdjustBsButton_Click" Grid.Column="1"/>
|
Click="UnAdjustBsButton_Click" Grid.Column="1"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
</GroupBox>
|
</GroupBox>
|
||||||
|
|
||||||
|
<GroupBox Header="Benutzerdefinierte Zu-/Abschläge" Margin="5,10,10,10" Height="180" Width="360"
|
||||||
|
VerticalAlignment="Bottom" HorizontalAlignment="Left">
|
||||||
|
<Grid>
|
||||||
|
<Label Content="Mitglied:" Margin="10,10,10,10"/>
|
||||||
|
<TextBox x:Name="MgNrInput" Width="48" Margin="70,10,10,10" HorizontalAlignment="Left" TextAlignment="Right"
|
||||||
|
TextChanged="MgNrInput_TextChanged" LostFocus="MgNrInput_LostFocus"/>
|
||||||
|
<ComboBox x:Name="MemberInput" Margin="123,10,40,10" IsEditable="True"
|
||||||
|
ItemTemplate="{StaticResource MemberAdminNameTemplate}" TextSearch.TextPath="AdministrativeName"
|
||||||
|
SelectionChanged="MemberInput_SelectionChanged"
|
||||||
|
VerticalAlignment="Top" Height="25" FontSize="14"/>
|
||||||
|
<Button x:Name="MemberReferenceButton" Grid.Column="1" Height="25" Width="25" FontFamily="Segoe MDL2 Assets" Content="" Padding="0,0,0,0"
|
||||||
|
Margin="10,10,10,10" VerticalAlignment="Top" HorizontalAlignment="Right" ToolTip="Zu Mitglied springen"
|
||||||
|
Click="MemberReferenceButton_Click"/>
|
||||||
|
|
||||||
|
<Label Content="Betrag:" Margin="10,40,10,10"/>
|
||||||
|
<ctrl:UnitTextBox x:Name="CustomAmountInput" Width="80" Margin="70,40,10,10" Unit="€"
|
||||||
|
TextChanged="CustomAmountInput_TextChanged"/>
|
||||||
|
|
||||||
|
<Label Content="Freitext:" Margin="10,70,10,10"/>
|
||||||
|
<TextBox x:Name="CustomCommentInput" Margin="70,70,10,10"/>
|
||||||
|
|
||||||
|
<Button x:Name="SaveCustomButton" Content="Speichern" Margin="0,0,125,10" Width="120"
|
||||||
|
HorizontalAlignment="Center" VerticalAlignment="Bottom"
|
||||||
|
Click="CustomButton_Click"/>
|
||||||
|
<Button x:Name="RemoveCustomButton" Content="Entfernen" Margin="125,0,0,10" Width="120"
|
||||||
|
HorizontalAlignment="Center" VerticalAlignment="Bottom"
|
||||||
|
Click="CustomButton_Click"/>
|
||||||
|
</Grid>
|
||||||
|
</GroupBox>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<StatusBar Grid.Row="2" Grid.ColumnSpan="3" BorderThickness="0,1,0,0" BorderBrush="Gray">
|
<StatusBar Grid.Row="2" Grid.ColumnSpan="3" BorderThickness="0,1,0,0" BorderBrush="Gray">
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using Elwig.Helpers;
|
using Elwig.Helpers;
|
||||||
using Elwig.Helpers.Billing;
|
using Elwig.Helpers.Billing;
|
||||||
using Elwig.Models.Dtos;
|
using Elwig.Models.Dtos;
|
||||||
|
using Elwig.Models.Entities;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -17,6 +18,8 @@ namespace Elwig.Windows {
|
|||||||
public readonly int Year;
|
public readonly int Year;
|
||||||
public readonly bool SeasonLocked;
|
public readonly bool SeasonLocked;
|
||||||
|
|
||||||
|
public Dictionary<int, PaymentCustom>? CustomPayments;
|
||||||
|
|
||||||
public PaymentAdjustmentWindow(int year) {
|
public PaymentAdjustmentWindow(int year) {
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
Year = year;
|
Year = year;
|
||||||
@ -26,6 +29,10 @@ namespace Elwig.Windows {
|
|||||||
Title = $"Auszahlung anpassen - Lese {Year} - Elwig";
|
Title = $"Auszahlung anpassen - Lese {Year} - Elwig";
|
||||||
AutoAdjustBsButton.IsEnabled = !SeasonLocked;
|
AutoAdjustBsButton.IsEnabled = !SeasonLocked;
|
||||||
UnAdjustBsButton.IsEnabled = !SeasonLocked;
|
UnAdjustBsButton.IsEnabled = !SeasonLocked;
|
||||||
|
SaveCustomButton.IsEnabled = !SeasonLocked;
|
||||||
|
RemoveCustomButton.IsEnabled = !SeasonLocked;
|
||||||
|
CustomAmountInput.IsEnabled = !SeasonLocked;
|
||||||
|
CustomCommentInput.IsEnabled = !SeasonLocked;
|
||||||
|
|
||||||
AllowanceKgInput.Text = $"{App.Client.AutoAdjustBs.AllowanceKg}";
|
AllowanceKgInput.Text = $"{App.Client.AutoAdjustBs.AllowanceKg}";
|
||||||
AllowanceBsInput.Text = $"{App.Client.AutoAdjustBs.AllowanceBs}";
|
AllowanceBsInput.Text = $"{App.Client.AutoAdjustBs.AllowanceBs}";
|
||||||
@ -54,6 +61,7 @@ namespace Elwig.Windows {
|
|||||||
var tbl2 = await AreaComUnderDeliveryData.ForSeason(ctx.AreaComUnderDeliveryRows, Year);
|
var tbl2 = await AreaComUnderDeliveryData.ForSeason(ctx.AreaComUnderDeliveryRows, Year);
|
||||||
var weight = tbl1.Rows.ToDictionary(r => r.MgNr, r => r.Weight);
|
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 areaComs = tbl2.Rows.ToDictionary(r => r.MgNr, r => r.VtrgIds.Zip(r.UnderDeliveries).ToDictionary(r => r.First, r => r.Second));
|
||||||
|
CustomPayments = await ctx.CustomPayments.Where(p => p.Year == Year).ToDictionaryAsync(p => p.MgNr, p => p);
|
||||||
|
|
||||||
var history = await ctx.MemberHistory
|
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)
|
.Where(h => h.DateString.CompareTo($"{Year}-01-01") >= 0 && h.DateString.CompareTo($"{Year}-12-31") <= 0 && h.Type == "auto" && h.BusinessShares > 0)
|
||||||
@ -95,6 +103,7 @@ namespace Elwig.Windows {
|
|||||||
}).Sum() : (decimal?)null,
|
}).Sum() : (decimal?)null,
|
||||||
m.Adjust,
|
m.Adjust,
|
||||||
m.AdjustAmount,
|
m.AdjustAmount,
|
||||||
|
Custom = CustomPayments!.GetValueOrDefault(m.MgNr, null)?.Amount,
|
||||||
})
|
})
|
||||||
.Select(m => new {
|
.Select(m => new {
|
||||||
m.MgNr, m.FamilyName, m.GivenName,
|
m.MgNr, m.FamilyName, m.GivenName,
|
||||||
@ -103,22 +112,23 @@ namespace Elwig.Windows {
|
|||||||
PenaltyAc = m.PenaltyAc == null ? (decimal?)null : Math.Round((decimal)m.PenaltyAc, 2),
|
PenaltyAc = m.PenaltyAc == null ? (decimal?)null : Math.Round((decimal)m.PenaltyAc, 2),
|
||||||
m.Adjust,
|
m.Adjust,
|
||||||
AdjustAmount = m.AdjustAmount == null ? (decimal?)null : Math.Round((decimal)m.AdjustAmount, 2),
|
AdjustAmount = m.AdjustAmount == null ? (decimal?)null : Math.Round((decimal)m.AdjustAmount, 2),
|
||||||
|
m.Custom
|
||||||
})
|
})
|
||||||
.Select(m => new {
|
.Select(m => new {
|
||||||
m.MgNr, m.FamilyName, m.GivenName,
|
m.MgNr, m.FamilyName, m.GivenName,
|
||||||
m.BusinessShares, m.Weight, m.OverUnder,
|
m.BusinessShares, m.Weight, m.OverUnder,
|
||||||
m.PenaltyBs, m.PenaltyAc, m.Adjust, m.AdjustAmount,
|
m.PenaltyBs, m.PenaltyAc, m.Adjust, m.AdjustAmount, m.Custom,
|
||||||
Total = (m.PenaltyBs ?? 0) + (m.PenaltyAc ?? 0) + (m.AdjustAmount ?? 0),
|
Total = (m.PenaltyBs ?? 0) + (m.PenaltyAc ?? 0) + (m.AdjustAmount ?? 0) + (m.Custom ?? 0),
|
||||||
})
|
})
|
||||||
.Select(m => new {
|
.Select(m => new {
|
||||||
m.MgNr, m.FamilyName, m.GivenName,
|
m.MgNr, m.FamilyName, m.GivenName,
|
||||||
m.BusinessShares, m.Weight, m.OverUnder,
|
m.BusinessShares, m.Weight, m.OverUnder,
|
||||||
m.PenaltyBs, m.PenaltyAc, m.Adjust, m.AdjustAmount,
|
m.PenaltyBs, m.PenaltyAc, m.Adjust, m.AdjustAmount, m.Custom,
|
||||||
m.Total,
|
m.Total,
|
||||||
Background = m.Weight == 0 ? Brushes.Orange : m.Weight / 2 < -m.Total ? Brushes.Red : Brushes.White,
|
Background = m.Weight == 0 ? Brushes.Orange : m.Weight / 2 < -m.Total ? Brushes.Red : Brushes.White,
|
||||||
Foreground = m.Total == 0 ? Brushes.Gray : Brushes.Black,
|
Foreground = m.Total == 0 ? Brushes.Gray : Brushes.Black,
|
||||||
})
|
})
|
||||||
.Where(m => m.OverUnder != null || m.Adjust != null || m.PenaltyBs != null || m.PenaltyAc != null)
|
.Where(m => m.OverUnder != null || m.Adjust != null || m.PenaltyBs != null || m.PenaltyAc != null || m.Custom != null)
|
||||||
.OrderByDescending(m => m.OverUnder ?? 0)
|
.OrderByDescending(m => m.OverUnder ?? 0)
|
||||||
.ThenBy(m => m.FamilyName)
|
.ThenBy(m => m.FamilyName)
|
||||||
.ThenBy(m => m.GivenName)
|
.ThenBy(m => m.GivenName)
|
||||||
@ -131,8 +141,16 @@ namespace Elwig.Windows {
|
|||||||
PenaltyBusinessShares.Text = $"{list.Count(r => r.PenaltyBs != null && r.PenaltyBs != 0)} Mg. / {list.Sum(r => r.PenaltyBs):N2} {sym}";
|
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}";
|
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}";
|
AutoBusinessShareAdjustment.Text = $"{list.Count(r => r.Adjust > 0)} Mg. / {list.Sum(r => r.Adjust)} GA / {list.Sum(r => r.AdjustAmount):N2} {sym}";
|
||||||
|
CustomModifiers.Text = $"{list.Count(r => r.Custom != null)} Mg. / {list.Sum(r => r.Custom):N2} {sym}";
|
||||||
TotalModifiers.Text = $"{list.Count(r => r.Total != 0)} Mg. / {list.Sum(r => r.Total):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}";
|
NonDeliveries.Text = $"{list.Count(r => r.Weight == 0):N0}";
|
||||||
|
|
||||||
|
ControlUtils.RenewItemsSource(MemberInput, await ctx.Members
|
||||||
|
.OrderBy(m => m.FamilyName)
|
||||||
|
.ThenBy(m => m.GivenName)
|
||||||
|
.ThenBy(m => m.MgNr)
|
||||||
|
.ToListAsync());
|
||||||
|
CustomAmountInput.Unit = sym;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void AutoAdjustBsButton_Click(object sender, RoutedEventArgs evt) {
|
private async void AutoAdjustBsButton_Click(object sender, RoutedEventArgs evt) {
|
||||||
@ -191,5 +209,82 @@ namespace Elwig.Windows {
|
|||||||
private void PercentInput_TextChanged(object sender, TextChangedEventArgs evt) {
|
private void PercentInput_TextChanged(object sender, TextChangedEventArgs evt) {
|
||||||
Validator.CheckDecimal((TextBox)sender, false, 3, 2);
|
Validator.CheckDecimal((TextBox)sender, false, 3, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void MemberList_SelectionChanged(object sender, SelectionChangedEventArgs evt) {
|
||||||
|
if (MemberList.SelectedItem != null) {
|
||||||
|
var i = MemberList.SelectedItem;
|
||||||
|
var t = i.GetType();
|
||||||
|
MgNrInput.Text = t.GetProperty("MgNr")?.GetValue(i)?.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MgNrInput_TextChanged(object sender, TextChangedEventArgs evt) {
|
||||||
|
var res = Validator.CheckMgNr((TextBox)sender, true);
|
||||||
|
ControlUtils.SelectItemWithPk(MemberInput, res.IsValid ? int.Parse(MgNrInput.Text) : null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MgNrInput_LostFocus(object sender, RoutedEventArgs evt) {
|
||||||
|
var res = Validator.CheckMgNr((TextBox)sender, true);
|
||||||
|
ControlUtils.SelectItemWithPk(MemberInput, res.IsValid ? int.Parse(MgNrInput.Text) : null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MemberInput_SelectionChanged(object sender, SelectionChangedEventArgs evt) {
|
||||||
|
if (MemberInput.SelectedItem is Member m) {
|
||||||
|
MgNrInput.Text = m.MgNr.ToString();
|
||||||
|
MemberList.SelectedItem = MemberList.ItemsSource.Cast<object>().FirstOrDefault(i => {
|
||||||
|
var t = i.GetType();
|
||||||
|
return (int?)t.GetProperty("MgNr")?.GetValue(i) == m.MgNr;
|
||||||
|
});
|
||||||
|
if (MemberList.SelectedItem != null)
|
||||||
|
MemberList.ScrollIntoView(MemberList.SelectedItem);
|
||||||
|
|
||||||
|
if (CustomPayments?.TryGetValue(m.MgNr, out var p) == true) {
|
||||||
|
CustomAmountInput.Text = $"{p.Amount:N2}";
|
||||||
|
CustomCommentInput.Text = p.Comment ?? "";
|
||||||
|
} else {
|
||||||
|
CustomAmountInput.Text = "";
|
||||||
|
CustomCommentInput.Text = "";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
CustomAmountInput.Text = "";
|
||||||
|
CustomCommentInput.Text = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MemberReferenceButton_Click(object sender, RoutedEventArgs evt) {
|
||||||
|
if (MemberInput.SelectedItem is not Member m) return;
|
||||||
|
App.FocusMember(m.MgNr);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CustomAmountInput_TextChanged(object sender, TextChangedEventArgs evt) {
|
||||||
|
Validator.CheckDecimal((TextBox)sender, false, 4, 2, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void CustomButton_Click(object sender, RoutedEventArgs evt) {
|
||||||
|
if (MemberInput.SelectedItem is not Member m) return;
|
||||||
|
Mouse.OverrideCursor = Cursors.AppStarting;
|
||||||
|
try {
|
||||||
|
using var ctx = new AppDbContext();
|
||||||
|
if (CustomPayments?.TryGetValue(m.MgNr, out var p) == true) {
|
||||||
|
ctx.Remove(p);
|
||||||
|
}
|
||||||
|
if (sender == SaveCustomButton && decimal.TryParse(CustomAmountInput.Text, out var num)) {
|
||||||
|
var text = CustomCommentInput.Text.Trim();
|
||||||
|
ctx.Add(new PaymentCustom {
|
||||||
|
MgNr = m.MgNr,
|
||||||
|
Year = Year,
|
||||||
|
Amount = num,
|
||||||
|
Comment = text == "" ? null : text,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await ctx.SaveChangesAsync();
|
||||||
|
} catch (Exception exc) {
|
||||||
|
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
|
||||||
|
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
|
||||||
|
MessageBox.Show(str, "Benutzerdefinierten Zu-/Abschlag speichern", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
|
}
|
||||||
|
await App.HintContextChange();
|
||||||
|
Mouse.OverrideCursor = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ namespace Tests.DocumentTests {
|
|||||||
var m = await ctx.Members.FindAsync(101);
|
var m = await ctx.Members.FindAsync(101);
|
||||||
var p = await ctx.MemberPayments.Where(p => p.Year == 2020 && p.AvNr == 1).SingleAsync();
|
var p = await ctx.MemberPayments.Where(p => p.Year == 2020 && p.AvNr == 1).SingleAsync();
|
||||||
var data = await CreditNoteDeliveryData.ForPaymentVariant(ctx.CreditNoteDeliveryRows, ctx.Seasons, 2020, 1);
|
var data = await CreditNoteDeliveryData.ForPaymentVariant(ctx.CreditNoteDeliveryRows, ctx.Seasons, 2020, 1);
|
||||||
using var doc = new CreditNote(ctx, p, data[m!.MgNr], false, false, false,
|
using var doc = new CreditNote(ctx, p, data[m!.MgNr], false, false, false, false,
|
||||||
ctx.GetMemberUnderDelivery(2020, m!.MgNr).GetAwaiter().GetResult());
|
ctx.GetMemberUnderDelivery(2020, m!.MgNr).GetAwaiter().GetResult());
|
||||||
var text = await Utils.GeneratePdfText(doc);
|
var text = await Utils.GeneratePdfText(doc);
|
||||||
Assert.Multiple(() => {
|
Assert.Multiple(() => {
|
||||||
|
@ -1 +1 @@
|
|||||||
curl --fail -s -L "https://elwig.at/files/create.sql?v=21" -u "elwig:ganzGeheim123!" -o "Resources\Sql\Create.sql"
|
curl --fail -s -L "https://elwig.at/files/create.sql?v=22" -u "elwig:ganzGeheim123!" -o "Resources\Sql\Create.sql"
|
||||||
|
Reference in New Issue
Block a user