diff --git a/Program.cs b/Program.cs index 2705c4c..62dc7a9 100644 --- a/Program.cs +++ b/Program.cs @@ -34,6 +34,7 @@ namespace dezentrale public static MemberList members = new MemberList(); public static MvList mvList = new MvList(); + public static MailTemplates mailTemplates = new MailTemplates(); public static bool MoneyTransfersLoaded { get { return moneyTransfers != null; } @@ -104,7 +105,16 @@ namespace dezentrale return 1; } - + try + { + mailTemplates = (MailTemplates)XmlData.LoadFromFile(Path.Combine(config.DbDirectory, "MailTemplates.xml"), typeof(MailTemplates)); + } catch(Exception ex) + { + Console.WriteLine("Error while loading mail templates:"); + Console.WriteLine(ex.Message); + } + mailTemplates.InitializeNonSerializedFields(); + try { string mvFileName = System.IO.Path.Combine(Program.config.DbDirectory, MvList.FileName); diff --git a/core/Cronjob.cs b/core/Cronjob.cs index 5f93f54..353049f 100644 --- a/core/Cronjob.cs +++ b/core/Cronjob.cs @@ -84,7 +84,7 @@ namespace dezentrale.core m.StartLogEvent("Sending greetings", LogEvent.eEventType.Greetings, "automatic"); try { - FormMail tmp = FormMail.GenerateNewMemberWelcome().ReplaceReflect(m); + FormMail tmp = Program.mailTemplates.NewMemberWelcome.ReplaceReflect(m); LogSubEvent lse = tmp.Send(); m.CurrentLog.SubEvents.Add(lse); if (lse.Type == LogEvent.eEventType.Error) throw new Exception("Sending mail to user failed"); @@ -92,7 +92,7 @@ namespace dezentrale.core try { - FormMail tmp = FormMail.GenerateNewMemberVorstand().ReplaceReflect(Program.config.VS).ReplaceReflect(m); + FormMail tmp = Program.mailTemplates.NewMemberVorstand.ReplaceReflect(Program.config.VS).ReplaceReflect(m); LogSubEvent lse = tmp.Send(); m.CurrentLog.SubEvents.Add(lse); if (lse.Type == LogEvent.eEventType.Error) throw new Exception("Sending mail to vorstand failed"); @@ -154,12 +154,12 @@ namespace dezentrale.core try { FormMail - tmp = FormMail.GenerateMemberAccountActivated().ReplaceReflect(Program.config).ReplaceReflect(m); + tmp = Program.mailTemplates.MemberAccountActivated.ReplaceReflect(Program.config).ReplaceReflect(m); LogSubEvent lse = tmp.Send(); m.CurrentLog.SubEvents.Add(lse); if (lse.Type == LogEvent.eEventType.Error) throw new Exception("Sending mail to user failed"); - tmp = FormMail.GenerateMemberAccountVorstand().ReplaceReflect(Program.config).ReplaceReflect(Program.config.VS).ReplaceReflect(m); + tmp = Program.mailTemplates.MemberActiveVorstand.ReplaceReflect(Program.config).ReplaceReflect(Program.config.VS).ReplaceReflect(m); lse = tmp.Send(); m.CurrentLog.SubEvents.Add(lse); if (lse.Type == LogEvent.eEventType.Error) throw new Exception("Sending mail to vorstand failed"); @@ -191,7 +191,7 @@ namespace dezentrale.core LogSubEvent lse; try { - lse = FormMail.GenerateReducedFeeReminder().Send(m); + lse = Program.mailTemplates.ReducedFeeReminder.Send(m); m.LastCronjobReducedFeeMail = ProgramStartTime; } catch(Exception ex) { @@ -296,7 +296,7 @@ namespace dezentrale.core m.StartLogEvent($"Excess amount of payments", LogEvent.eEventType.EMail, "automatic"); if (smContact != null) { - FormMail above200 = FormMail.GenerateBalanceAbove200NotifySM().ReplaceReflect(m); + FormMail above200 = Program.mailTemplates.BalanceAbove200NotifySM.ReplaceReflect(m); above200.To = smContact.ToString(); try { @@ -333,7 +333,7 @@ namespace dezentrale.core m.StartLogEvent($"Insufficient amount of payments #1", LogEvent.eEventType.EMail, "automatic"); try { - m.CurrentLog.SubEvents.Add(FormMail.GenerateBalanceNegativeMemberNotify1().Send(m)); + m.CurrentLog.SubEvents.Add(Program.mailTemplates.BalanceNegativeMemberNotify1.Send(m)); } catch(Exception ex) { m.CurrentLog.SubEvents.Add(new LogSubEvent() @@ -356,7 +356,7 @@ namespace dezentrale.core m.StartLogEvent($"Insufficient amount of payments #2", LogEvent.eEventType.EMail, "automatic"); try { - m.CurrentLog.SubEvents.Add(FormMail.GenerateBalanceNegativeMemberNotify2().Send(m)); + m.CurrentLog.SubEvents.Add(Program.mailTemplates.BalanceNegativeMemberNotify2.Send(m)); } catch (Exception ex) { m.CurrentLog.SubEvents.Add(new LogSubEvent() @@ -368,7 +368,7 @@ namespace dezentrale.core Console.WriteLine($"Cannot send Insufficient amount #2 notification: {ex.Message}"); } - FormMail below2sm = FormMail.GenerateBalanceNegativeNotify2SM().ReplaceReflect(m); + FormMail below2sm = Program.mailTemplates.BalanceNegativeNotify2SM.ReplaceReflect(m); below2sm.To = smContact.ToString(); try { @@ -388,7 +388,7 @@ namespace dezentrale.core m.StartLogEvent($"Deactivation (insufficient payment)", LogEvent.eEventType.Deactivation, "automatic"); try { - m.CurrentLog.SubEvents.Add(FormMail.GenerateBalanceNegativeMemberDeactivation().ReplaceReflect(Program.config.VS).Send(m)); + m.CurrentLog.SubEvents.Add(Program.mailTemplates.BalanceNegativeMemberDeactivation.ReplaceReflect(Program.config.VS).Send(m)); } catch(Exception ex) { m.CurrentLog.SubEvents.Add(new LogSubEvent() @@ -398,7 +398,7 @@ namespace dezentrale.core } try { - m.CurrentLog.SubEvents.Add(FormMail.GenerateBalanceNegativeMemberDeactivationVS().ReplaceReflect(Program.config.VS).Send(m)); + m.CurrentLog.SubEvents.Add(Program.mailTemplates.BalanceNegativeMemberDeactivationVS.ReplaceReflect(Program.config.VS).Send(m)); } catch(Exception ex) { m.CurrentLog.SubEvents.Add(new LogSubEvent() diff --git a/core/MvFinishProcess.cs b/core/MvFinishProcess.cs index 5a47f43..f317692 100644 --- a/core/MvFinishProcess.cs +++ b/core/MvFinishProcess.cs @@ -40,8 +40,8 @@ namespace dezentrale.core throw new Exception($"MV is not in state {Mv.MvStatus.Started}"); - FormMail mvFinishedNotification = FormMail.GenerateMvFinishedNotification(); - FormMail mvTypeChangeNotification = FormMail.GenerateMembershipTypeChanged(); + FormMail mvFinishedNotification = Program.mailTemplates.MvFinishedNotification; + FormMail mvTypeChangeNotification = Program.mailTemplates.MembershipTypeChanged; foreach (MvInvitedMember mvi in mv.Members) { diff --git a/core/PaymentReceiptProcess.cs b/core/PaymentReceiptProcess.cs index cb9e7d2..ed8785b 100644 --- a/core/PaymentReceiptProcess.cs +++ b/core/PaymentReceiptProcess.cs @@ -172,7 +172,7 @@ namespace dezentrale.core LogTarget.StepStarted(++step, "E-Mail the PDFs to the members"); if (data.SendEmail) { - FormMail receiptMail = FormMail.GenerateMemberPaymentReceipts().ReplaceReflect(data); + FormMail receiptMail = Program.mailTemplates.MemberPaymentReceipts.ReplaceReflect(data); foreach (Member m in memberList) { //gather entries per member diff --git a/core/ReplaceReflectEntity.cs b/core/ReplaceReflectEntity.cs index 450fea0..29b1e3a 100644 --- a/core/ReplaceReflectEntity.cs +++ b/core/ReplaceReflectEntity.cs @@ -1,16 +1,26 @@ using System; +using System.Collections.Generic; using System.Reflection; namespace dezentrale.core { public class ReplaceReflectEntity where T : ReplaceReflectEntity //Only child classes are allowed as T parameters { + [System.Xml.Serialization.XmlIgnore] + public List AllowedObjectFields { get; set; } + = new List(); + protected ReplaceReflectEntity() { } public T ReplaceReflect(object o) + { + //return ReplaceReflect(o, null); + return ReplaceReflect(o, o.GetType().Name); + } + public T ReplaceReflect(object o, string oTypeName) { T ret = (T) this.MemberwiseClone(); @@ -25,13 +35,21 @@ namespace dezentrale.core string propVal = (string)childProperty.GetValue(ret, null); if (propVal == null) continue; bool changed = false; - foreach (var objProperty in objProperties) + foreach (PropertyInfo objProperty in objProperties) { if (!objProperty.CanRead) continue; //check if objProperty occurs in mailProperty contents, then replace - string token = $"{{{objProperty.Name}}}"; + string token; string tokenValue; + if (oTypeName == null) + { + token = $"{{{objProperty.Name}}}"; + } + else + { + token = $"{{{oTypeName}.{objProperty.Name}}}"; + } try { tokenValue = objProperty.GetValue(o, null).ToString(); diff --git a/dezentrale-members.csproj b/dezentrale-members.csproj index 261e1ef..0d93080 100644 --- a/dezentrale-members.csproj +++ b/dezentrale-members.csproj @@ -52,12 +52,13 @@ - - - - + + + + + @@ -216,6 +217,10 @@ + + + + diff --git a/model/FormMail.cs b/model/FormMail.cs index 3762a89..539fbfa 100644 --- a/model/FormMail.cs +++ b/model/FormMail.cs @@ -4,25 +4,29 @@ using System.Linq; using System.Net.Mail; using System.Reflection; using System.Text; +using System.Xml.Serialization; using dezentrale.core; namespace dezentrale.model { public class FormMail : ReplaceReflectEntity { + //[XmlIgnore] public string TemplateName { get; set; } = "n/a"; public string To { get; set; } = "{Nickname} <{EMail}>"; public string Subject { get; set; } public string Body { get; set; } - + //public override string ToString() { return TemplateName; } public FormMail() { } public FormMail(FormMail copyFrom) { if(copyFrom != null) { + //this.TemplateName = copyFrom.TemplateName; this.To = copyFrom.To; this.Subject = copyFrom.Subject; this.Body = copyFrom.Body; + this.AllowedObjectFields = copyFrom.AllowedObjectFields; } } @@ -51,8 +55,8 @@ namespace dezentrale.model if (!string.IsNullOrEmpty(Program.config.Smtp.CcTo)) { string[] addr = Program.config.Smtp.CcTo.Split(',', ';'); - foreach(string s in addr) - if(!string.IsNullOrEmpty(s)) message.CC.Add(new MailAddress(s)); + foreach (string s in addr) + if (!string.IsNullOrEmpty(s)) message.CC.Add(new MailAddress(s)); } message.SubjectEncoding = Encoding.UTF8; @@ -98,10 +102,11 @@ namespace dezentrale.model }; client.Send(message); //client.Send(Program.config.Smtp.From, src.To, src.Subject, src.Body); - } catch(Exception ex) + } + catch (Exception ex) { Console.WriteLine($"FormMail.Send() Error: {ex.Message}\n"); - if(ex.InnerException != null) Console.WriteLine($" inner exception: {ex.InnerException.Message}"); + if (ex.InnerException != null) Console.WriteLine($" inner exception: {ex.InnerException.Message}"); throw ex; //ret.Type = LogEvent.eEventType.Error; @@ -109,520 +114,5 @@ namespace dezentrale.model return ret; } - - - public static FormMail GenerateNewMemberWelcome() - { - return new FormMail() - { - To = "{EMailName} <{EMail}>", - Subject = "Willkommen in der dezentrale, {EMailName}! Welcome to the dezentrale, {EMailName}", - Body = "Hallo {EMailName}!\n" - + "\n" - + "Willkommen im dezentrale Hackspace.\n" - + "Deine Mitgliedsnummer ist {NumberString}.\n" - + "Bitte benutze diese Nummer im Betreff von Überweisungen der Mitgliedsbeiträge. Die Höhe deines monatlichen Beitrages ist {PaymentAmountString} {PaymentAmountCurrency}.\n" - + "Dein Mitgliedsaccount ist aktiv nach 7 Tagen und dem Eingang des ersten Mitgliedsbeitrages.\n" - + "\n" - + "\n" - + "\n" - + "Hello {EMailName}!\n" - + "\n" - + "Welcome to the dezentrale hackspace.\n" - + "Your membership number is {NumberString}.\n" - + "Please use this number in the topic of the bank wire transfers of your membership fees. The monthly amount is {PaymentAmountString} {PaymentAmountCurrency}.\n" - + "Your membership account is active after 7 days, and after you paid the first membership fee.\n" - + "\n" - + "--\n" - + "Dies ist eine automatisch generierte E-Mail.\n" - + "This is an auto-generated E-Mail.\n", - }; - } - public static FormMail GenerateMemberAccountActivated() - { - return new FormMail() - { - To = "{EMailName} <{EMail}>", - Subject = "Dein Mitgliedsaccount wurde aktiviert, {EMailName}! Your membership account is now active, {EMailName}", - Body = "Hallo {EMailName}!\n" - + "\n" - + "Dein Mitgliedsaccount ist nun aktiv.\n" - + "Um die Tür zum Gebäude zu öffnen, kannst du den Schlüssel" - + " aus dem Tresor verwenden. Dieser befindet sich" - + " an der Fahrrad-Wand ganz links in der Ecke.\n" - + "Die Kombination für das Schloss lautet: {KeylockCombination}.\n" - + "Das Tor zum Innenhof kann man öffnen, indem man\n" - + "- 1x klingelt, wenn der Space auf ist (Logo leuchtet) oder\n" - + "- 3x klingelt, wenn der Space zu ist (direkt 3x hintereinander, während es noch klingelt)\n" - + "Für weitere Fragen per E-Mail kannst du dich an unsere Mailinglisten wenden:\n" - + "Die discuss-Liste ist für alle offen: discuss@dezentrale.space\n" - + "Die member-Liste ist für Kommunikation zwischen den Mitgliedern: members@dezentrale.space\n" - + "Für organisatorisches gibt es die Vorstands-Mailingliste: vorstand@dezentrale.space\n" - + "Note: Möglicherweise ist deine Registrierung" - + " auf der members-Liste zu diesem Zeitpunkt noch nicht abgeschlossen.\n" - + "Siehe auch: https://lists.dezentrale.space/mailman/listinfo\n" - + "\n" - + "\n" - + "\n" - + "Hello {EMailName}!\n" - + "\n" - + "Your member account is now active.\n" - + "To open the building door, you can use the key from the tresor.\n" - + "It is located in the corner at the left of the bicycle-wall.\n" - + "The combination for the number lock is: {KeylockCombination}.\n" - + "You can open the door to the courtyard by\n" - + "- ringing the doorbell once, if the space is open (logo is turned on)\n" - + "- ringing 3 times, if the space is closed (push 3 times directly, while it's still ringing)\n" - + "For further questions via E-Mail, you can use our mailing lists:\n" - + "The discuss list is open for everyone: discuss@dezentrale.space\n" - + "The member list is used for communication between members: members@dezentrale.space\n" - + "For organisational requests, there is the vorstand list: vorstand@dezentrale.space\n" - + "Note: Probably, your registration at the members list isn't finished at this point in time\n" - + "See also: https://lists.dezentrale.space/mailman/listinfo\n" - + "\n" - + "--\n" - + "Dies ist eine automatisch generierte E-Mail.\n" - + "This is an auto-generated E-Mail.\n", - }; - } - public static FormMail GenerateNewMemberVorstand() - { - return new FormMail() - { - To = "{VSName} <{VSEmail}>", - Subject = "Neuer Mitgliedsantrag, Nummer = {NumberString}, nick = {Nickname}!", - Body = "Hallo Vorstandsliste,\n" - + "\n" - + "Folgender Nutzer wurde in die Datenbank aufgenommen.\n" - + "Mitgliednummer: {NumberString}\n" - + "Nickname: {Nickname}\n" - + "Realname: {FirstName} {LastName}\n" - + "EMail: {EMail}\n" - + "\n" - + "Damit beginnt eine 7-Tage-Einspruchsfrist für den Vorstand.\n" - + "\n" - + "--\n" - + "Dies ist eine automatisch generierte E-Mail.\n", - }; - } - public static FormMail GenerateMemberAccountVorstand() - { - return new FormMail() - { - To = "{VSName} <{VSEmail}>", - Subject = "Mitgliedsaccount aktiv, Nummer = {NumberString}, nick = {Nickname}!", - Body = "Hallo Vorstandsliste,\n" - + "\n" - + "Der Mitgliedsaccount ist nun aktiv:\n" - + "Mitgliednummer: {NumberString}\n" - + "Nickname: {Nickname}\n" - + "EMail: {EMail}\n" - + "\n" - + "--\n" - + "Dies ist eine automatisch generierte E-Mail.\n", - }; - } - - public static FormMail GenerateAutoTypeFoerdermitglied() - { - return new FormMail() - { - To = "{EMailName} <{EMail}>", - Subject = "Mitgliedschaft geändert in \"Fördermitglied\"", - Body = "Hallo {EMailName}!\n" - + "\n" - + "Dein Mitgliedsstatus bei uns war bisher \"reguläres Mitglied\".\n" - + "Da du zu den letzten beiden Mitgliedsversammlungen nicht anwesend warst," - + " wurde dein Status automatisch zu \"Fördermitglied\" geändert.\n" - + "\n" - + "Für dich bedeutet dies keinerlei Änderungen. Die Beschlussfähigkeit" - + " zukünftiger Mitgliedsversammlungen kann auf diese Weise besser erreicht werden.\n" - + "\n" - + "Du kannst zu diesen Versammlungen als Gast anwesend sein oder deinen Status zum Anfang" - + " der MV wieder auf \"reguläres Mitglied\" ändern.\n" - + "\n" - + "--\n" - + "Dies ist eine automatisch generierte E-Mail.\n", - }; - } - - - public static FormMail GenerateMembershipTypeChanged() - { - //Regular / Foerdermitglied - return new FormMail() - { - To = "{EMailName} <{EMail}>", - Subject = "Mitgliedschaft geändert in \"{Type}\". Membership type changed to \"{Type}\"", - Body = "Hallo {EMailName}!\n" - + "\n" - + "Deine Mitgliedschaft bei uns wurde geändert zu \"{Type}\".\n" - + "Verpasste Mitgliederversammlungen: {MvMissCounter}\n" - + "\n" - + "\n" - + "Hello {EMailName}!\n" - + "\n" - + "Your membership type was changed to \"{Type}\".\n" - + "Missed MV: {MvMissCounter}\n" - + "\n" - + "\n" - + "--\n" - + "Dies ist eine automatisch generierte E-Mail.\n" - + "This is an auto-generated E-Mail.\n", - }; - } - - public static FormMail GenerateBalanceNegativeMemberNotify1() - { - //Konto im Minus zw. -2x Beitrag und 0 - //Achtung: xx euro im Minus, bei 2 Monaten Zahlungsverzug wird dein Account deaktiviert - return new FormMail() - { - To = "{EMailName} <{EMail}>", - Subject = "Beitragskonto im negativen Bereich. Membership fee balance is negative.", - Body = "Hallo {EMailName}!\n" - + "\n" - + "Dein Konto für Mitgliedsbeiträge ist im negativen Bereich:\n" - + "Monatsbeitrag: {PaymentAmountString} {PaymentAmountCurrency}\n" - + "Kontostand: {AccountBalanceString} {PaymentAmountCurrency}\n" - + "Bitte bezahle deine Mitgliedsbeiträge.\n" - + "\n" - + "\n" - + "Hello {EMailName}!\n" - + "\n" - + "Your membership account balance is negative:\n" - + "Monthly fee: {PaymentAmountString} {PaymentAmountCurrency}\n" - + "Account balance: {AccountBalanceString} {PaymentAmountCurrency}\n" - + "Please pay your membership fee.\n" - + "\n" - + "\n" - + "--\n" - + "Dies ist eine automatisch generierte E-Mail.\n" - + "This is an auto-generated E-Mail.\n", - }; - } - - public static FormMail GenerateBalanceNegativeMemberNotify2() - { - //Konto im Minus < -2x Beitrag - //Achtung: 2 Monate im Verzug, Account wird zum Ende des Monats deaktiviert - //xx euro im Minus - return new FormMail() - { - To = "{EMailName} <{EMail}>", - Subject = "Beitragskonto im negativen Bereich. Membership fee balance is negative.", - Body = "Hallo {EMailName}!\n" - + "\n" - + "Dein Konto für Mitgliedsbeiträge ist im negativen Bereich:\n" - + "Monatsbeitrag: {PaymentAmountString} {PaymentAmountCurrency}\n" - + "Kontostand: {AccountBalanceString} {PaymentAmountCurrency}\n" - + "Bitte bezahle deine Mitgliedsbeiträge.\n" - + "\n" - + "Hinweis: Zum Ende des Monats wird dein Mitgliedsaccount deaktiviert.\n" - + "\n" - + "\n" - + "Hello {EMailName}!\n" - + "\n" - + "Your membership account balance is negative:\n" - + "Monthly fee: {PaymentAmountString} {PaymentAmountCurrency}\n" - + "Account balance: {AccountBalanceString} {PaymentAmountCurrency}\n" - + "Please pay your membership fee.\n" - + "\n" - + "Note: At the end of the month, your membership account will be disabled.\n" - + "\n" - + "\n" - + "--\n" - + "Dies ist eine automatisch generierte E-Mail.\n" - + "This is an auto-generated E-Mail.\n", - }; - } - - public static FormMail GenerateBalanceNegativeMemberDeactivation() - { - //Konto im Minus < -2x Beitrag - //Konto wird nun deaktiviert --> member. - return new FormMail() - { - To = "{EMailName} <{EMail}>", - Subject = "Dein Mitgliedsaccount wurde deaktiviert. Your membership account was disabled.", - Body = "Hallo {EMailName}\n" - + "\n" - + "Dein Mitgliedsaccount wurde wegen fehlender Beitragszahlungen deaktiviert.\n" - + "Monatsbeitrag: {PaymentAmountString} {PaymentAmountCurrency}\n" - + "Kontostand: {AccountBalanceString} {PaymentAmountCurrency}\n" - + "Bitte wende dich zur Klärung der Sache an: {VSName} <{VSEmail}>\n" - + "\n" - + "\n" - + "Hello {EMailName}\n" - + "\n" - + "Your membership account was disabled due to lack of payments.\n" - + "Monthly fee: {PaymentAmountString} {PaymentAmountCurrency}\n" - + "Account balance: {AccountBalanceString} {PaymentAmountCurrency}\n" - + "To settle this issue, please contact: {VSName} <{VSEmail}>\n" - + "\n" - + "\n" - + "--\n" - + "Dies ist eine automatisch generierte E-Mail.\n" - + "This is an auto-generated E-Mail.\n", - }; - } - public static FormMail GenerateBalanceNegativeMemberDeactivationVS() - { - //Konto im Minus < -2x Beitrag - //Konto wird nun deaktiviert --> vorstand. - return new FormMail() - { - To = "{VSName} <{VSEmail}>", - Subject = "Mitgliedsaccount wurde deaktiviert, Nummer = {NumberString}, nick = {Nickname}!", - Body = "Hallo Vorstandsliste,\n" - + "\n" - + "Folgender Nutzer wurde mangels Beitragszahlung in der Datenbank deaktiviert.\n" - + "Mitgliednummer: {NumberString}\n" - + "Nickname: {Nickname} <{EMail}>\n" - + "Monatsbeitrag: {PaymentAmountString} {PaymentAmountCurrency}\n" - + "Kontostand: {AccountBalanceString} {PaymentAmountCurrency}\n" - + "\n" - + "--\n" - + "Dies ist eine automatisch generierte E-Mail.\n", - }; - } - public static FormMail GenerateBalanceNegativeNotify2SM() - { - //Konto im Minus < -2x Beitrag - //Achtung: Mitglied ist 2 Monate im Verzug, Account wird zum Ende des Monats deaktiviert - //xx euro im Minus - return new FormMail() - { - To = "schatzmeister ", //to be replaced! - Subject = "Konto eines Mitgliedes ist <= -2 Monatsbeiträge.", - Body = "Hallo Schatzmeister,\n" - + "\n" - + "Folgender Nutzer hat mangels Beitragszahlungen einen negativen Kontostand.\n" - + "Mitgliednummer: {NumberString}\n" - + "Nickname: {Nickname} <{EMail}>\n" - + "Monatsbeitrag: {PaymentAmountString} {PaymentAmountCurrency}\n" - + "Kontostand: {AccountBalanceString} {PaymentAmountCurrency}\n" - + "\n" - + "--\n" - + "Dies ist eine automatisch generierte E-Mail.\n", - }; - } - public static FormMail GenerateDisabledMemberGettingPayments2SM() - { - return new FormMail() - { - To = "schatzmeister ", //to be replaced! - Subject = "Inaktives Mitglied hat Mitgliedsbeitrag bezahlt", - Body = "Hallo Schatzmeister,\n" - + "\n" - + "Für folgenden deaktivierten Mitgliedsaccount wurde Mitgliedsbeitrag bezahlt:\n" - + "Mitgliednummer: {NumberString}\n" - + "Nickname: {Nickname} <{EMail}>\n" - + "Monatsbeitrag: {PaymentAmountString} {PaymentAmountCurrency}\n" - + "Kontostand: {AccountBalanceString} {PaymentAmountCurrency}\n" - + "\n" - + "--\n" - + "Dies ist eine automatisch generierte E-Mail.\n", - }; - } - public static FormMail GenerateBalanceAbove200NotifySM() - { - //Konto > 200 EUR - return new FormMail() - { - To = "schatzmeister ", //to be replaced! - Subject = "Konto eines Mitgliedes ist > 200 Euro.", - Body = "Hallo Schatzmeister,\n" - + "\n" - + "Folgender Nutzer hat sehr viel in sein Mitgliedskonto eingezahlt.\n" - + "Mitgliednummer: {NumberString}\n" - + "Nickname: {Nickname} <{EMail}>\n" - + "Monatsbeitrag: {PaymentAmountString} {PaymentAmountCurrency}\n" - + "Kontostand: {AccountBalanceString} {PaymentAmountCurrency}\n" - + "\n" - + "--\n" - + "Dies ist eine automatisch generierte E-Mail.\n", - }; - } - - public static FormMail GenerateMemberPaymentNotify(bool odd) - { - return new FormMail() - { - To = "{EMailName} <{EMail}>", - Subject = "dezentrale - Mitgliedsbeitrag erhalten", - Body = "Hallo {EMailName}!\n" - + "\n" - + "Dein Mitgliedsbeitrag ist angekommen. Vielen Dank.\n" - + "\n" - + "\nEingangsdatum: {ValutaDate}\n" - + "Betrag: {AmountString} {Currency}\n" - + (odd ? "Hinweis: Der Betrag passt nicht zum eingestellten Mitgliedsbeitrag ({PaymentAmountString} " + Program.config.RegularPaymentCurrency + ")\n" : "\n") - + "\n" - + "Der nächste Mitgliedsbeitrag ist damit fällig am Anfang des Monats {PaymentDueMonth} (AccountBalance = {AccountBalanceString})\n" - + "\n" - + "--\n" - + "Dies ist eine automatisch generierte E-Mail.\n", - }; - } - public static FormMail GenerateKeylockChanged() - { - return new FormMail() - { - To = "{EMailName} <{EMail}>", - Subject = "dezentrale - Schlosscode hat sich geändert", - Body = "Hallo {EMailName}!\n" - + "\n" - + "Der Schlosscode für den Schlüsseltresor hat sich geändert.\n" - + "Die neue Kombination lautet {KeylockCombination}\n" - + "\n" - + "--\n" - + "Dies ist eine automatisch generierte E-Mail.\n", - }; - } - - public static FormMail GenerateTestmail() - { - return new FormMail() - { - To = "{EMailName} <{EMail}>", - Subject = "dezentrale-members - Testmail", - Body = "Hallo {EMailName}!\n" - + "\n" - + "Dies ist ein Test der Mail-Einstellungen von dezentrale-members.\n" - + "\n" - + "--\n" - + "Dies ist eine automatisch generierte E-Mail.\n", - }; - } - - public static FormMail GenerateSingleMemberStatusReport() - { - return new FormMail() - { - To = "{EMailName} <{EMail}>", - Subject = "dezentrale-members - Status #{Number}", - Body = "Hallo {EMailName}!\n" - + "\n" - + "Hier ein Paar Statistiken zu Deinem Account\n" - + "Mitgliedsnummer: {Number}\n" - + "Mitgliedstyp (regulär/fördermitglied): {Type}\n" - + "Mitglied seit: {SpawnDate}\n" - + "Status der Mitgliedschaft: {Status}\n" - + "Nutzerrolle: {Role}\n" - + "Verpasste MV: {MvMissCounter}\n" - + "Mitgliedsbeitrag pro Monat: {PaymentAmountString}\n" - + "Mitgliedsbeitrag - Kontostand: {AccountBalanceString}\n" - + "Mitgliedsbeitrag - Klasse: {PaymentClass}\n" - + "Mitgliedsbeitrag - letzte Kontoverringerung: {LastBalanceDegrade}\n" - + "Mitgliedsbeitrag - DebtLevel: {DebtLevel}\n" - //+ "Mitgliedsbeitrag - letzter Eingang: {LastPaymentProcessed}\n" - //+ "Mitgliedsbeitrag - Fälligkeit (Monat): {PaymentDueMonth}\n" - + "\n" - + "Hello {EMailName}!\n" - + "\n" - + "Here are some stats about your membership account\n" - + "Membership number: {Number}\n" - + "Membership type (regulaer/foerdermitglied): {Type}\n" - + "Member since: {SpawnDate}\n" - + "Membership state: {Status}\n" - + "User role: {Role}\n" - + "Missed MV: {MvMissCounter}\n" - + "Membership fee per month: {PaymentAmountString}\n" - + "Membership fee - account balance: {AccountBalanceString}\n" - + "Membership fee - class: {PaymentClass}\n" - + "Membership fee - last balance degrade: {LastBalanceDegrade}\n" - + "Membership fee - debt level: {DebtLevel}\n" - //+ "Membership fee - last reception: {LastPaymentProcessed}\n" - //+ "Membership fee - due (month): {PaymentDueMonth}\n" - + "\n" - + "\n" - + "--\n" - + "Dies ist eine automatisch generierte E-Mail.\n" - + "This is an auto-generated E-Mail.\n", - }; - } - - public static FormMail GenerateReducedFeeReminder() - { - return new FormMail() - { - To = "{EMailName} <{EMail}>", - Subject = "dezentrale-members - Ermäßigte Mitgliedschaft (Reduced membership fee)", - Body = "Hallo {EMailName}!\n" - + "\n" - + "In der Datenbank ist erfasst, dass Dein Nachweis für ermäßigte Mitgliedschaft bis {ReducedFeeValid} gilt.\n" - + "Bitte reiche einen gültigen Nachweis ein, um weiter ermäßigt zu bleiben.\n" - + "\n" - + "\n" - + "Hello {EMailName}!\n" - + "\n" - + "In our database we noted your prove for reduced membership fee is valid until {ReducedFeeValid}.\n" - + "Please hand in a new document to be able to stay with the reduced fee.\n" - + "\n" - + "\n" - + "--\n" - + "Dies ist eine automatisch generierte E-Mail.\n" - + "This is an auto-generated E-Mail.\n", - }; - } - - public static FormMail GenerateMemberPaymentReceipts() - { - return new FormMail() - { - To = "{EMailName} <{EMail}>", - Subject = "dezentrale-members - Bestätigungen über Mitgliedsbeiträge (Membership payment receipts)", - Body = "Hallo {EMailName}!\n" - + "\n" - + "Danke für die Bezahlung deiner Mitgliedsbeiträge!\n" - + "Anbei die Bestätigungen für die Mitgliedsbeiträge im Zeitraum von {StartDateString} bis {EndDateString}.\n" - + "\n" - + "\n" - + "Hello {EMailName}!\n" - + "\n" - + "Thank you for paying your membership fees!\n" - + "Attached to this E-Mail there are the membership payment receipts from {StartDateString} to {EndDateString}.\n" - + "\n" - + "\n" - + "--\n" - + "Dies ist eine automatisch generierte E-Mail.\n" - + "This is an auto-generated E-Mail.\n", - }; - } - - public static FormMail GenerateMvCancelNotification() - { - return new FormMail() - { - To = "{EMailName} <{EMail}>", - Subject = "Mitgliederversammlung abgebrochen", - Body = "Hallo {EMailName}!\n" - + "\n" - + "Folgende Einladung zur MV ist hinfällig:\n" - + "The following MV invitation is cancelled:\n" - + "Titel/Subject: \"{InviteHeadline}\"\n" - + "\n" - + "--\n" - + "Dies ist eine automatisch generierte E-Mail.\n" - + "This is an auto-generated E-Mail.\n", - }; - } - - public static FormMail GenerateMvFinishedNotification() - { - return new FormMail() - { - To = "{EMailName} <{EMail}>", - Subject = "Mitgliederversammlung beendet", - Body = "Hallo {EMailName}!\n" - + "\n" - + "Danke für Deine Teilnahme an der Mitgliederversammlung!\n" - + "\n" - + "--\n" - + "Dies ist eine automatisch generierte E-Mail.\n" - + "This is an auto-generated E-Mail.\n", - }; - } } } diff --git a/model/MailTemplates.cs b/model/MailTemplates.cs new file mode 100644 index 0000000..72094cb --- /dev/null +++ b/model/MailTemplates.cs @@ -0,0 +1,517 @@ +using System.Reflection; +using System.Xml.Serialization; + +namespace dezentrale.model +{ + //This is a stupid data class + public class MailTemplates : XmlData + { + [XmlElement("NewMemberWelcome")] + public FormMail NewMemberWelcome { get; set; } = new FormMail() + { + //TemplateName = "NewMemberWelcome", + To = "{EMailName} <{EMail}>", + Subject = "Willkommen in der dezentrale, {EMailName}! Welcome to the dezentrale, {EMailName}", + Body = "Hallo {EMailName}!\n" + + "\n" + + "Willkommen im dezentrale Hackspace.\n" + + "Deine Mitgliedsnummer ist {NumberString}.\n" + + "Bitte benutze diese Nummer im Betreff von Überweisungen der Mitgliedsbeiträge. Die Höhe deines monatlichen Beitrages ist {PaymentAmountString} {PaymentAmountCurrency}.\n" + + "Dein Mitgliedsaccount ist aktiv nach 7 Tagen und dem Eingang des ersten Mitgliedsbeitrages.\n" + + "\n" + + "\n" + + "\n" + + "Hello {EMailName}!\n" + + "\n" + + "Welcome to the dezentrale hackspace.\n" + + "Your membership number is {NumberString}.\n" + + "Please use this number in the topic of the bank wire transfers of your membership fees. The monthly amount is {PaymentAmountString} {PaymentAmountCurrency}.\n" + + "Your membership account is active after 7 days, and after you paid the first membership fee.\n" + + "\n" + + "--\n" + + "Dies ist eine automatisch generierte E-Mail.\n" + + "This is an auto-generated E-Mail.\n", + }; + + [XmlElement("MemberAccountActivated")] + public FormMail MemberAccountActivated { get; set; } = new FormMail() + { + //TemplateName = "MemberAccountActivated", + To = "{EMailName} <{EMail}>", + Subject = "Dein Mitgliedsaccount wurde aktiviert, {EMailName}! Your membership account is now active, {EMailName}", + Body = "Hallo {EMailName}!\n" + + "\n" + + "Dein Mitgliedsaccount ist nun aktiv.\n" + + "Um die Tür zum Gebäude zu öffnen, kannst du den Schlüssel" + + " aus dem Tresor verwenden. Dieser befindet sich" + + " an der Fahrrad-Wand ganz links in der Ecke.\n" + + "Die Kombination für das Schloss lautet: {KeylockCombination}.\n" + + "Das Tor zum Innenhof kann man öffnen, indem man\n" + + "- 1x klingelt, wenn der Space auf ist (Logo leuchtet) oder\n" + + "- 3x klingelt, wenn der Space zu ist (direkt 3x hintereinander, während es noch klingelt)\n" + + "Für weitere Fragen per E-Mail kannst du dich an unsere Mailinglisten wenden:\n" + + "Die discuss-Liste ist für alle offen: discuss@dezentrale.space\n" + + "Die member-Liste ist für Kommunikation zwischen den Mitgliedern: members@dezentrale.space\n" + + "Für organisatorisches gibt es die Vorstands-Mailingliste: vorstand@dezentrale.space\n" + + "Note: Möglicherweise ist deine Registrierung" + + " auf der members-Liste zu diesem Zeitpunkt noch nicht abgeschlossen.\n" + + "Siehe auch: https://lists.dezentrale.space/mailman/listinfo\n" + + "\n" + + "\n" + + "\n" + + "Hello {EMailName}!\n" + + "\n" + + "Your member account is now active.\n" + + "To open the building door, you can use the key from the tresor.\n" + + "It is located in the corner at the left of the bicycle-wall.\n" + + "The combination for the number lock is: {KeylockCombination}.\n" + + "You can open the door to the courtyard by\n" + + "- ringing the doorbell once, if the space is open (logo is turned on)\n" + + "- ringing 3 times, if the space is closed (push 3 times directly, while it's still ringing)\n" + + "For further questions via E-Mail, you can use our mailing lists:\n" + + "The discuss list is open for everyone: discuss@dezentrale.space\n" + + "The member list is used for communication between members: members@dezentrale.space\n" + + "For organisational requests, there is the vorstand list: vorstand@dezentrale.space\n" + + "Note: Probably, your registration at the members list isn't finished at this point in time\n" + + "See also: https://lists.dezentrale.space/mailman/listinfo\n" + + "\n" + + "--\n" + + "Dies ist eine automatisch generierte E-Mail.\n" + + "This is an auto-generated E-Mail.\n", + }; + + public FormMail NewMemberVorstand { get; set; } = new FormMail() + { + //TemplateName = "NewMemberVorstand", + To = "{VSName} <{VSEmail}>", + Subject = "Neuer Mitgliedsantrag, Nummer = {NumberString}, nick = {Nickname}!", + Body = "Hallo Vorstandsliste,\n" + + "\n" + + "Folgender Nutzer wurde in die Datenbank aufgenommen.\n" + + "Mitgliednummer: {NumberString}\n" + + "Nickname: {Nickname}\n" + + "Realname: {FirstName} {LastName}\n" + + "EMail: {EMail}\n" + + "\n" + + "Damit beginnt eine 7-Tage-Einspruchsfrist für den Vorstand.\n" + + "\n" + + "--\n" + + "Dies ist eine automatisch generierte E-Mail.\n", + }; + + public FormMail MemberActiveVorstand { get; set; } = new FormMail() + { + //TemplateName = "MemberActiveVorstand", + To = "{VSName} <{VSEmail}>", + Subject = "Mitgliedsaccount aktiv, Nummer = {NumberString}, nick = {Nickname}!", + Body = "Hallo Vorstandsliste,\n" + + "\n" + + "Der Mitgliedsaccount ist nun aktiv:\n" + + "Mitgliednummer: {NumberString}\n" + + "Nickname: {Nickname}\n" + + "EMail: {EMail}\n" + + "\n" + + "--\n" + + "Dies ist eine automatisch generierte E-Mail.\n", + }; +/* + public FormMail AutoTypeFoerdermitglied { get; set; }= new FormMail() + { + //Name = "AutoTypeFoerdermitglied", + To = "{EMailName} <{EMail}>", + Subject = "Mitgliedschaft geändert in \"Fördermitglied\"", + Body = "Hallo {EMailName}!\n" + + "\n" + + "Dein Mitgliedsstatus bei uns war bisher \"reguläres Mitglied\".\n" + + "Da du zu den letzten beiden Mitgliedsversammlungen nicht anwesend warst," + + " wurde dein Status automatisch zu \"Fördermitglied\" geändert.\n" + + "\n" + + "Für dich bedeutet dies keinerlei Änderungen. Die Beschlussfähigkeit" + + " zukünftiger Mitgliedsversammlungen kann auf diese Weise besser erreicht werden.\n" + + "\n" + + "Du kannst zu diesen Versammlungen als Gast anwesend sein oder deinen Status zum Anfang" + + " der MV wieder auf \"reguläres Mitglied\" ändern.\n" + + "\n" + + "--\n" + + "Dies ist eine automatisch generierte E-Mail.\n", + }; +*/ + //Regular / Foerdermitglied + public FormMail MembershipTypeChanged { get; set; } = new FormMail() + { + //TemplateName = "MembershipTypeChanged", + To = "{EMailName} <{EMail}>", + Subject = "Mitgliedschaft geändert in \"{Type}\". Membership type changed to \"{Type}\"", + Body = "Hallo {EMailName}!\n" + + "\n" + + "Deine Mitgliedschaft bei uns wurde geändert zu \"{Type}\".\n" + + "Verpasste Mitgliederversammlungen: {MvMissCounter}\n" + + "\n" + + "\n" + + "Hello {EMailName}!\n" + + "\n" + + "Your membership type was changed to \"{Type}\".\n" + + "Missed MV: {MvMissCounter}\n" + + "\n" + + "\n" + + "--\n" + + "Dies ist eine automatisch generierte E-Mail.\n" + + "This is an auto-generated E-Mail.\n", + }; + + //Konto im Minus zw. -2x Beitrag und 0 + //Achtung: xx euro im Minus, bei 2 Monaten Zahlungsverzug wird dein Account deaktiviert + public FormMail BalanceNegativeMemberNotify1 { get; set; } = new FormMail() + { + //TemplateName = "BalanceNegativeMemberNotify1", + To = "{EMailName} <{EMail}>", + Subject = "Beitragskonto im negativen Bereich. Membership fee balance is negative.", + Body = "Hallo {EMailName}!\n" + + "\n" + + "Dein Konto für Mitgliedsbeiträge ist im negativen Bereich:\n" + + "Monatsbeitrag: {PaymentAmountString} {PaymentAmountCurrency}\n" + + "Kontostand: {AccountBalanceString} {PaymentAmountCurrency}\n" + + "Bitte bezahle deine Mitgliedsbeiträge.\n" + + "\n" + + "\n" + + "Hello {EMailName}!\n" + + "\n" + + "Your membership account balance is negative:\n" + + "Monthly fee: {PaymentAmountString} {PaymentAmountCurrency}\n" + + "Account balance: {AccountBalanceString} {PaymentAmountCurrency}\n" + + "Please pay your membership fee.\n" + + "\n" + + "\n" + + "--\n" + + "Dies ist eine automatisch generierte E-Mail.\n" + + "This is an auto-generated E-Mail.\n", + }; + + //Konto im Minus < -2x Beitrag + //Achtung: 2 Monate im Verzug, Account wird zum Ende des Monats deaktiviert + //xx euro im Minus + public FormMail BalanceNegativeMemberNotify2 { get; set; } = new FormMail() + { + //TemplateName = "BalanceNegativeMemberNotify2", + To = "{EMailName} <{EMail}>", + Subject = "Beitragskonto im negativen Bereich. Membership fee balance is negative.", + Body = "Hallo {EMailName}!\n" + + "\n" + + "Dein Konto für Mitgliedsbeiträge ist im negativen Bereich:\n" + + "Monatsbeitrag: {PaymentAmountString} {PaymentAmountCurrency}\n" + + "Kontostand: {AccountBalanceString} {PaymentAmountCurrency}\n" + + "Bitte bezahle deine Mitgliedsbeiträge.\n" + + "\n" + + "Hinweis: Zum Ende des Monats wird dein Mitgliedsaccount deaktiviert.\n" + + "\n" + + "\n" + + "Hello {EMailName}!\n" + + "\n" + + "Your membership account balance is negative:\n" + + "Monthly fee: {PaymentAmountString} {PaymentAmountCurrency}\n" + + "Account balance: {AccountBalanceString} {PaymentAmountCurrency}\n" + + "Please pay your membership fee.\n" + + "\n" + + "Note: At the end of the month, your membership account will be disabled.\n" + + "\n" + + "\n" + + "--\n" + + "Dies ist eine automatisch generierte E-Mail.\n" + + "This is an auto-generated E-Mail.\n", + }; + + //Konto im Minus < -2x Beitrag + //Konto wird nun deaktiviert --> member. + public FormMail BalanceNegativeMemberDeactivation { get; set; } = new FormMail() + { + //TemplateName = "BalanceNegativeMemberDeactivation", + To = "{EMailName} <{EMail}>", + Subject = "Dein Mitgliedsaccount wurde deaktiviert. Your membership account was disabled.", + Body = "Hallo {EMailName}\n" + + "\n" + + "Dein Mitgliedsaccount wurde wegen fehlender Beitragszahlungen deaktiviert.\n" + + "Monatsbeitrag: {PaymentAmountString} {PaymentAmountCurrency}\n" + + "Kontostand: {AccountBalanceString} {PaymentAmountCurrency}\n" + + "Bitte wende dich zur Klärung der Sache an: {VSName} <{VSEmail}>\n" + + "\n" + + "\n" + + "Hello {EMailName}\n" + + "\n" + + "Your membership account was disabled due to lack of payments.\n" + + "Monthly fee: {PaymentAmountString} {PaymentAmountCurrency}\n" + + "Account balance: {AccountBalanceString} {PaymentAmountCurrency}\n" + + "To settle this issue, please contact: {VSName} <{VSEmail}>\n" + + "\n" + + "\n" + + "--\n" + + "Dies ist eine automatisch generierte E-Mail.\n" + + "This is an auto-generated E-Mail.\n", + }; + + //Konto im Minus < -2x Beitrag + //Konto wird nun deaktiviert --> vorstand. + public FormMail BalanceNegativeMemberDeactivationVS { get; set; } = new FormMail() + { + //TemplateName = "BalanceNegativeMemberDeactivationVS", + To = "{VSName} <{VSEmail}>", + Subject = "Mitgliedsaccount wurde deaktiviert, Nummer = {NumberString}, nick = {Nickname}!", + Body = "Hallo Vorstandsliste,\n" + + "\n" + + "Folgender Nutzer wurde mangels Beitragszahlung in der Datenbank deaktiviert.\n" + + "Mitgliednummer: {NumberString}\n" + + "Nickname: {Nickname} <{EMail}>\n" + + "Monatsbeitrag: {PaymentAmountString} {PaymentAmountCurrency}\n" + + "Kontostand: {AccountBalanceString} {PaymentAmountCurrency}\n" + + "\n" + + "--\n" + + "Dies ist eine automatisch generierte E-Mail.\n", + }; + + //Konto im Minus < -2x Beitrag + //Achtung: Mitglied ist 2 Monate im Verzug, Account wird zum Ende des Monats deaktiviert + //xx euro im Minus + public FormMail BalanceNegativeNotify2SM { get; set; } = new FormMail() + { + //TemplateName = "BalanceNegativeNotify2SM", + To = "schatzmeister ", //to be replaced! + Subject = "Konto eines Mitgliedes ist <= -2 Monatsbeiträge.", + Body = "Hallo Schatzmeister,\n" + + "\n" + + "Folgender Nutzer hat mangels Beitragszahlungen einen negativen Kontostand.\n" + + "Mitgliednummer: {NumberString}\n" + + "Nickname: {Nickname} <{EMail}>\n" + + "Monatsbeitrag: {PaymentAmountString} {PaymentAmountCurrency}\n" + + "Kontostand: {AccountBalanceString} {PaymentAmountCurrency}\n" + + "\n" + + "--\n" + + "Dies ist eine automatisch generierte E-Mail.\n", + }; + + public FormMail DisabledMemberGettingPayments2SM { get; set; } = new FormMail() + { + //TemplateName = "DisabledMemberGettingPayments2SM", + To = "schatzmeister ", //to be replaced! + Subject = "Inaktives Mitglied hat Mitgliedsbeitrag bezahlt", + Body = "Hallo Schatzmeister,\n" + + "\n" + + "Für folgenden deaktivierten Mitgliedsaccount wurde Mitgliedsbeitrag bezahlt:\n" + + "Mitgliednummer: {NumberString}\n" + + "Nickname: {Nickname} <{EMail}>\n" + + "Monatsbeitrag: {PaymentAmountString} {PaymentAmountCurrency}\n" + + "Kontostand: {AccountBalanceString} {PaymentAmountCurrency}\n" + + "\n" + + "--\n" + + "Dies ist eine automatisch generierte E-Mail.\n", + }; + + //Konto > 200 EUR + public FormMail BalanceAbove200NotifySM { get; set; } = new FormMail() + { + //TemplateName = "BalanceAbove200NotifySM", + To = "schatzmeister ", //to be replaced! + Subject = "Konto eines Mitgliedes ist > 200 Euro.", + Body = "Hallo Schatzmeister,\n" + + "\n" + + "Folgender Nutzer hat sehr viel in sein Mitgliedskonto eingezahlt.\n" + + "Mitgliednummer: {NumberString}\n" + + "Nickname: {Nickname} <{EMail}>\n" + + "Monatsbeitrag: {PaymentAmountString} {PaymentAmountCurrency}\n" + + "Kontostand: {AccountBalanceString} {PaymentAmountCurrency}\n" + + "\n" + + "--\n" + + "Dies ist eine automatisch generierte E-Mail.\n", + }; + + public FormMail GenerateMemberPaymentNotify(bool odd) + { + return new FormMail() + { + //TemplateName = "MemberPaymentNotify", + To = "{EMailName} <{EMail}>", + Subject = "dezentrale - Mitgliedsbeitrag erhalten", + Body = "Hallo {EMailName}!\n" + + "\n" + + "Dein Mitgliedsbeitrag ist angekommen. Vielen Dank.\n" + + "\n" + + "\nEingangsdatum: {ValutaDate}\n" + + "Betrag: {AmountString} {Currency}\n" + + (odd ? "Hinweis: Der Betrag passt nicht zum eingestellten Mitgliedsbeitrag ({PaymentAmountString} " + Program.config.RegularPaymentCurrency + ")\n" : "\n") + + "\n" + + "Der nächste Mitgliedsbeitrag ist damit fällig am Anfang des Monats {PaymentDueMonth} (AccountBalance = {AccountBalanceString})\n" + + "\n" + + "--\n" + + "Dies ist eine automatisch generierte E-Mail.\n", + }; + } + public FormMail KeylockChanged { get; set; } = new FormMail() + { + //TemplateName = "KeylockChanged", + To = "{EMailName} <{EMail}>", + Subject = "dezentrale - Schlosscode hat sich geändert", + Body = "Hallo {EMailName}!\n" + + "\n" + + "Der Schlosscode für den Schlüsseltresor hat sich geändert.\n" + + "Die neue Kombination lautet {KeylockCombination}\n" + + "\n" + + "--\n" + + "Dies ist eine automatisch generierte E-Mail.\n", + }; + + public FormMail Testmail { get; set; } = new FormMail() + { + //TemplateName = "Testmail", + To = "{EMailName} <{EMail}>", + Subject = "dezentrale-members - Testmail", + Body = "Hallo {EMailName}!\n" + + "\n" + + "Dies ist ein Test der Mail-Einstellungen von dezentrale-members.\n" + + "\n" + + "--\n" + + "Dies ist eine automatisch generierte E-Mail.\n", + }; + + public FormMail SingleMemberStatusReport { get; set; } = new FormMail() + { + //TemplateName = "GenerateSingleMemberStatusReport", + To = "{EMailName} <{EMail}>", + Subject = "dezentrale-members - Status #{Number}", + Body = "Hallo {EMailName}!\n" + + "\n" + + "Hier ein Paar Statistiken zu Deinem Account\n" + + "Mitgliedsnummer: {Number}\n" + + "Mitgliedstyp (regulär/fördermitglied): {Type}\n" + + "Mitglied seit: {SpawnDate}\n" + + "Status der Mitgliedschaft: {Status}\n" + + "Nutzerrolle: {Role}\n" + + "Verpasste MV: {MvMissCounter}\n" + + "Mitgliedsbeitrag pro Monat: {PaymentAmountString}\n" + + "Mitgliedsbeitrag - Kontostand: {AccountBalanceString}\n" + + "Mitgliedsbeitrag - Klasse: {PaymentClass}\n" + + "Mitgliedsbeitrag - letzte Kontoverringerung: {LastBalanceDegrade}\n" + + "Mitgliedsbeitrag - DebtLevel: {DebtLevel}\n" + //+ "Mitgliedsbeitrag - letzter Eingang: {LastPaymentProcessed}\n" + //+ "Mitgliedsbeitrag - Fälligkeit (Monat): {PaymentDueMonth}\n" + + "\n" + + "Hello {EMailName}!\n" + + "\n" + + "Here are some stats about your membership account\n" + + "Membership number: {Number}\n" + + "Membership type (regulaer/foerdermitglied): {Type}\n" + + "Member since: {SpawnDate}\n" + + "Membership state: {Status}\n" + + "User role: {Role}\n" + + "Missed MV: {MvMissCounter}\n" + + "Membership fee per month: {PaymentAmountString}\n" + + "Membership fee - account balance: {AccountBalanceString}\n" + + "Membership fee - class: {PaymentClass}\n" + + "Membership fee - last balance degrade: {LastBalanceDegrade}\n" + + "Membership fee - debt level: {DebtLevel}\n" + //+ "Membership fee - last reception: {LastPaymentProcessed}\n" + //+ "Membership fee - due (month): {PaymentDueMonth}\n" + + "\n" + + "\n" + + "--\n" + + "Dies ist eine automatisch generierte E-Mail.\n" + + "This is an auto-generated E-Mail.\n", + }; + + public FormMail ReducedFeeReminder { get; set; } = new FormMail() + { + //TemplateName = "ReducedFeeReminder", + To = "{EMailName} <{EMail}>", + Subject = "dezentrale-members - Ermäßigte Mitgliedschaft (Reduced membership fee)", + Body = "Hallo {EMailName}!\n" + + "\n" + + "In der Datenbank ist erfasst, dass Dein Nachweis für ermäßigte Mitgliedschaft bis {ReducedFeeValid} gilt.\n" + + "Bitte reiche einen gültigen Nachweis ein, um weiter ermäßigt zu bleiben.\n" + + "\n" + + "\n" + + "Hello {EMailName}!\n" + + "\n" + + "In our database we noted your prove for reduced membership fee is valid until {ReducedFeeValid}.\n" + + "Please hand in a new document to be able to stay with the reduced fee.\n" + + "\n" + + "\n" + + "--\n" + + "Dies ist eine automatisch generierte E-Mail.\n" + + "This is an auto-generated E-Mail.\n", + }; + + public FormMail MemberPaymentReceipts { get; set; } = new FormMail() + { + //TemplateName = "MemberPaymentReceipts", + To = "{EMailName} <{EMail}>", + Subject = "dezentrale-members - Bestätigungen über Mitgliedsbeiträge (Membership payment receipts)", + Body = "Hallo {EMailName}!\n" + + "\n" + + "Danke für die Bezahlung deiner Mitgliedsbeiträge!\n" + + "Anbei die Bestätigungen für die Mitgliedsbeiträge im Zeitraum von {StartDateString} bis {EndDateString}.\n" + + "\n" + + "\n" + + "Hello {EMailName}!\n" + + "\n" + + "Thank you for paying your membership fees!\n" + + "Attached to this E-Mail there are the membership payment receipts from {StartDateString} to {EndDateString}.\n" + + "\n" + + "\n" + + "--\n" + + "Dies ist eine automatisch generierte E-Mail.\n" + + "This is an auto-generated E-Mail.\n", + }; + + public FormMail MvCancelNotification { get; set; } = new FormMail() + { + //TemplateName = "MvCancelNotification", + To = "{EMailName} <{EMail}>", + Subject = "Mitgliederversammlung abgebrochen", + Body = "Hallo {EMailName}!\n" + + "\n" + + "Folgende Einladung zur MV ist hinfällig:\n" + + "The following MV invitation is cancelled:\n" + + "Titel/Subject: \"{InviteHeadline}\"\n" + + "\n" + + "--\n" + + "Dies ist eine automatisch generierte E-Mail.\n" + + "This is an auto-generated E-Mail.\n", + }; + + public FormMail MvFinishedNotification { get; set; } = new FormMail() + { + //TemplateName = "MvFinishedNotification", + To = "{EMailName} <{EMail}>", + Subject = "Mitgliederversammlung beendet", + Body = "Hallo {EMailName}!\n" + + "\n" + + "Danke für Deine Teilnahme an der Mitgliederversammlung!\n" + + "\n" + + "--\n" + + "Dies ist eine automatisch generierte E-Mail.\n" + + "This is an auto-generated E-Mail.\n", + }; + + + private static void AddAllowedObjects(FormMail m, System.Type t) + { + PropertyInfo[] properties = t.GetProperties(); + foreach(PropertyInfo p in properties) + { + m.AllowedObjectFields.Add($"{t.Name}.{p.Name}"); + } + + } + public void InitializeNonSerializedFields() + { + //MemberAccountActivated.TemplateName = "MemberAccountActivated"; + AddAllowedObjects(MemberAccountActivated, typeof(Configuration)); + AddAllowedObjects(MemberAccountActivated, typeof(Member)); + + //MemberAccountActivated.TemplateName = "MemberActiveVorstand"; + AddAllowedObjects(MemberActiveVorstand, typeof(Configuration)); + + AddAllowedObjects(NewMemberVorstand, typeof(ConfigEMail)); + AddAllowedObjects(NewMemberVorstand, typeof(Member)); + + AddAllowedObjects(NewMemberWelcome, typeof(Member)); + } + } +} \ No newline at end of file diff --git a/model/Member.cs b/model/Member.cs index e394a5a..04ca6f0 100644 --- a/model/Member.cs +++ b/model/Member.cs @@ -188,7 +188,7 @@ namespace dezentrale.model } catch (Exception ex) { - Console.WriteLine($"Member {this.Number:D3} invalid RegEx: {ex.Message}"); + Console.WriteLine($"Member {this.Number:D3} invalid RegEx: {ex.Message}"); } return bankAccountInCharge.Equals(t.IBAN); @@ -211,7 +211,7 @@ namespace dezentrale.model public void TestMail() { - FormMail testMail = FormMail.GenerateTestmail(); + FormMail testMail = Program.mailTemplates.Testmail; try { testMail.Send(this); @@ -224,7 +224,7 @@ namespace dezentrale.model public void AccountStatusMail(string user = null) { StartLogEvent("Member Status Mail", LogEvent.eEventType.EMail, user); - FormMail accountStatusMail = FormMail.GenerateSingleMemberStatusReport(); + FormMail accountStatusMail = Program.mailTemplates.SingleMemberStatusReport; try { CurrentLog.SubEvents.Add(accountStatusMail.Send(this)); @@ -276,7 +276,7 @@ namespace dezentrale.model FormMail fm = null; if (this.Status == eStatus.Deleted || this.Status == eStatus.Disabled) { - fm = FormMail.GenerateDisabledMemberGettingPayments2SM(); + fm = Program.mailTemplates.DisabledMemberGettingPayments2SM; } else if (odd) { @@ -309,7 +309,7 @@ namespace dezentrale.model if (paymentNotify) { - FormMail notify = FormMail.GenerateMemberPaymentNotify(odd).ReplaceReflect(t); + FormMail notify = Program.mailTemplates.GenerateMemberPaymentNotify(odd).ReplaceReflect(t); try { diff --git a/model/money/BankTransfer.cs b/model/money/BankTransfer.cs index d59625f..3b987a1 100644 --- a/model/money/BankTransfer.cs +++ b/model/money/BankTransfer.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using System.Numerics; +using System.Text.RegularExpressions; using System.Xml.Serialization; namespace dezentrale.model.money @@ -55,9 +57,9 @@ namespace dezentrale.model.money case "Auslagenersatz Ruecklastschrift": AuslagenersatzRuecklastschrift = csvEntry[i]; break; case "Beguenstigter/Zahlungspflichtiger": RecipientOrDebitor = csvEntry[i]; break; case "Kontonummer/IBAN": - case "Kontonummer": IBAN = csvEntry[i]; break; + case "Kontonummer": IBAN = csvEntry[i].Trim(); break; case "BIC (SWIFT-Code)": - case "BLZ": BIC = csvEntry[i]; break; + case "BLZ": BIC = csvEntry[i].Trim(); break; case "Betrag": { string sAmount = csvEntry[i].Replace(',', '.'); @@ -71,5 +73,82 @@ namespace dezentrale.model.money } } } + + private const string ibanPattern = "^[A-Z]{2}\\d{2}\\d{8}\\d{10}$"; + public static string IbanRegexAssert(string iban, bool checkPz = true) + { + iban = iban.Replace(" ", "").Replace("-", ""); + if (!Regex.IsMatch(iban, ibanPattern)) + { + throw new FormatException("IBAN format invalid"); + } + if(checkPz) + { + if(!_PzOk(iban)) + { + throw new Exception("IBAN checksum error"); + } + } + return iban; + } + private static int _CCodeToInt(string cCode) + { + char[] c = cCode.ToCharArray(); + string ret = String.Format("{0}{1}", c[0] + 10 - 'A', c[1] + 10 - 'A'); + return Convert.ToInt32(ret); + } + private static string _CalcPz(string cCode, string blz, string kto) + { + //https://www.iban.de/iban-pruefsumme.html + int cci = _CCodeToInt(cCode); + + string modBaseS = String.Format("{0}{1}{2}00", blz, kto, cci); + //760909001234567890131400 + BigInteger mod = BigInteger.Parse(modBaseS); + mod = BigInteger.Remainder(mod, new BigInteger(97)); + string pz = String.Format("{0:D2}", 98 - mod); + return pz; + } + private static string _CalcPz(string iban) + { + return _CalcPz(iban.Substring(0, 2), iban.Substring(4, 8), iban.Substring(12,10)); + } + public static string CalcPz(string iban) + { + iban = IbanRegexAssert(iban, false); + return _CalcPz(iban); + } + private static bool _PzOk(string iban) + { + return _CalcPz(iban).Equals(iban.Substring(2, 2)); + } + public static bool PzOk(string iban) + { + iban = IbanRegexAssert(iban, false); + return _PzOk(iban); + } + public static string GetKtoFromIban(string iban) + { + iban = IbanRegexAssert(iban); + return iban.Substring(12); + } + public static string GetBlzFromIban(string iban) + { + iban = IbanRegexAssert(iban); + return iban.Substring(4, 8); + } + public static string GetCCodeFromIban(string iban) + { + iban = IbanRegexAssert(iban); + return iban.Substring(0,2); + } + public static string GetIbanFromKtoBlz(string cCode, string blz, string kto) + { + //build iban + string Pz = _CalcPz(cCode, blz, kto); + string iban = String.Format("{0}{1}{2}{3}", cCode, Pz, blz, kto); + + return IbanRegexAssert(iban); + } } } diff --git a/view/LvFormmailTemplateFields.cs b/view/LvFormmailTemplateFields.cs new file mode 100644 index 0000000..a5bd899 --- /dev/null +++ b/view/LvFormmailTemplateFields.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Windows.Forms; + +using dezentrale.model; + +namespace dezentrale.view +{ + public class LvFormmailTemplateFields : CustomListView + { + //KeyValuePair<> + protected override List DefaultColumns + { + get + { + return new List() + { + new ConfigLVDataHandler() + { + Name = "templateField", + Display = "Field", + Width = 160, + CustomToString = ( x => x.ToString() ), + } + }; + } + } + + public LvFormmailTemplateFields() : base(Program.config.MemberListColumns, LvFormmailTemplateFields_ColumnsChanged) { } + + private static void LvFormmailTemplateFields_ColumnsChanged(object sender, ColumnsChangedArgs e) + { + Console.WriteLine("LvFormmailTemplateFields_ColumnsChanged"); + //Program.config.MvListColumns.Clear(); + //foreach (ConfigLVDataHandler c in e.Columns) Program.config.MvListColumns.Add(new ConfigLVColumn(c)); + //XmlData.SaveToFile(Program.ConfigFile, Program.config); + } + } +} diff --git a/view/LvMailTemplates.cs b/view/LvMailTemplates.cs new file mode 100644 index 0000000..5ca7850 --- /dev/null +++ b/view/LvMailTemplates.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Windows.Forms; + +using dezentrale.model; + +namespace dezentrale.view +{ + public class LvMailTemplates : CustomListView + { + protected override List DefaultColumns + { + get + { + return new List() + { + new ConfigLVDataHandler() + { + Name = "templateName", + Display = "Template", + Width = 250, + CustomToString = ( x => ((FormMail)x).ToString()), + } + }; + } + } + + public LvMailTemplates() : base(Program.config.MemberListColumns, LvMailTemplates_ColumnsChanged) { + MultiSelect = false; + } + + private static void LvMailTemplates_ColumnsChanged(object sender, ColumnsChangedArgs e) + { + Console.WriteLine("LvMailTemplates_ColumnsChanged"); + //Program.config.MvListColumns.Clear(); + //foreach (ConfigLVDataHandler c in e.Columns) Program.config.MvListColumns.Add(new ConfigLVColumn(c)); + //XmlData.SaveToFile(Program.ConfigFile, Program.config); + } + } +} \ No newline at end of file diff --git a/view/LvMv.cs b/view/LvMv.cs index c1a6610..2e71a23 100644 --- a/view/LvMv.cs +++ b/view/LvMv.cs @@ -30,7 +30,7 @@ namespace dezentrale.view }; } } - public LvMv() : base(Program.config.MemberListColumns, LvMv_ColumnsChanged) { } + public LvMv() : base(Program.config.MvListColumns, LvMv_ColumnsChanged) { } private static void LvMv_ColumnsChanged(object sender, ColumnsChangedArgs e) { diff --git a/view/frmConfiguration.cs b/view/frmConfiguration.cs index c816fe3..5f1a5a0 100644 --- a/view/frmConfiguration.cs +++ b/view/frmConfiguration.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Drawing; using System.Linq; +using System.Reflection; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; @@ -30,6 +31,12 @@ namespace dezentrale.view private TextBox tbSmtpPassword; private TextBox tbSmtpCcTo; + //Mail template settings + private LvMailTemplates lvMailTemplates; + private LvFormmailTemplateFields lvMailTemplateFields; + private TextBox tbMailTemplateSubject; + private TextBox tbMailTemplateBody; + //Vorstand settings private TextBox tbVSName; private TextBox tbVSEmail; @@ -338,6 +345,181 @@ namespace dezentrale.view tbSFEmail.Text = Program.config.Schriftfuehrer.EMail; return gui; } + public TabPage BuildMailTemplateGui() + { + TabPage gui = new TabPage("Mail templates"); + + gui.BackColor = Color.LightBlue; + SplitContainer split1 = new SplitContainer() + { + Dock = DockStyle.Fill, + Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom, + //BackColor = Color.LightBlue, + }; + gui.Controls.Add(split1); + GroupBox gbTemplates = new GroupBox() + { + Width = 45, Height = 95, + Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom, + Text = "Templates", + }; + try + { + split1.Panel1MinSize = 250; + } catch(Exception ex) { MessageBox.Show(ex.Message); } + split1.Panel1.Controls.Add(gbTemplates); + + gbTemplates.Controls.Add(lvMailTemplates = new LvMailTemplates() + { + Location = new Point(lm + 6, 15 + 0 * line + tm), + Width = 25, + Height = 70, + Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom, + }); + lvMailTemplates.SelectedIndexChanged += (sender, e) => { + FormMail m = lvMailTemplates.GetFirstSelectedItem(); + try + { + if (m != null) + { + tbMailTemplateSubject.Enabled = true; + tbMailTemplateBody.Enabled = true; + lvMailTemplateFields.Enabled = true; + tbMailTemplateSubject.Text = m.Subject; + tbMailTemplateBody.Text = m.Body; + lvMailTemplateFields.LoadFromList(m.AllowedObjectFields); + } + else + { + tbMailTemplateSubject.Enabled = false; + tbMailTemplateBody.Enabled = false; + lvMailTemplateFields.Enabled = false; + tbMailTemplateSubject.Text = ""; + tbMailTemplateBody.Text = ""; + lvMailTemplateFields.LoadFromList(new List()); + } + } catch(Exception ex) + { + MessageBox.Show(ex.Message); + } + }; + + GroupBox gbContents = new GroupBox() + { + Dock = DockStyle.Fill, + Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom, + Text = "Contents", + }; + + + split1.Panel2.Controls.Add(gbContents); + SplitContainer split2 = new SplitContainer() + { + Dock = DockStyle.Fill, + Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom, + //BackColor = Color.Orange, + }; + gbContents.Controls.Add(split2); + split2.Panel1.Controls.Add(lvMailTemplateFields = new LvFormmailTemplateFields() + { + Enabled = false, + Location = new Point(lm, 0 * line + tm), + Width = 43, + Height = 90, + Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom, + }); + split2.Panel2.Controls.Add(tbMailTemplateSubject = new TextBox() + { + Enabled = false, + Location = new Point(lm, 0 * line + tm), + Width = 35, + Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right, + }); + split2.Panel2.Controls.Add(tbMailTemplateBody = new TextBox() + { + Enabled = false, + Location = new Point(lm, 1 * line + tm), + Multiline = true, + ScrollBars = ScrollBars.Both, + Width = 35, + Height = 446, + Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom, + }); + /* + gui.Controls.Add(new Label() + { + Text = "Template", + Location = new Point(lm + 113, 0 * line + tm), + Width = 300, + });*/ + LoadMailTemplates(); + return gui; + } + private MailTemplates mailTemplates = new MailTemplates(); + private bool mailTemplatesChanged = false; + private void LoadMailTemplates() + { + PropertyInfo[] properties = typeof(MailTemplates).GetProperties(); + foreach (PropertyInfo p in properties) + { + if (p.PropertyType != typeof(FormMail)) continue; + if (!p.CanRead) continue; + if (!p.CanWrite) continue; + //m.AllowedObjectFields.Add($"{p.Name}"); + FormMail fm = (FormMail)p.GetValue(Program.mailTemplates); + //lvMailTemplates.AddEntry(); + } + lvMailTemplates.AddEntry(mailTemplates.NewMemberWelcome = new FormMail(Program.mailTemplates.NewMemberWelcome)); + lvMailTemplates.AddEntry(mailTemplates.MemberAccountActivated = new FormMail(Program.mailTemplates.MemberAccountActivated)); + lvMailTemplates.AddEntry(mailTemplates.NewMemberVorstand = new FormMail(Program.mailTemplates.NewMemberVorstand)); + lvMailTemplates.AddEntry(mailTemplates.MemberActiveVorstand = new FormMail(Program.mailTemplates.MemberActiveVorstand)); + //lvMailTemplates.AddEntry(mailTemplates.AutoTypeFoerdermitglied = new FormMail(Program.mailTemplates.AutoTypeFoerdermitglied)); + lvMailTemplates.AddEntry(mailTemplates.MembershipTypeChanged = new FormMail(Program.mailTemplates.MembershipTypeChanged)); + lvMailTemplates.AddEntry(mailTemplates.BalanceNegativeMemberNotify1 = new FormMail(Program.mailTemplates.BalanceNegativeMemberNotify1)); + lvMailTemplates.AddEntry(mailTemplates.BalanceNegativeMemberNotify2 = new FormMail(Program.mailTemplates.BalanceNegativeMemberNotify2)); + lvMailTemplates.AddEntry(mailTemplates.BalanceNegativeMemberDeactivation = new FormMail(Program.mailTemplates.BalanceNegativeMemberDeactivation)); + lvMailTemplates.AddEntry(mailTemplates.BalanceNegativeMemberDeactivationVS = new FormMail(Program.mailTemplates.BalanceNegativeMemberDeactivationVS)); + lvMailTemplates.AddEntry(mailTemplates.BalanceNegativeNotify2SM = new FormMail(Program.mailTemplates.BalanceNegativeNotify2SM)); + lvMailTemplates.AddEntry(mailTemplates.DisabledMemberGettingPayments2SM = new FormMail(Program.mailTemplates.DisabledMemberGettingPayments2SM)); + lvMailTemplates.AddEntry(mailTemplates.BalanceAbove200NotifySM = new FormMail(Program.mailTemplates.BalanceAbove200NotifySM)); + //lvMailTemplates.AddEntry(mailTemplates.MemberPaymentNotify = new FormMail(Program.mailTemplates.MemberPaymentNotify)); + lvMailTemplates.AddEntry(mailTemplates.KeylockChanged = new FormMail(Program.mailTemplates.KeylockChanged)); + lvMailTemplates.AddEntry(mailTemplates.Testmail = new FormMail(Program.mailTemplates.Testmail)); + lvMailTemplates.AddEntry(mailTemplates.SingleMemberStatusReport = new FormMail(Program.mailTemplates.SingleMemberStatusReport)); + lvMailTemplates.AddEntry(mailTemplates.ReducedFeeReminder = new FormMail(Program.mailTemplates.ReducedFeeReminder)); + lvMailTemplates.AddEntry(mailTemplates.MemberPaymentReceipts = new FormMail(Program.mailTemplates.MemberPaymentReceipts)); + lvMailTemplates.AddEntry(mailTemplates.MvCancelNotification = new FormMail(Program.mailTemplates.MvCancelNotification)); + lvMailTemplates.AddEntry(mailTemplates.MvFinishedNotification = new FormMail(Program.mailTemplates.MvFinishedNotification)); + mailTemplatesChanged = false; + } + private void StoreMailTemplates() + { + if (mailTemplatesChanged) + { + Program.mailTemplates.NewMemberWelcome = mailTemplates.NewMemberWelcome; + Program.mailTemplates.MemberAccountActivated = mailTemplates.MemberAccountActivated; + Program.mailTemplates.NewMemberVorstand = mailTemplates.NewMemberVorstand; + Program.mailTemplates.MemberActiveVorstand = mailTemplates.MemberActiveVorstand; + //Program.mailTemplates.AutoTypeFoerdermitglied = mailTemplates.AutoTypeFoerdermitglied; + Program.mailTemplates.MembershipTypeChanged = mailTemplates.MembershipTypeChanged; + Program.mailTemplates.BalanceNegativeMemberNotify1 = mailTemplates.BalanceNegativeMemberNotify1; + Program.mailTemplates.BalanceNegativeMemberNotify2 = mailTemplates.BalanceNegativeMemberNotify2; + Program.mailTemplates.BalanceNegativeMemberDeactivation = mailTemplates.BalanceNegativeMemberDeactivation; + Program.mailTemplates.BalanceNegativeMemberDeactivationVS = mailTemplates.BalanceNegativeMemberDeactivationVS; + Program.mailTemplates.BalanceNegativeNotify2SM = mailTemplates.BalanceNegativeNotify2SM; + Program.mailTemplates.DisabledMemberGettingPayments2SM = mailTemplates.DisabledMemberGettingPayments2SM; + Program.mailTemplates.BalanceAbove200NotifySM = mailTemplates.BalanceAbove200NotifySM; + //Program.mailTemplates.MemberPaymentNotify = mailTemplates.MemberPaymentNotify; + Program.mailTemplates.KeylockChanged = mailTemplates.KeylockChanged; + Program.mailTemplates.Testmail = mailTemplates.Testmail; + Program.mailTemplates.SingleMemberStatusReport = mailTemplates.SingleMemberStatusReport; + Program.mailTemplates.ReducedFeeReminder = mailTemplates.ReducedFeeReminder; + Program.mailTemplates.MemberPaymentReceipts = mailTemplates.MemberPaymentReceipts; + Program.mailTemplates.MvCancelNotification = mailTemplates.MvCancelNotification; + Program.mailTemplates.MvFinishedNotification = mailTemplates.MvFinishedNotification; + } + } + public TabPage BuildMoneyTransfersGui() { TabPage gui = new TabPage("MoneyTransfers"); @@ -495,11 +677,13 @@ namespace dezentrale.view this.Text = "dezentrale-members :: Configuration"; this.Controls.Add(new TabControl() { - Size = new System.Drawing.Size(this.Width - 16, this.Height - 95), + Size = new System.Drawing.Size(this.Width - 16, this.Height - 95), + Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom, TabPages = { BuildGenericGui(), BuildSmtpGui(), + BuildMailTemplateGui(), BuildMoneyTransfersGui(), BuildImportExportGui(), } @@ -551,6 +735,9 @@ namespace dezentrale.view Program.config.Schriftfuehrer.EMailName = tbSFName.Text; Program.config.Schriftfuehrer.EMail = tbSFEmail.Text; + + StoreMailTemplates(); + //use MoneyTransferList for that, not Program.config //[XmlElement] public List MoneyTransferRegEx { get; set; } = new List(); @@ -575,6 +762,7 @@ namespace dezentrale.view XmlData.SaveToFile(Program.ConfigFile, Program.config); Program.MoneyTransfers.SaveToFile(); Console.WriteLine("Stored new configuration."); + XmlData.SaveToFile(System.IO.Path.Combine(Program.config.DbDirectory, "MailTemplates.xml"), Program.mailTemplates); } catch (Exception ex) { diff --git a/view/frmEditEntry.cs b/view/frmEditEntry.cs index 36bf7b5..8139c0b 100644 --- a/view/frmEditEntry.cs +++ b/view/frmEditEntry.cs @@ -37,6 +37,7 @@ namespace dezentrale.view private TextBox tbAccountBalance; private CheckBox cbEvaluateAccountInCharge; private TextBox tbBankAccountInCharge; + private Button btnEnterBlzKto; private CheckBox cbPaymentNotification; private TextBox tbBankTransferRegEx; private TextBox tbRemarks; @@ -403,24 +404,63 @@ namespace dezentrale.view Width = 20, Anchor = AnchorStyles.Top | AnchorStyles.Left, }); + + cbEvaluateAccountInCharge.CheckedChanged += (sender, e) => + { + tbBankAccountInCharge.ReadOnly = !cbEvaluateAccountInCharge.Checked; + tbBankTransferRegEx.ReadOnly = !cbEvaluateAccountInCharge.Checked; + btnEnterBlzKto.Enabled = cbEvaluateAccountInCharge.Checked; + }; parent.Controls.Add(tbBankAccountInCharge = new TextBox() { Location = new Point(lm + 138, 4 * line + tm), Width = 160, Anchor = AnchorStyles.Top | AnchorStyles.Left, }); - parent.Controls.Add(cbPaymentNotification = new CheckBox() + tbBankAccountInCharge.TextChanged += (sender, e) => { - Text = "Send payment notification via E-Mail", - Location = new Point(lm + 308, 4 * line + tm), - Width = 240, - Anchor = AnchorStyles.Top | AnchorStyles.Left, - }); + Color bg = SystemColors.Window; + try + { + if(tbBankAccountInCharge.Text.Length > 0) + BankTransfer.IbanRegexAssert(tbBankAccountInCharge.Text); + } catch(Exception ex) + { + bg = Color.LightPink; + ToolTip tt = new ToolTip(); + tt.IsBalloon = true; + tt.InitialDelay = 0; + tt.ShowAlways = true; + tt.SetToolTip(tbBankAccountInCharge, ex.Message); + } + tbBankAccountInCharge.BackColor = bg; + }; + parent.Controls.Add(btnEnterBlzKto = new Button() + { + Text = "Enter Blz/Kto instead", + Location = new Point(lm + 308, 4 * line + tm), + Width = 160, + }); + btnEnterBlzKto.Click += (sender, e) => + { + frmEnterBlzKto enterBlzKto = new frmEnterBlzKto(tbBankAccountInCharge.Text); + DialogResult dr = enterBlzKto.ShowDialog(); + if(dr == DialogResult.OK) + { + try + { + tbBankAccountInCharge.Text = enterBlzKto.Iban; + } catch(Exception ex) + { + MessageBox.Show($"Error:\r\n{ex.Message}"); + } + } + }; parent.Controls.Add(new Label() { - Text = "BankRegEx:", + Text = "BankSubjContains:", Location = new Point(lm, 5 * line + tm + labelOffs), Size = new Size(110, labelHeight), TextAlign = ContentAlignment.BottomRight, @@ -431,11 +471,13 @@ namespace dezentrale.view Width = 160, Anchor = AnchorStyles.Top | AnchorStyles.Left, }); - cbEvaluateAccountInCharge.CheckedChanged += (sender, e) => - { - tbBankAccountInCharge.ReadOnly = !cbEvaluateAccountInCharge.Checked; - tbBankTransferRegEx.ReadOnly = !cbEvaluateAccountInCharge.Checked; - }; + parent.Controls.Add(cbPaymentNotification = new CheckBox() + { + Text = "Send payment notification via E-Mail", + Location = new Point(lm + 118, 6 * line + tm), + Width = 240, + Anchor = AnchorStyles.Top | AnchorStyles.Left, + }); /* [XmlElement] public DateTime GreetedDate { get; set; } diff --git a/view/frmEnterBlzKto.cs b/view/frmEnterBlzKto.cs new file mode 100644 index 0000000..23915be --- /dev/null +++ b/view/frmEnterBlzKto.cs @@ -0,0 +1,85 @@ +using System; +using System.Drawing; +using System.Windows.Forms; + +using dezentrale.model.money; + +namespace dezentrale.view +{ + public class frmEnterBlzKto : FormWithActionButtons + { + private TextBox tbBlz; + private TextBox tbKtoNummer; + private Label lblCcPz; + private string cc; + + public string Iban + { + get + { + return BankTransfer.GetIbanFromKtoBlz("DE", tbBlz.Text, tbKtoNummer.Text); + } + set + { + cc = BankTransfer.GetCCodeFromIban(value); + lblCcPz.Text = cc + BankTransfer.CalcPz(value); + tbBlz.Text = BankTransfer.GetBlzFromIban(value); + tbKtoNummer.Text = BankTransfer.GetKtoFromIban(value); + } + } + public frmEnterBlzKto(string ibanInput) + { + DialogResult = DialogResult.Cancel; + this.StartPosition = FormStartPosition.CenterParent; + this.Size = new System.Drawing.Size(370, 90); + this.Text = "dezentrale-members :: Enter BLZ/KTO"; + + this.Controls.Add(tbBlz = new TextBox() + { + Location = new Point(lm + 113, 0 * line + tm), + Width = 80, + }); + tbBlz.TextChanged += tbBlzKto_Changed; + this.Controls.Add(tbKtoNummer = new TextBox() + { + Location = new Point(lm + 203, 0 * line + tm), + Width = 100, + }); + tbKtoNummer.TextChanged += tbBlzKto_Changed; + + this.Controls.Add(lblCcPz = new Label() + { + Location = new Point(lm + 5, 0 * line + tm), + TextAlign = ContentAlignment.MiddleRight, + + }); + try { Iban = ibanInput; } catch (Exception) { } + + AddButton("Apply", btnApply_Click); + AddButton("Cancel", btnCancel_Click); + } + + private void tbBlzKto_Changed(object sender, EventArgs e) + { + try + { + string iban = BankTransfer.GetIbanFromKtoBlz(cc, tbBlz.Text, tbKtoNummer.Text); + lblCcPz.Text = cc + BankTransfer.CalcPz(iban); + lblCcPz.BackColor = SystemColors.Control; + } catch(Exception ex) + { + lblCcPz.Text = $"ERROR\r\n{ex.Message}"; + lblCcPz.BackColor = Color.LightPink; + } + } + private void btnApply_Click(object sender, EventArgs e) + { + DialogResult = DialogResult.OK; + this.Close(); + } + private void btnCancel_Click(object sender, EventArgs e) + { + this.Close(); + } + } +} diff --git a/view/frmMain.cs b/view/frmMain.cs index e37c566..02b805c 100644 --- a/view/frmMain.cs +++ b/view/frmMain.cs @@ -180,7 +180,7 @@ namespace dezentrale.view DialogResult dr = MessageBox.Show("You've changed the keylock combination.\n Do you want to send an E-Mail to every active member to inform them?", "Keylock-Combi changed", MessageBoxButtons.YesNo); if (dr == DialogResult.Yes) { - FormMail keylockChanged = FormMail.GenerateKeylockChanged().ReplaceReflect(Program.config); + FormMail keylockChanged = Program.mailTemplates.KeylockChanged.ReplaceReflect(Program.config); foreach (Member m in Program.members.Entries) { if (m.Status != Member.eStatus.Active) continue; @@ -367,7 +367,7 @@ namespace dezentrale.view res = MessageBox.Show("Send cancel mails to previously invited members?", "Send cancel mails?", MessageBoxButtons.YesNo); if (res == DialogResult.Yes) { - FormMail fm = FormMail.GenerateMvCancelNotification().ReplaceReflect(mv); + FormMail fm = Program.mailTemplates.MvCancelNotification.ReplaceReflect(mv); foreach (MvInvitedMember mvi in mv.Members) { if (!mvi.Invited) continue; @@ -563,14 +563,12 @@ namespace dezentrale.view } private void lstMembers_TestMail(object sender, EventArgs e) { - Member m = lstMembers.GetFirstSelectedItem(); - FormMail testMail = FormMail.GenerateTestmail(); - SendMail(testMail, m); + SendMail(Program.mailTemplates.Testmail, lstMembers.GetFirstSelectedItem()); } private void lstMembers_AccountStatusMail(object sender, EventArgs e) { Member m = lstMembers.GetFirstSelectedItem(); - FormMail statusMail = FormMail.GenerateSingleMemberStatusReport(); + FormMail statusMail = Program.mailTemplates.SingleMemberStatusReport; SendMail(statusMail, m); }