From c1b8b68513fc5d2ceb0acfb1f3b253bba0de0a05 Mon Sep 17 00:00:00 2001 From: Lorenz Stechauner Date: Sat, 27 May 2023 17:56:17 +0200 Subject: [PATCH] Add telephone numbers --- Elwig/Helpers/AppDbContext.cs | 1 + Elwig/Helpers/Validator.cs | 25 ++++-- Elwig/Models/Member.cs | 12 +-- Elwig/Models/MemberTelNr.cs | 25 ++++++ Elwig/Windows/MemberAdminWindow.xaml | 61 +++++++++++--- Elwig/Windows/MemberAdminWindow.xaml.cs | 105 ++++++++++++++++++++++-- 6 files changed, 195 insertions(+), 34 deletions(-) create mode 100644 Elwig/Models/MemberTelNr.cs diff --git a/Elwig/Helpers/AppDbContext.cs b/Elwig/Helpers/AppDbContext.cs index 1b8a77e..c514056 100644 --- a/Elwig/Helpers/AppDbContext.cs +++ b/Elwig/Helpers/AppDbContext.cs @@ -30,6 +30,7 @@ namespace Elwig.Helpers { public DbSet Branches { get; private set; } public DbSet Members { get; private set; } public DbSet BillingAddresses { get; private set; } + public DbSet MemberTelephoneNrs { get; private set; } public DbSet AreaCommitments { get; private set; } public DbSet AreaCommitmentAttributes { get; private set; } public DbSet Seasons { get; private set; } diff --git a/Elwig/Helpers/Validator.cs b/Elwig/Helpers/Validator.cs index 1da1e5a..2ed59c2 100644 --- a/Elwig/Helpers/Validator.cs +++ b/Elwig/Helpers/Validator.cs @@ -141,7 +141,7 @@ namespace Elwig.Helpers { public static ValidationResult CheckPhoneNumber(TextBox input, bool required) { string text = ""; int pos = input.CaretIndex; - for (int i = 0, v = 0; i < input.Text.Length && v < 15; i++) { + for (int i = 0, v = 0; i < input.Text.Length && v <= 15; i++) { char ch = input.Text[i]; if (v == 0 && input.Text.Length - i >= 2 && ch == '0' && input.Text[i + 1] == '0') { v++; i++; @@ -154,21 +154,30 @@ namespace Elwig.Helpers { } else if (v == 0 && ch == '+') { v++; text += ch; - } else if (v > 0 && char.IsAsciiDigit(ch)) { + } else if (v > 0 && (char.IsAsciiDigit(ch) || ch == ' ' || ch == '-')) { if (PHONE_NRS.Any(kv => text == "+" + kv.Key)) text += ' '; if (text.StartsWith("+43 ")) { var nr = text[4..]; var vws = PHONE_NRS["43"]; - if (v >= 4 && v - 4 < vws.Length && vws[v - 4].Any(vw => nr.StartsWith(vw))) + if (!text.EndsWith(" ") && v >= 4 && v - 4 < vws.Length && vws[v - 4].Any(vw => nr.StartsWith(vw))) { text += ' '; - else if (nr == "1") + } else if (nr == "1") { text += ' '; - else if (v == 7 && nr.Length == 4) + } else if (v == 7 && nr.Length == 4) { text += ' '; + } + var vw = text.Split(" "); + if (char.IsAsciiDigit(ch)) { + v++; + text += ch; + } else if (char.IsAsciiDigit(text[^1]) && vw.Length > 2 && v >= 10 && (vw[1].Length - 1 >= vws.Length || !vws[vw[1].Length - 1].Any(v => vw[1].StartsWith(v)))) { + text += ch; + } + } else { + v++; + text += ch; } - v++; - text += ch; } if (i == input.CaretIndex - 1) pos = text.Length; @@ -182,7 +191,7 @@ namespace Elwig.Helpers { return new(false, "Telefonnummer zu kurz"); } - return new(true, null); + return new(char.IsAsciiDigit(text[^1]), null); } public static ValidationResult CheckEmailAddress(TextBox input, bool required) { diff --git a/Elwig/Models/Member.cs b/Elwig/Models/Member.cs index 8ce0d05..64a55ba 100644 --- a/Elwig/Models/Member.cs +++ b/Elwig/Models/Member.cs @@ -128,15 +128,6 @@ namespace Elwig.Models { [Column("email")] public string? Email { get; set; } - [Column("phone_landline")] - public string? PhoneLandline { get; set; } - - [Column("phone_mobile_1")] - public string? PhoneMobile1 { get; set; } - - [Column("phone_mobile_2")] - public string? PhoneMobile2 { get; set; } - [Column("default_kgnr")] public int? DefaultKgNr { get; set; } @@ -177,6 +168,9 @@ namespace Elwig.Models { [InverseProperty("Member")] public virtual ISet Deliveries { get; private set; } + [InverseProperty("Member")] + public virtual ISet TelephoneNumbers { get; private set; } + public string FullAddress => $"{Address}, {PostalDest.AtPlz.Plz} {PostalDest.AtPlz.Ort.Name}"; public int SearchScore(IEnumerable keywords) { diff --git a/Elwig/Models/MemberTelNr.cs b/Elwig/Models/MemberTelNr.cs new file mode 100644 index 0000000..430e44b --- /dev/null +++ b/Elwig/Models/MemberTelNr.cs @@ -0,0 +1,25 @@ +using Microsoft.EntityFrameworkCore; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Elwig.Models { + [Table("member_telephone_number"), PrimaryKey("MgNr", "Nr")] + public class MemberTelNr { + [Column("mgnr")] + public int MgNr { get; set; } + + [Column("nr")] + public int Nr { get; set; } + + [Column("type")] + public string Type { get; set; } + + [Column("number")] + public string Number { get; set; } + + [Column("comment")] + public string? Comment { get; set; } + + [ForeignKey("MgNr")] + public virtual Member Member { get; private set; } + } +} diff --git a/Elwig/Windows/MemberAdminWindow.xaml b/Elwig/Windows/MemberAdminWindow.xaml index 562faa4..1344598 100644 --- a/Elwig/Windows/MemberAdminWindow.xaml +++ b/Elwig/Windows/MemberAdminWindow.xaml @@ -160,29 +160,68 @@ - - + + + diff --git a/Elwig/Windows/MemberAdminWindow.xaml.cs b/Elwig/Windows/MemberAdminWindow.xaml.cs index fdbcfc8..9a538bb 100644 --- a/Elwig/Windows/MemberAdminWindow.xaml.cs +++ b/Elwig/Windows/MemberAdminWindow.xaml.cs @@ -9,12 +9,20 @@ using Elwig.Helpers; using Elwig.Models; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore.ChangeTracking; +using System.Collections.ObjectModel; namespace Elwig.Windows { public partial class MemberAdminWindow : AdministrationWindow { private List TextFilter = new(); private readonly RoutedCommand CtrlF = new(); + private readonly (ComboBox, TextBox, TextBox)[] PhoneNrInputs; + + private static ObservableCollection> PhoneNrTypes { get; set; } = new() { + new("landline", "Tel.-Nr. (Festnetz)"), + new("mobile", "Tel.-Nr. (mobil)"), + new("fax", "Fax-Nr."), + }; public MemberAdminWindow() { InitializeComponent(); @@ -30,10 +38,23 @@ namespace Elwig.Windows { AddressInput, PlzInput, OrtInput, BillingOrtInput, BusinessSharesInput, BranchInput, DefaultKgInput }; + PhoneNrInputs = new (ComboBox, TextBox, TextBox)[] { + (PhoneNr1TypeInput, PhoneNr1Input, PhoneNr1CommentInput), + (PhoneNr2TypeInput, PhoneNr2Input, PhoneNr2CommentInput), + (PhoneNr3TypeInput, PhoneNr3Input, PhoneNr3CommentInput), + (PhoneNr4TypeInput, PhoneNr4Input, PhoneNr4CommentInput), + (PhoneNr5TypeInput, PhoneNr5Input, PhoneNr5CommentInput), + (PhoneNr6TypeInput, PhoneNr6Input, PhoneNr6CommentInput), + (PhoneNr7TypeInput, PhoneNr7Input, PhoneNr7CommentInput), + (PhoneNr8TypeInput, PhoneNr8Input, PhoneNr8CommentInput), + (PhoneNr9TypeInput, PhoneNr9Input, PhoneNr9CommentInput), + }; + foreach (var input in PhoneNrInputs) input.Item1.ItemsSource = PhoneNrTypes; } private void Window_Loaded(object sender, RoutedEventArgs evt) { ActiveMemberInput.IsChecked = true; + UpdatePhoneNrInputVisibility(); } private async Task RefreshMemberList() { @@ -108,6 +129,31 @@ namespace Elwig.Windows { await RefreshMemberList(); } + private void SetPhoneNrInput(int nr, string? type, string? number, string? comment) { + var inputs = PhoneNrInputs[nr]; + inputs.Item1.SelectedItem = (type == null) ? null : inputs.Item1.ItemsSource.Cast>().FirstOrDefault(p => p.Key == type); + inputs.Item2.Text = number; + inputs.Item3.Text = comment; + } + + private (string, string, string?)? GetPhonenrInput(int nr) { + var inputs = PhoneNrInputs[nr]; + var number = inputs.Item2.Text; + if (string.IsNullOrEmpty(number)) + return null; + var type = (inputs.Item1.SelectedItem as KeyValuePair?)?.Key ?? (number.StartsWith("+43 ") && number[4] == '6' ? "mobile" : "landline"); + var comment = inputs.Item3.Text; + return (type, number, comment == "" ? null : comment); + } + + private void SetPhoneNrInputVisible(int nr, bool visible) { + var inputs = PhoneNrInputs[nr]; + var vis = visible ? Visibility.Visible : Visibility.Hidden; + inputs.Item1.Visibility = vis; + inputs.Item2.Visibility = vis; + inputs.Item3.Visibility = vis; + } + private void MemberList_SelectionChanged(object sender, RoutedEventArgs evt) { RefreshInputs(); } @@ -123,6 +169,7 @@ namespace Elwig.Windows { HideNewEditDeleteButtons(); ShowSaveResetCancelButtons(); UnlockInputs(); + UpdatePhoneNrInputVisibility(true); InitInputs(); LockSearchInputs(); } @@ -137,6 +184,7 @@ namespace Elwig.Windows { HideNewEditDeleteButtons(); ShowSaveResetCancelButtons(); UnlockInputs(); + UpdatePhoneNrInputVisibility(true); LockSearchInputs(); } @@ -164,6 +212,7 @@ namespace Elwig.Windows { HideSaveResetCancelButtons(); ShowNewEditDeleteButtons(); LockInputs(); + UpdatePhoneNrInputVisibility(); UnlockSearchInputs(); await RefreshMemberList(); SearchInput.Text = ""; @@ -189,6 +238,7 @@ namespace Elwig.Windows { RefreshInputs(); ClearInputStates(); LockInputs(); + UpdatePhoneNrInputVisibility(); UnlockSearchInputs(); } @@ -259,6 +309,17 @@ namespace Elwig.Windows { ActiveMemberInput.IsEnabled = true; } + private void UpdatePhoneNrInputVisibility(bool extra = false) { + bool lastVisible = true; + var m = (Member)MemberList.SelectedItem; + for (int i = 0; i < PhoneNrInputs.Length; i++) { + var input = PhoneNrInputs[i]; + var vis = !string.IsNullOrEmpty(input.Item2.Text) || (m?.TelephoneNumbers.Any(p => p.Nr - 1 == i) ?? false); + SetPhoneNrInputVisible(i, vis || (extra && lastVisible)); + lastVisible = vis; + } + } + private async Task UpdateMember(Member m) { int newMgNr = int.Parse(MgNrInput.Text); m.PredecessorMgNr = (PredecessorMgNrInput.Text == "") ? null : int.Parse(PredecessorMgNrInput.Text); @@ -272,9 +333,6 @@ namespace Elwig.Windows { m.Address = AddressInput.Text; m.Email = (EmailInput.Text == "") ? null : EmailInput.Text; - m.PhoneLandline = (PhoneLandlineInput.Text == "") ? null : PhoneLandlineInput.Text.Replace(" ", ""); - m.PhoneMobile1 = (PhoneMobile1Input.Text == "") ? null : PhoneMobile1Input.Text.Replace(" ", ""); - m.PhoneMobile2 = (PhoneMobile2Input.Text == "") ? null : PhoneMobile2Input.Text.Replace(" ", ""); m.Iban = (IbanInput.Text == "") ? null : IbanInput.Text.Replace(" ", ""); m.Bic = (BicInput.Text == "") ? null : BicInput.Text; @@ -324,6 +382,29 @@ namespace Elwig.Windows { } } + for (int i = 0, j = 0; i < PhoneNrInputs.Length; i++) { + var input = GetPhonenrInput(i); + var phoneNr = m.TelephoneNumbers.FirstOrDefault(p => p.Nr - 1 == i); + if (input == null) { + if (phoneNr != null) { + Context.Remove(phoneNr); + } + } else { + var pInput = input.Value; + MemberTelNr p = phoneNr ?? Context.CreateProxy(); + p.Nr = ++j; + p.Type = pInput.Item1; + p.Number = pInput.Item2; + p.Comment = pInput.Item3; + if (phoneNr == null) { + p.MgNr = newMgNr; + await Context.AddAsync(p); + } else { + Context.Update(p); + } + } + } + await Context.SaveChangesAsync(); if (newMgNr != m.MgNr) { @@ -369,9 +450,16 @@ namespace Elwig.Windows { } EmailInput.Text = m.Email; - PhoneLandlineInput.Text = m.PhoneLandline; - PhoneMobile1Input.Text = m.PhoneMobile1; - PhoneMobile2Input.Text = m.PhoneMobile2; + var phoneNrs = m.TelephoneNumbers.OrderBy(p => p.Nr).ToList(); + for (int i = 0; i < PhoneNrInputs.Length; i++) { + if (i < phoneNrs.Count) { + var phoneNr = phoneNrs[i]; + SetPhoneNrInput(i, phoneNr.Type, phoneNr.Number, phoneNr.Comment); + } else { + SetPhoneNrInput(i, null, null, null); + } + } + UpdatePhoneNrInputVisibility(IsEditing || IsCreating); IbanInput.Text = m.Iban; BicInput.Text = m.Bic; @@ -453,5 +541,10 @@ namespace Elwig.Windows { private void PredecessorMgNrInput_LostFocus(object sender, RoutedEventArgs evt) { InputLostFocus((TextBox)sender, Validator.CheckPredecessorMgNr); } + + private new void PhoneNrInput_TextChanged(object sender, RoutedEventArgs evt) { + base.PhoneNrInput_TextChanged(sender, evt); + UpdatePhoneNrInputVisibility(IsEditing || IsCreating); + } } }