diff --git a/Elwig/App.xaml b/Elwig/App.xaml
index 439374a..157b9b3 100644
--- a/Elwig/App.xaml
+++ b/Elwig/App.xaml
@@ -5,13 +5,7 @@
StartupUri="Windows\MainWindow.xaml"
xmlns:ui="http://schemas.modernwpf.com/2019">
-
-
+
@@ -19,16 +13,6 @@
-
-
-
-
-
-
-
-
-
-
@@ -37,5 +21,59 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Elwig/Helpers/AppDbContext.cs b/Elwig/Helpers/AppDbContext.cs
index 3d2d6ce..832f62f 100644
--- a/Elwig/Helpers/AppDbContext.cs
+++ b/Elwig/Helpers/AppDbContext.cs
@@ -33,6 +33,7 @@ namespace Elwig.Helpers {
public DbSet AreaCommitments { get; private set; }
public DbSet AreaCommitmentAttributes { get; private set; }
public DbSet Seasons { get; private set; }
+ public DbSet Modifiers { get; private set; }
public DbSet Deliveries { get; private set; }
public DbSet DeliveryParts { get; private set; }
public DbSet DeliveryPartAttributes { get; private set; }
@@ -78,6 +79,14 @@ namespace Elwig.Helpers {
return await AreaCommitments.FindAsync(fbnr) != null;
}
+ public async Task SortIdExists(string sortId) {
+ return await WineVarieties.FindAsync(sortId) != null;
+ }
+
+ public async Task AttrIdExists(string attrId) {
+ return await WineAttributes.FindAsync(attrId) != null;
+ }
+
public async Task NextMgNr() {
int c = await Members.Select(m => m.MgNr).MinAsync();
(await Members.OrderBy(m => m.MgNr).Select(m => m.MgNr).ToListAsync())
diff --git a/Elwig/Helpers/Validator.cs b/Elwig/Helpers/Validator.cs
index bc9f3e1..3697acc 100644
--- a/Elwig/Helpers/Validator.cs
+++ b/Elwig/Helpers/Validator.cs
@@ -59,6 +59,71 @@ namespace Elwig.Helpers {
return new(true, null);
}
+ public static ValidationResult CheckDecimal(TextBox input, bool required) {
+ return CheckDecimal(input, required, -1, -1);
+ }
+
+ public static ValidationResult CheckDecimal(TextBox input, bool required, int maxLen, int maxDecimal) {
+ string text = "";
+ int pos = input.CaretIndex;
+ int v1 = 0, v2 = -1;
+ for (int i = 0; i < input.Text.Length; i++) {
+ char ch = input.Text[i];
+ if (char.IsAsciiDigit(ch)) {
+ if (v2 == -1 && v1 < maxLen) {
+ text += ch; v1++;
+ } else if (v2 != -1 && v2 < maxDecimal) {
+ text += ch; v2++;
+ }
+ } else if (v2 == 0-1 && ch == ',' || ch == '.') {
+ if (v1 == 0) { text += '0'; v1++; }
+ text += ',';
+ v2 = 0;
+ }
+ if (i == input.CaretIndex - 1)
+ pos = text.Length;
+ }
+ input.Text = text;
+ input.CaretIndex = pos;
+
+ if (text.Length == 0) {
+ return required ? new(false, "Wert ist nicht optional") : new(true, null);
+ } else if (v2 == 0) {
+ return new(false, "Ungültige Kommazahl");
+ }
+
+ return new(true, null);
+ }
+
+ public static ValidationResult CheckUpperCase(TextBox input, bool required) {
+ return CheckUpperCase(input, required, -1);
+ }
+
+ public static ValidationResult CheckUpperCase(TextBox input, bool required, int maxLen) {
+ string text = "";
+ int pos = input.CaretIndex;
+ for (int i = 0; i < input.Text.Length; i++) {
+ char ch = input.Text[i];
+ if (char.IsAsciiLetter(ch))
+ text += char.ToUpper(ch);
+ if (i == input.CaretIndex - 1)
+ pos = text.Length;
+ }
+ input.Text = text;
+ input.CaretIndex = pos;
+
+ if (text.Length == 0) {
+ return required ? new(false, "Wert ist nicht optional") : new(true, null);
+ }
+
+ if (maxLen >= 0 && input.Text.Length > maxLen) {
+ input.Text = input.Text[..maxLen];
+ input.CaretIndex = Math.Min(pos, maxLen);
+ }
+
+ return new(true, null);
+ }
+
public static ValidationResult CheckPlz(TextBox input, bool required, AppDbContext ctx) {
CheckInteger(input, false, 4);
if (!required && input.Text.Length == 0) {
@@ -315,7 +380,23 @@ namespace Elwig.Helpers {
return new(true, null);
}
- public static ValidationResult CheckMgNr(TextBox input, bool required, AppDbContext ctx, Member? m) {
+ public static ValidationResult CheckMgNr(TextBox input, bool required, AppDbContext ctx) {
+ var res = CheckInteger(input, required);
+ if (!res.IsValid) {
+ return res;
+ } else if (!required && input.Text.Length == 0) {
+ return new(true, null);
+ }
+
+ int nr = int.Parse(input.Text);
+ if (!ctx.MgNrExists(nr).GetAwaiter().GetResult()) {
+ return new(false, "Ungültige Mitgliedsnummer");
+ }
+
+ return new(true, null);
+ }
+
+ public static ValidationResult CheckNewMgNr(TextBox input, bool required, AppDbContext ctx, Member? m) {
var res = CheckInteger(input, required);
if (!res.IsValid) {
return res;
@@ -331,6 +412,26 @@ namespace Elwig.Helpers {
return new(true, null);
}
+ public static ValidationResult CheckSortId(TextBox input, bool required, AppDbContext ctx) {
+ var res = CheckUpperCase(input, required, 3);
+ if (!res.IsValid) {
+ return res;
+ } else if (!required && input.Text.Length == 0) {
+ return new(true, null);
+ }
+
+ if (input.Text.Length < 2 || !ctx.SortIdExists(input.Text[0..2]).GetAwaiter().GetResult()) {
+ return new(false, "Ungültige Sorte");
+ } else if (input.Text.Length >= 3) {
+ var attr = input.Text[2..];
+ if (!ctx.AttrIdExists(attr).GetAwaiter().GetResult()) {
+ return new(false, "Ungültiges Attribut");
+ }
+ }
+
+ return new(true, null);
+ }
+
public static ValidationResult CheckPredecessorMgNr(TextBox input, bool required, AppDbContext ctx) {
var res = CheckInteger(input, required);
if (!res.IsValid) {
@@ -431,5 +532,37 @@ namespace Elwig.Helpers {
// TODO
return new(true, "Not implemented yet");
}
+
+ public static ValidationResult CheckGradatoinOe(TextBox input, bool required) {
+ var res = CheckInteger(input, required, 3);
+ if (!res.IsValid) {
+ return res;
+ } else if (!required && input.Text.Length == 0) {
+ return new(true, null);
+ }
+
+ var oe = double.Parse(input.Text);
+ if (oe < 10 || oe >= 200) {
+ return new(false, "Ungültiger Oechsle-Wert");
+ }
+
+ return new(true, null);
+ }
+
+ public static ValidationResult CheckGradationKmw(TextBox input, bool required) {
+ var res = CheckDecimal(input, required, 2, 1);
+ if (!res.IsValid) {
+ return res;
+ } else if (!required && input.Text.Length == 0) {
+ return new(true, null);
+ }
+
+ var kmw = double.Parse(input.Text);
+ if (kmw < 0 || kmw >= 50) {
+ return new(false, "Ungültiger KMW-Wert");
+ }
+
+ return new(true, null);
+ }
}
}
diff --git a/Elwig/Models/Member.cs b/Elwig/Models/Member.cs
index bde59d1..8ce0d05 100644
--- a/Elwig/Models/Member.cs
+++ b/Elwig/Models/Member.cs
@@ -44,11 +44,14 @@ namespace Elwig.Models {
public string ShortName => GivenName + " " + FamilyName;
- public string AdministrativeName =>
- FamilyName.ToUpper() + " " +
+ public string AdministrativeName => AdministrativeName1 + " " + AdministrativeName2;
+
+ public string AdministrativeName1 => FamilyName.ToUpper();
+
+ public string AdministrativeName2 =>
(Prefix != null ? Prefix + " " : "") +
GivenName +
- (MiddleName != null ? " " + MiddleName: "") +
+ (MiddleName != null ? " " + MiddleName : "") +
(Suffix != null ? " " + Suffix : "");
[Column("birthday")]
@@ -174,6 +177,8 @@ namespace Elwig.Models {
[InverseProperty("Member")]
public virtual ISet Deliveries { get; private set; }
+ public string FullAddress => $"{Address}, {PostalDest.AtPlz.Plz} {PostalDest.AtPlz.Ort.Name}";
+
public int SearchScore(IEnumerable keywords) {
keywords = keywords.Where(s => s.Length >= 2 || (s.Length > 0 && s.All(c => char.IsAsciiDigit(c))));
if (!keywords.Any())
diff --git a/Elwig/Models/Modifier.cs b/Elwig/Models/Modifier.cs
index 20365df..cd0f223 100644
--- a/Elwig/Models/Modifier.cs
+++ b/Elwig/Models/Modifier.cs
@@ -1,4 +1,5 @@
using Microsoft.EntityFrameworkCore;
+using System;
using System.ComponentModel.DataAnnotations.Schema;
namespace Elwig.Models {
@@ -38,5 +39,12 @@ namespace Elwig.Models {
[ForeignKey("Year")]
public virtual Season Season { get; private set; }
+ public string ValueStr => (Abs != null) ?
+ $"{(Abs < 0 ? " -" : "+")}{Math.Abs(Abs.Value)} {Season.Currency.Symbol}/kg" :
+ $"{(Rel < 0 ? " -" : "+")}{Math.Abs(Rel.Value):P2}";
+
+ public override string ToString() {
+ return Name;
+ }
}
}
diff --git a/Elwig/Models/WineOrigin.cs b/Elwig/Models/WineOrigin.cs
index 291c8ce..335b3f8 100644
--- a/Elwig/Models/WineOrigin.cs
+++ b/Elwig/Models/WineOrigin.cs
@@ -1,6 +1,8 @@
using Microsoft.EntityFrameworkCore;
+using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
+using System.Linq;
namespace Elwig.Models {
[Table("wine_origin"), PrimaryKey("HkId"), Index("Name", IsUnique = true)]
@@ -22,5 +24,21 @@ namespace Elwig.Models {
[InverseProperty("Origin")]
public virtual ISet Gems { get; private set; }
+
+ [InverseProperty("Parent")]
+ public virtual ISet Children { get; private set; }
+
+ public int Level => (Parent?.Level + 1) ?? 0;
+
+ public string HkIdLevel => $"{new string(' ', Level * 2)}{HkId}";
+
+ public int TotalChildNum => 1 + Children.Select(c => c.TotalChildNum).Sum();
+
+ private int SortKey1 => (Parent?.SortKey1 ?? 0) | (TotalChildNum << ((3 - Level) * 8));
+ public int SortKey => SortKey1 | ((Level < 3) ? (-1 >>> (Level * 8 + 8)) : 0);
+
+ public override string ToString() {
+ return Name;
+ }
}
}
diff --git a/Elwig/Models/WineVar.cs b/Elwig/Models/WineVar.cs
index 0646347..7293496 100644
--- a/Elwig/Models/WineVar.cs
+++ b/Elwig/Models/WineVar.cs
@@ -15,5 +15,11 @@ namespace Elwig.Models {
[Column("comment")]
public string? Comment { get; private set; }
+
+ public string NameWithComment => Name + ((Comment != null) ? $" ({Comment})" : "");
+
+ public override string ToString() {
+ return Name;
+ }
}
}
diff --git a/Elwig/Windows/DeliveryAdminWindow.xaml b/Elwig/Windows/DeliveryAdminWindow.xaml
new file mode 100644
index 0000000..47fdec7
--- /dev/null
+++ b/Elwig/Windows/DeliveryAdminWindow.xaml
@@ -0,0 +1,144 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Elwig/Windows/DeliveryAdminWindow.xaml.cs b/Elwig/Windows/DeliveryAdminWindow.xaml.cs
new file mode 100644
index 0000000..5af538d
--- /dev/null
+++ b/Elwig/Windows/DeliveryAdminWindow.xaml.cs
@@ -0,0 +1,125 @@
+using Elwig.Helpers;
+using Elwig.Models;
+using System.Linq;
+using System.Windows;
+using System.Windows.Controls;
+using Xceed.Wpf.Toolkit.Primitives;
+
+namespace Elwig.Windows {
+ public partial class DeliveryAdminWindow : AdministrationWindow {
+
+ private bool IsUpdatingGradation = false;
+
+ public DeliveryAdminWindow() {
+ InitializeComponent();
+ RequiredInputs = new Control[] {
+ MgNrInput, MemberInput,
+ SortIdInput, WineVarietyInput,
+ GradationOeInput, GradationKmwInput,
+ WineOriginInput
+ };
+ ExemptInputs = new Control[] {
+ MgNrInput, MemberInput,
+ MemberAddressField
+ };
+ }
+
+ private void Window_Loaded(object sender, RoutedEventArgs evt) {
+ MemberInput.ItemsSource = Context.Members.OrderBy(m => m.FamilyName).ThenBy(m => m.GivenName).ToList();
+ WineVarietyInput.ItemsSource = Context.WineVarieties.OrderBy(v => v.Name).ToList();
+ AttributesInput.ItemsSource = Context.WineAttributes.OrderBy(a => a.Name).ToList();
+ ModifiersInput.ItemsSource = Context.Modifiers.Where(m => m.Season.Year == 2022).OrderBy(m => m.Name).ToList();
+ WineOriginInput.ItemsSource = Context.WineOrigins.ToList().OrderByDescending(o => o.SortKey).ThenBy(o => o.HkId);
+ }
+
+ protected override void UpdateButtons() {
+
+ }
+
+ private void MgNrInput_TextChanged(object sender, TextChangedEventArgs evt) {
+ var valid = InputTextChanged((TextBox)sender, Validator.CheckMgNr);
+ MemberInput.SelectedItem = valid ? Context.Members.Find(int.Parse(MgNrInput.Text)) : null;
+ }
+
+ private void MgNrInput_LostFocus(object sender, RoutedEventArgs evt) {
+ var valid = InputLostFocus((TextBox)sender, Validator.CheckMgNr);
+ MemberInput.SelectedItem = valid ? Context.Members.Find(int.Parse(MgNrInput.Text)) : null;
+ }
+
+ private void MemberInput_SelectionChanged(object sender, SelectionChangedEventArgs evt) {
+ var m = MemberInput.SelectedItem as Member;
+ if (m != null) MgNrInput.Text = m.MgNr.ToString();
+ MemberAddressField.Text = m?.FullAddress;
+ }
+
+ private void UpdateWineVariety(bool valid) {
+ if (valid) {
+ var text = SortIdInput.Text;
+ WineVarietyInput.SelectedItem = Context.WineVarieties.Find(text[0..2]);
+ if (text.Length >= 3) {
+ AttributesInput.UnSelectAll();
+ AttributesInput.SelectedItems.Add(Context.WineAttributes.Find(text[2..]));
+ SortIdInput.Text = text[0..2];
+ }
+ } else {
+ WineVarietyInput.SelectedItem = null;
+ AttributesInput.UnSelectAll();
+ }
+ }
+
+ private void SortIdInput_TextChanged(object sender, TextChangedEventArgs evt) {
+ UpdateWineVariety(InputTextChanged((TextBox)sender, Validator.CheckSortId));
+ }
+
+ private void SortIdInput_LostFocus(object sender, RoutedEventArgs evt) {
+ UpdateWineVariety(InputLostFocus((TextBox)sender, Validator.CheckSortId));
+ }
+
+ private void WineVarietyInput_SelectionChanged(object sender, SelectionChangedEventArgs evt) {
+ var s = WineVarietyInput.SelectedItem as WineVar;
+ if (s != null) SortIdInput.Text = s.SortId;
+ }
+
+ private void UpdateGradationKmw() {
+ IsUpdatingGradation = true;
+ var caret = GradationKmwInput.CaretIndex;
+ GradationKmwInput.Text = $"{Utils.OeToKmw(double.Parse(GradationOeInput.Text)):#.0}";
+ GradationKmwInput.CaretIndex = caret;
+ IsUpdatingGradation = false;
+ }
+
+ private void UpdateGradationOe() {
+ IsUpdatingGradation = true;
+ var caret = GradationOeInput.CaretIndex;
+ GradationOeInput.Text = $"{Utils.KmwToOe(double.Parse(GradationKmwInput.Text)):#}";
+ GradationOeInput.CaretIndex = caret;
+ IsUpdatingGradation = false;
+ }
+
+ private void GradationOeInput_TextChanged(object sender, TextChangedEventArgs evt) {
+ var valid = InputTextChanged((TextBox)sender, Validator.CheckGradatoinOe);
+ if (valid && !IsUpdatingGradation) UpdateGradationKmw();
+ }
+
+ private void GradationOeInput_LostFocus(object sender, RoutedEventArgs evt) {
+ InputLostFocus((TextBox)sender, Validator.CheckGradatoinOe);
+ }
+
+ private void GradationKmwInput_TextChanged(object sender, TextChangedEventArgs evt) {
+ var valid = InputTextChanged((TextBox)sender, Validator.CheckGradationKmw);
+ if (valid && !IsUpdatingGradation) UpdateGradationOe();
+ }
+
+ private void GradationKmwInput_LostFocus(object sender, RoutedEventArgs evt) {
+ InputLostFocus((TextBox)sender, Validator.CheckGradationKmw);
+ }
+
+ private void AttributesInput_SelectionChanged(object sender, ItemSelectionChangedEventArgs evt) {
+
+ }
+
+ private void ModifiersInput_SelectionChanged(object sender, ItemSelectionChangedEventArgs evt) {
+
+ }
+ }
+}
diff --git a/Elwig/Windows/MainWindow.xaml b/Elwig/Windows/MainWindow.xaml
index c031b16..be68467 100644
--- a/Elwig/Windows/MainWindow.xaml
+++ b/Elwig/Windows/MainWindow.xaml
@@ -38,13 +38,17 @@
HorizontalAlignment="Left" Margin="0,70,0,0" VerticalAlignment="Top"/>
-
-
-
-
+
+
diff --git a/Elwig/Windows/MainWindow.xaml.cs b/Elwig/Windows/MainWindow.xaml.cs
index a1222aa..c2879cd 100644
--- a/Elwig/Windows/MainWindow.xaml.cs
+++ b/Elwig/Windows/MainWindow.xaml.cs
@@ -12,20 +12,29 @@ namespace Elwig.Windows {
}
private void Window_Loaded(object sender, RoutedEventArgs evt) {
- Button4.IsEnabled = App.IsPrintingReady;
+ PdfButton.IsEnabled = App.IsPrintingReady;
}
- private void Button2_Click(object sender, RoutedEventArgs evt) {
+ private void MemberAdminButton_Click(object sender, RoutedEventArgs evt) {
var w = new MemberAdminWindow();
w.Show();
}
- private void Button3_Click(object sender, RoutedEventArgs evt) {
+ private void MemberListButton_Click(object sender, RoutedEventArgs evt) {
var w = new MemberListWindow();
w.Show();
}
- private void Button4_Click(object sender, RoutedEventArgs evt) {
+ private void DeliveryAdminButton_Click(object sender, RoutedEventArgs evt) {
+ var w = new DeliveryAdminWindow();
+ w.Show();
+ }
+
+ private void DeliveryListButton_Click(object sender, RoutedEventArgs evt) {
+ // TODO
+ }
+
+ private void PdfButton_Click(object sender, RoutedEventArgs evt) {
Utils.RunBackground("PDF Generation", async () => {
using var ctx = new AppDbContext();
using var doc = new DeliveryNote(ctx.Deliveries.OrderBy(d => d.Parts.Count).ThenBy(d => d.Year).ThenBy(d => d.DId).Last());
diff --git a/Elwig/Windows/MemberAdminWindow.xaml b/Elwig/Windows/MemberAdminWindow.xaml
index 47a42c2..8b57c04 100644
--- a/Elwig/Windows/MemberAdminWindow.xaml
+++ b/Elwig/Windows/MemberAdminWindow.xaml
@@ -153,7 +153,7 @@
-
@@ -241,7 +241,7 @@
-
@@ -283,12 +283,12 @@
Grid.Column="2" HorizontalAlignment="Left" Margin="10,75,0,0" VerticalAlignment="Top" IsChecked="False"/>
-
-
diff --git a/Elwig/Windows/MemberAdminWindow.xaml.cs b/Elwig/Windows/MemberAdminWindow.xaml.cs
index 1a8895d..a144484 100644
--- a/Elwig/Windows/MemberAdminWindow.xaml.cs
+++ b/Elwig/Windows/MemberAdminWindow.xaml.cs
@@ -439,11 +439,11 @@ namespace Elwig.Windows {
}
private void MgNrInput_TextChanged(object sender, RoutedEventArgs evt) {
- InputTextChanged((TextBox)sender, Validator.CheckMgNr);
+ InputTextChanged((TextBox)sender, Validator.CheckNewMgNr);
}
private void MgNrInput_LostFocus(object sender, RoutedEventArgs evt) {
- InputLostFocus((TextBox)sender, Validator.CheckMgNr);
+ InputLostFocus((TextBox)sender, Validator.CheckNewMgNr);
}
private void PredecessorMgNrInput_TextChanged(object sender, RoutedEventArgs evt) {