From dc236bab62405522b1ad0ff98a622078af8569e3 Mon Sep 17 00:00:00 2001 From: Lorenz Stechauner Date: Mon, 22 May 2023 21:32:06 +0200 Subject: [PATCH] Add DeliveryAdminWindow --- Elwig/App.xaml | 72 ++++++++--- Elwig/Helpers/AppDbContext.cs | 9 ++ Elwig/Helpers/Validator.cs | 135 +++++++++++++++++++- Elwig/Models/Member.cs | 11 +- Elwig/Models/Modifier.cs | 8 ++ Elwig/Models/WineOrigin.cs | 18 +++ Elwig/Models/WineVar.cs | 6 + Elwig/Windows/DeliveryAdminWindow.xaml | 144 ++++++++++++++++++++++ Elwig/Windows/DeliveryAdminWindow.xaml.cs | 125 +++++++++++++++++++ Elwig/Windows/MainWindow.xaml | 12 +- Elwig/Windows/MainWindow.xaml.cs | 17 ++- Elwig/Windows/MemberAdminWindow.xaml | 8 +- Elwig/Windows/MemberAdminWindow.xaml.cs | 4 +- 13 files changed, 534 insertions(+), 35 deletions(-) create mode 100644 Elwig/Windows/DeliveryAdminWindow.xaml create mode 100644 Elwig/Windows/DeliveryAdminWindow.xaml.cs 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"/> -