Compare commits

..

5 Commits

Author SHA1 Message Date
lorenz.stechauner 5cbad9a195 Bump version to 1.0.5.5
Test / Run tests (push) Successful in 6m43s
Deploy / Build and Deploy (push) Successful in 2m10s
2026-06-24 14:36:44 +02:00
lorenz.stechauner 4e027a9add Elwig: Update dependencies
Test / Run tests (push) Successful in 4m40s
2026-06-24 14:24:25 +02:00
lorenz.stechauner f32ff945ec BillingData: Preserve all settings when using FromGraphEntries() 2026-06-24 14:24:15 +02:00
lorenz.stechauner ba3f66591e BilllingVariant: Allow for credits with negative value 2026-06-24 13:20:46 +02:00
lorenz.stechauner 3f65b2350b PaymentVariantService: Fix crash in GenerateEbics()
Test / Run tests (push) Successful in 2m48s
2026-06-24 10:36:28 +02:00
6 changed files with 87 additions and 31 deletions
+18
View File
@@ -2,6 +2,24 @@
Changelog
=========
[v1.0.5.5][v1.0.5.5] (2026-06-24) {#v1.0.5.5}
---------------------------------------------
### Behobene Fehler {#v1.0.5.5-bugfixes}
* Beim Exportieren der Überweisungsdaten (EBICS) im Auszahlungsvarianten-Fenster (`PaymentVariantsWindow`) kam es zu einem Absturz. (3f65b2350b)
* Einige Einstellungen einer Auszahlungsvariante wurden vom Auszahlungsvariante-Fenster (`ChartWindow`) beim Speichern überschrieben. (f32ff945ec)
### Sonstiges {#v1.0.5.5-misc}
* Traubengutschriften mit negativem Betrag sind nun wieder möglich. (ba3f66591e)
* Abhängigkeiten aktualisiert. (4e027a9add)
[v1.0.5.5]: https://git.necronda.net/winzer/elwig/releases/tag/v1.0.5.5
[v1.0.5.4][v1.0.5.4] (2026-06-22) {#v1.0.5.4}
---------------------------------------------
+2 -2
View File
@@ -9,7 +9,7 @@
<UseWindowsForms>true</UseWindowsForms>
<PreserveCompilationContext>true</PreserveCompilationContext>
<ApplicationIcon>Resources\Images\Elwig.ico</ApplicationIcon>
<Version>1.0.5.4</Version>
<Version>1.0.5.5</Version>
<SatelliteResourceLanguages>de-AT</SatelliteResourceLanguages>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<ApplicationManifest>app.manifest</ApplicationManifest>
@@ -33,7 +33,7 @@
<PackageReference Include="Microsoft.Extensions.Configuration.Ini" Version="10.0.9" />
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.4022.49" />
<PackageReference Include="NJsonSchema" Version="11.6.1" />
<PackageReference Include="ScottPlot.WPF" Version="5.1.58" />
<PackageReference Include="ScottPlot.WPF" Version="5.1.59" />
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="3.0.3" />
<PackageReference Include="System.IO.Hashing" Version="10.0.9" />
<PackageReference Include="System.IO.Ports" Version="10.0.9" />
+26 -20
View File
@@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Threading.Tasks;
@@ -92,6 +93,14 @@ namespace Elwig.Helpers.Billing {
Mode = (mode == "elwig") ? CalculationMode.Elwig : CalculationMode.WgMaster;
}
public BillingData() {
Data = new JsonObject {
["mode"] = "elwig",
["version"] = 1,
};
Mode = CalculationMode.Elwig;
}
protected static JsonObject ParseJson(string json) {
if (Schema == null) throw new InvalidOperationException("Schema has to be initialized first");
try {
@@ -107,6 +116,10 @@ namespace Elwig.Helpers.Billing {
return new(ParseJson(json));
}
public string ToJsonString(JsonSerializerOptions? options = null) {
return Data.ToJsonString(options);
}
protected JsonArray GetCurvesEntry() {
return Data[Mode == CalculationMode.Elwig ? "curves" : "Kurven"]?.AsArray() ?? throw new InvalidOperationException();
}
@@ -412,7 +425,7 @@ namespace Elwig.Helpers.Billing {
}
}
public static JsonObject FromGraphEntries(
public static BillingData FromGraphEntries(
IEnumerable<GraphEntry> graphEntries,
BillingData? origData = null,
IEnumerable<RawVaribute>? vaributes = null,
@@ -449,37 +462,30 @@ namespace Elwig.Helpers.Billing {
CollapsePaymentData(payment, payment.DeepClone().AsObject(), vaributes ?? payment.Select(e => new RawVaribute(e.Key)).ToList(), useDefaultPayment);
CollapsePaymentData(qualityWei, qualityWei.DeepClone().AsObject(), vaributes ?? qualityWei.Select(e => new RawVaribute(e.Key)).ToList(), useDefaultQuality);
var data = new JsonObject {
["mode"] = "elwig",
["version"] = 1,
};
if (origData?.ConsiderDelieryModifiers == true)
data["consider_delivery_modifiers"] = true;
if (origData?.ConsiderContractPenalties == true)
data["consider_contract_penalties"] = true;
if (origData?.ConsiderTotalPenalty == true)
data["consider_total_penalty"] = true;
if (origData?.ConsiderAutoBusinessShares == true)
data["consider_auto_business_shares"] = true;
BillingData data;
if (origData != null && origData.Mode == CalculationMode.Elwig) {
data = new BillingData((JsonObject)origData.Data.DeepClone());
} else {
data = new BillingData();
}
if (payment.Count == 0) {
data["payment"] = 0;
data.Data["payment"] = 0;
} else if (payment.Count == 1 && payment.First().Key == "default") {
data["payment"] = payment.Single().Value?.DeepClone();
data.Data["payment"] = payment.Single().Value?.DeepClone();
} else {
data["payment"] = payment;
data.Data["payment"] = payment;
}
if (qualityWei.Count == 1 && qualityWei.First().Key == "default") {
data["quality"] = new JsonObject() {
data.Data["quality"] = new JsonObject() {
["WEI"] = qualityWei.Single().Value?.DeepClone()
};
} else if (qualityWei.Count >= 1) {
data["quality"] = new JsonObject() {
data.Data["quality"] = new JsonObject() {
["WEI"] = qualityWei
};
}
data["curves"] = curves;
data.Data["curves"] = curves;
return data;
}
+1 -1
View File
@@ -98,7 +98,7 @@ namespace Elwig.Helpers.Billing {
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 payment_custom x ON (x.year, x.mgnr) = (s.year, m.mgnr)
WHERE s.year = {Year} AND v.avnr = {AvNr} AND p.amount > COALESCE(lp.amount, 0);
WHERE s.year = {Year} AND v.avnr = {AvNr} AND p.amount != COALESCE(lp.amount, 0);
""");
await cnx.ExecuteBatch($"""
UPDATE payment_variant SET test_variant = FALSE WHERE (year, avnr) = ({Year}, {AvNr});
+38 -6
View File
@@ -8,6 +8,7 @@ using Elwig.ViewModels;
using Microsoft.EntityFrameworkCore;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
@@ -142,7 +143,7 @@ namespace Elwig.Services {
});
var credits = ctx.Credits.Where(c => c.Year == v.Year && c.AvNr == v.AvNr);
if (!credits.Any()) {
if (!(await credits.AnyAsync())) {
long lastTotalSum = 0;
decimal vatSum = 0;
var currentPayments = await ctx.MemberPayments
@@ -150,8 +151,7 @@ namespace Elwig.Services {
.ToDictionaryAsync(p => p.MgNr);
var lastV = await ctx.PaymentVariants
.Where(l => l.Year == v.Year && !l.TestVariant)
.OrderByDescending(l => l.TransferDateString ?? l.DateString)
.ThenByDescending(l => l.AvNr)
.OrderByDescending(l => l.TransferDateString ?? l.DateString).ThenByDescending(l => l.AvNr)
.FirstOrDefaultAsync();
if (lastV != null) {
var lastPayments = await ctx.MemberPayments
@@ -160,8 +160,8 @@ namespace Elwig.Services {
lastTotalSum = lastPayments.Sum(e => e.Value.AmountValue);
foreach (int mgnr in currentPayments.Keys) {
var c = currentPayments[mgnr];
var l = lastPayments[mgnr];
vatSum += (c.Amount - l.Amount) * (decimal)(c.Member.IsBuchführend ? v.Season.VatNormal : v.Season.VatFlatrate);
var l = lastPayments.GetValueOrDefault(mgnr);
vatSum += (c.Amount - (l?.Amount ?? 0)) * (decimal)(c.Member.IsBuchführend ? v.Season.VatNormal : v.Season.VatFlatrate);
}
} else {
vatSum = currentPayments.Sum(e => e.Value.Amount * (decimal)(e.Value.Member.IsBuchführend ? v.Season.VatNormal : v.Season.VatFlatrate));
@@ -226,7 +226,7 @@ namespace Elwig.Services {
public static async Task GenerateEbics(int year, int avnr) {
using var ctx = new AppDbContext();
var v = (await ctx.PaymentVariants.FindAsync(year, avnr))!;
var v = await ctx.PaymentVariants.Include(v => v.Credits).Where(v => v.Year == year && v.AvNr == avnr).SingleAsync();
var withoutIban = v.Credits.Count(c => c.Member.Iban == null);
if (withoutIban > 0) {
@@ -369,10 +369,42 @@ namespace Elwig.Services {
}
public static async Task Commit(int year, int avnr) {
List<Member> membersLess = [];
using (var ctx = new AppDbContext()) {
var lastAvNr = await ctx.PaymentVariants
.Where(v => v.Year == year && !v.TestVariant)
.OrderByDescending(v => v.TransferDateString ?? v.DateString).ThenByDescending(v => v.AvNr)
.Select(v => v.AvNr)
.FirstOrDefaultAsync();
if (lastAvNr != 0) {
var cur = await ctx.MemberPayments.Include(p => p.Member).Where(p => p.Year == year && p.AvNr == avnr).ToDictionaryAsync(p => p.Member.MgNr, p => p);
var last = await ctx.MemberPayments.Include(p => p.Member).Where(p => p.Year == year && p.AvNr == lastAvNr).ToDictionaryAsync(p => p.Member.MgNr, p => p);
membersLess = [.. last.Where(p => (cur.TryGetValue(p.Key, out var c) ? c.Amount : 0) < p.Value.Amount).Select(p => p.Value.Member)];
}
}
if (membersLess.Count > 0) {
var res = MessageBox.Show($"Achtung: Bei {membersLess.Count:N0} Mitglied(ern) ist der Soll-Betrag der Auszahlung (\"Gesamtbetrag\") kleiner als bei der letzten Auszahlung. Das sollte nicht vorkommen!\n\n" +
$"{string.Join(", ", membersLess.Select(m => $"{m.AdministrativeName} ({m.MgNr})"))}\n\n" +
"Soll trotzdem forgefahren werden?",
"Kleinerer Gesamtbetrag", MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
if (res != MessageBoxResult.OK)
return;
}
await Task.Run(async () => {
var b = await BillingVariant.Create(year, avnr);
await b.Commit();
});
List<Member> membersNeg = [];
using (var ctx = new AppDbContext()) {
membersNeg = await ctx.Credits.Where(c => c.Year == year && c.AvNr == avnr && c.AmountValue < 0).Select(c => c.Member).ToListAsync();
}
if (membersNeg.Count > 0) {
var res = MessageBox.Show($"Achtung: Bei {membersNeg.Count:N0} Mitglied(ern) ist der Auszahlungsbetrag negativ!\n\n" +
$"{string.Join(", ", membersNeg.Select(m => $"{m.AdministrativeName} ({m.MgNr})"))}",
"Negativer Auszahlungsbetrag", MessageBoxButton.OK, MessageBoxImage.Warning);
}
}
public static async Task Revert(int year, int avnr) {
+2 -2
View File
@@ -13,7 +13,7 @@ About
**Product:** Elwig
**Description:** Electronic Management for Vintners' Cooperatives
**Type:** ERP system
**Version:** 1.0.5.4 ([Changelog](./CHANGELOG.md))
**Version:** 1.0.5.5 ([Changelog](./CHANGELOG.md))
**License:** [GNU General Public License 3.0 (GPLv3)](./LICENSE)
**Website:** https://elwig.at/
**Source code:** https://git.necronda.net/winzer/elwig
@@ -33,7 +33,7 @@ Packaging: [WiX Toolset](https://www.firegiant.com/wixtoolset/)
**Produkt:** Elwig
**Beschreibung:** Elektronische Winzergenossenschaftsverwaltung
**Typ:** Warenwirtschaftssystem (ERP-System)
**Version:** 1.0.5.4 ([Änderungsprotokoll](./CHANGELOG.md))
**Version:** 1.0.5.5 ([Änderungsprotokoll](./CHANGELOG.md))
**Lizenz:** [GNU General Public License 3.0 (GPLv3)](./LICENSE)
**Website:** https://elwig.at/
**Quellcode:** https://git.necronda.net/winzer/elwig