Compare commits
2
Commits
8bf827e2bb
...
015ec5f2d4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
015ec5f2d4 | ||
|
|
c293fa0ac7 |
No files matched your search
@@ -170,16 +170,25 @@ namespace Elwig.Helpers {
|
||||
SavedChanges += OnSavedChanges;
|
||||
}
|
||||
|
||||
private static void CreateFunctions(SqliteConnection cnx) {
|
||||
cnx.CreateFunction<string, string?, bool?>("REGEXP", (pattern, value) => {
|
||||
return value == null ? null : Regex.IsMatch(value, pattern);
|
||||
}, true);
|
||||
cnx.CreateFunction<string?, string?, string?>("NORMALIZE_ADDRESS", (address, locality) => {
|
||||
return string.IsNullOrWhiteSpace(address) ? null : Normalizer.NormalizeAddress(address, locality);
|
||||
}, true);
|
||||
}
|
||||
|
||||
public static SqliteConnection Connect(string? connectionString = null) {
|
||||
var cnx = new SqliteConnection(connectionString ?? ConnectionString);
|
||||
cnx.CreateFunction<string, string?, bool?>("REGEXP", (pattern, value) => value == null ? null : Regex.Match(value, pattern).Success, true);
|
||||
CreateFunctions(cnx);
|
||||
cnx.Open();
|
||||
return cnx;
|
||||
}
|
||||
|
||||
public static async Task<SqliteConnection> ConnectAsync(string? connectionString = null) {
|
||||
var cnx = new SqliteConnection(connectionString ?? ConnectionString);
|
||||
cnx.CreateFunction<string, string?, bool?>("REGEXP", (pattern, value) => value == null ? null : Regex.Match(value, pattern).Success, true);
|
||||
CreateFunctions(cnx);
|
||||
await cnx.OpenAsync();
|
||||
return cnx;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
using Elwig.Services;
|
||||
using Microsoft.Data.Sqlite;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace Elwig.Helpers {
|
||||
public static class AppDbUpdater {
|
||||
@@ -68,11 +71,11 @@ namespace Elwig.Helpers {
|
||||
})
|
||||
.OrderBy(s => s.Item1).ThenBy(s => s.Item2)];
|
||||
|
||||
List<string> toExecute = [];
|
||||
List<(int ToVersion, string File)> toExecute = [];
|
||||
var vers = fromVersion;
|
||||
while (vers < toVersion) {
|
||||
var (_, to, name) = scripts.Last(s => s.From == vers);
|
||||
toExecute.Add(name);
|
||||
toExecute.Add((to, name));
|
||||
vers = to;
|
||||
}
|
||||
if (toExecute.Count == 0)
|
||||
@@ -87,8 +90,11 @@ namespace Elwig.Helpers {
|
||||
await cnx.IntegrityCheck();
|
||||
await cnx.ForeignKeyCheck();
|
||||
|
||||
foreach (var script in toExecute) {
|
||||
foreach (var (to, script) in toExecute) {
|
||||
await cnx.ExecuteEmbeddedScript(asm, script);
|
||||
if (to == 42) {
|
||||
await UpdateDbSchema_41_To_42(cnx);
|
||||
}
|
||||
}
|
||||
|
||||
await cnx.IntegrityCheck();
|
||||
@@ -103,5 +109,57 @@ namespace Elwig.Helpers {
|
||||
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 abzurufen. Dies könnte einen kurzen Moment dauern.");
|
||||
|
||||
try {
|
||||
Mouse.OverrideCursor = Cursors.Wait;
|
||||
foreach (var m in members) {
|
||||
string? oocId = null;
|
||||
string? authCode = null;
|
||||
|
||||
var certs = await OrganicService.FetchTracesCertificates(lfbisNr: m.LfbisNr, address: (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}");
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
Mouse.OverrideCursor = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,303 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Elwig.Helpers {
|
||||
public static partial class Normalizer {
|
||||
|
||||
[GeneratedRegex(@"(?=(?:(?:bundes)?straße|gasse|weg|platz|allee|ring|zeile?|steig|hof|markt|kai|ufer|brücke|tor|stiege|promenade|gang|siedlung)\b)|[\s-]+", RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase)]
|
||||
private static partial Regex GeneratedStreetNameWordsRegex();
|
||||
private static readonly Regex StreetNameWordsRegex = GeneratedStreetNameWordsRegex();
|
||||
|
||||
private static readonly HashSet<string> StreetTypes = [
|
||||
"Straße", "Gasse", "Weg", "Platz", "Allee", "Ring", "Zeile", "Zeil", "Steig", "Hof",
|
||||
"Markt", "Kai", "Ufer", "Brücke", "Tor", "Stiege", "Promenade", "Gang", "Siedlung"];
|
||||
|
||||
private static readonly HashSet<string> StreetArticles = ["der", "die", "das", "des", "dem", "den"];
|
||||
|
||||
private static readonly HashSet<string> StreetPrepositions = [
|
||||
"an", "am", "auf", "aus", "bei", "beim", "hinter", "hinterm", "in", "im", "ins", "nach",
|
||||
"neben", "über", "unter", "von", "vom", "van", "vor", "zu", "zum", "zur", "zwischen",
|
||||
"durch", "mit"];
|
||||
|
||||
private static readonly HashSet<string> StreetNumbers = [ "Zwei", "Drei", "Vier", "Fünf", "Sechs", "Sieben" ];
|
||||
|
||||
private static readonly HashSet<string> StreetAdjectives = [
|
||||
"alter", "alte", "alten", "altem", "altes",
|
||||
"äußere", "äußere", "äußeren", "äußerem", "äußeres",
|
||||
// "breiter", "breite", "breiten", "breitem", "breites",
|
||||
"dritter", "dritte", "dritten", "drittem", "drittes",
|
||||
"erster", "erste", "ersten", "erstem", "erstes",
|
||||
"großer", "große", "großen", "großem", "großes",
|
||||
"hoher", "hohe", "hohen", "hohem", "hohes",
|
||||
"innerer", "innere", "inneren", "innerem", "inneres",
|
||||
"kleiner", "kleine", "kleinen", "kleinem", "kleines",
|
||||
"kurzer", "kurze", "kurzen", "kurzem", "kurzes",
|
||||
"langer", "lange", "langen", "langem", "langes",
|
||||
"linker", "linke", "linken", "linkem", "linkes",
|
||||
"mittlerer", "mittlere", "mittleren", "mittlerem", "mittleres",
|
||||
"neuer", "neue", "neuen", "neuem", "neues",
|
||||
"oberer", "obere", "oberen", "oberem", "oberes",
|
||||
"rechter", "rechte", "rechten", "rechtem", "rechtes",
|
||||
"schmaler", "schmale", "schmalen", "schmalem", "schmales",
|
||||
"schöner", "schöne", "schönen", "schönem", "schönes",
|
||||
"unterer", "untere", "unteren", "unterem", "unteres",
|
||||
"hinterer", "hintere", "hinteren", "hinterem", "hinteres",
|
||||
"vorderer", "vordere", "vorderen", "vorderem", "vorderes",
|
||||
"runder", "runde", "runden", "rundem", "rundes",
|
||||
"kalter", "kalte", "kalten", "kaltem", "kaltes"];
|
||||
|
||||
private static readonly HashSet<string> StreetLastNames = [
|
||||
"Habsburger", "Lothringer", "Leitzenberger", "Luyderer", "Preiner", "Radinger", "Seefelder", "Staribacher", "Gschmeidler",
|
||||
"Hannover", "Münster", "Salzgitter", "Speyer", "Trier"];
|
||||
|
||||
private static readonly HashSet<string> StreetPersonTitles = [
|
||||
"St.", "Familie",
|
||||
"Dr.", "DDr.", "Hofrat", "Baurat", "Kommerzialrat", "Dir.", "Ing.", "Prof.", "Mag.", "DI", "OSR", "Präsident",
|
||||
"Landeshauptmann", "LH", "Bürgermeister", "Bgm.", "Minister",
|
||||
"Kaiser", "Kaiserin", "König", "Königin", "Erzherzog", "Erzherzogin", "Herzog", "Fürst", "Graf", "Gräfin", "Markgraf", "Kronprinz", "Prinz", "Ritter", "Freiherr", "Lord",
|
||||
"Abt", "Bischof", "Propst", "Dechant", "Kardinal", "Monsignore", "Pfarrer", "Pater", "Prälat",
|
||||
"Oberst"];
|
||||
|
||||
private static readonly HashSet<string> StreetGivenNames = [
|
||||
"Adalbert", "Adam", "Adele", "Adelheid", "Adolf", "Adolph", "Adrian", "Albert", "Albrecht", "Alexander", "Alfons", "Alfred", "Alois", "Aloisia",
|
||||
"Andreas", "Andrea", "Andre", "Anna", "Anton", "Arnold", "Arthur", "August", "Augustin", "Augustine", "Agnes", "Angelika", "Ada", "Adelheid", "Anni", "Anita",
|
||||
"Barbara", "Beate", "Beatrix", "Benedikt", "Bernhard", "Berta", "Bertha", "Berthold", "Brüder", "Bruno", "Brigitte",
|
||||
"Camillo", "Carl", "Caspar", "Catharina", "Christian", "Christine", "Christof", "Christoph", "Clara", "Clemens", "Conrad", "Claus", "Camillo", "Claudia",
|
||||
"Daniel", "Dietmar", "Dietrich",
|
||||
"Edgar", "Edi", "Edith", "Edmund", "Egon", "Elsa", "Eduard", "Emmerich", "Erhard", "Erich", "Ernst", "Erwin", "Eugen", "Ewald", "Eberhard",
|
||||
"Elisabeth", "Emanuel", "Emerich", "Emil", "Emma", "Engelbert", "Elias",
|
||||
"Franz", "Ferdinand", "Friedrich", "Felix", "Florian", "Fritz", "Franziska", "Fred",
|
||||
"Georg", "Gregor", "Gustav", "Gabriel", "Gebrüder", "Gabriele", "Gerhard", "Gerhart", "Gertrude", "Gottfried", "Gottlieb", "Grete",
|
||||
"Günther", "Günter",
|
||||
"Hans", "Hanns", "Heinrich", "Heinz", "Helmut", "Helmuth", "Hermann", "Herta", "Herbert", "Hubert", "Harald", "Horst", "Helene", "Helga",
|
||||
"Hieronymus", "Hilde", "Hugo",
|
||||
"Isabelle", "Ignaz", "Ilse", "Ingeborg", "Isidor",
|
||||
"Josef", "Josefine", "Joseph", "Johann", "Johanna", "Johan", "Johannes", "Hannes", "Harry", "Jakob", "Jacob", "Jan", "Julian", "Julius", "Julia", "Jürgen",
|
||||
"Karl", "Kasimir", "Konrad", "Klemens", "Klara", "Katharina", "Kurt", "Kaspar", "Klaus", "Koloman", "Konstantin", "Killian",
|
||||
"Leopold", "Leo", "Lorenz", "Lothar", "Louise", "Ludmilla", "Ludwig", "Lukas", "Ladislaus", "Lambert", "Laurenz", "Liese",
|
||||
"Lise", "Lilly", "Lina", "Lothar", "Lotte", "Luise", "Leonhard", "Lotte", "Martha",
|
||||
"Maria", "Marie", "Michael", "Martin", "Max", "Maximilian", "Manuel", "Manuela", "Moritz", "Marianne", "Manfred", "Marc",
|
||||
"Mathias", "Matthias", "Matthäus",
|
||||
"Margarete", "Margarethe",
|
||||
"Nico", "Niko", "Niklas", "Niclas", "Nikolaus", "Norbert",
|
||||
"Otto", "Ottokar", "Oskar", "Olga", "Oswald", "Othmar",
|
||||
"Paul", "Pauline", "Patrick", "Pepi", "Peter", "Philipp", "Philip", "Petrus",
|
||||
"Robert", "Rudolf", "Richard", "Ruprecht", "Raffael", "Rolf", "Roman", "Rosa", "Rosalia", "Rupert", "Raimund",
|
||||
"Sigmund", "Siegfried", "Simon", "Stanislaus", "Stefan", "Stephan", "Sepp", "Samuel", "Sebastian", "Susi",
|
||||
"Theodor", "Thomas", "Theresia", "Thaddäus", "Theo", "Theophil", "Tina", "Titus", "Toni", "Trude",
|
||||
"Ullrich", "Ulrich", "Udo",
|
||||
"Viktor", "Vinzenz", "Victor",
|
||||
"Wolfgang", "Willibald", "Wilhelm", "Willhelm", "Wilhelmine", "Walter", "Walther", "Wenzel", "Werner", "Willi",
|
||||
"Zacharias"];
|
||||
|
||||
private static readonly HashSet<string> LocalityNames = [
|
||||
"Groß-Enzersdorf",
|
||||
"Groß Burgstall", "Klein Eberharts", "Klein-Engersdorf", "Groß-Enzersdorf", "Klein-Erlauf",
|
||||
"Groß Gerungs", "Klein Gundholz", "Klein-Harras", "Klein-Heinrichschlag", "Groß-Höbarten",
|
||||
"Klein-Jetzelsdorf", "Klein-Mariazell", "Groß Meinharts", "Klein-Meiseldorf", "Groß-Neusiedl", "Klein-Neusiedl", "Klein-Pöchlarn",
|
||||
"Groß-Radischen", "Klein-Radischen", "Groß Raßberg", "Klein Reinprechts", "Klein-Reinprechtsdorf", "Groß-Reipersdorf", "Klein-Ruprechts",
|
||||
"Groß-Schollach", "Klein-Schollach", "Groß-Schweinbarth", "Groß-Siegharts", "Klein-Siegharts", "Groß Sierning",
|
||||
"Klein-Ulrichschlag", "Klein Weinberg", "Klein Wetzles", "Klein-Wien",
|
||||
];
|
||||
|
||||
private static bool IsGivenName(this string word) {
|
||||
return StreetGivenNames.Contains(word);
|
||||
}
|
||||
|
||||
private static bool IsFamilyName(this string word) {
|
||||
if (StreetLastNames.Contains(word))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool IsPersonalName(this string word) {
|
||||
return word.IsGivenName() || word.IsFamilyName();
|
||||
}
|
||||
|
||||
private static bool IsGeographicalDerivativeName(this string word) {
|
||||
if (!word.EndsWith("er") || word.IsPersonalName() || word == "Weißer")
|
||||
return false;
|
||||
return word.StartsWith("St. ") || word.StartsWith("Ober ") || word.StartsWith("Unter ") || word.StartsWith("Maria") ||
|
||||
word.EndsWith("sdorfer") || word.EndsWith("ndorfer") || word.EndsWith("ldorfer") ||
|
||||
word.EndsWith("felder") ||
|
||||
word.EndsWith("sthaler") || word.EndsWith("nthaler") || word.EndsWith("lthaler") ||
|
||||
word.EndsWith("dauer") || word.EndsWith("lauer") || word.EndsWith("mauer") || word.EndsWith("nauer") || word.EndsWith("ßauer") ||
|
||||
word.EndsWith("lbacher") || word.EndsWith("nbacher") || word.EndsWith("ßbacher") ||
|
||||
word.EndsWith("ringer") || word.EndsWith("singer") ||
|
||||
word.EndsWith("sbrunner") || word.EndsWith("nbrunner") || word.EndsWith("lbrunner") || word.EndsWith("abrunner") || word.EndsWith("ingbrunner") ||
|
||||
word.EndsWith("sburger") || word.EndsWith("nburger") || word.EndsWith("mburger") || word.EndsWith("lburger") || word.EndsWith("neuburger") ||
|
||||
word.EndsWith("berger") ||
|
||||
word.EndsWith("winkler") ||
|
||||
word.EndsWith("lsteiner") || word.EndsWith("nsteiner") ||
|
||||
word.EndsWith("städter") ||
|
||||
word.EndsWith("stättner") || word.EndsWith("stettner") ||
|
||||
word.EndsWith("brücker") ||
|
||||
word.EndsWith("further") || word.EndsWith("furter") ||
|
||||
word.EndsWith("aaer") ||
|
||||
word.EndsWith("seer") || word.EndsWith("leer") ||
|
||||
word.EndsWith("tzner") ||
|
||||
word.EndsWith("zeller") ||
|
||||
word.EndsWith("rther") ||
|
||||
word.EndsWith("sdner") ||
|
||||
word.EndsWith("gerner") || word.EndsWith("berner") ||
|
||||
word.EndsWith("frieder") ||
|
||||
word.EndsWith("litzer") || word.EndsWith("mitzer") || word.EndsWith("eutzer") ||
|
||||
word.EndsWith("loner") ||
|
||||
word.EndsWith("skirchner") || word.EndsWith("nkirchner") || word.EndsWith("ingkirchner") ||
|
||||
word.EndsWith("ziger") ||
|
||||
word.EndsWith("ließer") ||
|
||||
word.EndsWith("gerer") ||
|
||||
word.EndsWith("kreuzer") ||
|
||||
word == "Wiener" || word == "Brünner" || word == "Znaimer" || word == "Triester" || word == "Prager" || word == "Berliner" || word == "Basler" ||
|
||||
word == "Retzer" || word == "Tullner" || word == "Badner" ||
|
||||
word == "Gruber" || word == "Sulzer" || word == "Harraser" || word == "Dörfleser" || word == "Neusiedler" ||
|
||||
word == "Dornauer" || word == "Siebenhauser" || word == "Alser" ||
|
||||
word == "Bockenheimer";
|
||||
}
|
||||
|
||||
public static string NormalizeAddress(string address, string? locality = null) {
|
||||
var idx = address.IndexOf(',');
|
||||
if (idx >= 0) address = address[..idx];
|
||||
var (name, nr) = Utils.SplitAddress(address);
|
||||
return (NormalizeStreetName(name, locality) + " " + nr).Trim();
|
||||
}
|
||||
|
||||
public static string NormalizeStreetName(string name, string? locality = null) {
|
||||
name = name.Trim().ToLowerInvariant();
|
||||
if (name == "") {
|
||||
return "";
|
||||
} else if (name == "nr.") {
|
||||
if (locality == null)
|
||||
return "Nr.";
|
||||
name = locality.Trim().ToLowerInvariant();
|
||||
}
|
||||
|
||||
name = name.Replace("hautp", "haupt")
|
||||
.Replace("leop.", "leopold ").Replace("ferd.", "ferdinand ").Replace("gottfr.", "gottfried ")
|
||||
.Replace("heinr.", "heinrich").Replace("joh.", "johann ").Replace("jos.", "josef ")
|
||||
.Replace("msgr.", "monsignore ").Replace("pf.", "pfarrer ")
|
||||
.Replace("präs.", "präsident ");
|
||||
name = name.Replace("str.", "straße").Replace("strasse", "straße")
|
||||
.Replace("bruecke", "brücke").Replace("pl.", "platz")
|
||||
.Replace("gr.", "groß").Replace("kl.", "klein")
|
||||
.Replace("sankt-", "st.").Replace("sankt ", "st.")
|
||||
.Replace("wr.", "wiener ")
|
||||
.Replace(".", ". ");
|
||||
List<string> words = [.. StreetNameWordsRegex.Split(name)
|
||||
.Where(w => !string.IsNullOrWhiteSpace(w))
|
||||
.Select(w => StreetArticles.Contains(w) || StreetPrepositions.Contains(w) ? w : string.Concat(w[0..1].ToUpper(), w.AsSpan(1)))
|
||||
.Select(w => w == "Ddr." ? "DDr." : w == "Lh" || w == "Osr" ? w.ToUpper() : w)
|
||||
];
|
||||
if (words[0] == "Di") words[0] = "DI";
|
||||
|
||||
var temp = "|" + string.Join('|', words) + "|";
|
||||
temp = temp.Replace("|Dipl.|Ing.|", "|DI|").Replace("|Dipl|Ing.|", "|DI|")
|
||||
.Replace("|Kaiser|Ebersdorf|", "|Kaiser-Ebersdorf|")
|
||||
.Replace("|Kalk|Deutz|", "|Kalk-Deutz|").Replace("|Kalk|Deutzer|", "|Kalk-Deutzer|")
|
||||
.Replace("|Hohe|Wand|", "|Hohe Wand|").Replace("|Hohen|Wand|", "|Hohen Wand|").Replace("|Hohewand|", "|Hohe Wand|")
|
||||
.Replace("|Alten|Markt|", "|Altenmarkt|")
|
||||
.Replace("|Kirch|Hof|", "|Kirchhof|").Replace("|Bisc|Hof|", "|Bischof|")
|
||||
.Replace("|Wiener|Neustadt|", "|Wiener Neustadt|").Replace("|Wiener|Neustädter|", "|Wiener Neustädter|")
|
||||
.Replace("|St.|Pölten|", "|St. Pölten|").Replace("|St.|Pöltner|", "|St. Pöltner|")
|
||||
.Replace("|Gross|", "|Groß|")
|
||||
.Replace("|Nr|", "|Nr.|").Replace("|Und|", "|und|");
|
||||
words = [.. temp.Trim('|').Split('|')];
|
||||
|
||||
if (words.Count > 1 && (words[0] == "Groß" || words[0] == "Klein") && !StreetTypes.Contains(words[1])) {
|
||||
var w = words[0] + words[1].ToLowerInvariant();
|
||||
words.RemoveRange(0, 2);
|
||||
words.Insert(0, w);
|
||||
}
|
||||
if (words[0].StartsWith("Groß") || words[0].StartsWith("Klein")) {
|
||||
var repl = LocalityNames.FirstOrDefault(n => n.Replace(" ", "").Replace("-", "").Equals(words[0], StringComparison.InvariantCultureIgnoreCase));
|
||||
if (repl != null) words[0] = repl;
|
||||
}
|
||||
|
||||
if (words.Count > 2 && words[^2] == "in") {
|
||||
// remove suffix "in ..."
|
||||
words.RemoveRange(words.Count - 2, 2);
|
||||
}
|
||||
|
||||
char sep = name.Contains('-') ? '-' : ' ';
|
||||
if (words.Count <= 1) {
|
||||
// single word
|
||||
} else if (StreetTypes.Contains(words[0]) && !StreetTypes.Contains(words[^1])) {
|
||||
// "Straße der ..." / "Straße des ..."
|
||||
sep = ' ';
|
||||
} else if (StreetTypes.Contains(words[^1])) {
|
||||
// "... Straße" / "...straße"
|
||||
var type = words[^1];
|
||||
var isCompound = true;
|
||||
var isAdjective = StreetAdjectives.Contains(words[^2].ToLowerInvariant());
|
||||
var isGeographical = false;
|
||||
var isPerson = false;
|
||||
|
||||
var geo = words.FindLastIndex(IsGeographicalDerivativeName);
|
||||
if (geo >= 0 && geo < words.Count - 2 && words[^2] != "Haupt" && words[^2] != "Bundes" && words[^2] != "Keller") {
|
||||
isPerson = true;
|
||||
isGeographical = true;
|
||||
} else if (words.Any(w => w.Contains(' ') && !w.IsGeographicalDerivativeName())) {
|
||||
isPerson = true;
|
||||
isGeographical = true;
|
||||
} else if (StreetNumbers.Contains(words[0])) {
|
||||
isPerson = true;
|
||||
isGeographical = true;
|
||||
} else if (!StreetPrepositions.Contains(words[0]) && !StreetArticles.Contains(words[0]) && words.FindIndex(StreetPrepositions.Contains) > 0) {
|
||||
isPerson = true;
|
||||
isGeographical = true;
|
||||
}
|
||||
|
||||
if (words.Count(w => w.Contains('.')) >= 2 || words.Contains("van") || words.Contains("von") || words.Contains("St.") ||
|
||||
StreetPersonTitles.Contains(words[0]) || words.Any(w => w.IsGivenName()))
|
||||
{
|
||||
isPerson = true;
|
||||
}
|
||||
|
||||
if (!isPerson && isAdjective || StreetArticles.Contains(words[^2]) || StreetPrepositions.Contains(words[^2])) {
|
||||
isCompound = false;
|
||||
}
|
||||
|
||||
if (!isPerson && words[^2].EndsWith("er") && !StreetLastNames.Contains(words[^2])) {
|
||||
isGeographical = IsGeographicalDerivativeName(words[^2]);
|
||||
} else if (words.Count >= 3 && words.Contains("Bad")) {
|
||||
isPerson = true;
|
||||
isGeographical = true;
|
||||
}
|
||||
|
||||
sep = isPerson ? '-' : ' ';
|
||||
|
||||
if (isPerson && words.Count == 2 && !isGeographical) {
|
||||
isPerson = false;
|
||||
isCompound = true;
|
||||
}
|
||||
if (isGeographical || isPerson) {
|
||||
isCompound = false;
|
||||
}
|
||||
if (isCompound) {
|
||||
var w = words[^2] + type.ToLowerInvariant();
|
||||
words.RemoveRange(words.Count - 2, 2);
|
||||
words.Add(w);
|
||||
}
|
||||
|
||||
if (isPerson) {
|
||||
words = [.. words.Select(w => w.Replace(' ', '-'))];
|
||||
}
|
||||
} else {
|
||||
// unknown
|
||||
}
|
||||
|
||||
if (sep == '-' && StreetPrepositions.Contains(words[0]) && words[0] != "von" && words[0] != "van") {
|
||||
sep = ' ';
|
||||
int i;
|
||||
for (i = 0; StreetPrepositions.Contains(words[i]) && i < words.Count; i++);
|
||||
var word = string.Join('-', words.Skip(i));
|
||||
words = [.. words.Take(i).Append(word)];
|
||||
}
|
||||
|
||||
var norm = string.Join(sep, words);
|
||||
return string.Concat(norm[0..1].ToUpperInvariant(), norm.AsSpan(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -711,5 +711,25 @@ namespace Elwig.Helpers {
|
||||
|
||||
return new(true, null);
|
||||
}
|
||||
|
||||
public static ValidationResult CheckAddress(TextBox input, bool required, string? locality = null) {
|
||||
var text = input.Text;
|
||||
var (name, nr) = Utils.SplitAddress(text);
|
||||
if (!string.IsNullOrWhiteSpace(nr)) {
|
||||
var street = Normalizer.NormalizeStreetName(name.Replace(",", ""), locality);
|
||||
var idx = input.CaretIndex;
|
||||
input.Text = $"{street} {nr}".Trim();
|
||||
if (idx >= (text.Length - nr.Length)) {
|
||||
input.CaretIndex = street.Length + (idx - (text.Length - nr.Length)) + 1;
|
||||
} else if (idx > 0) {
|
||||
input.CaretIndex = idx;
|
||||
}
|
||||
}
|
||||
|
||||
if (text.Length == 0)
|
||||
return required ? new(false, "Adresse ist nicht optional") : new(true, null);
|
||||
|
||||
return new(true, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,8 +8,12 @@ ALTER TABLE wine_cultivation ADD COLUMN organic INTEGER NOT NULL CHECK (orga
|
||||
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 client_parameter SET value = '0' WHERE param = 'ENABLE_TIME_TRIGGERS';
|
||||
|
||||
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 m.mgnr = member.mgnr AND 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-%';
|
||||
@@ -18,5 +22,18 @@ 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 = '';
|
||||
|
||||
UPDATE member SET address = 'Untere Weißgerberstraße' WHERE address = 'U. Weißgasse Straße';
|
||||
UPDATE member SET address = 'Edgar-Penzig-Franz-Straße' WHERE address = 'Edgar-Penzing-Franz-Straße';
|
||||
|
||||
UPDATE member
|
||||
SET address = NORMALIZE_ADDRESS(address, (SELECT o.name FROM AT_plz_dest p JOIN AT_ort o ON o.okz = p.okz WHERE p.id = member.postal_dest))
|
||||
WHERE address != NORMALIZE_ADDRESS(address, (SELECT o.name FROM AT_plz_dest p JOIN AT_ort o ON o.okz = p.okz WHERE p.id = member.postal_dest));
|
||||
UPDATE member_billing_address
|
||||
SET address = NORMALIZE_ADDRESS(address, (SELECT o.name FROM AT_plz_dest p JOIN AT_ort o ON o.okz = p.okz WHERE p.id = member_billing_address.postal_dest))
|
||||
WHERE address != NORMALIZE_ADDRESS(address, (SELECT o.name FROM AT_plz_dest p JOIN AT_ort o ON o.okz = p.okz WHERE p.id = member_billing_address.postal_dest));
|
||||
|
||||
UPDATE client_parameter SET value = '1' WHERE param = 'ENABLE_TIME_TRIGGERS';
|
||||
@@ -10,6 +10,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace Elwig.Services {
|
||||
public static class MemberService {
|
||||
@@ -19,6 +20,7 @@ namespace Elwig.Services {
|
||||
};
|
||||
|
||||
public static async Task InitInputs(this MemberAdminViewModel vm) {
|
||||
vm.IsMemberSelectedOrCreating = true;
|
||||
using var ctx = new AppDbContext();
|
||||
vm.MgNr = await ctx.NextMgNr();
|
||||
vm.EntryDate = DateTime.Now.ToString("dd.MM.yyyy");
|
||||
@@ -31,6 +33,7 @@ namespace Elwig.Services {
|
||||
|
||||
public static void ClearInputs(this MemberAdminViewModel vm) {
|
||||
vm.IsMemberSelected = false;
|
||||
vm.IsMemberSelectedOrCreating = false;
|
||||
vm.MemberHasEmail = false;
|
||||
vm.MemberCanSendEmail = false;
|
||||
vm.EnableMemberReferenceButton = false;
|
||||
@@ -49,10 +52,15 @@ namespace Elwig.Services {
|
||||
vm.ModifiedAtShort = "-";
|
||||
vm.ExportedAt = "-";
|
||||
vm.ImportedAt = "-";
|
||||
vm.OrganicState = null;
|
||||
vm.OrganicColor = Brushes.Black;
|
||||
vm.OrganicDetails = "-";
|
||||
vm.OrganicToolTip = null;
|
||||
}
|
||||
|
||||
public static void FillInputs(this MemberAdminViewModel vm, Member m) {
|
||||
vm.IsMemberSelected = true;
|
||||
vm.IsMemberSelectedOrCreating = true;
|
||||
vm.MgNr = m.MgNr;
|
||||
vm.PredecessorMgNr = m.PredecessorMgNr;
|
||||
vm.IsJuridicalPerson = m.IsJuridicalPerson;
|
||||
@@ -189,10 +197,9 @@ namespace Elwig.Services {
|
||||
.GroupBy(d => d.Year)
|
||||
.ToDictionaryAsync(g => g.Key, g => g.Any());
|
||||
|
||||
await App.MainDispatcher.BeginInvoke(() => {
|
||||
if (m.MgNr != vm.MgNr)
|
||||
return;
|
||||
|
||||
await App.MainDispatcher.BeginInvoke(() => {
|
||||
var (d1Grid, _) = DeliveryService.GenerateToolTip(d1GridData, []);
|
||||
var (d2Grid, _) = DeliveryService.GenerateToolTip(d2GridData, []);
|
||||
var grid = AreaComService.GenerateToolTip(gridData);
|
||||
@@ -205,13 +212,76 @@ namespace Elwig.Services {
|
||||
vm.StatusAreaCommitmentInfo = $"{Utils.CurrentLastSeason}";
|
||||
vm.StatusAreaCommitment = text;
|
||||
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.OrganicState = null;
|
||||
vm.OrganicColor = Brushes.Black;
|
||||
vm.OrganicToolTip = null;
|
||||
if (!vm.IsOrganic) {
|
||||
vm.OrganicDetails = "-";
|
||||
} else {
|
||||
vm.OrganicDetails = "...";
|
||||
Utils.RunBackground("Bio-Zertifikatsdaten laden", async () => {
|
||||
if (App.MainDispatcher == null) return;
|
||||
var certs = await OrganicService.GetTracesCertificates(m);
|
||||
await App.MainDispatcher.BeginInvoke(() => {
|
||||
if (m.MgNr != vm.MgNr) return;
|
||||
vm.FillOrganicInputs(certs.Length > 0 ? certs[0] : null);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
vm.MemberHasEmail = 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 void FillOrganicInputs(this MemberAdminViewModel vm, OrganicService.TracesCertificate? cert) {
|
||||
vm.OrganicDetails = null;
|
||||
if (cert == null) {
|
||||
vm.OrganicState = "Nicht gefunden";
|
||||
vm.OrganicColor = Brushes.DarkRed;
|
||||
vm.OrganicToolTip = null;
|
||||
return;
|
||||
}
|
||||
|
||||
vm.OrganicToolTip = $"""
|
||||
Zertifikat-Nr.: {cert.Id}
|
||||
Status: {cert.Status}
|
||||
Bio-KSt.: {cert.AuthorityCode}
|
||||
EU Operator-ID: {cert.OperatorId}
|
||||
Operator: {cert.OperatorName}
|
||||
Ausgestellt am: {cert.IssuedOn:dd.MM.yyyy}
|
||||
Aktualisiert am: {cert.LastStatusUpdateOn:dd.MM.yyyy}
|
||||
Erlischt am: {cert.ExpiresOn:dd.MM.yyyy}
|
||||
""";
|
||||
if (cert.IsValidForWineProduction) {
|
||||
vm.OrganicState = "Gültig";
|
||||
vm.OrganicDetails = $" ({cert.ExpiresOn:MMM. yyyy})";
|
||||
vm.OrganicColor = Brushes.DarkGreen;
|
||||
} else if (cert.IsValid) {
|
||||
vm.OrganicState = "Gültig";
|
||||
vm.OrganicDetails = $" ({cert.ExpiresOn:MMM. yyyy})";
|
||||
vm.OrganicColor = Brushes.OrangeRed;
|
||||
} else {
|
||||
vm.OrganicColor = Brushes.DarkRed;
|
||||
switch (cert.Status) {
|
||||
case OrganicService.TracesStatus.ISSUED:
|
||||
vm.OrganicState = "Ausgestellt";
|
||||
vm.OrganicDetails = $" ({cert.LastStatusUpdateOn:MMM. yyyy})"; break;
|
||||
case OrganicService.TracesStatus.SUSPENDED:
|
||||
vm.OrganicState = "Gesperrt";
|
||||
vm.OrganicDetails = $" ({cert.LastStatusUpdateOn:MMM. yyyy})"; break;
|
||||
case OrganicService.TracesStatus.EXPIRED:
|
||||
vm.OrganicState = "Ausgelaufen";
|
||||
vm.OrganicDetails = $" ({cert.LastStatusUpdateOn:MMM. yyyy})"; break;
|
||||
case OrganicService.TracesStatus.WITHDRAWN:
|
||||
vm.OrganicState = "Widerrufen";
|
||||
vm.OrganicDetails = $" ({cert.LastStatusUpdateOn:MMM. yyyy})"; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<(List<string>, IQueryable<Member>, List<string>)> GetFilters(this MemberAdminViewModel vm, AppDbContext ctx) {
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
using Elwig.Helpers;
|
||||
using Elwig.Models.Entities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Text.RegularExpressions;
|
||||
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));
|
||||
}
|
||||
|
||||
private static readonly Dictionary<int, (DateTime Timestamp, TracesCertificate[] Certificates)> _memberCerts = [];
|
||||
|
||||
public async static Task<TracesCertificate[]> GetTracesCertificates(Member m, bool? tryNameAndAddress = null) {
|
||||
if (_memberCerts.TryGetValue(m.MgNr, out var entry) && entry.Timestamp >= DateTime.Now.AddDays(-1))
|
||||
return entry.Certificates;
|
||||
var certs = await FetchTracesCertificates(m, tryNameAndAddress);
|
||||
_memberCerts[m.MgNr] = (DateTime.Now, certs);
|
||||
return certs;
|
||||
}
|
||||
|
||||
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());
|
||||
return resJson?.AsArray() ?? throw new JsonException();
|
||||
}
|
||||
|
||||
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 = null, string? lfbisNr = null, (string Name, string Address, string PostalCode)? address = null) {
|
||||
bool searchedByName = false;
|
||||
JsonArray jsonCerts = [];
|
||||
|
||||
if (jsonCerts.Count == 0 && oocId != null) {
|
||||
jsonCerts = await TryFetchTracesCertificates(new Dictionary<string, string> {
|
||||
{ "operatorIdentifierType", "ooc_identifier" },
|
||||
{ "operatorIdentifierSearchOperator", "STRICT" },
|
||||
{ "operatorIdentifier", oocId },
|
||||
});
|
||||
}
|
||||
|
||||
if (jsonCerts.Count == 0 && lfbisNr != null) {
|
||||
jsonCerts = await TryFetchTracesCertificates(new Dictionary<string, string> {
|
||||
{ "operatorIdentifierType", "comp_reg" },
|
||||
{ "operatorIdentifierSearchOperator", "STRICT" },
|
||||
{ "operatorIdentifier", lfbisNr.TrimStart('0') },
|
||||
});
|
||||
}
|
||||
|
||||
if (jsonCerts.Count == 0 && address != null) {
|
||||
jsonCerts = await TryFetchTracesCertificates(new Dictionary<string, string> {
|
||||
{ "operatorPostalCode", address.Value.PostalCode },
|
||||
// FIXME maxlen 40!
|
||||
{ "query", $"{Regex.Replace(address.Value.Name, @"\(.*?\)", "")} {address.Value.Address}" },
|
||||
});
|
||||
searchedByName = true;
|
||||
}
|
||||
|
||||
if (jsonCerts.Count == 0)
|
||||
return [];
|
||||
|
||||
TracesCertificate[] 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()),
|
||||
})];
|
||||
|
||||
return (!searchedByName || certs.Where(c => c.Status == TracesStatus.ISSUED).Select(c => c.OperatorId).ToHashSet().Count == 1) ? certs : [];
|
||||
}
|
||||
|
||||
public static string? GetTracesSearchUrl(Member m, bool? tryNameAndAddress = null) {
|
||||
return GetTracesSearchUrl(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 static string? GetTracesSearchUrl(string? oocId = null, string? lfbisNr = null, (string Name, string Address, string PostalCode)? address = null) {
|
||||
var baseUrl = "https://webgate.ec.europa.eu/tracesnt/directory/publication/organic-operator/index";
|
||||
if (oocId != null) {
|
||||
return $"{baseUrl}#!?countryCode=AT&operatorIdentifierType=ooc_identifier&operatorIdentifierSearchOperator=STRICT&operatorIdentifier={oocId}&states=ISSUED";
|
||||
} else if (lfbisNr != null) {
|
||||
return $"{baseUrl}#!?countryCode=AT&operatorIdentifierType=comp_reg&operatorIdentifierSearchOperator=STRICT&operatorIdentifier={lfbisNr.TrimStart('0')}&states=ISSUED";
|
||||
} else if (address != null) {
|
||||
return $"{baseUrl}#!?countryCode=AT&operatorPostalCode={address?.PostalCode}&query={address?.Name.Replace(' ', '+')}+{address?.Address.Replace(' ', '+')}&states=ISSUED";
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static string? GetEasyCertSearchUrl(string lfbisNr) {
|
||||
var baseUrl = "https://www.easy-cert.com/htm/suchergebnis.htm";
|
||||
return $"{baseUrl}?CountryCode=AT&CustomerNumber={lfbisNr.TrimStart('0')}";
|
||||
}
|
||||
|
||||
public static string? GetBiocSearchUrl(string lfbisNr) {
|
||||
var baseUrl = "https://www.bioc.info/search/producersearchresult";
|
||||
return $"{baseUrl}?producerSearch[country]=a1e51f85-27b5-a1e3-65f7-561569884d38&producerSearch[operatorId]={lfbisNr.TrimStart('0')}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace Elwig.ViewModels {
|
||||
public partial class MemberAdminViewModel : ObservableObject {
|
||||
@@ -33,6 +34,8 @@ namespace Elwig.ViewModels {
|
||||
[ObservableProperty]
|
||||
private bool _isMemberSelected;
|
||||
[ObservableProperty]
|
||||
private bool _isMemberSelectedOrCreating;
|
||||
[ObservableProperty]
|
||||
private bool _memberHasEmail;
|
||||
[ObservableProperty]
|
||||
private bool _memberCanSendEmail;
|
||||
@@ -126,6 +129,15 @@ namespace Elwig.ViewModels {
|
||||
[ObservableProperty]
|
||||
private bool _isOrganic;
|
||||
|
||||
[ObservableProperty]
|
||||
private string? _organicState;
|
||||
[ObservableProperty]
|
||||
private string? _organicDetails = "-";
|
||||
[ObservableProperty]
|
||||
private Brush? _organicColor = Brushes.Black;
|
||||
[ObservableProperty]
|
||||
private string? _organicToolTip;
|
||||
|
||||
[ObservableProperty]
|
||||
private string? _entryDate;
|
||||
[ObservableProperty]
|
||||
|
||||
@@ -434,7 +434,7 @@ namespace Elwig.Windows {
|
||||
UpdateButtons();
|
||||
}
|
||||
|
||||
protected void TextBox_TextChanged(object sender, RoutedEventArgs? evt) {
|
||||
protected void TextBox_TextChanged(object sender, TextChangedEventArgs? evt) {
|
||||
var input = (Control)sender;
|
||||
var tb = input as TextBox;
|
||||
if (SenderIsRequired(input) && tb?.Text.Length == 0) {
|
||||
@@ -603,5 +603,13 @@ namespace Elwig.Windows {
|
||||
protected void AreaComTypeDetailsButton_Click(object sender, RoutedEventArgs? evt) {
|
||||
App.FocusBaseDataAreaComType();
|
||||
}
|
||||
|
||||
protected void AddressInput_TextChanged(object sender, TextChangedEventArgs? evt) {
|
||||
if ((IsCreating || IsEditing) && sender is TextBox b) {
|
||||
InputTextChanged(b, (i, r) => Validator.CheckAddress(i, r));
|
||||
} else {
|
||||
TextBox_TextChanged(sender, evt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -90,7 +90,7 @@
|
||||
<Label Content="Adresse:"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Column="0" Margin="10,160,0,10"/>
|
||||
<TextBox x:Name="ClientAddressInput"
|
||||
TextChanged="TextBox_TextChanged"
|
||||
TextChanged="AddressInput_TextChanged"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Stretch" Grid.Column="1" Margin="0,160,10,10"/>
|
||||
|
||||
<Label Content="PLZ/Ort:"
|
||||
|
||||
@@ -371,7 +371,7 @@
|
||||
<Label Content="Adresse:" Margin="10,130,0,0"/>
|
||||
<TextBox x:Name="AddressInput" Text="{Binding Address, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
Margin="0,130,10,0" Grid.Column="1" Grid.ColumnSpan="3"
|
||||
TextChanged="TextBox_TextChanged"/>
|
||||
TextChanged="AddressInput_TextChanged"/>
|
||||
|
||||
<Label Content="PLZ/Ort:" Margin="10,160,0,0" Grid.Column="0"/>
|
||||
<TextBox x:Name="PlzInput" Margin="0,160,0,0" Text="{Binding PlzString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
@@ -379,6 +379,7 @@
|
||||
TextChanged="PlzInput_TextChanged" LostFocus="PlzInput_LostFocus" Tag="PLZ"/>
|
||||
<ComboBox x:Name="OrtInput" SelectedItem="{Binding Ort, Mode=TwoWay}" ItemsSource="{Binding OrtSource, Mode=TwoWay}"
|
||||
ItemTemplate="{StaticResource PostalDestTemplate}" TextSearch.TextPath="Ort.Name"
|
||||
SelectionChanged="OrtInput_SelectionChanged"
|
||||
Margin="47,160,10,0" Grid.Column="1" Grid.ColumnSpan="3"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
@@ -565,7 +566,7 @@
|
||||
TextChanged="UstIdNrInput_TextChanged" LostFocus="UstIdNrInput_LostFocus"/>
|
||||
|
||||
<CheckBox x:Name="OrganicInput" Content="Bio" IsChecked="{Binding IsOrganic, Mode=TwoWay}" IsEnabled="False"
|
||||
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"
|
||||
Checked="OrganicInput_Changed" Unchecked="OrganicInput_Changed"
|
||||
Grid.Column="2" HorizontalAlignment="Left" Margin="5,15,0,0" VerticalAlignment="Top"/>
|
||||
|
||||
<CheckBox x:Name="BuchführendInput" Content="Buchführend" IsChecked="{Binding IsBuchführend, Mode=TwoWay}" IsEnabled="False"
|
||||
@@ -603,7 +604,7 @@
|
||||
<Label Content="Adresse:" Margin="10,40,0,0" Grid.Column="0"/>
|
||||
<TextBox x:Name="BillingAddressInput" Text="{Binding BillingAddress, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
Margin="0,40,10,0" Grid.Column="1"
|
||||
TextChanged="TextBox_TextChanged"/>
|
||||
TextChanged="AddressInput_TextChanged"/>
|
||||
|
||||
<Label Content="PLZ/Ort:" Margin="10,70,0,0" Grid.Column="0"/>
|
||||
<TextBox x:Name="BillingPlzInput" Text="{Binding BillingPlzString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
@@ -611,6 +612,7 @@
|
||||
TextChanged="PlzInput_TextChanged" LostFocus="PlzInput_LostFocus" Tag="PLZ"/>
|
||||
<ComboBox x:Name="BillingOrtInput" SelectedItem="{Binding BillingOrt, Mode=TwoWay}" ItemsSource="{Binding BillingOrtSource, Mode=TwoWay}"
|
||||
ItemTemplate="{StaticResource PostalDestTemplate}" TextSearch.TextPath="Ort.Name"
|
||||
SelectionChanged="OrtInput_SelectionChanged"
|
||||
Margin="47,70,10,0" Grid.Column="1"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
@@ -618,7 +620,8 @@
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="90"/>
|
||||
<ColumnDefinition Width="90"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
@@ -655,46 +658,64 @@
|
||||
|
||||
<CheckBox x:Name="ActiveInput" Content="Aktiv" IsChecked="{Binding IsActive, Mode=TwoWay}" IsEnabled="False"
|
||||
Checked="ActiveInput_Changed" Unchecked="ActiveInput_Changed"
|
||||
Grid.Column="2" HorizontalAlignment="Left" Margin="10,15,0,0" VerticalAlignment="Top"/>
|
||||
Grid.Column="2" HorizontalAlignment="Left" Margin="0,15,0,0" VerticalAlignment="Top"/>
|
||||
|
||||
<CheckBox x:Name="VollLieferantInput" Content="Volllieferant" IsChecked="{Binding IsVollLieferant, Mode=TwoWay}" IsEnabled="False"
|
||||
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"
|
||||
Grid.Column="2" HorizontalAlignment="Left" Margin="10,45,0,0" VerticalAlignment="Top"/>
|
||||
Grid.Column="2" HorizontalAlignment="Left" Margin="0,45,0,0" VerticalAlignment="Top"/>
|
||||
|
||||
<CheckBox x:Name="FunkionärInput" Content="Funktionär" IsChecked="{Binding IsFunktionär, Mode=TwoWay}" IsEnabled="False"
|
||||
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"
|
||||
Grid.Column="2" HorizontalAlignment="Left" Margin="10,75,0,0" VerticalAlignment="Top"/>
|
||||
Grid.Column="2" HorizontalAlignment="Left" Margin="0,75,0,0" VerticalAlignment="Top"/>
|
||||
|
||||
<Label Content="Bio-Zertifikate:" Margin="0,-2.5,20,0" Grid.Column="3" HorizontalAlignment="Right"/>
|
||||
<Button x:Name="OrganicTracesButton" IsEnabled="{Binding IsMemberSelectedOrCreating}" ToolTip="{Binding OrganicToolTip}"
|
||||
Click="OrganicTracesButton_Click"
|
||||
HorizontalAlignment="Right" Margin="0,20,10,0" Width="100" Padding="0" Height="35" VerticalAlignment="Top" Grid.Column="2" Grid.ColumnSpan="2" HorizontalContentAlignment="Stretch">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<TextBlock FontSize="12" TextAlignment="Center" VerticalAlignment="Top" Margin="0,0,0,-3">EU TRACES</TextBlock>
|
||||
<TextBlock FontSize="10" TextAlignment="Center" VerticalAlignment="Bottom" Margin="0,0,0,0">
|
||||
<Run Text="{Binding OrganicState}" FontWeight="Bold" Foreground="{Binding OrganicColor}"/><Run Text="{Binding OrganicDetails}"/>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<Button x:Name="OrganicEasyCertButton" IsEnabled="{Binding IsMemberSelectedOrCreating}" Content="Easy-Cert"
|
||||
Click="OrganicEasyCertButton_Click"
|
||||
HorizontalAlignment="Right" Margin="0,60,10,0" Width="100" Height="30" VerticalAlignment="Top" Grid.Column="2" Grid.ColumnSpan="2"/>
|
||||
<Button x:Name="OrganicBiocButton" IsEnabled="{Binding IsMemberSelectedOrCreating}" Content="BioC"
|
||||
Click="OrganicBiocButton_Click"
|
||||
HorizontalAlignment="Right" Margin="0,95,10,0" Width="100" Height="30" VerticalAlignment="Top" Grid.Column="2" Grid.ColumnSpan="2"/>
|
||||
|
||||
<Label Content="Stamm-Zwst.:" Margin="10,130,0,0" Grid.Column="0"/>
|
||||
<ComboBox x:Name="BranchInput" SelectedItem="{Binding Branch, Mode=TwoWay}" ItemsSource="{Binding BranchSource, Mode=TwoWay}"
|
||||
DisplayMemberPath="Name" TextSearch.TextPath="Name"
|
||||
Margin="0,130,10,0" Grid.Column="1" Grid.ColumnSpan="2"/>
|
||||
Margin="0,130,10,0" Grid.Column="1" Grid.ColumnSpan="3"/>
|
||||
|
||||
<Label Content="Stammgemeinde:" Margin="10,160,0,0" Grid.Column="0"/>
|
||||
<ComboBox x:Name="DefaultKgInput" SelectedItem="{Binding DefaultKg, Mode=TwoWay}" ItemsSource="{Binding DefaultKgSource, Mode=TwoWay}"
|
||||
DisplayMemberPath="Name" TextSearch.TextPath="Name"
|
||||
Margin="0,160,40,10" Grid.Column="1" Grid.ColumnSpan="2"/>
|
||||
Margin="0,160,40,10" Grid.Column="1" Grid.ColumnSpan="3"/>
|
||||
<Button x:Name="KgDetailsButton" Content="" FontFamily="Segoe MDL2 Assets" FontSize="14" Padding="0,1,0,0"
|
||||
Click="KgDetailsButton_Click"
|
||||
Grid.Column="2" VerticalAlignment="Top" HorizontalAlignment="Right" Width="25" Height="25" Margin="10,160,10,10"/>
|
||||
Grid.Column="3" VerticalAlignment="Top" HorizontalAlignment="Right" Width="25" Height="25" Margin="10,160,10,10"/>
|
||||
|
||||
<Label Content="Anmerkung:" Margin="10,190,0,0" Grid.Column="0"/>
|
||||
<TextBox x:Name="CommentInput" Text="{Binding Comment, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
Margin="0,190,10,70" Grid.Column="1" Grid.ColumnSpan="2" FontSize="12"
|
||||
Margin="0,190,10,70" Grid.Column="1" Grid.ColumnSpan="3" FontSize="12"
|
||||
TextChanged="TextBox_TextChanged"
|
||||
VerticalAlignment="Stretch" Height="auto" AcceptsReturn="True" TextWrapping="Wrap" VerticalScrollBarVisibility="Visible"/>
|
||||
|
||||
<Label Content="Kontaktart:" Margin="10,10,0,40" Grid.Column="0" VerticalAlignment="Bottom"/>
|
||||
<CheckBox x:Name="ContactPostalInput" Content="Post" IsChecked="{Binding ContactViaPost, Mode=TwoWay}" IsEnabled="False"
|
||||
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"
|
||||
HorizontalAlignment="Left" Margin="0,0,0,45" VerticalAlignment="Bottom" Grid.Column="1" Grid.ColumnSpan="2"/>
|
||||
HorizontalAlignment="Left" Margin="0,0,0,45" VerticalAlignment="Bottom" Grid.Column="1" Grid.ColumnSpan="3"/>
|
||||
<CheckBox x:Name="ContactEmailInput" Content="E-Mail" IsChecked="{Binding ContactViaEmail, Mode=TwoWay}" IsEnabled="False"
|
||||
Checked="ContactEmailInput_Changed" Unchecked="ContactEmailInput_Changed"
|
||||
HorizontalAlignment="Left" Margin="60,0,0,45" VerticalAlignment="Bottom" Grid.Column="1" Grid.ColumnSpan="2"/>
|
||||
HorizontalAlignment="Left" Margin="60,0,0,45" VerticalAlignment="Bottom" Grid.Column="1" Grid.ColumnSpan="3"/>
|
||||
|
||||
<Label Content="Zuletzt geändert:" Margin="10,10,0,10" Grid.Column="0" VerticalAlignment="Bottom"/>
|
||||
<TextBlock x:Name="LastModified" Text="{Binding ModifiedAtShort}"
|
||||
Margin="0,10,0,15" Grid.Column="1" TextWrapping="NoWrap" VerticalAlignment="Bottom">
|
||||
Margin="0,10,0,15" Grid.Column="1" Grid.ColumnSpan="2" TextWrapping="NoWrap" VerticalAlignment="Bottom">
|
||||
<TextBlock.ToolTip>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
@@ -721,7 +742,7 @@
|
||||
|
||||
<Button x:Name="DeliveryButton" IsEnabled="{Binding IsMemberSelected}"
|
||||
Click="DeliveryButton_Click"
|
||||
HorizontalAlignment="Right" Margin="10,00,10,37" Width="160" VerticalAlignment="Bottom" Grid.ColumnSpan="3" HorizontalContentAlignment="Stretch">
|
||||
HorizontalAlignment="Right" Margin="10,00,10,37" Width="160" VerticalAlignment="Bottom" Grid.ColumnSpan="4" HorizontalContentAlignment="Stretch">
|
||||
<Grid>
|
||||
<TextBlock Margin="0,0,10,0" TextAlignment="Center">Lieferungen</TextBlock>
|
||||
<TextBlock FontFamily="Segoe MDL2 Assets" FontSize="16" Text=""
|
||||
@@ -730,7 +751,7 @@
|
||||
</Button>
|
||||
<Button x:Name="AreaCommitmentButton" IsEnabled="{Binding IsMemberSelected}"
|
||||
Click="AreaCommitmentButton_Click"
|
||||
HorizontalAlignment="Right" Margin="10,10,10,5" Width="160" VerticalAlignment="Bottom" Grid.ColumnSpan="3" HorizontalContentAlignment="Stretch">
|
||||
HorizontalAlignment="Right" Margin="10,10,10,5" Width="160" VerticalAlignment="Bottom" Grid.ColumnSpan="4" HorizontalContentAlignment="Stretch">
|
||||
<Grid>
|
||||
<TextBlock Margin="0,0,15,0" TextAlignment="Center">Flächenbindungen</TextBlock>
|
||||
<TextBlock FontFamily="Segoe MDL2 Assets" FontSize="16" Text=""
|
||||
|
||||
@@ -7,6 +7,7 @@ using Elwig.ViewModels;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
@@ -502,6 +503,8 @@ namespace Elwig.Windows {
|
||||
UnlockInputs();
|
||||
UpdateContactInfoVisibility(true);
|
||||
ViewModel.EnableSearchInputs = false;
|
||||
|
||||
UpdateOrganic();
|
||||
}
|
||||
|
||||
protected override void ShortcutDelete() {
|
||||
@@ -971,6 +974,7 @@ namespace Elwig.Windows {
|
||||
}
|
||||
|
||||
private async void ActiveInput_Changed(object sender, RoutedEventArgs evt) {
|
||||
CheckBox_Changed(sender, evt);
|
||||
if (MemberList.SelectedItem is not Member m)
|
||||
return;
|
||||
if ((IsEditing || IsCreating) && ViewModel.IsActive == false && ViewModel.MgNr is int mgnr) {
|
||||
@@ -985,7 +989,6 @@ namespace Elwig.Windows {
|
||||
}
|
||||
}
|
||||
}
|
||||
CheckBox_Changed(sender, evt);
|
||||
}
|
||||
|
||||
private void JuridicalPersonInput_Changed(object sender, RoutedEventArgs evt) {
|
||||
@@ -1008,5 +1011,100 @@ namespace Elwig.Windows {
|
||||
ValidateRequiredInputs();
|
||||
UpdateButtons();
|
||||
}
|
||||
|
||||
new protected void AddressInput_TextChanged(object sender, TextChangedEventArgs? evt) {
|
||||
if ((IsCreating || IsEditing) && sender is TextBox b) {
|
||||
InputTextChanged(b, (i, r) => Validator.CheckAddress(i, r, b == BillingAddressInput ? ViewModel.BillingOrt?.Ort.Name : ViewModel.Ort?.Ort.Name));
|
||||
} else {
|
||||
TextBox_TextChanged(sender, evt);
|
||||
}
|
||||
}
|
||||
|
||||
private void OrtInput_SelectionChanged(object sender, SelectionChangedEventArgs? evt) {
|
||||
if (!IsCreating && !IsEditing)
|
||||
return;
|
||||
if (sender == BillingOrtInput) {
|
||||
InputTextChanged(BillingAddressInput, (i, r) => Validator.CheckAddress(i, r, ViewModel.BillingOrt?.Ort.Name));
|
||||
} else {
|
||||
InputTextChanged(AddressInput, (i, r) => Validator.CheckAddress(i, r, ViewModel.Ort?.Ort.Name));
|
||||
}
|
||||
}
|
||||
|
||||
private void OrganicInput_Changed(object sender, RoutedEventArgs evt) {
|
||||
CheckBox_Changed(sender, evt);
|
||||
if (IsEditing || IsCreating) {
|
||||
UpdateOrganic();
|
||||
}
|
||||
}
|
||||
|
||||
private new void LfbisNrInput_TextChanged(object sender, TextChangedEventArgs evt) {
|
||||
base.LfbisNrInput_TextChanged(sender, evt);
|
||||
if (IsEditing || IsCreating) {
|
||||
UpdateOrganic();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateOrganic() {
|
||||
if (!ViewModel.IsOrganic || string.IsNullOrWhiteSpace(ViewModel.LfbisNr) || !GetInputValid(LfbisNrInput)) {
|
||||
ViewModel.OrganicState = null;
|
||||
ViewModel.OrganicColor = Brushes.Black;
|
||||
ViewModel.OrganicDetails = "-";
|
||||
ViewModel.OrganicToolTip = null;
|
||||
return;
|
||||
} else {
|
||||
ViewModel.OrganicState = null;
|
||||
ViewModel.OrganicColor = Brushes.Black;
|
||||
ViewModel.OrganicToolTip = null;
|
||||
ViewModel.OrganicDetails = "...";
|
||||
var lfbisNr = ViewModel.LfbisNr;
|
||||
Utils.RunBackground("Bio-Zertifikatsdaten laden", async () => {
|
||||
if (App.MainDispatcher == null) return;
|
||||
var certs = await OrganicService.FetchTracesCertificates(lfbisNr: lfbisNr);
|
||||
await App.MainDispatcher.BeginInvoke(() => {
|
||||
if (certs.Length == 0) {
|
||||
ViewModel.FillOrganicInputs(null);
|
||||
} else {
|
||||
var cert = certs[0];
|
||||
ViewModel.FillOrganicInputs(cert);
|
||||
ViewModel.OrganicAuthorityCode = cert.AuthorityCode;
|
||||
ViewModel.OrganicOperatorId = cert.OperatorId;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void OrganicTracesButton_Click(object sender, RoutedEventArgs evt) {
|
||||
string? url = null;
|
||||
if ((IsCreating || IsEditing) && !string.IsNullOrWhiteSpace(ViewModel.LfbisNr) && GetInputValid(LfbisNrInput)) {
|
||||
url = OrganicService.GetTracesSearchUrl(lfbisNr: ViewModel.LfbisNr);
|
||||
} else if (ViewModel.SelectedMember is Member m) {
|
||||
url = OrganicService.GetTracesSearchUrl(m);
|
||||
}
|
||||
if (url != null)
|
||||
Process.Start(new ProcessStartInfo(url) { UseShellExecute = true });
|
||||
}
|
||||
|
||||
private void OrganicEasyCertButton_Click(object sender, RoutedEventArgs evt) {
|
||||
string? url = null;
|
||||
if ((IsCreating || IsEditing) && !string.IsNullOrWhiteSpace(ViewModel.LfbisNr) && GetInputValid(LfbisNrInput)) {
|
||||
url = OrganicService.GetEasyCertSearchUrl(ViewModel.LfbisNr);
|
||||
} else if (ViewModel.SelectedMember is Member m && m.LfbisNr != null) {
|
||||
url = OrganicService.GetEasyCertSearchUrl(m.LfbisNr);
|
||||
}
|
||||
if (url != null)
|
||||
Process.Start(new ProcessStartInfo(url) { UseShellExecute = true });
|
||||
}
|
||||
|
||||
private void OrganicBiocButton_Click(object sender, RoutedEventArgs evt) {
|
||||
string? url = null;
|
||||
if ((IsCreating || IsEditing) && !string.IsNullOrWhiteSpace(ViewModel.LfbisNr) && GetInputValid(LfbisNrInput)) {
|
||||
url = OrganicService.GetBiocSearchUrl(ViewModel.LfbisNr);
|
||||
} else if (ViewModel.SelectedMember is Member m && m.LfbisNr != null) {
|
||||
url = OrganicService.GetBiocSearchUrl(m.LfbisNr);
|
||||
}
|
||||
if (url != null)
|
||||
Process.Start(new ProcessStartInfo(url) { UseShellExecute = true });
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user