Compare commits

...
6 Commits
Author SHA1 Message Date
lorenz.stechauner 034c0c4eb7 [WIP] certs
Test / Run tests (push) Successful in 1m56s
2026-09-22 15:38:23 +02:00
lorenz.stechauner c46094fe35 Entities/MemberHistory: Add CompanyHasSigned
Test / Run tests (push) Successful in 2m4s
2026-09-22 15:23:24 +02:00
lorenz.stechauner 64bef27f9f ClientParameters: Add ClientOrganicOperatorId 2026-09-22 15:16:59 +02:00
lorenz.stechauner f8cce56ecb Entities/WineCult: Add IsOrganic 2026-09-22 15:16:55 +02:00
lorenz.stechauner 3541f36831 Entities/Member: Add OrganicOperatorId
Test / Run tests (push) Failing after 2m14s
2026-09-22 14:33:03 +02:00
lorenz.stechauner 569913fe8f Entities/Member: Add OrganicAuthorityCode 2026-09-22 11:21:05 +02:00
32 changed files with 509 additions and 109 deletions
+25 -11
View File
@@ -34,19 +34,23 @@ namespace Elwig.Documents {
} }
} }
protected Cell NewAsideCell(Paragraph text, int colspan = 1, bool isName = false) { protected Cell NewAsideCell(Paragraph text, int colspan = 1, bool isName = false, bool right = false, bool center = false) {
var cell = NewCell(text, colspan: colspan).SetPaddingsMM(0.25f, 0.5f, 0.25f, isName ? 1 : 0); var cell = NewCell(text, colspan: colspan).SetPaddingsMM(0.25f, center ? 0 : right ? 1 : 0.5f, 0.25f, isName ? 1 : 0);
if (colspan == 26) { if (colspan == 26) {
cell.SetTextAlignment(TextAlignment.CENTER).SetFont(BF) cell.SetTextAlignment(TextAlignment.CENTER).SetFont(BF)
.SetBackgroundColor(new DeviceRgb(0xe0, 0xe0, 0xe0)) .SetBackgroundColor(new DeviceRgb(0xe0, 0xe0, 0xe0))
.SetBorderTop(new SolidBorder(new DeviceRgb(0x80, 0x80, 0x80), BorderThickness)) .SetBorderTop(new SolidBorder(new DeviceRgb(0x80, 0x80, 0x80), BorderThickness))
.SetPaddingsMM(0.5f, 1, 0.5f, 1); .SetPaddingsMM(0.5f, 1, 0.5f, 1);
} else if (isName) {
cell.SetBorderLeft(new SolidBorder(new DeviceRgb(0x80, 0x80, 0x80), BorderThickness));
} }
if (right) cell.SetTextAlignment(TextAlignment.RIGHT);
if (center) cell.SetTextAlignment(TextAlignment.CENTER);
return cell; return cell;
} }
protected Cell NewAsideCell(string text, int colspan = 1, bool isName = false) { protected Cell NewAsideCell(string text, int colspan = 1, bool isName = false, bool right = false, bool center = false) {
return NewAsideCell(new KernedParagraph(text, 10), colspan, isName); return NewAsideCell(new KernedParagraph(text, 10), colspan, isName, right, center);
} }
public BusinessDocument(string title, Member m, DateOnly? dateFrom, bool includeSender = false) : public BusinessDocument(string title, Member m, DateOnly? dateFrom, bool includeSender = false) :
@@ -60,17 +64,27 @@ namespace Elwig.Documents {
protected override void BeforeRenderBody(iText.Layout.Document doc, PdfDocument pdf) { protected override void BeforeRenderBody(iText.Layout.Document doc, PdfDocument pdf) {
base.BeforeRenderBody(doc, pdf); base.BeforeRenderBody(doc, pdf);
var uid = new KernedParagraph(Member.UstIdNr ?? "-", 10);
if (!Member.IsBuchführend) uid.Add(Normal(" ")).Add(Italic("(pauschaliert)"));
Aside = new Table(ColsMM(2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5)) Aside = new Table(ColsMM(2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5))
.SetWidth(UnitValue.CreatePointValue(65 * PtInMM)).SetFixedLayout() .SetWidth(UnitValue.CreatePointValue(65 * PtInMM)).SetFixedLayout()
.SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE) .SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE)
.SetFont(NF).SetFontSize(10) .SetFont(NF).SetFontSize(10)
.SetBorder(new SolidBorder(new DeviceRgb(0x80, 0x80, 0x80), BorderThickness)) .SetBorder(new SolidBorder(new DeviceRgb(0x80, 0x80, 0x80), BorderThickness))
.AddCell(NewAsideCell("Mitglied", 26)) .AddCell(NewAsideCell("Mitglied", 26));
.AddCell(NewAsideCell("Mitglieds-Nr.:", 9, isName: true)).AddCell(NewAsideCell($"{Member.MgNr}", 17)) if (Member.IsOrganic) {
.AddCell(NewAsideCell("Betriebs-Nr.:", 9, isName: true)).AddCell(NewAsideCell(Member.LfbisNr ?? "", 17)) Aside
.AddCell(NewAsideCell("UID:", 9, isName: true)).AddCell(NewAsideCell(uid, 17)); .AddCell(NewAsideCell("Mitgl.-Nr.:", 8, isName: true)).AddCell(NewAsideCell($"{Member.MgNr}", 4, right: true))
.AddCell(NewAsideCell("Bio-KSt.:", 6, isName: true)).AddCell(NewAsideCell(Member.OrganicAuthorityCode ?? "-", 8, right: true, center: Member.OrganicAuthorityCode == null))
.AddCell(NewAsideCell("Betr.-Nr.:", 6, isName: true)).AddCell(NewAsideCell(Member.LfbisNr ?? "-", 6, right: true, center: Member.LfbisNr == null))
.AddCell(NewAsideCell("OOC-ID:", 6, isName: true)).AddCell(NewAsideCell(Member.OrganicOperatorId ?? "-", 8, right: true, center: Member.OrganicOperatorId == null))
.AddCell(NewAsideCell("UID:", 6, isName: true)).AddCell(NewAsideCell(Member.UstIdNr ?? "-", 10, right: true, center: Member.UstIdNr == null))
.AddCell(NewAsideCell(new KernedParagraph("", 10).Add(Italic(Member.IsBuchführend ? "(buchführend)" : "(pauschaliert)")), 10, center: true));
} else {
Aside
.AddCell(NewAsideCell("Mitglieds-Nr.:", 12, isName: true)).AddCell(NewAsideCell($"{Member.MgNr}", 4, right: true)).AddCell(NewAsideCell("", 10))
.AddCell(NewAsideCell("Betriebs-Nr.:", 10, isName: true)).AddCell(NewAsideCell(Member.LfbisNr ?? "-", 6, right: true, center: Member.LfbisNr == null)).AddCell(NewAsideCell("", 10))
.AddCell(NewAsideCell("UID:", 6, isName: true)).AddCell(NewAsideCell(Member.UstIdNr ?? "-", 10, right: true, center: Member.UstIdNr == null))
.AddCell(NewAsideCell(new KernedParagraph("", 10).Add(Italic(Member.IsBuchführend ? "(buchführend)" : "(pauschaliert)")), 10, center: true));
}
} }
protected void RenderAddress(Canvas canvas, Rectangle pageSize) { protected void RenderAddress(Canvas canvas, Rectangle pageSize) {
@@ -126,7 +140,7 @@ namespace Elwig.Documents {
.Item(c.Address).Item($"{c.Plz} {c.Ort}").Item("Österreich").Item("Tel.", c.PhoneNr).Item("Fax", c.FaxNr).NextLine() .Item(c.Address).Item($"{c.Plz} {c.Ort}").Item("Österreich").Item("Tel.", c.PhoneNr).Item("Fax", c.FaxNr).NextLine()
.Item(c.EmailAddress != null ? link1 : null) .Item(c.EmailAddress != null ? link1 : null)
.Item(c.Website != null ? link2 : null) .Item(c.Website != null ? link2 : null)
.Item("Betriebs-Nr.", c.LfbisNr).Item("Bio-KSt.", c.OrganicAuthority).NextLine() .Item("Betriebs-Nr.", c.LfbisNr).Item("Bio-KSt.", c.OrganicAuthorityCode).NextLine()
.Item("UID", c.UstIdNr).Item("BIC", c.Bic).Item("IBAN", c.Iban) .Item("UID", c.UstIdNr).Item("BIC", c.Bic).Item("IBAN", c.Iban)
.ToLeafElements()); .ToLeafElements());
} }
+3 -3
View File
@@ -56,9 +56,9 @@ namespace Elwig.Documents {
var firstDay = Data.Rows.MinBy(r => r.Date)?.Date; var firstDay = Data.Rows.MinBy(r => r.Date)?.Date;
var lastDay = Data.Rows.MaxBy(r => r.Date)?.Date; var lastDay = Data.Rows.MaxBy(r => r.Date)?.Date;
Aside?.AddCell(NewAsideCell("Saison", 26)) Aside?.AddCell(NewAsideCell("Saison", 26))
.AddCell(NewAsideCell("Lieferungen:", 9, isName: true)).AddCell(NewAsideCell($"{Data.Rows.DistinctBy(r => r.LsNr).Count():N0} (Teil-Lfrg.: {Data.RowNum:N0})", 17)) .AddCell(NewAsideCell("Lieferungen:", 12, isName: true)).AddCell(NewAsideCell($"{Data.Rows.DistinctBy(r => r.LsNr).Count():N0} (Teil-Lfrg.: {Data.RowNum:N0})", 14))
.AddCell(NewAsideCell("Zeitraum:", 9, isName: true)).AddCell(NewAsideCell(firstDay == null || lastDay == null ? "-" : firstDay == lastDay ? $"{firstDay:dd.MM.} (1 Tag)" : $"{firstDay:dd.MM.}\u2013{lastDay:dd.MM.} ({lastDay?.DayNumber - firstDay?.DayNumber + 1:N0} Tage)", 17)) .AddCell(NewAsideCell("Zeitraum:", 8, isName: true)).AddCell(NewAsideCell(firstDay == null || lastDay == null ? "-" : firstDay == lastDay ? $"{firstDay:dd.MM.} (1 Tag)" : $"{firstDay:dd.MM.}\u2013{lastDay:dd.MM.} ({lastDay?.DayNumber - firstDay?.DayNumber + 1:N0} Tage)", 18, center: true))
.AddCell(NewAsideCell("Menge:", 9, isName: true)).AddCell(NewAsideCell($"{MemberStats.Sum(s => s.Weight):N0} kg", 17)); .AddCell(NewAsideCell("Menge:", 12, isName: true)).AddCell(NewAsideCell($"{MemberStats.Sum(s => s.Weight):N0} kg", 14));
} }
protected override void RenderBody(iText.Layout.Document doc, PdfDocument pdf) { protected override void RenderBody(iText.Layout.Document doc, PdfDocument pdf) {
+3
View File
@@ -153,6 +153,9 @@ namespace Elwig.Documents {
if (part.Cultivation != null) { if (part.Cultivation != null) {
var cult = new KernedParagraph(8); var cult = new KernedParagraph(8);
cult.Add(Italic("Bewirtschaftung:")).Add(Normal(" " + part.Cultivation.Name + (part.Cultivation.Description != null ? $" ({part.Cultivation.Description})" : ""))); cult.Add(Italic("Bewirtschaftung:")).Add(Normal(" " + part.Cultivation.Name + (part.Cultivation.Description != null ? $" ({part.Cultivation.Description})" : "")));
if (part.Cultivation.IsOrganic) {
cult.Add(" \u2013 ").Add(Italic("Kontrollstelle:")).Add(Normal($" {Member.OrganicAuthorityCode ?? "?"}"));
}
sub.AddCell(NewTd()) sub.AddCell(NewTd())
.AddCell(NewTd(cult, colspan: 5)) .AddCell(NewTd(cult, colspan: 5))
.AddCell(NewTd(colspan: 3)); .AddCell(NewTd(colspan: 3));
+2 -1
View File
@@ -161,7 +161,8 @@ namespace Elwig.Documents {
.AddCell(NewDataTh("Buchführend:", colspan: 2)).AddCell(NewTd(new KernedParagraph(Member.IsBuchführend ? "Ja " : "Nein ", 10) .AddCell(NewDataTh("Buchführend:", colspan: 2)).AddCell(NewTd(new KernedParagraph(Member.IsBuchführend ? "Ja " : "Nein ", 10)
.Add(Normal($"({(Member.IsBuchführend ? season.VatNormal : season.VatFlatrate) * 100:N0}% USt.)", 8)), colspan: 2)) .Add(Normal($"({(Member.IsBuchführend ? season.VatNormal : season.VatFlatrate) * 100:N0}% USt.)", 8)), colspan: 2))
.AddCell(NewDataTh("(Katastralgemeinde mit dem größten Anteil an Weinbauflächen)", 8, colspan: 2)) .AddCell(NewDataTh("(Katastralgemeinde mit dem größten Anteil an Weinbauflächen)", 8, colspan: 2))
.AddCell(NewDataTh("Bio:", colspan: 2)).AddCell(NewTd(Member.IsOrganic ? "Ja" : "Nein", colspan: 2)) .AddCell(NewDataTh("Bio:", colspan: 2)).AddCell(NewTd(new KernedParagraph(Member.IsOrganic ? "Ja" : "Nein", 10)
.Add(Normal(Member.OrganicAuthorityCode != null || Member.OrganicOperatorId != null ? $" ({Member.OrganicAuthorityCode}{(Member.OrganicAuthorityCode != null && Member.OrganicOperatorId != null ? ", " : "")}{Member.OrganicOperatorId})" : "", 8)), colspan: 2))
.AddCell(NewDataHdr("Genossenschaft", colspan: 6)) .AddCell(NewDataHdr("Genossenschaft", colspan: 6))
.AddCell(NewDataTh("Status:")).AddCell(NewTd(new KernedParagraph(Member.IsActive ? "Aktiv " : "Nicht aktiv ", 10) .AddCell(NewDataTh("Status:")).AddCell(NewTd(new KernedParagraph(Member.IsActive ? "Aktiv " : "Nicht aktiv ", 10)
.Add(Normal("(" + (Member.ExitDate != null ? $"{Member.EntryDate:dd.MM.yyyy}\u2013{Member.ExitDate:dd.MM.yyyy}" : $"seit {Member.EntryDate:dd.MM.yyyy}") + ")", 8)))) .Add(Normal("(" + (Member.ExitDate != null ? $"{Member.EntryDate:dd.MM.yyyy}\u2013{Member.ExitDate:dd.MM.yyyy}" : $"seit {Member.EntryDate:dd.MM.yyyy}") + ")", 8))))
+56 -4
View File
@@ -1,3 +1,5 @@
using Elwig.Services;
using Microsoft.Data.Sqlite;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
@@ -9,7 +11,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 = 41; public static readonly int RequiredSchemaVersion = 42;
private static int VersionOffset = 0; private static int VersionOffset = 0;
@@ -68,11 +70,11 @@ namespace Elwig.Helpers {
}) })
.OrderBy(s => s.Item1).ThenBy(s => s.Item2)]; .OrderBy(s => s.Item1).ThenBy(s => s.Item2)];
List<string> toExecute = []; List<(int ToVersion, string File)> toExecute = [];
var vers = fromVersion; var vers = fromVersion;
while (vers < toVersion) { while (vers < toVersion) {
var (_, to, name) = scripts.Last(s => s.From == vers); var (_, to, name) = scripts.Last(s => s.From == vers);
toExecute.Add(name); toExecute.Add((to, name));
vers = to; vers = to;
} }
if (toExecute.Count == 0) if (toExecute.Count == 0)
@@ -87,8 +89,11 @@ namespace Elwig.Helpers {
await cnx.IntegrityCheck(); await cnx.IntegrityCheck();
await cnx.ForeignKeyCheck(); await cnx.ForeignKeyCheck();
foreach (var script in toExecute) { foreach (var (to, script) in toExecute) {
await cnx.ExecuteEmbeddedScript(asm, script); await cnx.ExecuteEmbeddedScript(asm, script);
if (to == 42) {
await UpdateDbSchema_41_To_42(cnx);
}
} }
await cnx.IntegrityCheck(); await cnx.IntegrityCheck();
@@ -103,5 +108,52 @@ namespace Elwig.Helpers {
File.Delete(backup); File.Delete(backup);
} }
} }
private static async Task UpdateDbSchema_41_To_42(SqliteConnection cnx) {
List<(int MgNr, string LfbisNr, string Name, string Address, int Plz)> members = [];
using (var cmd = cnx.CreateCommand()) {
cmd.CommandText = """
SELECT m.mgnr, m.lfbis_nr,
COALESCE(a.name, (COALESCE(m.prefix || ' ', '') || COALESCE(m.given_name || ' ', '') || m.name || COALESCE(' ' || m.middle_names, '') || COALESCE(' ' || m.suffix, ''))),
COALESCE(a.address, m.address),
COALESCE(aplz.plz, mplz.plz)
FROM member m
JOIN postal_dest mp ON (mp.country, mp.id) = (m.country, m.postal_dest)
JOIN AT_plz_dest ma ON (ma.country, ma.id) = (mp.country, mp.id)
JOIN AT_plz mplz ON mplz.plz = ma.plz
LEFT JOIN member_billing_address a ON a.mgnr = m.mgnr
LEFT JOIN postal_dest ap ON (ap.country, ap.id) = (a.country, a.postal_dest)
LEFT JOIN AT_plz_dest aa ON (aa.country, aa.id) = (ap.country, mp.id)
LEFT JOIN AT_plz aplz ON aplz.plz = aa.plz
WHERE organic
""";
using var reader = await cmd.ExecuteReaderAsync();
var header = await reader.GetColumnSchemaAsync();
while (await reader.ReadAsync()) {
members.Add((reader.GetInt32(0), reader.GetString(1), reader.GetString(2), reader.GetString(3), reader.GetInt32(4)));
}
}
if (members.Count > 0)
InteractionService.ShowInformation("Datenbank-Update", "Es wird versucht, die Bio-Kontrollstellen-Informationen der Mitglieder automatisch zu laden. Dies könnte einen kurzen Moment in Anspruch nehmen.");
foreach (var m in members) {
string? oocId = null;
string? authCode = null;
var certs = await OrganicService.FetchTracesCertificates(null, m.LfbisNr, (m.Name, m.Address, m.Plz.ToString()));
if (certs.Length > 0) {
oocId = certs[0].OperatorId;
authCode = certs[0].AuthorityCode;
}
if (oocId != null || authCode != null) {
oocId = oocId == null ? "NULL" : $"'{oocId}'";
authCode = authCode == null ? "NULL" : $"'{authCode}'";
await cnx.ExecuteBatch($"UPDATE member SET ooc_id = {oocId}, org_auth_code = {authCode} WHERE mgnr = {m.MgNr}");
}
}
}
} }
} }
+6 -3
View File
@@ -49,7 +49,8 @@ namespace Elwig.Helpers {
public string? Bic; public string? Bic;
public string? UstIdNr; public string? UstIdNr;
public string? LfbisNr; public string? LfbisNr;
public string? OrganicAuthority; public string? OrganicOperatorId;
public string? OrganicAuthorityCode;
public string? PhoneNr; public string? PhoneNr;
public string? FaxNr; public string? FaxNr;
@@ -114,7 +115,8 @@ namespace Elwig.Helpers {
UstIdNr = parameters.GetValueOrDefault("CLIENT_USTIDNR"); UstIdNr = parameters.GetValueOrDefault("CLIENT_USTIDNR");
Bic = parameters.GetValueOrDefault("CLIENT_BIC"); Bic = parameters.GetValueOrDefault("CLIENT_BIC");
Iban = parameters.GetValueOrDefault("CLIENT_IBAN"); Iban = parameters.GetValueOrDefault("CLIENT_IBAN");
OrganicAuthority = parameters.GetValueOrDefault("CLIENT_ORGANIC_AUTHORITY"); OrganicOperatorId = parameters.GetValueOrDefault("CLIENT_ORGANIC_OPERATORID");
OrganicAuthorityCode = parameters.GetValueOrDefault("CLIENT_ORGANIC_AUTHORITYCODE");
EnableMemberHistory = (parameters.GetValueOrDefault("ENABLE_MEMBERHISTORY")?.ToUpper()) switch { EnableMemberHistory = (parameters.GetValueOrDefault("ENABLE_MEMBERHISTORY")?.ToUpper()) switch {
"1" or "TRUE" or "YES" or "JA" => true, "1" or "TRUE" or "YES" or "JA" => true,
@@ -273,7 +275,8 @@ namespace Elwig.Helpers {
("CLIENT_USTIDNR", UstIdNr), ("CLIENT_USTIDNR", UstIdNr),
("CLIENT_BIC", Bic), ("CLIENT_BIC", Bic),
("CLIENT_IBAN", Iban), ("CLIENT_IBAN", Iban),
("CLIENT_ORGANIC_AUTHORITY", OrganicAuthority), ("CLIENT_ORGANIC_OPERATORID", OrganicOperatorId),
("CLIENT_ORGANIC_AUTHORITYCODE", OrganicAuthorityCode),
("ENABLE_MEMBERHISTORY", EnableMemberHistory ? "YES" : "NO"), ("ENABLE_MEMBERHISTORY", EnableMemberHistory ? "YES" : "NO"),
("MODE_BUSINESSSHARES", businessShares), ("MODE_BUSINESSSHARES", businessShares),
("MODE_DELIVERYNOTE_STATS", deliveryNoteStats), ("MODE_DELIVERYNOTE_STATS", deliveryNoteStats),
+8 -2
View File
@@ -638,6 +638,8 @@ namespace Elwig.Helpers.Export {
["zwstid"] = m.ZwstId, ["zwstid"] = m.ZwstId,
["lfbis_nr"] = m.LfbisNr, ["lfbis_nr"] = m.LfbisNr,
["ustid_nr"] = m.UstIdNr, ["ustid_nr"] = m.UstIdNr,
["ooc_id"] = m.OrganicOperatorId,
["org_auth_code"] = m.OrganicAuthorityCode,
["juridical_pers"] = m.IsJuridicalPerson, ["juridical_pers"] = m.IsJuridicalPerson,
["volllieferant"] = m.IsVollLieferant, ["volllieferant"] = m.IsVollLieferant,
["buchführend"] = m.IsBuchführend, ["buchführend"] = m.IsBuchführend,
@@ -710,6 +712,8 @@ namespace Elwig.Helpers.Export {
ZwstId = json["zwstid"]?.AsValue().GetValue<string>(), ZwstId = json["zwstid"]?.AsValue().GetValue<string>(),
LfbisNr = json["lfbis_nr"]?.AsValue().GetValue<string>(), LfbisNr = json["lfbis_nr"]?.AsValue().GetValue<string>(),
UstIdNr = json["ustid_nr"]?.AsValue().GetValue<string>(), UstIdNr = json["ustid_nr"]?.AsValue().GetValue<string>(),
OrganicOperatorId = json["ooc_id"]?.AsValue().GetValue<string>(),
OrganicAuthorityCode = json["org_auth_code"]?.AsValue().GetValue<string>(),
IsJuridicalPerson = json["juridical_pers"]?.AsValue().GetValue<bool>() ?? false, IsJuridicalPerson = json["juridical_pers"]?.AsValue().GetValue<bool>() ?? false,
IsVollLieferant = json["volllieferant"]?.AsValue().GetValue<bool>() ?? false, IsVollLieferant = json["volllieferant"]?.AsValue().GetValue<bool>() ?? false,
IsBuchführend = json["buchführend"]?.AsValue().GetValue<bool>() ?? false, IsBuchführend = json["buchführend"]?.AsValue().GetValue<bool>() ?? false,
@@ -762,7 +766,8 @@ namespace Elwig.Helpers.Export {
["reason"] = h.Reason, ["reason"] = h.Reason,
["source"] = h.Source, ["source"] = h.Source,
["shares"] = h.Shares, ["shares"] = h.Shares,
["signed"] = h.MemberHasSigned, ["signed_company"] = h.CompanyHasSigned,
["signed_member"] = h.MemberHasSigned,
["value_per_share"] = h.ValuePerShare, ["value_per_share"] = h.ValuePerShare,
["currency"] = h.CurrencyCode, ["currency"] = h.CurrencyCode,
["deduct_year"] = h.DeductYear, ["deduct_year"] = h.DeductYear,
@@ -782,7 +787,8 @@ namespace Elwig.Helpers.Export {
Reason = json["reason"]!.AsValue().GetValue<string>(), Reason = json["reason"]!.AsValue().GetValue<string>(),
Source = json["source"]!.AsValue().GetValue<string>(), Source = json["source"]!.AsValue().GetValue<string>(),
Shares = json["shares"]!.AsValue().GetValue<int>(), Shares = json["shares"]!.AsValue().GetValue<int>(),
MemberHasSigned = json["signed"]?.AsValue().GetValue<bool>() ?? false, CompanyHasSigned = json["signed_company"]?.AsValue().GetValue<bool>() ?? false,
MemberHasSigned = json["signed_member"]?.AsValue().GetValue<bool>() ?? false,
ValuePerShare = json["value_per_share"]?.AsValue().GetValue<decimal>(), ValuePerShare = json["value_per_share"]?.AsValue().GetValue<decimal>(),
CurrencyCode = json["currency"]?.AsValue().GetValue<string>(), CurrencyCode = json["currency"]?.AsValue().GetValue<string>(),
DeductYear = json["deduct_year"]?.AsValue().GetValue<int>(), DeductYear = json["deduct_year"]?.AsValue().GetValue<int>(),
+46 -7
View File
@@ -623,6 +623,37 @@ namespace Elwig.Helpers {
return new(true, null); return new(true, null);
} }
public static ValidationResult CheckOrganicOperatorId(TextBox input, bool required) {
string text = "";
int pos = input.CaretIndex;
for (int i = 0, v = 0; i < input.Text.Length; i++) {
char ch = input.Text[i];
if (char.IsAsciiDigit(ch)) {
if (v == 3 && text[^1] != '-')
text += "-";
v++;
text += ch;
}
if (i == input.CaretIndex - 1) {
pos = text.Length;
} else if (v >= 10) {
break;
}
}
input.Text = text;
input.CaretIndex = pos;
if (text.Length == 0) {
return required ? new(false, "OOC-ID ist nicht optional") : new(true, null);
} else if (!text.StartsWith("040-") || text.Length != 11) {
return new(false, "OOC-ID ist ungültig");
}
return new(true, null);
}
public static ValidationResult CheckOrganicAuthorityCode(TextBox input, bool required) { public static ValidationResult CheckOrganicAuthorityCode(TextBox input, bool required) {
string text = ""; string text = "";
int pos = input.CaretIndex; int pos = input.CaretIndex;
@@ -631,15 +662,18 @@ namespace Elwig.Helpers {
if (v < 2 && char.IsAsciiLetter(ch)) { if (v < 2 && char.IsAsciiLetter(ch)) {
v++; v++;
text += ch; text += ch;
} else if ((v == 2 || v == 6) && ch == '-') { } else if ((v == 2 || v == 5) && ch == '-' && text[^1] != '-') {
v++;
text += ch; text += ch;
} else if (v >= 2 && char.IsLetterOrDigit(ch)) { } else if (v >= 2 && v <= 4 && char.IsLetter(ch)) {
if (v == 2 && text[^1] != '-')
text += "-";
if (text.StartsWith("AT")) { if (text.StartsWith("AT")) {
if (v == 3 && ch == 'B' || v == 4 && ch == 'I' || v == 5 && ch == 'O') { if (v == 2 && ch == 'B' || v == 3 && ch == 'I' || v == 4 && ch == 'O') {
v++; v++;
text += ch; text += ch;
} else if (v > 6 && char.IsAsciiDigit(ch)) { }
} else if (text.StartsWith("DE")) {
if (v == 2 && ch == 'Ö' || v == 3 && ch == 'K' || v == 4 && ch == 'O') {
v++; v++;
text += ch; text += ch;
} }
@@ -647,11 +681,16 @@ namespace Elwig.Helpers {
v++; v++;
text += ch; text += ch;
} }
} else if (v >= 5 && v <= 7 && char.IsAsciiDigit(ch)) {
if (v == 5 && text[^1] != '-')
text += "-";
v++;
text += ch;
} }
if (i == input.CaretIndex - 1) { if (i == input.CaretIndex - 1) {
pos = text.Length; pos = text.Length;
} else if (text.StartsWith("AT") && v >= 10) { } else if ((text.StartsWith("AT") || text.StartsWith("DE")) && v >= 10) {
break; break;
} }
} }
@@ -662,7 +701,7 @@ namespace Elwig.Helpers {
if (text.Length == 0) if (text.Length == 0)
return required ? new(false, "Bio-Kontrollstellen-Code ist nicht optional") : new(true, null); return required ? new(false, "Bio-Kontrollstellen-Code ist nicht optional") : new(true, null);
if (text.StartsWith("AT")) { if (text.StartsWith("AT") || text.StartsWith("DE")) {
if (text.Length != 10) { if (text.Length != 10) {
return new(false, "Bio-Kontrollstellen-Code ist ungültig"); return new(false, "Bio-Kontrollstellen-Code ist ungültig");
} }
+6
View File
@@ -96,6 +96,12 @@ namespace Elwig.Models.Entities {
[Column("ustid_nr")] [Column("ustid_nr")]
public string? UstIdNr { get; set; } public string? UstIdNr { get; set; }
[Column("ooc_id")]
public string? OrganicOperatorId { get; set; }
[Column("org_auth_code")]
public string? OrganicAuthorityCode { get; set; }
[Column("juridical_pers")] [Column("juridical_pers")]
public bool IsJuridicalPerson { get; set; } public bool IsJuridicalPerson { get; set; }
+4 -1
View File
@@ -76,7 +76,10 @@ namespace Elwig.Models.Entities {
[Column("shares")] [Column("shares")]
public int Shares { get; set; } public int Shares { get; set; }
[Column("signed")] [Column("signed_company")]
public bool CompanyHasSigned { get; set; }
[Column("signed_member")]
public bool MemberHasSigned { get; set; } public bool MemberHasSigned { get; set; }
[Column("value_per_share")] [Column("value_per_share")]
+3
View File
@@ -11,6 +11,9 @@ namespace Elwig.Models.Entities {
[Column("name")] [Column("name")]
public required string Name { get; set; } public required string Name { get; set; }
[Column("organic")]
public bool IsOrganic { get; set; }
[Column("description")] [Column("description")]
public string? Description { get; set; } public string? Description { get; set; }
+22
View File
@@ -0,0 +1,22 @@
-- schema version 41 to 42
ALTER TABLE member ADD COLUMN ooc_id TEXT CHECK (ooc_id REGEXP '^[0-9]{3}-[0-9]{7}$') DEFAULT NULL;
ALTER TABLE member ADD COLUMN org_auth_code TEXT CHECK (org_auth_code REGEXP '^[A-Z]{2}-[A-ZÖØ]{3}-[0-9]{2,3}(-[A-Z]{2})?$') DEFAULT NULL;
ALTER TABLE wine_cultivation ADD COLUMN organic INTEGER NOT NULL CHECK (organic IN (TRUE, FALSE)) DEFAULT FALSE;
ALTER TABLE member_history RENAME COLUMN signed TO signed_member;
ALTER TABLE member_history ADD COLUMN signed_company INTEGER NOT NULL CHECK (signed_company IN (TRUE, FALSE)) DEFAULT FALSE;
UPDATE member SET org_auth_code = UPPER(SUBSTR(a.name, -11, 10)) FROM member m JOIN member_billing_address a ON a.mgnr = m.mgnr WHERE a.name LIKE '%AT-BIO-___)';
UPDATE member SET org_auth_code = UPPER(SUBSTR(a.name, -10, 10)) FROM member m JOIN member_billing_address a ON a.mgnr = m.mgnr WHERE a.name LIKE '%AT-BIO-___';
UPDATE member SET org_auth_code = UPPER(suffix) WHERE suffix LIKE 'AT-BIO-___';
UPDATE wine_cultivation SET organic = TRUE WHERE name LIKE '%bio%' OR name LIKE '%org%' OR description LIKE '%AT-BIO-%';
UPDATE wine_cultivation SET description = NULL WHERE description LIKE '%AT-BIO-%';
UPDATE wine_cultivation SET description = 'Biologische Produktion' WHERE organic;
UPDATE client_parameter SET param = 'CLIENT_ORGANIC_AUTHORITYCODE' WHERE param = 'CLIENT_ORGANIC_AUTHORITY';
UPDATE member_telephone_number SET comment = NULL WHERE comment = '';
UPDATE member_email_address SET comment = NULL WHERE comment = '';
@@ -26,6 +26,7 @@ namespace Elwig.Services {
vm.DateEffective = h.DateEffective; vm.DateEffective = h.DateEffective;
vm.Reason = h.Reason + (h.Reason == MemberHistory.REASON_TRANSFER ? $"_{(h.ToMgNr == mgnr ? "from" : "to")}" : ""); vm.Reason = h.Reason + (h.Reason == MemberHistory.REASON_TRANSFER ? $"_{(h.ToMgNr == mgnr ? "from" : "to")}" : "");
vm.Shares = h.Shares; vm.Shares = h.Shares;
vm.CompanyHasSigned = h.CompanyHasSigned;
vm.MemberHasSigned = h.MemberHasSigned; vm.MemberHasSigned = h.MemberHasSigned;
vm.ValuePerShare = h.ValuePerShare; vm.ValuePerShare = h.ValuePerShare;
vm.OtherMgNr = h.FromMgNr != null && h.FromMgNr != mgnr ? h.FromMgNr : h.ToMgNr != null && h.ToMgNr != mgnr ? h.ToMgNr : null; vm.OtherMgNr = h.FromMgNr != null && h.FromMgNr != mgnr ? h.FromMgNr : h.ToMgNr != null && h.ToMgNr != mgnr ? h.ToMgNr : null;
@@ -63,6 +64,7 @@ namespace Elwig.Services {
Reason = vm.Reason?.Split("_")[0] ?? MemberHistory.REASON_CONVERT, Reason = vm.Reason?.Split("_")[0] ?? MemberHistory.REASON_CONVERT,
Source = "manual", Source = "manual",
Shares = vm.Shares ?? 0, Shares = vm.Shares ?? 0,
CompanyHasSigned = vm.CompanyHasSigned,
MemberHasSigned = vm.MemberHasSigned, MemberHasSigned = vm.MemberHasSigned,
ValuePerShare = vm.ValuePerShare, ValuePerShare = vm.ValuePerShare,
CurrencyCode = vm.ValuePerShare != null ? "EUR" : null, CurrencyCode = vm.ValuePerShare != null ? "EUR" : null,
+60 -4
View File
@@ -10,6 +10,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Media;
namespace Elwig.Services { namespace Elwig.Services {
public static class MemberService { public static class MemberService {
@@ -106,6 +107,8 @@ namespace Elwig.Services {
vm.UstIdNr = m.UstIdNr; vm.UstIdNr = m.UstIdNr;
vm.LfbisNr = m.LfbisNr; vm.LfbisNr = m.LfbisNr;
vm.OrganicOperatorId = m.OrganicOperatorId;
vm.OrganicAuthorityCode = m.OrganicAuthorityCode;
vm.IsBuchführend = m.IsBuchführend; vm.IsBuchführend = m.IsBuchführend;
vm.IsOrganic = m.IsOrganic; vm.IsOrganic = m.IsOrganic;
@@ -187,10 +190,9 @@ namespace Elwig.Services {
.GroupBy(d => d.Year) .GroupBy(d => d.Year)
.ToDictionaryAsync(g => g.Key, g => g.Any()); .ToDictionaryAsync(g => g.Key, g => g.Any());
await App.MainDispatcher.BeginInvoke(() => {
if (m.MgNr != vm.MgNr) if (m.MgNr != vm.MgNr)
return; return;
await App.MainDispatcher.BeginInvoke(() => {
var (d1Grid, _) = DeliveryService.GenerateToolTip(d1GridData, []); var (d1Grid, _) = DeliveryService.GenerateToolTip(d1GridData, []);
var (d2Grid, _) = DeliveryService.GenerateToolTip(d2GridData, []); var (d2Grid, _) = DeliveryService.GenerateToolTip(d2GridData, []);
var grid = AreaComService.GenerateToolTip(gridData); var grid = AreaComService.GenerateToolTip(gridData);
@@ -203,13 +205,65 @@ namespace Elwig.Services {
vm.StatusAreaCommitmentInfo = $"{Utils.CurrentLastSeason}"; vm.StatusAreaCommitmentInfo = $"{Utils.CurrentLastSeason}";
vm.StatusAreaCommitment = text; vm.StatusAreaCommitment = text;
vm.StatusAreaCommitmentToolTip = grid; vm.StatusAreaCommitmentToolTip = grid;
vm.MemberHasDeliveries = Enumerable.Range(0, 9999).Select(i => deliveries.GetValueOrDefault(i, false)).ToList(); vm.MemberHasDeliveries = [.. Enumerable.Range(0, 9999).Select(i => deliveries.GetValueOrDefault(i, false))];
});
});
vm.OrganicTest1 = null;
vm.OrganicTest2 = "...";
vm.OrganicTest3 = Brushes.Black;
vm.OrganicTest4 = null;
Utils.RunBackground("Bio-Zertifikatsdaten laden", async () => {
if (App.MainDispatcher == null || !m.IsOrganic)
return;
var certs = await OrganicService.GetTracesCertificates(m);
// TODO button for TRACES search url
// TODO button for authority search url
await App.MainDispatcher.BeginInvoke(() => {
if (m.MgNr != vm.MgNr)
return;
vm.OrganicTest2 = null;
if (certs.Length == 0) {
vm.OrganicTest1 = "Nicht gefunden";
vm.OrganicTest3 = Brushes.DarkRed;
} else {
var cert = certs[0];
vm.OrganicTest4 = $"Zertifikat-Nr.: {cert.Id}\nBio-KSt.: {cert.AuthorityCode}\nEU Operator-ID: {cert.OperatorId}\nOperator: {cert.OperatorName}";
if (cert.IsValidForWineProduction) {
vm.OrganicTest1 = "Gültig";
vm.OrganicTest2 = $" (bis {cert.ExpiresOn:dd.MM.yyyy})";
vm.OrganicTest3 = Brushes.DarkGreen;
} else if (cert.IsValid) {
vm.OrganicTest1 = "Teilw. gültig";
vm.OrganicTest2 = $" (bis {cert.ExpiresOn:dd.MM.yyyy})";
vm.OrganicTest3 = Brushes.OrangeRed;
} else {
vm.OrganicTest3 = Brushes.DarkRed;
switch (cert.Status) {
case OrganicService.TracesStatus.ISSUED:
vm.OrganicTest1 = "Ausgestellt";
vm.OrganicTest2 = $" (am {cert.LastStatusUpdateOn:dd.MM.yyyy})"; break;
case OrganicService.TracesStatus.SUSPENDED:
vm.OrganicTest1 = "Gesperrt";
vm.OrganicTest2 = $" (am {cert.LastStatusUpdateOn:dd.MM.yyyy})"; break;
case OrganicService.TracesStatus.EXPIRED:
vm.OrganicTest1 = "Ausgelaufen";
vm.OrganicTest2 = $" (am {cert.LastStatusUpdateOn:dd.MM.yyyy})"; break;
case OrganicService.TracesStatus.WITHDRAWN:
vm.OrganicTest1 = "Widerrufen";
vm.OrganicTest2 = $" (am {cert.LastStatusUpdateOn:dd.MM.yyyy})"; break;
}
}
}
}); });
}); });
vm.MemberHasEmail = m.EmailAddresses.Count > 0; vm.MemberHasEmail = m.EmailAddresses.Count > 0;
vm.MemberCanSendEmail = App.Config.Smtp != null && m.EmailAddresses.Count > 0; vm.MemberCanSendEmail = App.Config.Smtp != null && m.EmailAddresses.Count > 0;
vm.MemberHasDeliveries = Enumerable.Range(0, 9999).Select(i => false).ToList(); vm.MemberHasDeliveries = [.. Enumerable.Range(0, 9999).Select(i => false)];
} }
public static async Task<(List<string>, IQueryable<Member>, List<string>)> GetFilters(this MemberAdminViewModel vm, AppDbContext ctx) { public static async Task<(List<string>, IQueryable<Member>, List<string>)> GetFilters(this MemberAdminViewModel vm, AppDbContext ctx) {
@@ -555,6 +609,8 @@ namespace Elwig.Services {
UstIdNr = string.IsNullOrWhiteSpace(vm.UstIdNr) ? null : vm.UstIdNr, UstIdNr = string.IsNullOrWhiteSpace(vm.UstIdNr) ? null : vm.UstIdNr,
LfbisNr = string.IsNullOrWhiteSpace(vm.LfbisNr) ? null : vm.LfbisNr, LfbisNr = string.IsNullOrWhiteSpace(vm.LfbisNr) ? null : vm.LfbisNr,
OrganicOperatorId = string.IsNullOrWhiteSpace(vm.OrganicOperatorId) ? null : vm.OrganicOperatorId,
OrganicAuthorityCode = string.IsNullOrWhiteSpace(vm.OrganicAuthorityCode) ? null : vm.OrganicAuthorityCode,
IsBuchführend = vm.IsBuchführend, IsBuchführend = vm.IsBuchführend,
IsOrganic = vm.IsOrganic, IsOrganic = vm.IsOrganic,
+143
View File
@@ -0,0 +1,143 @@
using Elwig.Helpers;
using Elwig.Models.Entities;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.Json.Nodes;
using System.Threading.Tasks;
using System.Web;
namespace Elwig.Services {
public static class OrganicService {
public const string TRACES_API_URL = "https://webgate.ec.europa.eu/tracesnt/directory/publication/organic-operator/for/query";
public const string TRACES_PDF_URL_PREFIX = "https://webgate.ec.europa.eu/tracesnt/directory/publication/organic-operator/digitally-signed/";
public enum TracesStatus {
ISSUED, SUSPENDED, WITHDRAWN, EXPIRED
}
public enum TracesActivity {
PREPARATION, EXPORT, IMPORT, STORING, PRODUCTION, DISTRIBUTION, DISTRIBUTION_PLACING_ON_THE_MARKET
}
public enum TracesCategoryOfProduct {
UNPROCESSED_PLANT_PRODUCTS_INCLUDING_SEEDS, LIVESTOCK_AND_UNPROCESSED_LIVESTOCK_PRODUCTS, ALGAE_AND_UNPROCESSED_AQUACULTURE_PRODUCTS,
PROCESSED_AGRICULTURAL_PRODUCTS_INCLUDING_AQUACULTURE_FOR_USE_AS_FOOD, FEED, WINE, OTHER_PRODUCTS_NOT_COVERED_BY_PREVIOUS_CATEGORIES
}
public record TracesCertificate {
public required string Id { get; init; }
public required string AuthorityCode { get; init; }
public required string OperatorId { get; init; }
public required string OperatorName { get; init; }
public required TracesActivity[] Activities { get; init; }
public required TracesCategoryOfProduct[] CategoriesOfProduct { get; init; }
public required DateOnly IssuedOn { get; init; }
public required DateOnly ExpiresOn { get; init; }
public required DateOnly LastStatusUpdateOn { get; init; }
public required TracesStatus Status { get; init; }
public string PdfUrl => TRACES_PDF_URL_PREFIX + Id + ".pdf";
public bool IsValid => Status == TracesStatus.ISSUED && IssuedOn.ToDateTime(new()) <= DateTime.Today && ExpiresOn.ToDateTime(new()) >= DateTime.Today;
public bool IsValidForWineProduction => IsValid && Activities.Contains(TracesActivity.PRODUCTION) &&
(CategoriesOfProduct.Contains(TracesCategoryOfProduct.UNPROCESSED_PLANT_PRODUCTS_INCLUDING_SEEDS) || CategoriesOfProduct.Contains(TracesCategoryOfProduct.WINE));
}
public async static Task<TracesCertificate[]> GetTracesCertificates(Member m, bool? tryNameAndAddress = null) {
// TODO cache
return await FetchTracesCertificates(m, tryNameAndAddress);
}
private async static Task<JsonArray> TryFetchTracesCertificates(Dictionary<string, string> query) {
var q = HttpUtility.ParseQueryString("");
q.Add("sort", "-issuedOn");
q.Add("countryCode", "AT");
foreach (var (k, v) in query) {
q.Add(k, v);
}
using var client = Utils.GetHttpClient();
using var res = await client.GetAsync($"{TRACES_API_URL}?{q}");
res.EnsureSuccessStatusCode();
var resJson = JsonNode.Parse(await res.Content.ReadAsStringAsync());
var certs = resJson?.AsArray() ?? throw new Exception();
if (certs.Count == 0)
throw new Exception();
return certs;
}
public static Task<TracesCertificate[]> FetchTracesCertificates(Member m, bool? tryNameAndAddress = null) {
return FetchTracesCertificates(m.OrganicOperatorId, m.LfbisNr,
(tryNameAndAddress ?? m.IsOrganic) ? m.BillingAddress is BillingAddr a ?
(a.FullName, a.Address, $"{a.PostalDest.AtPlz?.Plz}") :
(m.FullName, m.Address, $"{m.PostalDest.AtPlz?.Plz}") :
null);
}
public async static Task<TracesCertificate[]> FetchTracesCertificates(string? oocId, string? lfbisNr, (string Name, string Address, string PostalCode)? address) {
bool searchedByName = false;
JsonArray? jsonCerts = null;
if (oocId != null) {
try {
jsonCerts = await TryFetchTracesCertificates(new Dictionary<string, string> {
{ "operatorIdentifierType", "ooc_identifier" },
{ "operatorIdentifierSearchOperator", "STRICT" },
{ "operatorIdentifier", oocId },
});
} catch {
jsonCerts = null;
}
}
if (jsonCerts == null && lfbisNr != null) {
try {
jsonCerts = await TryFetchTracesCertificates(new Dictionary<string, string> {
{ "operatorIdentifierType", "comp_reg" },
{ "operatorIdentifierSearchOperator", "STRICT" },
{ "operatorIdentifier", lfbisNr.TrimStart('0') },
});
} catch {
jsonCerts = null;
}
}
if (jsonCerts == null && address != null) {
try {
jsonCerts = await TryFetchTracesCertificates(new Dictionary<string, string> {
{ "operatorPostalCode", address.Value.PostalCode },
{ "query", $"{address.Value.Name} {address.Value.Address}" },
});
searchedByName = true;
} catch {
jsonCerts = null;
}
}
if (jsonCerts == null)
return [];
TracesCertificate[] certs = [];
try {
certs = [.. jsonCerts.Select(j => new TracesCertificate {
Id = j!["reference"]?.GetValue<string>() ?? throw new Exception(),
AuthorityCode = j["issuingBody"]?["code"]?.GetValue<string>() ?? throw new Exception(),
OperatorId = j["operatorIdentifier"]?.GetValue<string>() ?? throw new Exception(),
OperatorName = j["operator"]?["name"]?.GetValue<string>() ?? throw new Exception(),
Activities = [.. j["activities"]?.AsArray().Select(a => Enum.Parse<TracesActivity>(a?["id"]?.GetValue<string>().ToUpper().Replace("_IMPORT", "IMPORT") ?? throw new Exception())) ?? []],
CategoriesOfProduct = [.. j["categoriesOfProduct"]?.AsArray().Select(c => Enum.Parse<TracesCategoryOfProduct>(c?["id"]?.GetValue<string>() ?? throw new Exception())) ?? []],
IssuedOn = DateOnly.FromDateTime(DateTime.ParseExact(j["issuedOn"]?.GetValue<string>() ?? throw new Exception(), "yyyy-MM-ddTHH:mm:ss.fffK", CultureInfo.InvariantCulture, DateTimeStyles.None)),
ExpiresOn = DateOnly.ParseExact(j["expiresOn"]?.GetValue<string>() ?? throw new Exception(), "yyyy-MM-dd"),
LastStatusUpdateOn = DateOnly.FromDateTime(DateTime.ParseExact(j["lastStatusUpdateDateTime"]?.GetValue<string>() ?? throw new Exception(), "yyyy-MM-ddTHH:mm:ss.fffK", CultureInfo.InvariantCulture, DateTimeStyles.None)),
Status = Enum.Parse<TracesStatus>(j["status"]?["id"]?.GetValue<string>() ?? throw new Exception()),
})];
} catch {
return [];
}
return (!searchedByName || certs.Where(c => c.Status == TracesStatus.ISSUED).Select(c => c.OperatorId).ToHashSet().Count == 1) ? certs : [];
}
}
}
+14
View File
@@ -6,6 +6,7 @@ using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Media;
namespace Elwig.ViewModels { namespace Elwig.ViewModels {
public partial class MemberAdminViewModel : ObservableObject { public partial class MemberAdminViewModel : ObservableObject {
@@ -118,10 +119,23 @@ namespace Elwig.ViewModels {
[ObservableProperty] [ObservableProperty]
private string? _lfbisNr; private string? _lfbisNr;
[ObservableProperty] [ObservableProperty]
private string? _organicOperatorId;
[ObservableProperty]
private string? _organicAuthorityCode;
[ObservableProperty]
private bool _isBuchführend; private bool _isBuchführend;
[ObservableProperty] [ObservableProperty]
private bool _isOrganic; private bool _isOrganic;
[ObservableProperty]
private string? _organicTest1;
[ObservableProperty]
private string? _organicTest2;
[ObservableProperty]
private Brush? _organicTest3;
[ObservableProperty]
private string? _organicTest4;
[ObservableProperty] [ObservableProperty]
private string? _entryDate; private string? _entryDate;
[ObservableProperty] [ObservableProperty]
@@ -52,6 +52,8 @@ namespace Elwig.ViewModels {
[ObservableProperty] [ObservableProperty]
private bool _deduct; private bool _deduct;
[ObservableProperty] [ObservableProperty]
private bool _companyHasSigned;
[ObservableProperty]
private bool _memberHasSigned; private bool _memberHasSigned;
[ObservableProperty] [ObservableProperty]
private string? _valuePerShareString; private string? _valuePerShareString;
+8
View File
@@ -576,6 +576,14 @@ namespace Elwig.Windows {
InputLostFocus((TextBox)sender, Validator.CheckLfbisNr); InputLostFocus((TextBox)sender, Validator.CheckLfbisNr);
} }
protected void OrganicOperatorIdInput_TextChanged(object sender, TextChangedEventArgs? evt) {
InputTextChanged((TextBox)sender, Validator.CheckOrganicOperatorId);
}
protected void OrganicOperatorIdInput_LostFocus(object sender, RoutedEventArgs? evt) {
InputLostFocus((TextBox)sender, Validator.CheckOrganicOperatorId);
}
protected void OrganicAuthorityCodeInput_TextChanged(object sender, TextChangedEventArgs? evt) { protected void OrganicAuthorityCodeInput_TextChanged(object sender, TextChangedEventArgs? evt) {
InputTextChanged((TextBox)sender, Validator.CheckOrganicAuthorityCode); InputTextChanged((TextBox)sender, Validator.CheckOrganicAuthorityCode);
} }
+14 -4
View File
@@ -121,12 +121,18 @@
VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="3" Margin="0,130,10,10" Width="64" VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="3" Margin="0,130,10,10" Width="64"
TextChanged="LfbisNrInput_TextChanged" LostFocus="LfbisNrInput_LostFocus"/> TextChanged="LfbisNrInput_TextChanged" LostFocus="LfbisNrInput_LostFocus"/>
<Label Content="Bio-Kontrollstelle:" <Label Content="Bio-KSt.:" ToolTip="Bio-Konstrollstelle"
VerticalAlignment="Top" HorizontalAlignment="Right" Grid.Column="3" Margin="10,130,110,10"/> VerticalAlignment="Top" HorizontalAlignment="Right" Grid.Column="3" Margin="10,100,110,10"/>
<TextBox x:Name="ClientOrganicAuthorityInput" <TextBox x:Name="ClientOrganicAuthorityCodeInput"
VerticalAlignment="Top" HorizontalAlignment="Right" Grid.Column="3" Margin="10,130,10,10" Width="90" VerticalAlignment="Top" HorizontalAlignment="Right" Grid.Column="3" Margin="10,100,10,10" Width="82"
TextChanged="OrganicAuthorityCodeInput_TextChanged" LostFocus="OrganicAuthorityCodeInput_LostFocus"/> TextChanged="OrganicAuthorityCodeInput_TextChanged" LostFocus="OrganicAuthorityCodeInput_LostFocus"/>
<Label Content="OOC-ID:" ToolTip="Bio-EU-Operator-ID / Organic Operator Certificate ID"
VerticalAlignment="Top" HorizontalAlignment="Right" Grid.Column="3" Margin="10,130,110,10"/>
<TextBox x:Name="ClientOrganicOperatorIdInput"
VerticalAlignment="Top" HorizontalAlignment="Right" Grid.Column="3" Margin="10,130,10,10" Width="91"
TextChanged="OrganicOperatorIdInput_TextChanged" LostFocus="OrganicOperatorIdInput_LostFocus"/>
<Label Content="Telefon-Nr.:" <Label Content="Telefon-Nr.:"
VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="2" Margin="10,160,0,10"/> VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="2" Margin="10,160,0,10"/>
<TextBox x:Name="ClientPhoneNrInput" Margin="0,160,10,10" Grid.Column="3" <TextBox x:Name="ClientPhoneNrInput" Margin="0,160,10,10" Grid.Column="3"
@@ -320,6 +326,10 @@
<Label Content="Beschreibung:" Margin="10,70,0,10"/> <Label Content="Beschreibung:" Margin="10,70,0,10"/>
<TextBox x:Name="WineCultivationDescriptionInput" Grid.Column="1" Margin="0,70,10,10" <TextBox x:Name="WineCultivationDescriptionInput" Grid.Column="1" Margin="0,70,10,10"
TextChanged="WineCultivation_Changed"/> TextChanged="WineCultivation_Changed"/>
<CheckBox x:Name="WineCultivationOrganicInput" Content="Bio" Grid.Column="1" Margin="0,105,10,10"
Checked="WineCultivation_Changed" Unchecked="WineCultivation_Changed"
HorizontalAlignment="Left" VerticalAlignment="Top"/>
</Grid> </Grid>
</Grid> </Grid>
</TabItem> </TabItem>
@@ -72,10 +72,12 @@ namespace Elwig.Windows {
WineCultivationIdInput.Text = ""; WineCultivationIdInput.Text = "";
WineCultivationNameInput.Text = ""; WineCultivationNameInput.Text = "";
WineCultivationDescriptionInput.Text = ""; WineCultivationDescriptionInput.Text = "";
WineCultivationOrganicInput.IsChecked = false;
} else { } else {
WineCultivationIdInput.Text = cult.CultId; WineCultivationIdInput.Text = cult.CultId;
WineCultivationNameInput.Text = cult.Name; WineCultivationNameInput.Text = cult.Name;
WineCultivationDescriptionInput.Text = cult.Description; WineCultivationDescriptionInput.Text = cult.Description;
WineCultivationOrganicInput.IsChecked = cult.IsOrganic;
} }
_cultUpdate = false; _cultUpdate = false;
} }
@@ -105,7 +107,8 @@ namespace Elwig.Windows {
_cultChanged = _cultChanged || _cultChanged = _cultChanged ||
WineCultivationIdInput.Text != cult.CultId || WineCultivationIdInput.Text != cult.CultId ||
WineCultivationNameInput.Text != cult.Name || WineCultivationNameInput.Text != cult.Name ||
WineCultivationDescriptionInput.Text != (cult.Description ?? ""); WineCultivationDescriptionInput.Text != (cult.Description ?? "") ||
WineCultivationOrganicInput.IsChecked != cult.IsOrganic;
var old = _cultIds.GetValueOrDefault(cult); var old = _cultIds.GetValueOrDefault(cult);
var id = WineCultivationIdInput.Text ?? ""; var id = WineCultivationIdInput.Text ?? "";
@@ -113,7 +116,8 @@ namespace Elwig.Windows {
cult.CultId = id; cult.CultId = id;
cult.Name = WineCultivationNameInput.Text ?? ""; cult.Name = WineCultivationNameInput.Text ?? "";
cult.Description = WineCultivationDescriptionInput.Text ?? ""; cult.Description = WineCultivationDescriptionInput.Text ?? "";
if (cult.Description.Length == 0) cult.Description = null; cult.IsOrganic = WineCultivationOrganicInput.IsChecked ?? false;
if (string.IsNullOrWhiteSpace(cult.Description)) cult.Description = null;
CollectionViewSource.GetDefaultView(_cultList).Refresh(); CollectionViewSource.GetDefaultView(_cultList).Refresh();
UpdateButtons(); UpdateButtons();
+7 -3
View File
@@ -25,7 +25,7 @@ namespace Elwig.Windows {
BranchAddressInput, BranchPhoneNrInput, BranchFaxNrInput, BranchMobileNrInput, BranchAddressInput, BranchPhoneNrInput, BranchFaxNrInput, BranchMobileNrInput,
WineAttributeIdInput, WineAttributeNameInput, WineAttributeActiveInput, WineAttributeIdInput, WineAttributeNameInput, WineAttributeActiveInput,
WineAttributeMaxKgPerHaInput, WineAttributeStrictInput, WineAttributeFillLowerInput, WineAttributeMaxKgPerHaInput, WineAttributeStrictInput, WineAttributeFillLowerInput,
WineCultivationIdInput, WineCultivationNameInput, WineCultivationDescriptionInput, WineCultivationIdInput, WineCultivationNameInput, WineCultivationDescriptionInput, WineCultivationOrganicInput,
AreaCommitmentTypeIdInput, AreaCommitmentTypeWineVariantInput, AreaCommitmentTypeWineAttributeInput, AreaCommitmentTypeIdInput, AreaCommitmentTypeWineVariantInput, AreaCommitmentTypeWineAttributeInput,
AreaCommitmentTypeMinKgPerHaInput, AreaCommitmentTypePenaltyPerKgInput, AreaCommitmentTypeMinKgPerHaInput, AreaCommitmentTypePenaltyPerKgInput,
AreaCommitmentTypePenaltyInput, AreaCommitmentTypePenaltyNoneInput, AreaCommitmentTypePenaltyInput, AreaCommitmentTypePenaltyNoneInput,
@@ -67,6 +67,7 @@ namespace Elwig.Windows {
WineCultivationIdInput.IsReadOnly = true; WineCultivationIdInput.IsReadOnly = true;
WineCultivationNameInput.IsReadOnly = true; WineCultivationNameInput.IsReadOnly = true;
WineCultivationDescriptionInput.IsReadOnly = true; WineCultivationDescriptionInput.IsReadOnly = true;
WineCultivationOrganicInput.IsEnabled = false;
AreaCommitmentTypeWineVariantInput.IsEnabled = false; AreaCommitmentTypeWineVariantInput.IsEnabled = false;
AreaCommitmentTypeWineAttributeInput.IsEnabled = false; AreaCommitmentTypeWineAttributeInput.IsEnabled = false;
@@ -115,6 +116,7 @@ namespace Elwig.Windows {
WineCultivationIdInput.IsReadOnly = false; WineCultivationIdInput.IsReadOnly = false;
WineCultivationNameInput.IsReadOnly = false; WineCultivationNameInput.IsReadOnly = false;
WineCultivationDescriptionInput.IsReadOnly = false; WineCultivationDescriptionInput.IsReadOnly = false;
WineCultivationOrganicInput.IsEnabled = true;
AreaCommitmentTypeWineVariantInput.IsEnabled = true; AreaCommitmentTypeWineVariantInput.IsEnabled = true;
AreaCommitmentTypeWineAttributeInput.IsEnabled = true; AreaCommitmentTypeWineAttributeInput.IsEnabled = true;
@@ -329,7 +331,8 @@ namespace Elwig.Windows {
ClientBicInput.Text = p.Bic; ClientBicInput.Text = p.Bic;
ClientUstIdNrInput.Text = p.UstIdNr; ClientUstIdNrInput.Text = p.UstIdNr;
ClientLfbisNrInput.Text = p.LfbisNr; ClientLfbisNrInput.Text = p.LfbisNr;
ClientOrganicAuthorityInput.Text = p.OrganicAuthority; ClientOrganicOperatorIdInput.Text = p.OrganicOperatorId;
ClientOrganicAuthorityCodeInput.Text = p.OrganicAuthorityCode;
ClientPhoneNrInput.Text = p.PhoneNr; ClientPhoneNrInput.Text = p.PhoneNr;
ClientFaxNrInput.Text = p.FaxNr; ClientFaxNrInput.Text = p.FaxNr;
ClientEmailAddressInput.Text = p.EmailAddress; ClientEmailAddressInput.Text = p.EmailAddress;
@@ -369,7 +372,8 @@ namespace Elwig.Windows {
p.Bic = string.IsNullOrWhiteSpace(ClientBicInput.Text) ? null : ClientBicInput.Text; p.Bic = string.IsNullOrWhiteSpace(ClientBicInput.Text) ? null : ClientBicInput.Text;
p.UstIdNr = string.IsNullOrWhiteSpace(ClientUstIdNrInput.Text) ? null : ClientUstIdNrInput.Text; p.UstIdNr = string.IsNullOrWhiteSpace(ClientUstIdNrInput.Text) ? null : ClientUstIdNrInput.Text;
p.LfbisNr = string.IsNullOrWhiteSpace(ClientLfbisNrInput.Text) ? null : ClientLfbisNrInput.Text; p.LfbisNr = string.IsNullOrWhiteSpace(ClientLfbisNrInput.Text) ? null : ClientLfbisNrInput.Text;
p.OrganicAuthority = string.IsNullOrWhiteSpace(ClientOrganicAuthorityInput.Text) ? null : ClientOrganicAuthorityInput.Text; p.OrganicOperatorId = string.IsNullOrWhiteSpace(ClientOrganicOperatorIdInput.Text) ? null : ClientOrganicOperatorIdInput.Text;
p.OrganicAuthorityCode = string.IsNullOrWhiteSpace(ClientOrganicAuthorityCodeInput.Text) ? null : ClientOrganicAuthorityCodeInput.Text;
p.PhoneNr = string.IsNullOrWhiteSpace(ClientPhoneNrInput.Text) ? null : ClientPhoneNrInput.Text; p.PhoneNr = string.IsNullOrWhiteSpace(ClientPhoneNrInput.Text) ? null : ClientPhoneNrInput.Text;
p.FaxNr = string.IsNullOrWhiteSpace(ClientFaxNrInput.Text) ? null : ClientFaxNrInput.Text; p.FaxNr = string.IsNullOrWhiteSpace(ClientFaxNrInput.Text) ? null : ClientFaxNrInput.Text;
p.EmailAddress = string.IsNullOrWhiteSpace(ClientEmailAddressInput.Text) ? null : ClientEmailAddressInput.Text; p.EmailAddress = string.IsNullOrWhiteSpace(ClientEmailAddressInput.Text) ? null : ClientEmailAddressInput.Text;
+34 -19
View File
@@ -547,37 +547,52 @@
<GroupBox Header="Betrieb" Grid.Column="1" Grid.Row="0" Grid.RowSpan="1" Margin="5,5,5,5"> <GroupBox Header="Betrieb" Grid.Column="1" Grid.Row="0" Grid.RowSpan="1" Margin="5,5,5,5">
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="90"/> <ColumnDefinition Width="85"/>
<ColumnDefinition Width="150"/> <ColumnDefinition Width="69"/>
<ColumnDefinition/> <ColumnDefinition Width="*"/>
<ColumnDefinition Width="55"/>
<ColumnDefinition Width="101"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Label Content="UID:" Margin="10,10,0,0" Grid.Column="0" ToolTip="USt-IdNr. / Umsatzsteuer-Identifikationsnummer"/> <Label Content="Betriebs-Nr.:" Margin="10,10,0,0" Grid.Column="0"/>
<TextBox x:Name="UstIdNrInput" Text="{Binding UstIdNr, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,10,10,0" Grid.Column="1" Width="96" HorizontalAlignment="Left"
TextChanged="UstIdNrInput_TextChanged" LostFocus="UstIdNrInput_LostFocus"/>
<Label Content="Betriebs-Nr.:" Margin="10,40,0,0" Grid.Column="0"/>
<TextBox x:Name="LfbisNrInput" Text="{Binding LfbisNr, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" <TextBox x:Name="LfbisNrInput" Text="{Binding LfbisNr, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,40,10,0" Grid.Column="1" Width="64" HorizontalAlignment="Left" TextAlignment="Right" Margin="0,10,5,0" Grid.Column="1" Width="64" HorizontalAlignment="Left" TextAlignment="Right"
TextChanged="LfbisNrInput_TextChanged" LostFocus="LfbisNrInput_LostFocus"/> TextChanged="LfbisNrInput_TextChanged" LostFocus="LfbisNrInput_LostFocus"/>
<CheckBox x:Name="BuchführendInput" Content="Buchführend" IsChecked="{Binding IsBuchführend, Mode=TwoWay}" IsEnabled="False" <Label Content="UID:" Margin="10,40,0,0" Grid.Column="0" ToolTip="USt-IdNr. / Umsatzsteuer-Identifikationsnummer"/>
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed" <TextBox x:Name="UstIdNrInput" Text="{Binding UstIdNr, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Grid.Column="2" HorizontalAlignment="Left" Margin="10,15,0,0" VerticalAlignment="Top"/> Margin="0,40,5,0" Grid.Column="0" Grid.ColumnSpan="2" Width="96" HorizontalAlignment="Right"
TextChanged="UstIdNrInput_TextChanged" LostFocus="UstIdNrInput_LostFocus"/>
<CheckBox x:Name="OrganicInput" Content="Bio" IsChecked="{Binding IsOrganic, Mode=TwoWay}" IsEnabled="False" <CheckBox x:Name="OrganicInput" Content="Bio" IsChecked="{Binding IsOrganic, Mode=TwoWay}" IsEnabled="False"
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed" Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"
Grid.Column="2" HorizontalAlignment="Left" Margin="10,45,0,0" VerticalAlignment="Top"/> Grid.Column="2" HorizontalAlignment="Left" Margin="5,15,0,0" VerticalAlignment="Top"/>
<Button x:Name="OrganicButton" Content="easy-cert.com" IsEnabled="{Binding IsMemberSelected}"
Height="25" FontSize="12" <CheckBox x:Name="BuchführendInput" Content="Buchführend" IsChecked="{Binding IsBuchführend, Mode=TwoWay}" IsEnabled="False"
Click="OrganicButton_Click" Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"
Grid.Column="2" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="60,40,0,0"/> Grid.Column="2" HorizontalAlignment="Left" Margin="5,45,0,0" VerticalAlignment="Top"/>
<Label Content="Kontrollstelle:" Margin="0,10,5,0" Grid.Column="2" Grid.ColumnSpan="2" HorizontalAlignment="Right" ToolTip="Bio-Kontrollstelle"/>
<TextBox x:Name="OrganicAuthorityCodeInput" Text="{Binding OrganicAuthorityCode, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,10,19,0" Grid.Column="4" Width="82" HorizontalAlignment="Left"
TextChanged="OrganicAuthorityCodeInput_TextChanged" LostFocus="OrganicAuthorityCodeInput_LostFocus"/>
<Label Content="OOC-ID:" Margin="0,40,0,0" Grid.Column="3" HorizontalAlignment="Left" ToolTip="Bio-EU-Operator-ID / Organic Operator Certificate ID"/>
<TextBox x:Name="OrganicOperatorIdInput" Text="{Binding OrganicOperatorId, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,40,10,0" Grid.Column="4" Width="91" HorizontalAlignment="Left"
TextChanged="OrganicOperatorIdInput_TextChanged" LostFocus="OrganicOperatorIdInput_LostFocus"/>
<Label Content="Bio-Zert.:" Margin="50,10,0,0" Grid.Column="2" HorizontalAlignment="Left"/>
<TextBlock FontSize="14" Margin="105,12,10,0" Grid.Column="2" HorizontalAlignment="Left" ToolTip="{Binding OrganicTest4}">
<Run Text="{Binding OrganicTest1}" FontWeight="Bold" Foreground="{Binding OrganicTest3}"/><Run FontSize="12" Text="{Binding OrganicTest2}"/>
</TextBlock>
</Grid> </Grid>
</GroupBox> </GroupBox>
<GroupBox Grid.Column="1" Grid.Row="1" Grid.RowSpan="2" Margin="5,5,5,5"> <GroupBox Grid.Column="1" Grid.Row="1" Grid.RowSpan="2" Margin="5,5,5,5">
<GroupBox.Header> <GroupBox.Header>
<TextBlock>Rechnungsadresse (optional) <Run FontSize="10">für Lieferschein, Anlfrg.-Bstng., Tr.-Gutschr.</Run></TextBlock> <TextBlock>Rechnungsadresse (optional)
<Run FontSize="10">für Lieferschein, Anlfrg.-Bstng., Tr.-Gutschr.</Run>
</TextBlock>
</GroupBox.Header> </GroupBox.Header>
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
-12
View File
@@ -7,7 +7,6 @@ using Elwig.ViewModels;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows; using System.Windows;
@@ -966,17 +965,6 @@ namespace Elwig.Windows {
} }
} }
private void OrganicButton_Click(object sender, RoutedEventArgs evt) {
if (ViewModel.SelectedMember is not Member m) return;
var url = "https://www.easy-cert.com/htm/suchergebnis.htm?" +
//$"CustomerNumber={m.LfbisNr}&" +
$"Name={(m.BillingAddress?.FullName ?? m.FullName).Replace(' ', '+')}&" +
$"PostalCode={(m.BillingAddress?.PostalDest ?? m.PostalDest).AtPlz?.Plz}";
Process.Start(new ProcessStartInfo(url) {
UseShellExecute = true,
});
}
private void MemberReferenceButton_Click(object sender, RoutedEventArgs evt) { private void MemberReferenceButton_Click(object sender, RoutedEventArgs evt) {
if (ViewModel.SelectedMember is not Member m || m.PredecessorMgNr == null) return; if (ViewModel.SelectedMember is not Member m || m.PredecessorMgNr == null) return;
FocusMember((int)m.PredecessorMgNr); FocusMember((int)m.PredecessorMgNr);
@@ -173,8 +173,11 @@
Margin="0,100,10,0" Width="78" Grid.Column="1" HorizontalAlignment="Left" TextAlignment="Right" Margin="0,100,10,0" Width="78" Grid.Column="1" HorizontalAlignment="Left" TextAlignment="Right"
TextChanged="DateNoticeInput_TextChanged" LostFocus="DateInput_LostFocus"/> TextChanged="DateNoticeInput_TextChanged" LostFocus="DateInput_LostFocus"/>
<CheckBox x:Name="HasCompanySignedInput" IsChecked="{Binding CompanyHasSigned, Mode=TwoWay}" Content="Von WG unterfertigt"
Margin="88,105,10,0" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Top"
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"/>
<CheckBox x:Name="HasMemberSignedInput" IsChecked="{Binding MemberHasSigned, Mode=TwoWay}" Content="Von Mg. unterfertigt" <CheckBox x:Name="HasMemberSignedInput" IsChecked="{Binding MemberHasSigned, Mode=TwoWay}" Content="Von Mg. unterfertigt"
Margin="88,105,10,0" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="TOp" Margin="88,135,10,0" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Top"
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"/> Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"/>
<Label Content="Wirksam:" Margin="10,130,0,0" Grid.Column="0"/> <Label Content="Wirksam:" Margin="10,130,0,0" Grid.Column="0"/>
+4 -4
View File
@@ -84,12 +84,12 @@ namespace Tests.E2ETests {
Window.FindElement(By.WpfId("SearchInput")).SendKeys("9999"); Window.FindElement(By.WpfId("SearchInput")).SendKeys("9999");
Thread.Sleep(500); Thread.Sleep(500);
var memberListRow = Window.FindElement(By.WpfId("MemberList")).FindElement(By.ClassName("DataGridRow")); var memberListRow = Window.FindElement(By.WpfId("MemberList")).FindElement(By.ClassName("DataGridRow"));
Assert.Multiple(() => { using (Assert.EnterMultipleScope()) {
Assert.That(memberListRow, Is.Not.Null); Assert.That(memberListRow, Is.Not.Null);
Assert.That(memberListRow.FindElement(By.Name("9999 ")), Is.Not.Null); Assert.That(memberListRow.FindElement(By.Name("9999 ")), Is.Not.Null);
Assert.That(memberListRow.FindElement(By.Name("Norbert")), Is.Not.Null); Assert.That(memberListRow.FindElement(By.Name("Norbert")), Is.Not.Null);
Assert.That(memberListRow.FindElement(By.Name("Neuling")), Is.Not.Null); Assert.That(memberListRow.FindElement(By.Name("Neuling")), Is.Not.Null);
}); }
} }
[Test] [Test]
@@ -128,12 +128,12 @@ namespace Tests.E2ETests {
Assert.That(memberListRows, Has.Count.EqualTo(1)); Assert.That(memberListRows, Has.Count.EqualTo(1));
var memberListRow = memberListRows.First(); var memberListRow = memberListRows.First();
Assert.Multiple(() => { using (Assert.EnterMultipleScope()) {
Assert.That(memberListRow, Is.Not.Null); Assert.That(memberListRow, Is.Not.Null);
Assert.That(memberListRow.FindElement(By.Name("9999 ")), Is.Not.Null); Assert.That(memberListRow.FindElement(By.Name("9999 ")), Is.Not.Null);
Assert.That(memberListRow.FindElement(By.Name("Norbert")), Is.Not.Null); Assert.That(memberListRow.FindElement(By.Name("Norbert")), Is.Not.Null);
Assert.That(memberListRow.FindElement(By.Name("Neuling")), Is.Not.Null); Assert.That(memberListRow.FindElement(By.Name("Neuling")), Is.Not.Null);
}); }
Window.FindElement(By.WpfId("DeleteMemberButton")).Click(); Window.FindElement(By.WpfId("DeleteMemberButton")).Click();
var dialog = Session.CreateWindowDriver("DeleteMemberDialog"); var dialog = Session.CreateWindowDriver("DeleteMemberDialog");
+3 -3
View File
@@ -1,8 +1,8 @@
-- inserts for HelperTests.BillingTest -- inserts for HelperTests.BillingTest
INSERT INTO wine_cultivation (cultid, name, description) VALUES INSERT INTO wine_cultivation (cultid, name, description, organic) VALUES
('KIP', 'KIP', 'Kontrollierte Integrierte Produktion'), ('KIP', 'KIP', 'Kontrollierte Integrierte Produktion', FALSE),
('B', 'Bio', 'AT-BIO-302'); ('B', 'Bio', 'Biologische Produktion', TRUE);
INSERT INTO wine_attribute (attrid, name, active, max_kg_per_ha, strict, fill_lower) VALUES INSERT INTO wine_attribute (attrid, name, active, max_kg_per_ha, strict, fill_lower) VALUES
('K', 'Kabinett', TRUE, NULL, FALSE, 0), ('K', 'Kabinett', TRUE, NULL, FALSE, 0),
+2 -2
View File
@@ -1,7 +1,7 @@
-- inserts for DocumentTests -- inserts for DocumentTests
INSERT INTO wine_cultivation (cultid, name, description) VALUES INSERT INTO wine_cultivation (cultid, name, description, organic) VALUES
('B', 'Bio', 'AT-BIO-302'); ('B', 'Bio', 'Biologische Produktion', TRUE);
INSERT INTO wine_attribute (attrid, name, active, max_kg_per_ha, strict, fill_lower) VALUES INSERT INTO wine_attribute (attrid, name, active, max_kg_per_ha, strict, fill_lower) VALUES
('K', 'Kabinett', TRUE, NULL, FALSE, 0); ('K', 'Kabinett', TRUE, NULL, FALSE, 0);
+3 -3
View File
@@ -1,8 +1,8 @@
-- inserts for E2ETests -- inserts for E2ETests
INSERT INTO wine_cultivation (cultid, name, description) VALUES INSERT INTO wine_cultivation (cultid, name, description, organic) VALUES
('KIP', 'KIP', 'Kontrollierte Integrierte Produktion'), ('KIP', 'KIP', 'Kontrollierte Integrierte Produktion', FALSE),
('B', 'Bio', 'AT-BIO-302'); ('B', 'Bio', 'Biologische Produktion', TRUE);
INSERT INTO wine_attribute (attrid, name, active, max_kg_per_ha, strict, fill_lower) VALUES INSERT INTO wine_attribute (attrid, name, active, max_kg_per_ha, strict, fill_lower) VALUES
('K', 'Kabinett', TRUE, NULL, FALSE, 0), ('K', 'Kabinett', TRUE, NULL, FALSE, 0),
+5 -5
View File
@@ -66,11 +66,11 @@ INSERT INTO wb_kg (kgnr, glnr) VALUES
(15216, 2), (15216, 2),
(15224, 2); (15224, 2);
INSERT INTO member (mgnr, given_name, name, zwstid, volllieferant, buchführend, country, postal_dest, address, default_kgnr, iban, lfbis_nr, ustid_nr) VALUES INSERT INTO member (mgnr, given_name, name, zwstid, volllieferant, buchführend, country, postal_dest, address, default_kgnr, iban, lfbis_nr, ustid_nr, org_auth_code) VALUES
(101, 'Max', 'Mustermann', 'X', FALSE, FALSE, 40, 222303524, 'Winzerstraße 1', 06109, 'AT811234567890123457', '0123463', NULL ), (101, 'Max', 'Mustermann', 'X', FALSE, FALSE, 40, 222303524, 'Winzerstraße 1', 06109, 'AT811234567890123457', '0123463', NULL , NULL ),
(102, 'Wernhardt', 'Weinbauer', 'X', FALSE, FALSE, 40, 222303524, 'Winzerstraße 2', 06109, 'AT541234567890123458', '0123471', 'ATU12345684'), (102, 'Wernhardt', 'Weinbauer', 'X', FALSE, FALSE, 40, 222303524, 'Winzerstraße 2', 06109, 'AT541234567890123458', '0123471', 'ATU12345684', NULL ),
(103, 'Matthäus', 'Musterbauer', 'X', FALSE, FALSE, 40, 212005138, 'Brünner Straße 10', 15224, 'AT271234567890123459', '0123480', NULL ), (103, 'Matthäus', 'Musterbauer', 'X', FALSE, FALSE, 40, 212005138, 'Brünner Straße 10', 15224, 'AT271234567890123459', '0123480', NULL , 'AT-BIO-302'),
(104, 'Waltraud', 'Winzer', 'X', FALSE, TRUE , 40, 212005138, 'Wiener Straße 15', 15224, 'AT971234567890123460', '0123498', 'ATU12345693'); (104, 'Waltraud', 'Winzer', 'X', FALSE, TRUE , 40, 212005138, 'Wiener Straße 15', 15224, 'AT971234567890123460', '0123498', 'ATU12345693', NULL );
INSERT INTO member_billing_address (mgnr, name, country, postal_dest, address) VALUES INSERT INTO member_billing_address (mgnr, name, country, postal_dest, address) VALUES
(102, 'W&B Weinbauer GesbR', 40, 222303524, 'Winzerstraße 2'), (102, 'W&B Weinbauer GesbR', 40, 222303524, 'Winzerstraße 2'),
+2 -3
View File
@@ -1,8 +1,7 @@
-- inserts for ServiceTests -- inserts for ServiceTests
INSERT INTO wine_cultivation (cultid, name, description, organic) VALUES
INSERT INTO wine_cultivation (cultid, name, description) VALUES ('B', 'Bio', 'Biologische Produktion', TRUE);
('B', 'Bio', 'AT-BIO-302');
INSERT INTO wine_attribute (attrid, name, active, max_kg_per_ha, strict, fill_lower) VALUES INSERT INTO wine_attribute (attrid, name, active, max_kg_per_ha, strict, fill_lower) VALUES
('K', 'Kabinett', TRUE, NULL, FALSE, 0); ('K', 'Kabinett', TRUE, NULL, FALSE, 0);
@@ -8,7 +8,7 @@ namespace Tests.UnitTests.DocumentTests {
public async Task Test_01_OneDeliveryPart() { public async Task Test_01_OneDeliveryPart() {
using var doc = await DeliveryNote.Initialize(2020, 1); using var doc = await DeliveryNote.Initialize(2020, 1);
var text = await Utils.GeneratePdfText(doc); var text = await Utils.GeneratePdfText(doc);
Assert.Multiple(() => { using (Assert.EnterMultipleScope()) {
Assert.That(text, Contains.Substring(""" Assert.That(text, Contains.Substring("""
MUSTERMANN Max MUSTERMANN Max
Winzerstraße 1 Winzerstraße 1
@@ -26,14 +26,14 @@ namespace Tests.UnitTests.DocumentTests {
Waage/Terminal: ?/1, ID: 321 09:02, 01.10.2020 Waage/Terminal: ?/1, ID: 321 09:02, 01.10.2020
Brutto: 3 219 kg Tara: 0 kg Netto: 3 219 kg gerebelt gewogen Brutto: 3 219 kg Tara: 0 kg Netto: 3 219 kg gerebelt gewogen
""")); """));
}); }
} }
[Test] [Test]
public async Task Test_02_TwoDeliveryParts() { public async Task Test_02_TwoDeliveryParts() {
using var doc = await DeliveryNote.Initialize(2020, 4); using var doc = await DeliveryNote.Initialize(2020, 4);
var text = await Utils.GeneratePdfText(doc); var text = await Utils.GeneratePdfText(doc);
Assert.Multiple(() => { using (Assert.EnterMultipleScope()) {
Assert.That(text, Contains.Substring(""" Assert.That(text, Contains.Substring("""
W&B Weinbauer GesbR W&B Weinbauer GesbR
WEINBAUER Wernhardt WEINBAUER Wernhardt
@@ -58,14 +58,14 @@ namespace Tests.UnitTests.DocumentTests {
Waage/Terminal: ?/?, ID: ? (gerebelt gewogen) Waage/Terminal: ?/?, ID: ? (gerebelt gewogen)
""")); """));
Assert.That(text, Contains.Substring("Gesamt: 81 16,5 4 483")); Assert.That(text, Contains.Substring("Gesamt: 81 16,5 4 483"));
}); }
} }
[Test] [Test]
public async Task Test_03_DeliveryPartsWithAttribute() { public async Task Test_03_DeliveryPartsWithAttribute() {
using var doc = await DeliveryNote.Initialize(2020, 3); using var doc = await DeliveryNote.Initialize(2020, 3);
var text = await Utils.GeneratePdfText(doc); var text = await Utils.GeneratePdfText(doc);
Assert.Multiple(() => { using (Assert.EnterMultipleScope()) {
Assert.That(text, Contains.Substring(""" Assert.That(text, Contains.Substring("""
MUSTERMANN Max MUSTERMANN Max
Winzerstraße 1 Winzerstraße 1
@@ -95,14 +95,14 @@ namespace Tests.UnitTests.DocumentTests {
Waage/Terminal: ?/?, ID: ? (gerebelt gewogen) Waage/Terminal: ?/?, ID: ? (gerebelt gewogen)
""")); """));
Assert.That(text, Contains.Substring("Gesamt: 81 16,5 6 970")); Assert.That(text, Contains.Substring("Gesamt: 81 16,5 6 970"));
}); }
} }
[Test] [Test]
public async Task Test_04_DeliveryPartsWithCultivation() { public async Task Test_04_DeliveryPartsWithCultivation() {
using var doc = await DeliveryNote.Initialize(2020, 7); using var doc = await DeliveryNote.Initialize(2020, 7);
var text = await Utils.GeneratePdfText(doc); var text = await Utils.GeneratePdfText(doc);
Assert.Multiple(() => { using (Assert.EnterMultipleScope()) {
Assert.That(text, Contains.Substring(""" Assert.That(text, Contains.Substring("""
MUSTERBAUER Matthäus MUSTERBAUER Matthäus
Brünner Straße 10 Brünner Straße 10
@@ -115,20 +115,20 @@ namespace Tests.UnitTests.DocumentTests {
Assert.That(text, Contains.Substring("Das Mitglied erklärt, dass die gelieferte Ware dem österreichischen Weingesetz entspricht")); Assert.That(text, Contains.Substring("Das Mitglied erklärt, dass die gelieferte Ware dem österreichischen Weingesetz entspricht"));
Assert.That(text, Contains.Substring(""" Assert.That(text, Contains.Substring("""
1 Grüner Veltliner Wein 80 16,3 3 198 1 Grüner Veltliner Wein 80 16,3 3 198
Bewirtschaftung: Bio (AT-BIO-302) Bewirtschaftung: Bio (Biologische Produktion) Kontrollstelle: AT-BIO-302
Herkunft: Österreich Herkunft: Österreich
/ Wolkersdorfer Hochleithen / Wolkersdorf im Weinviertel / KG Wolkersdorf / Wolkersdorfer Hochleithen / Wolkersdorf im Weinviertel / KG Wolkersdorf
Waage/Terminal: ?/?, ID: ? (gerebelt gewogen) Waage/Terminal: ?/?, ID: ? (gerebelt gewogen)
""")); """));
Assert.That(text, Contains.Substring(""" Assert.That(text, Contains.Substring("""
2 Grüner Veltliner Qualitätswein 75 15,4 2 134 2 Grüner Veltliner Qualitätswein 75 15,4 2 134
Bewirtschaftung: Bio (AT-BIO-302) Bewirtschaftung: Bio (Biologische Produktion) Kontrollstelle: AT-BIO-302
Herkunft: Österreich / Weinland / Niederösterreich Herkunft: Österreich / Weinland / Niederösterreich
/ Wolkersdorfer Hochleithen / Wolkersdorf im Weinviertel / KG Wolkersdorf / Wolkersdorfer Hochleithen / Wolkersdorf im Weinviertel / KG Wolkersdorf
Waage/Terminal: ?/?, ID: ? (gerebelt gewogen) Waage/Terminal: ?/?, ID: ? (gerebelt gewogen)
""")); """));
Assert.That(text, Contains.Substring("Gesamt: 78 15,9 5 332")); Assert.That(text, Contains.Substring("Gesamt: 78 15,9 5 332"));
}); }
} }
[Test] [Test]
+1 -1
View File
@@ -1 +1 @@
curl --fail -s -L "https://elwig.at/files/create.sql?v=41" -u "elwig:ganzGeheim123!" -o "Resources\Sql\Create.sql" curl --fail -s -L "https://elwig.at/files/create.sql?v=42" -u "elwig:ganzGeheim123!" -o "Resources\Sql\Create.sql"