diff --git a/Elwig/Elwig.csproj b/Elwig/Elwig.csproj
index 5fd4b0b..2cd4e77 100644
--- a/Elwig/Elwig.csproj
+++ b/Elwig/Elwig.csproj
@@ -19,6 +19,7 @@
+
diff --git a/Elwig/Helpers/Utils.cs b/Elwig/Helpers/Utils.cs
index 452e79c..6c6387e 100644
--- a/Elwig/Helpers/Utils.cs
+++ b/Elwig/Helpers/Utils.cs
@@ -24,7 +24,7 @@ namespace Elwig.Helpers {
public static readonly Regex SerialRegex = GeneratedSerialRegex();
public static readonly Regex TcpRegex = GeneratedTcpRegex();
- public static readonly Regex PartialDateRegex = GeneratedPartialDateRegex();
+ public static readonly Regex DateFromToRegex = GeneratedFromToDateRegex();
public static readonly Regex FromToRegex = GeneratedFromToRegex();
public static readonly Regex FromToTimeRegex = GeneratedFromToTimeRegex();
public static readonly Regex AddressRegex = GeneratedAddressRegex();
@@ -35,8 +35,8 @@ namespace Elwig.Helpers {
[GeneratedRegex("^tcp://([A-Za-z0-9._-]+):([0-9]+)$", RegexOptions.Compiled)]
private static partial Regex GeneratedTcpRegex();
- [GeneratedRegex(@"^(0?[1-9]|[12][0-9]|3[01])\.(0?[1-9]|1[0-2])\.$", RegexOptions.Compiled)]
- private static partial Regex GeneratedPartialDateRegex();
+ [GeneratedRegex(@"^(-?(0?[1-9]|[12][0-9]|3[01])\.(0?[1-9]|1[0-2])\.([0-9]{4})?-?){1,2}$", RegexOptions.Compiled)]
+ private static partial Regex GeneratedFromToDateRegex();
[GeneratedRegex(@"^([0-9]+([\.,][0-9]+)?)?-([0-9]+([\.,][0-9]+)?)?$", RegexOptions.Compiled)]
private static partial Regex GeneratedFromToRegex();
diff --git a/Elwig/Models/AT_PlzDest.cs b/Elwig/Models/AT_PlzDest.cs
index d080829..bd6b04a 100644
--- a/Elwig/Models/AT_PlzDest.cs
+++ b/Elwig/Models/AT_PlzDest.cs
@@ -1,5 +1,6 @@
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations.Schema;
+using IndexAttribute = Microsoft.EntityFrameworkCore.IndexAttribute;
namespace Elwig.Models {
[Table("AT_plz_dest"), PrimaryKey("Id"), Index("Plz", "Okz", IsUnique = true)]
diff --git a/Elwig/Models/AreaComType.cs b/Elwig/Models/AreaComType.cs
index e981da9..ce532de 100644
--- a/Elwig/Models/AreaComType.cs
+++ b/Elwig/Models/AreaComType.cs
@@ -1,6 +1,7 @@
using Elwig.Helpers;
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations.Schema;
+using IndexAttribute = Microsoft.EntityFrameworkCore.IndexAttribute;
namespace Elwig.Models {
[Table("area_commitment_type"), PrimaryKey("VtrgId"), Index("SortId", "AttrId1", "AttrId2", "Discriminator")]
diff --git a/Elwig/Models/Country.cs b/Elwig/Models/Country.cs
index 9134a95..564cd53 100644
--- a/Elwig/Models/Country.cs
+++ b/Elwig/Models/Country.cs
@@ -1,5 +1,6 @@
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations.Schema;
+using IndexAttribute = Microsoft.EntityFrameworkCore.IndexAttribute;
namespace Elwig.Models {
[Table("country"), PrimaryKey("Num"), Index("Alpha2", IsUnique = true), Index("Alpha3", IsUnique = true)]
diff --git a/Elwig/Models/Credit.cs b/Elwig/Models/Credit.cs
index b6ea2f9..cae904a 100644
--- a/Elwig/Models/Credit.cs
+++ b/Elwig/Models/Credit.cs
@@ -2,6 +2,7 @@ using Elwig.Helpers;
using Microsoft.EntityFrameworkCore;
using System;
using System.ComponentModel.DataAnnotations.Schema;
+using IndexAttribute = Microsoft.EntityFrameworkCore.IndexAttribute;
namespace Elwig.Models {
[Table("credit"), PrimaryKey("Year", "TgNr"), Index("Year", "AvNr", "MgNr", IsUnique = true)]
diff --git a/Elwig/Models/Delivery.cs b/Elwig/Models/Delivery.cs
index e548137..44f8548 100644
--- a/Elwig/Models/Delivery.cs
+++ b/Elwig/Models/Delivery.cs
@@ -4,6 +4,7 @@ using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
+using IndexAttribute = Microsoft.EntityFrameworkCore.IndexAttribute;
namespace Elwig.Models {
[Table("delivery"), PrimaryKey("Year", "DId"), Index("DateString", "ZwstId", "LNr", IsUnique = true), Index("LsNr", IsUnique = true)]
diff --git a/Elwig/Models/WineOrigin.cs b/Elwig/Models/WineOrigin.cs
index ac7bff6..4291146 100644
--- a/Elwig/Models/WineOrigin.cs
+++ b/Elwig/Models/WineOrigin.cs
@@ -3,6 +3,7 @@ using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
+using IndexAttribute = Microsoft.EntityFrameworkCore.IndexAttribute;
namespace Elwig.Models {
[Table("wine_origin"), PrimaryKey("HkId"), Index("Name", IsUnique = true)]
diff --git a/Elwig/Windows/DeliveryAdminWindow.xaml b/Elwig/Windows/DeliveryAdminWindow.xaml
index edcec92..ce757dc 100644
--- a/Elwig/Windows/DeliveryAdminWindow.xaml
+++ b/Elwig/Windows/DeliveryAdminWindow.xaml
@@ -91,7 +91,8 @@
+ TextChanged="SearchInput_TextChanged"
+ ToolTip="Lieferungen filtern und durchsuchen. Die Filter sind beliebig kombinierbar.
Filtern nach:
Sorte: z.B. GV, ZW, rr, sa, ...
Qualitätsstufe: z.B. QUW, kab, ldw, ...
Gradation: z.B. >73, <15, 17-18, 15-, >17,5, 62-75, ...
Mitglied: z.B. 1234, 987, ...
Saison: z.B. 2020, >2015, 2017-2019, <2005, 2019-, ...
Zweigstelle: z.B. musterort, ...
Attribute: z.B. kabinett, !kabinett (alle außer kabinett), ...
Datum: z.B. 1.9., 15.9.-10.10., -15.10.2020, ...
Uhrzeit: z.B. 06:00-08:00, 18:00-, ...
Freitext: z.B. Lieferscheinnummern, "quw" (sucht nach dem Text "quw")"/>
diff --git a/Elwig/Windows/DeliveryAdminWindow.xaml.cs b/Elwig/Windows/DeliveryAdminWindow.xaml.cs
index fa95407..7513f13 100644
--- a/Elwig/Windows/DeliveryAdminWindow.xaml.cs
+++ b/Elwig/Windows/DeliveryAdminWindow.xaml.cs
@@ -2,6 +2,7 @@ using Elwig.Documents;
using Elwig.Helpers;
using Elwig.Helpers.Export;
using Elwig.Models;
+using LinqKit;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.Win32;
@@ -292,28 +293,25 @@ namespace Elwig.Windows {
.ThenBy(p => p.Delivery.LsNr)
.ThenBy(p => p.DPNr);
- // TODO add filter for:
- // attributes
- // branches
var filterVar = new List();
var filterQual = new List();
var filterMgNr = new List();
- var filterDate = new List();
- var filterPartDate = new List();
- string? filterTimeGt = null;
- string? filterTimeLt = null;
- int filterYearGt = 0;
- int filterYearLt = 0;
- double filterKmwGt = 0;
- double filterKmwLt = 0;
- double filterOeGt = 0;
- double filterOeLt = 0;
+ var filterZwst = new List();
+ var filterAttr = new List();
+ var filterNotAttr = new List();
+ var filterDate = new List<(string?, string?)>();
+ var filterTime = new List<(string?, string?)>();
+ int filterYearGt = 0, filterYearLt = 0;
+ double filterKmwGt = 0, filterKmwLt = 0;
+ double filterOeGt = 0, filterOeLt = 0;
var filter = TextFilter.ToList();
if (filter.Count > 0) {
var var = await Context.WineVarieties.ToDictionaryAsync(v => v.SortId, v => v);
var qual = await Context.WineQualityLevels.ToDictionaryAsync(q => q.QualId, q => q);
var mgnr = await Context.Members.ToDictionaryAsync(m => m.MgNr.ToString(), m => m);
+ var zwst = await Context.Branches.ToDictionaryAsync(b => b.Name.ToLower().Split(" ")[0], b => b);
+ var attr = await Context.WineAttributes.ToDictionaryAsync(a => a.Name.ToLower().Split(" ")[0], a => a);
for (int i = 0; i < filter.Count; i++) {
var e = filter[i];
@@ -329,6 +327,21 @@ namespace Elwig.Windows {
filterMgNr.Add(int.Parse(e));
filter.RemoveAt(i--);
filterNames.Add(mgnr[e].AdministrativeName);
+ } else if (attr.ContainsKey(e.ToLower())) {
+ var a = attr[e.ToLower()];
+ filterAttr.Add(a.AttrId);
+ filter.RemoveAt(i--);
+ filterNames.Add($"Attribut {a.Name}");
+ } else if (e[0] == '!' && attr.ContainsKey(e[1..].ToLower())) {
+ var a = attr[e[1..].ToLower()];
+ filterNotAttr.Add(a.AttrId);
+ filter.RemoveAt(i--);
+ filterNames.Add($"ohne Attribut {a.Name}");
+ } else if (zwst.ContainsKey(e.ToLower())) {
+ var b = zwst[e.ToLower()];
+ filterZwst.Add(b.ZwstId);
+ filter.RemoveAt(i--);
+ filterNames.Add($"Zweigstelle {b.Name}");
} else if (e.StartsWith(">") || e.StartsWith("<")) {
if (double.TryParse(e[1..], out var num)) {
switch ((e[0], num)) {
@@ -340,12 +353,6 @@ namespace Elwig.Windows {
case ('<', _): filterOeLt = num; break;
}
filter.RemoveAt(i--);
- } else if (TimeOnly.TryParse(e[1..], out var time)) {
- switch ((e[0], time)) {
- case ('>', _): filterTimeGt = $"{time:HH:mm}"; break;
- case ('<', _): filterTimeLt = $"{time:HH:mm}"; break;
- }
- filter.RemoveAt(i--);
}
if (e.Length == 1) filter.RemoveAt(i--);
} else if (e.Length > 1 && Utils.FromToRegex.IsMatch(e)) {
@@ -353,14 +360,14 @@ namespace Elwig.Windows {
double? from = (parts[0].Length > 0) ? double.Parse(parts[0].Replace(".", ",")) : null;
double? to = (parts[1].Length > 0) ? double.Parse(parts[1].Replace(".", ",")) : null;
switch ((from, to)) {
- case (<= 30, <= 30):
- case (<= 30, null):
+ case ( <= 30, <= 30):
+ case ( <= 30, null):
case (null, <= 30):
filterKmwGt = from ?? 0;
filterKmwLt = to ?? 0;
break;
- case (>= 1900, >= 1900):
- case (>= 1900, null):
+ case ( >= 1900, >= 1900):
+ case ( >= 1900, null):
case (null, >= 1900):
filterYearGt = (int)(from ?? 0);
filterYearLt = (int)(to ?? -1) + 1;
@@ -373,26 +380,57 @@ namespace Elwig.Windows {
filter.RemoveAt(i--);
} else if (e.Length > 1 && Utils.FromToTimeRegex.IsMatch(e)) {
var parts = e.Split("-");
- filterTimeGt = TimeOnly.TryParse(parts[0], out var from) ? $"{from:HH:mm}" : null;
- filterTimeLt = TimeOnly.TryParse(parts[1], out var to) ? $"{to:HH:mm}" : null;
+ filterTime.Add((TimeOnly.TryParse(parts[0], out var from) ? $"{from:HH:mm}" : null, TimeOnly.TryParse(parts[1], out var to) ? $"{to:HH:mm}" : null));
filter.RemoveAt(i--);
+ var t = filterTime.Last();
+ if (t.Item1 != null && t.Item2 != null) {
+ filterNames.Add($"{t.Item1}–{t.Item2}");
+ } else if (t.Item1 != null) {
+ filterNames.Add($"ab {t.Item1}");
+ } else if (t.Item2 != null) {
+ filterNames.Add($"bis {t.Item2}");
+ }
} else if (DateOnly.TryParse(e, out var date)) {
- // TODO allow date ranges
- filterDate.Add(date.ToString("yyyy-MM-dd"));
+ var s = date.ToString("yyyy-MM-dd");
+ filterDate.Add((s, s));
filter.RemoveAt(i--);
- filterNames.Add(date.ToString("dd.MM.yyyy"));
- } else if (Utils.PartialDateRegex.IsMatch(e)) {
- // TODO allow date ranges
- var parts = e.Split(".");
- var p0 = int.Parse(parts[0]);
- var p1 = int.Parse(parts[1]);
- filterPartDate.Add($"-{p1:00}-{p0:00}");
- filter.RemoveAt(i--);
- if (filterNames.Contains(SeasonInput.Value.ToString())) {
+ if (filterNames.Contains(SeasonInput.Value.ToString()) && SeasonInput.Value == date.Year)
filterNames.Remove(SeasonInput.Value.ToString());
- filterNames.Add($"{p0:00}.{p1:00}.{SeasonInput.Value:0000}");
- } else {
- filterNames.Add($"{p0:00}.{p1:00}.");
+ filterNames.Add(date.ToString("dd.MM.yyyy"));
+ } else if (Utils.DateFromToRegex.IsMatch(e)) {
+ var parts = e.Split("-");
+ if (parts.Length == 1) {
+ // single date
+ var dParts = parts[0].Split('.');
+ var s = $"{dParts[2]}-{dParts[1].PadLeft(2, '0')}-{dParts[0].PadLeft(2, '0')}";
+ filterDate.Add((s, s));
+ filter.RemoveAt(i--);
+ var n = string.Join('.', s.Split('-').Reverse());
+ if (dParts[2] == "") {
+ filterNames.Remove(SeasonInput.Value.ToString());
+ filterNames.Add(n + SeasonInput.Value.ToString());
+ } else {
+ if (SeasonInput.Value.ToString() == dParts[2])
+ filterNames.Remove(SeasonInput.Value.ToString());
+ filterNames.Add(n);
+ }
+ } else if (parts.Length == 2) {
+ // from/to date
+ var d1Parts = parts[0].Split('.');
+ var d2Parts = parts[1].Split('.');
+ var s1 = d1Parts.Length < 2 ? null : $"{d1Parts.ElementAtOrDefault(2)}-{d1Parts[1].PadLeft(2, '0')}-{d1Parts[0].PadLeft(2, '0')}";
+ var s2 = d2Parts.Length < 2 ? null : $"{d2Parts.ElementAtOrDefault(2)}-{d2Parts[1].PadLeft(2, '0')}-{d2Parts[0].PadLeft(2, '0')}";
+ filterDate.Add((s1, s2));
+ filter.RemoveAt(i--);
+ var n1 = s1 == null ? null : string.Join('.', s1.Split('-').Reverse());
+ var n2 = s2 == null ? null : string.Join('.', s2.Split('-').Reverse());
+ if (n1 != null && n2 != null) {
+ filterNames.Add($"{n1}–{n2}");
+ } else if (n1 != null) {
+ filterNames.Add($"ab dem {n1}");
+ } else if (n2 != null) {
+ filterNames.Add($"bis zum {n2}");
+ }
}
} else if (e.Length > 2 && e.StartsWith("\"") && e.EndsWith("\"")) {
filter[i] = e[1..^1];
@@ -401,15 +439,30 @@ namespace Elwig.Windows {
}
}
- if (filterMgNr.Count > 0) dpq = dpq.Where(p => filterMgNr.Contains(p.Delivery.MgNr));
- if (filterDate.Count > 0) dpq = dpq.Where(p => filterDate.Contains(p.Delivery.DateString));
- if (filterPartDate.Count > 0) dpq = dpq.Where(p => filterPartDate.Contains(p.Delivery.DateString.Substring(4)));
if (filterYearGt > 0) dpq = dpq.Where(p => p.Year >= filterYearGt);
if (filterYearLt > 0) dpq = dpq.Where(p => p.Year < filterYearLt);
- if (filterTimeGt != null) dpq = dpq.Where(p => p.Delivery.TimeString != null && filterTimeGt.CompareTo(p.Delivery.TimeString) <= 0);
- if (filterTimeLt != null) dpq = dpq.Where(p => p.Delivery.TimeString != null && filterTimeLt.CompareTo(p.Delivery.TimeString) > 0);
+ if (filterMgNr.Count > 0) dpq = dpq.Where(p => filterMgNr.Contains(p.Delivery.MgNr));
+ if (filterDate.Count > 0) {
+ var pr = PredicateBuilder.New(false);
+ foreach (var (d1, d2) in filterDate)
+ pr.Or(p => (d1 == null || d1.CompareTo(p.Delivery.DateString.Substring(10 - d1.Length)) <= 0) && (d2 == null || d2.CompareTo(p.Delivery.DateString.Substring(10 - d2.Length)) >= 0));
+ dpq = dpq.Where(pr);
+ }
+ if (filterTime.Count > 0) {
+ var pr = PredicateBuilder.New(false);
+ foreach (var (t1, t2) in filterTime)
+ pr.Or(p => (t1 == null || t1.CompareTo(p.Delivery.TimeString) <= 0) && (t2 == null || t2.CompareTo(p.Delivery.TimeString) > 0));
+ dpq = dpq.Where(p => p.Delivery.TimeString != null).Where(pr);
+ }
if (filterVar.Count > 0) dpq = dpq.Where(p => filterVar.Contains(p.SortId));
if (filterQual.Count > 0) dpq = dpq.Where(p => filterQual.Contains(p.QualId));
+ if (filterZwst.Count > 0) dpq = dpq.Where(p => filterZwst.Contains(p.Delivery.ZwstId));
+ if (filterAttr.Count > 0)
+ foreach (var a in filterAttr)
+ dpq = dpq.Where(p => p.PartAttributes.Select(a => a.Attr.AttrId).Contains(a));
+ if (filterNotAttr.Count > 0)
+ foreach (var a in filterNotAttr)
+ dpq = dpq.Where(p => !p.PartAttributes.Select(a => a.Attr.AttrId).Contains(a));
if (filterKmwGt > 0) dpq = dpq.Where(p => p.Kmw >= filterKmwGt);
if (filterKmwLt > 0) dpq = dpq.Where(p => p.Kmw < filterKmwLt);
if (filterOeGt > 0) dpq = dpq.Where(p => p.Kmw * (4.54 + 0.022 * p.Kmw) >= filterOeGt);
@@ -436,13 +489,6 @@ namespace Elwig.Windows {
} else if (filterOeLt > 0) {
filterNames.Add($"unter {filterOeLt:N1} °Oe");
}
- if (filterTimeGt != null && filterTimeLt != null) {
- filterNames.Add($"{filterTimeGt}–{filterTimeLt}");
- } else if (filterTimeGt != null) {
- filterNames.Add($"ab {filterTimeGt}");
- } else if (filterTimeLt != null) {
- filterNames.Add($"bis {filterTimeLt}");
- }
}
return (filterNames, dpq.Select(p => p.Delivery).Distinct().OrderBy(d => d.DateString).ThenBy(d => d.TimeString), dpq, filter);