diff --git a/Elwig/Controls/UnitTextBox.xaml b/Elwig/Controls/UnitTextBox.xaml
index 1d09491..40c4ce4 100644
--- a/Elwig/Controls/UnitTextBox.xaml
+++ b/Elwig/Controls/UnitTextBox.xaml
@@ -5,7 +5,8 @@
-
@@ -22,9 +23,19 @@
FontSize="10" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="3"/>
+
+
+
+
+
+
+
+
+
+
diff --git a/Elwig/Helpers/AppDbContext.cs b/Elwig/Helpers/AppDbContext.cs
index 5be3128..1fdb9fe 100644
--- a/Elwig/Helpers/AppDbContext.cs
+++ b/Elwig/Helpers/AppDbContext.cs
@@ -354,6 +354,27 @@ namespace Elwig.Helpers {
_memberUnderDelivery[year] = buckets;
}
+ public async Task> GetBusinessSharePenalties(int year) {
+ using var cnx = await ConnectAsync();
+ var dict = new Dictionary();
+ using var cmd = cnx.CreateCommand();
+ cmd.CommandText = $"""
+ SELECT mgnr, 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 s.year = {year} AND u.diff < 0
+ """;
+ using var reader = await cmd.ExecuteReaderAsync();
+ while (await reader.ReadAsync()) {
+ dict[reader.GetInt32(0)] = reader.GetInt64(1);
+ }
+ return dict;
+ }
+
public async Task> GetMemberAreaCommitmentBuckets(int year, int mgnr, SqliteConnection? cnx = null) {
if (!_memberAreaCommitmentBuckets.ContainsKey(year))
await FetchMemberAreaCommitmentBuckets(year, cnx);
diff --git a/Elwig/Helpers/AppDbUpdater.cs b/Elwig/Helpers/AppDbUpdater.cs
index e7fa099..a82eae6 100644
--- a/Elwig/Helpers/AppDbUpdater.cs
+++ b/Elwig/Helpers/AppDbUpdater.cs
@@ -9,7 +9,7 @@ namespace Elwig.Helpers {
public static class AppDbUpdater {
// Don't forget to update value in Tests/fetch-resources.bat!
- public static readonly int RequiredSchemaVersion = 19;
+ public static readonly int RequiredSchemaVersion = 20;
private static int VersionOffset = 0;
diff --git a/Elwig/Helpers/Billing/BillingVariant.cs b/Elwig/Helpers/Billing/BillingVariant.cs
index 783b8f6..6c42156 100644
--- a/Elwig/Helpers/Billing/BillingVariant.cs
+++ b/Elwig/Helpers/Billing/BillingVariant.cs
@@ -47,7 +47,6 @@ namespace Elwig.Helpers.Billing {
ROUND(lp.amount / POW(10, s.precision - 2)) AS prev_amount,
IIF(m.buchführend, s.vat_normal, s.vat_flatrate) AS vat,
ROUND(IIF({Data.ConsiderContractPenalties}, COALESCE(u.total_penalty, 0), 0) / POW(10, 4 - 2)) +
- ROUND(IIF({Data.ConsiderTotalPenalty}, COALESCE(b.total_penalty, 0), 0) / POW(10, s.precision - 2)) +
ROUND(IIF({Data.ConsiderAutoBusinessShares}, -COALESCE(a.total_amount, 0), 0) / POW(10, s.precision - 2))
AS modifiers,
lc.modifiers AS prev_modifiers
@@ -66,12 +65,30 @@ namespace Elwig.Helpers.Billing {
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 v_penalty_area_commitments u ON (u.year, u.mgnr) = (s.year, m.mgnr)
- LEFT JOIN v_penalty_business_shares b ON (b.year, b.mgnr) = (s.year, m.mgnr)
LEFT JOIN v_auto_business_shares a ON (a.year, a.mgnr) = (s.year, m.mgnr)
WHERE s.year = {Year} AND v.avnr = {AvNr};
-
- UPDATE payment_variant SET test_variant = FALSE WHERE (year, avnr) = ({Year}, {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, $"""
+ UPDATE payment_variant SET test_variant = FALSE WHERE (year, avnr) = ({Year}, {AvNr});
+ """);
}
public async Task Revert() {
diff --git a/Elwig/Models/Dtos/CreditNoteData.cs b/Elwig/Models/Dtos/CreditNoteData.cs
index 2654d90..601210f 100644
--- a/Elwig/Models/Dtos/CreditNoteData.cs
+++ b/Elwig/Models/Dtos/CreditNoteData.cs
@@ -42,8 +42,9 @@ namespace Elwig.Models.Dtos {
public static async Task ForPaymentVariant(AppDbContext ctx, int year, int avnr) {
var variant = await ctx.PaymentVariants.FindAsync(year, avnr);
var name = variant!.Name;
+ var bsPenalty = await ctx.GetBusinessSharePenalties(year);
var data = BillingData.FromJson(variant!.Data);
- var rows = (await FromDbSet(ctx.CreditNoteRows, year, avnr)).Select(r => new CreditNoteRow(r, data)).ToList();
+ var rows = (await FromDbSet(ctx.CreditNoteRows, year, avnr)).Select(r => new CreditNoteRow(r, data, bsPenalty)).ToList();
return new CreditNoteData(rows, year, name);
}
@@ -56,7 +57,6 @@ namespace Elwig.Models.Dtos {
p.amount - p.net_amount AS surcharge,
c.net_amount, c.prev_net_amount, c.vat, c.vat_amount, c.gross_amount, c.modifiers, c.prev_modifiers, c.amount,
ROUND(COALESCE(u.total_penalty, 0) / POW(10, 4 - 2)) AS fb_penalty,
- ROUND(COALESCE(b.total_penalty, 0) / POW(10, s.precision - 2)) AS bs_penalty,
ROUND(COALESCE(a.total_amount, 0) / POW(10, s.precision - 2)) AS auto_bs
FROM credit c
LEFT JOIN member m ON m.mgnr = c.mgnr
@@ -65,7 +65,6 @@ namespace Elwig.Models.Dtos {
LEFT JOIN AT_ort o ON o.okz = p.okz
LEFT JOIN season s ON s.year = c.year
LEFT JOIN v_penalty_area_commitments u ON (u.year, u.mgnr) = (s.year, m.mgnr)
- LEFT JOIN v_penalty_business_shares b ON (b.year, b.mgnr) = (s.year, m.mgnr)
LEFT JOIN v_auto_business_shares a ON (a.year, a.mgnr) = (s.year, m.mgnr)
WHERE c.year = {year} AND c.avnr = {avnr}
ORDER BY m.mgnr
@@ -96,7 +95,7 @@ namespace Elwig.Models.Dtos {
public decimal? Considered;
public decimal Amount;
- public CreditNoteRow(CreditNoteRowSingle row, BillingData data) {
+ public CreditNoteRow(CreditNoteRowSingle row, BillingData data, Dictionary bsPenalty) {
byte prec1 = 2, prec2 = row.Precision;
MgNr = row.MgNr;
Name1 = row.Name1;
@@ -120,7 +119,7 @@ namespace Elwig.Models.Dtos {
if (data.ConsiderContractPenalties)
Penalties = (row.FbPenalty == null || row.FbPenalty == 0) ? null : Utils.DecFromDb((long)row.FbPenalty, prec1);
if (data.ConsiderTotalPenalty)
- Penalty = (row.BsPealty == null || row.BsPealty == 0) ? null : Utils.DecFromDb((long)row.BsPealty, prec1);
+ Penalty = (!bsPenalty.TryGetValue(row.MgNr, out var val) || val == 0) ? null : Utils.DecFromDb(val, prec1);
if (data.ConsiderAutoBusinessShares)
AutoBs = (row.AutoBs == null || row.AutoBs == 0) ? null : -Utils.DecFromDb((long)row.AutoBs, prec1);
mod -= (Penalties ?? 0) + (Penalty ?? 0) + (AutoBs ?? 0);
@@ -175,8 +174,6 @@ namespace Elwig.Models.Dtos {
public long Amount { get; set; }
[Column("fb_penalty")]
public long? FbPenalty { get; set; }
- [Column("bs_penalty")]
- public long? BsPealty { get; set; }
[Column("auto_bs")]
public long? AutoBs { get; set; }
}
diff --git a/Elwig/Models/Entities/Season.cs b/Elwig/Models/Entities/Season.cs
index 75f06d6..df61962 100644
--- a/Elwig/Models/Entities/Season.cs
+++ b/Elwig/Models/Entities/Season.cs
@@ -55,6 +55,22 @@ namespace Elwig.Models.Entities {
set => PenaltyNoneValue = value != null ? DecToDb(value.Value) : null;
}
+ [Column("penalty_per_bs_amount")]
+ public long? PenaltyPerBsAmountValue { get; set; }
+ [NotMapped]
+ public decimal? PenaltyPerBsAmount {
+ get => PenaltyPerBsAmountValue != null ? DecFromDb(PenaltyPerBsAmountValue.Value) : null;
+ set => PenaltyPerBsAmountValue = value != null ? DecToDb(value.Value) : null;
+ }
+
+ [Column("penalty_per_bs_none")]
+ public long? PenaltyPerBsNoneValue { get; set; }
+ [NotMapped]
+ public decimal? PenaltyPerBsNone {
+ get => PenaltyPerBsNoneValue != null ? DecFromDb(PenaltyPerBsNoneValue.Value) : null;
+ set => PenaltyPerBsNoneValue = value != null ? DecToDb(value.Value) : null;
+ }
+
[Column("bs_value")]
public long? BusinessShareValueValue { get; set; }
[NotMapped]
diff --git a/Elwig/Resources/Sql/19-20.sql b/Elwig/Resources/Sql/19-20.sql
new file mode 100644
index 0000000..f7e979e
--- /dev/null
+++ b/Elwig/Resources/Sql/19-20.sql
@@ -0,0 +1,7 @@
+-- schema version 19 to 20
+
+ALTER TABLE season ADD COLUMN penalty_per_bs_amount INTEGER DEFAULT NULL;
+ALTER TABLE season ADD COLUMN penalty_per_bs_none INTEGER DEFAULT NULL;
+DROP VIEW v_penalty_business_shares;
+
+UPDATE season SET penalty_none = NULL;
diff --git a/Elwig/Windows/BaseDataWindow.xaml b/Elwig/Windows/BaseDataWindow.xaml
index 6a80f7a..683773c 100644
--- a/Elwig/Windows/BaseDataWindow.xaml
+++ b/Elwig/Windows/BaseDataWindow.xaml
@@ -395,7 +395,7 @@
-
+
@@ -415,7 +415,7 @@
-
+
@@ -440,29 +440,32 @@
-
+
-
-
+
+
+
-
-
-
-
+
+
+
+
+
+
-
-
-
+
+ Grid.Column="3" Width="85" Margin="0,130,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"/>
diff --git a/Elwig/Windows/BaseDataWindow.xaml.Season.cs b/Elwig/Windows/BaseDataWindow.xaml.Season.cs
index 8ca61e4..d0d9b0d 100644
--- a/Elwig/Windows/BaseDataWindow.xaml.Season.cs
+++ b/Elwig/Windows/BaseDataWindow.xaml.Season.cs
@@ -49,13 +49,17 @@ namespace Elwig.Windows {
SeasonPenaltyPerKgInput.Text = s.PenaltyPerKg?.ToString() ?? "";
SeasonPenaltyInput.Text = s.PenaltyAmount?.ToString() ?? "";
SeasonPenaltyNoneInput.Text = s.PenaltyNone?.ToString() ?? "";
+ SeasonPenaltyPerBsInput.Text = s.PenaltyPerBsAmount?.ToString() ?? "";
+ SeasonPenaltyPerBsNoneInput.Text = s.PenaltyPerBsNone?.ToString() ?? "";
SeasonBsValueInput.Text = s.BusinessShareValue?.ToString() ?? "";
- var sym = s.Currency.Symbol ?? "";
+ var sym = s.Currency.Symbol ?? s.Currency.Code;
SeasonModifierAbsInput.Unit = $"{sym}/kg";
SeasonPenaltyPerKgInput.Unit = $"{sym}/kg";
SeasonPenaltyInput.Unit = sym;
SeasonPenaltyNoneInput.Unit = sym;
+ SeasonPenaltyPerBsInput.Unit = $"{sym}/GA";
+ SeasonPenaltyPerBsNoneInput.Unit = $"{sym}/GA";
SeasonBsValueInput.Unit = $"{sym}/GA";
AreaCommitmentTypePenaltyPerKgInput.Unit = $"{sym}/kg";
AreaCommitmentTypePenaltyInput.Unit = sym;
@@ -72,6 +76,8 @@ namespace Elwig.Windows {
SeasonPenaltyPerKgInput.Text = "";
SeasonPenaltyInput.Text = "";
SeasonPenaltyNoneInput.Text = "";
+ SeasonPenaltyPerBsInput.Text = "";
+ SeasonPenaltyPerBsNoneInput.Text = "";
SeasonBsValueInput.Text = "";
}
_seasonUpdate = false;
@@ -94,6 +100,8 @@ namespace Elwig.Windows {
s.PenaltyPerKg = (SeasonPenaltyPerKgInput.Text.Length > 0) ? decimal.Parse(SeasonPenaltyPerKgInput.Text) : null;
s.PenaltyAmount = (SeasonPenaltyInput.Text.Length > 0) ? decimal.Parse(SeasonPenaltyInput.Text) : null;
s.PenaltyNone = (SeasonPenaltyNoneInput.Text.Length > 0) ? decimal.Parse(SeasonPenaltyNoneInput.Text) : null;
+ s.PenaltyPerBsAmount = (SeasonPenaltyPerBsInput.Text.Length > 0) ? decimal.Parse(SeasonPenaltyPerBsInput.Text) : null;
+ s.PenaltyPerBsNone = (SeasonPenaltyPerBsNoneInput.Text.Length > 0) ? decimal.Parse(SeasonPenaltyPerBsNoneInput.Text) : null;
s.BusinessShareValue = (SeasonBsValueInput.Text.Length > 0) ? decimal.Parse(SeasonBsValueInput.Text) : null;
UpdateButtons();
@@ -119,5 +127,11 @@ namespace Elwig.Windows {
InputTextChanged((TextBox)sender, Validator.CheckDecimal((TextBox)sender, false, 4, 2));
Season_Changed(sender, evt);
}
+
+ private void SeasonPenaltyPerBsInput_TextChanged(object sender, TextChangedEventArgs evt) {
+ if (SeasonList.SelectedItem is not Season s) return;
+ InputTextChanged((TextBox)sender, Validator.CheckDecimal((TextBox)sender, false, 4, s.Precision));
+ Season_Changed(sender, evt);
+ }
}
}
diff --git a/Elwig/Windows/BaseDataWindow.xaml.cs b/Elwig/Windows/BaseDataWindow.xaml.cs
index da9173e..ac9d780 100644
--- a/Elwig/Windows/BaseDataWindow.xaml.cs
+++ b/Elwig/Windows/BaseDataWindow.xaml.cs
@@ -31,6 +31,7 @@ namespace Elwig.Windows {
SeasonMaxKgPerHaInput, SeasonVatNormalInput, SeasonVatFlatrateInput, SeasonStartInput, SeasonEndInput,
SeasonMinKgPerBsInput, SeasonMaxKgPerBsInput, SeasonBsValueInput,
SeasonPenaltyPerKgInput, SeasonPenaltyInput, SeasonPenaltyNoneInput,
+ SeasonPenaltyPerBsInput, SeasonPenaltyPerBsNoneInput,
SeasonModifierIdInput, SeasonModifierNameInput, SeasonModifierRelInput, SeasonModifierAbsInput,
];
WineAttributeFillLowerInput.Visibility = Visibility.Hidden;
diff --git a/Tests/fetch-resources.bat b/Tests/fetch-resources.bat
index ccc8ca7..bef7435 100644
--- a/Tests/fetch-resources.bat
+++ b/Tests/fetch-resources.bat
@@ -1 +1 @@
-curl --fail -s -L "https://elwig.at/files/create.sql?v=19" -u "elwig:ganzGeheim123!" -o "Resources\Sql\Create.sql"
+curl --fail -s -L "https://elwig.at/files/create.sql?v=20" -u "elwig:ganzGeheim123!" -o "Resources\Sql\Create.sql"