2021-01-24PX Multiple changes:
- Added CsvImportProcess (porting ProcessCsv as a background process), not finished yet - added comment window on member editing - Changed GUI to allow editing member account balance - Added Enable/Disable feature for Import/Export, in order to get rid of stupid messages at startup/shutdown - Added configuration for Schatzmeister/Schriftfuehrer contact to configuration - Fixed CurrentDebtLevel > 0 was able to prevent BalanceDegrade / postdegrade code from working - Fixed Member list wasn't refreshed after CSV import - Changed MembershipDonation enum type to Donation (as non-members can donate too)
This commit is contained in:
parent
105afdb203
commit
4d16e11b6e
22
Program.cs
22
Program.cs
|
@ -34,7 +34,11 @@ namespace dezentrale
|
|||
public static MemberList members = new MemberList();
|
||||
public static MvList mvList = new MvList();
|
||||
|
||||
public static bool MoneyTransfersLoaded { get { return moneyTransfers != null; } }
|
||||
public static bool MoneyTransfersLoaded
|
||||
{
|
||||
get { return moneyTransfers != null; }
|
||||
set { moneyTransfers = value ? MoneyTransferList.LoadFromFile() : null; }
|
||||
}
|
||||
private static MoneyTransferList moneyTransfers = null;
|
||||
public static MoneyTransferList MoneyTransfers
|
||||
{
|
||||
|
@ -220,8 +224,13 @@ namespace dezentrale
|
|||
case eMode.Cronjob:
|
||||
Cronjob.Run();
|
||||
break;
|
||||
case eMode.Export:
|
||||
{
|
||||
case eMode.Export:
|
||||
{
|
||||
if (!Program.config.ImportExport.Enabled)
|
||||
{
|
||||
Console.WriteLine("ImportExport is disabled in configuration");
|
||||
return 1;
|
||||
}
|
||||
ExportProcess export = new ExportProcess()
|
||||
{
|
||||
ImportExportSettings = Program.config.ImportExport,
|
||||
|
@ -239,7 +248,12 @@ namespace dezentrale
|
|||
} break;
|
||||
|
||||
case eMode.Import:
|
||||
{
|
||||
{
|
||||
if(!Program.config.ImportExport.Enabled)
|
||||
{
|
||||
Console.WriteLine("ImportExport is disabled in configuration");
|
||||
return 1;
|
||||
}
|
||||
ImportProcess import = new ImportProcess()
|
||||
{
|
||||
ImportExportSettings = Program.config.ImportExport,
|
||||
|
|
|
@ -16,52 +16,40 @@ namespace dezentrale.core
|
|||
//! \brief Perform a Run on one Member. This will perform all necessary actions
|
||||
//! at this point.
|
||||
//! \param m Member to check
|
||||
//! \param sm Member entry for the Schatzmeister account, in order to send notification mails for some events
|
||||
public static void Run(Member m, Member sm)
|
||||
//! \param smContact Mail contact entry for the Schatzmeister account, in order to send notification mails for some events
|
||||
public static void Run(Member m, ConfigEMail smContact)
|
||||
{
|
||||
Console.WriteLine($"Processing member {m.Number:D3} ({m.Nickname})...");
|
||||
CheckGreeting(m);
|
||||
CheckSpawning(m);
|
||||
// CheckReducedFeeValidity(m);
|
||||
CheckBalance_PreDegrade(m, sm);
|
||||
CheckBalance_PreDegrade(m, smContact);
|
||||
BalanceDegrade(m);
|
||||
CheckBalance_PostDegrade(m, sm);
|
||||
CheckBalance_PostDegrade(m, smContact);
|
||||
}
|
||||
//! \short Helper function for Run(m, sm). Determines sm automatically.
|
||||
//! \param m Member to check
|
||||
public static void Run(Member m)
|
||||
{
|
||||
Member sm = Program.members.Find(Member.eRole.Schatzmeister);
|
||||
if (sm == null)
|
||||
{
|
||||
Console.WriteLine($"Cronjob.Run(Member {m.Number}, {m.Nickname}): ERROR, cannot find sm account!");
|
||||
}
|
||||
else
|
||||
Run(m, sm);
|
||||
Run(m, Program.config.Schatzmeister);
|
||||
}
|
||||
|
||||
//! \short Perform a cronjob run on a List of members.
|
||||
//! \brief Perform a cronjob run on a List of members. This may be a
|
||||
//! partial List (e.g. by checking member entries from GUI)
|
||||
//! partial List (e.g. by checking member entries from GUI)sm
|
||||
//! \param partialList List of members to process. If null, the program will process the complete member list.
|
||||
public static void Run(List<Member> partialList = null)
|
||||
{
|
||||
Member sm = Program.members.Find(Member.eRole.Schatzmeister);
|
||||
if (sm == null)
|
||||
{
|
||||
Console.WriteLine($"Cronjob.Run(List of {partialList.Count} members): ERROR, cannot find schatzmeister account!");
|
||||
}
|
||||
if (partialList == null || partialList == Program.members.Entries)
|
||||
{
|
||||
foreach (Member m in Program.members.Entries) Run(m, sm);
|
||||
foreach (Member m in Program.members.Entries) Run(m, Program.config.Schatzmeister);
|
||||
|
||||
//GenerateReport();
|
||||
if (!Program.config.LastCronjobRun.Equals(ProgramStartTime))
|
||||
{
|
||||
Member schriftfuehrer = Program.members.Find(Member.eRole.Schriftfuehrer);
|
||||
try { if (sm != null) new MemberReport(true).Send(sm); }
|
||||
try { new MemberReport(true).Send(Program.config.Schatzmeister); }
|
||||
catch (Exception ex) { Console.WriteLine($"Cronjob.GenerateReport(): Error while sending report to Schatzmeister: {ex.Message}"); }
|
||||
try { if (schriftfuehrer != null) new MemberReport(false).Send(schriftfuehrer); }
|
||||
try { new MemberReport(false).Send(Program.config.Schriftfuehrer); }
|
||||
catch (Exception ex) { Console.WriteLine($"Cronjob.GenerateReport(): Error while sending report to schriftfuehrer: {ex.Message}"); }
|
||||
Console.WriteLine("Cronjob.Run(): Member Reports sent.");
|
||||
}
|
||||
|
@ -79,7 +67,7 @@ namespace dezentrale.core
|
|||
}
|
||||
else
|
||||
{
|
||||
foreach (Member m in partialList) Run(m, sm);
|
||||
foreach (Member m in partialList) Run(m, Program.config.Schatzmeister);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -262,11 +250,11 @@ namespace dezentrale.core
|
|||
private static DateTime ProgramStartTime { get; set; } = DateTime.Now;
|
||||
|
||||
//! \short Necessary actions prior to BalanceDegrade.
|
||||
private static void CheckBalance_PreDegrade(Member m, Member sm = null)
|
||||
private static void CheckBalance_PreDegrade(Member m, ConfigEMail smContact = null)
|
||||
{
|
||||
|
||||
}
|
||||
private static void CheckBalance_PostDegrade(Member m, Member sm = null)
|
||||
private static void CheckBalance_PostDegrade(Member m, ConfigEMail smContact = null)
|
||||
{
|
||||
if (m.Status != Member.eStatus.Active || m.PaymentAmount == 0) return;
|
||||
|
||||
|
@ -286,7 +274,7 @@ namespace dezentrale.core
|
|||
|
||||
if(!skipInsufficientNotify)
|
||||
{
|
||||
if (debtLevelDecrease) m.DebtLevel--;
|
||||
if (debtLevelDecrease) m.DebtLevel--;
|
||||
else m.DebtLevel = currentDebtLevel;
|
||||
//We don't set skipInsufficientNotify here as we don't want to not-warn
|
||||
//if it's still negative
|
||||
|
@ -300,10 +288,10 @@ namespace dezentrale.core
|
|||
{
|
||||
//Member has given much money
|
||||
m.StartLogEvent($"Excess amount of payments", LogEvent.eEventType.EMail, "automatic");
|
||||
if (sm != null)
|
||||
if (smContact != null)
|
||||
{
|
||||
FormMail above200 = FormMail.GenerateBalanceAbove200NotifySM().ReplaceReflect(m);
|
||||
above200.To = $"{sm.EMailName} <{sm.EMail}>";
|
||||
above200.To = smContact.ToString();
|
||||
try
|
||||
{
|
||||
m.CurrentLog.SubEvents.Add(above200.Send());
|
||||
|
@ -325,7 +313,11 @@ namespace dezentrale.core
|
|||
|
||||
case 0:
|
||||
{
|
||||
//all is fine.
|
||||
//all is fine.
|
||||
if (debtLevelDecrease || debtLevelIncrease)
|
||||
{
|
||||
m.StartLogEvent($"Debt level changed", LogEvent.eEventType.DataChange, "automatic");
|
||||
}
|
||||
} break;
|
||||
|
||||
case -1:
|
||||
|
@ -369,25 +361,22 @@ namespace dezentrale.core
|
|||
});
|
||||
Console.WriteLine($"Cannot send Insufficient amount #2 notification: {ex.Message}");
|
||||
}
|
||||
if (sm != null)
|
||||
|
||||
FormMail below2sm = FormMail.GenerateBalanceNegativeNotify2SM().ReplaceReflect(m);
|
||||
below2sm.To = smContact.ToString();
|
||||
try
|
||||
{
|
||||
FormMail below2sm = FormMail.GenerateBalanceNegativeNotify2SM().ReplaceReflect(m);
|
||||
below2sm.To = $"{sm.EMailName} <{sm.EMail}>";
|
||||
try
|
||||
m.CurrentLog.SubEvents.Add(below2sm.Send());
|
||||
} catch(Exception ex)
|
||||
{
|
||||
m.CurrentLog.SubEvents.Add(new LogSubEvent()
|
||||
{
|
||||
m.CurrentLog.SubEvents.Add(below2sm.Send());
|
||||
} catch(Exception ex)
|
||||
{
|
||||
m.CurrentLog.SubEvents.Add(new LogSubEvent()
|
||||
{
|
||||
Type = LogEvent.eEventType.Error,
|
||||
Topic = "Email notification error",
|
||||
Details = ex.Message,
|
||||
});
|
||||
Console.WriteLine($"Cannot send Insufficient amount #2 SM notification: {ex.Message}");
|
||||
}
|
||||
} else
|
||||
Console.WriteLine("ERROR: CheckBalance_PostDegrade: sm = null");
|
||||
Type = LogEvent.eEventType.Error,
|
||||
Topic = "Email notification error",
|
||||
Details = ex.Message,
|
||||
});
|
||||
Console.WriteLine($"Cannot send Insufficient amount #2 SM notification: {ex.Message}");
|
||||
}
|
||||
} else
|
||||
{
|
||||
m.StartLogEvent($"Deactivation (insufficient payment)", LogEvent.eEventType.Deactivation, "automatic");
|
||||
|
@ -420,6 +409,7 @@ namespace dezentrale.core
|
|||
break;
|
||||
}
|
||||
|
||||
//If there are data changes to the member, there's a log and we need to store everything
|
||||
if (m.CurrentLog != null)
|
||||
{
|
||||
m.LastCronjobBalanceMail = DateTime.Now;
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
|
||||
using dezentrale.model;
|
||||
using System.Collections.Generic;
|
||||
using dezentrale.model.money;
|
||||
|
||||
namespace dezentrale.core
|
||||
{
|
||||
public class CsvImportProcess : BackgroundProcess
|
||||
{
|
||||
private string fileName = "";
|
||||
public CsvImportProcess(string fileName)
|
||||
{
|
||||
this.fileName = fileName;
|
||||
|
||||
Caption = "Import CSV Money Transfers";
|
||||
Steps = 3;
|
||||
}
|
||||
protected override bool Run()
|
||||
{
|
||||
uint step = 0;
|
||||
LogTarget.LogLine($"Importing from {fileName}", LogEvent.ELogLevel.Info, "CsvImportProcess");
|
||||
|
||||
List<BankTransfer> tmpList = new List<BankTransfer>();
|
||||
List<string> headlineFields = null;
|
||||
List<Member> changedMembers = new List<Member>();
|
||||
|
||||
CsvFile csv = new CsvFile() { FieldSeparator = ';' };
|
||||
try
|
||||
{
|
||||
LogTarget.StepStarted(++step, "Reading file...");
|
||||
try
|
||||
{
|
||||
csv.ReadFile(fileName);
|
||||
LogTarget.StepCompleted(step, "Done reading file.", true);
|
||||
} catch(Exception ex)
|
||||
{
|
||||
LogTarget.LogLine($"Error: {ex.Message}", LogEvent.ELogLevel.Error, "CsvImportProcess");
|
||||
return false;
|
||||
}
|
||||
|
||||
List<List<string>> contents = csv.FileContents;
|
||||
LogTarget.StepStarted(++step, $"Parsing file ({contents.Count} csv lines, including headline)...");
|
||||
for(int csvLine = 0; csvLine < contents.Count; csvLine++)
|
||||
{
|
||||
List<string> l = contents[csvLine];
|
||||
|
||||
if (headlineFields == null)
|
||||
{
|
||||
//The first line is expected to have the headline field first, describing the contents
|
||||
headlineFields = l;
|
||||
string fields = "";
|
||||
foreach(string s in l)
|
||||
{
|
||||
fields += $"\"{s}\",";
|
||||
}
|
||||
LogTarget.LogLine($"Headline fields: {fields}", LogEvent.ELogLevel.Info, "CsvImportProcess");
|
||||
continue;
|
||||
}
|
||||
|
||||
BankTransfer bt = new BankTransfer(headlineFields, l, fileName, csvLine);
|
||||
MoneyTransfer duplicate = Program.MoneyTransfers.FindEqualEntry(bt);
|
||||
if (duplicate != null)
|
||||
{
|
||||
LogTarget.LogLine($"Line {csvLine}: is duplicate of MoneyTransfer {duplicate.Id} (ValutaDate {duplicate.ValutaDateString})", LogEvent.ELogLevel.Info, "CsvImportProcess");
|
||||
LogTarget.LogLine($" ValutaDate: {bt.ValutaDate}, Amount = {bt.AmountString} {bt.Currency}, Reason = \"{bt.TransferReason.Replace('\r', '\\').Replace('\n', '\\')}\"", LogEvent.ELogLevel.Info, "CsvImportProcess");
|
||||
}
|
||||
else
|
||||
{
|
||||
Program.MoneyTransfers.AddEntry(bt);
|
||||
tmpList.Add(bt);
|
||||
}
|
||||
}
|
||||
LogTarget.StepCompleted(step, $"Done parsing entries.", true);
|
||||
LogTarget.StepStarted(++step, $"Assigning found {tmpList.Count} entries to members");
|
||||
|
||||
//try to assign transfers to the members
|
||||
foreach (BankTransfer bt in tmpList)
|
||||
{
|
||||
if (bt.Amount < 0)
|
||||
{
|
||||
bt.TransferType = MoneyTransfer.eTransferType.RunningCost;
|
||||
LogTarget.LogLine($"{bt.Id}: (from CSV line {bt.CsvLine}): Amount = {bt.AmountString} --> RunningCost", LogEvent.ELogLevel.Info, "CsvImportProcess");
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (Member m in Program.members.Entries)
|
||||
{
|
||||
if (m.CheckBankTransfer(bt))
|
||||
{
|
||||
LogTarget.LogLine($"{bt.Id}: (from CSV line {bt.CsvLine}): adding to member {m}", LogEvent.ELogLevel.Info, "CsvImportProcess");
|
||||
bt.TransferType = MoneyTransfer.eTransferType.MembershipPayment;
|
||||
changedMembers.Add(m);
|
||||
m.StartLogEvent("Incoming bank transfer", LogEvent.eEventType.MembershipPayment, "automatic");
|
||||
m.ApplyMoneyTransfer(bt); //this also stores the member entry
|
||||
bt.AssignFixed = true;
|
||||
break; //this is important. We don't want to assign this to multiple members.
|
||||
}
|
||||
}
|
||||
|
||||
if(!bt.AssignFixed)
|
||||
{
|
||||
//bt matches no member!
|
||||
}
|
||||
}
|
||||
LogTarget.StepCompleted(step, $"Done assigning entries.", true);
|
||||
LogTarget.StepStarted(++step, $"Storing money transfers");
|
||||
//Store bank transfer list
|
||||
Program.MoneyTransfers.Entries.Sort();
|
||||
if (!Program.MoneyTransfers.SaveToFile())
|
||||
return false;
|
||||
|
||||
LogTarget.StepCompleted(step, "", true);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogTarget.LogLine($"Error while processing csv file \"{fileName}\": {ex.Message}", LogEvent.ELogLevel.Error, "CsvImportProcess");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -192,7 +192,7 @@ namespace dezentrale.core
|
|||
LogTarget.LogLine($"Cannot send payment receipts E-Mail: {ex.Message}", LogEvent.ELogLevel.Error);
|
||||
m.CurrentLog.SubEvents.Add(new LogSubEvent() { Type = LogEvent.eEventType.Error, Topic = "Email notification error", Details = ex.Message, });
|
||||
}
|
||||
m.SaveToFile(true);
|
||||
m.SaveToFile(null, true);
|
||||
}
|
||||
} else
|
||||
{
|
||||
|
|
|
@ -154,7 +154,7 @@
|
|||
</Compile>
|
||||
<Compile Include="model\ConfigSmtp.cs" />
|
||||
<Compile Include="model\Configuration.cs" />
|
||||
<Compile Include="model\ConfigVSMail.cs" />
|
||||
<Compile Include="model\ConfigEMail.cs" />
|
||||
<Compile Include="model\FormMail.cs" />
|
||||
<Compile Include="model\Member.cs" />
|
||||
<Compile Include="model\LogEvent.cs" />
|
||||
|
@ -214,6 +214,8 @@
|
|||
<Compile Include="view\LvSelectFields.cs" />
|
||||
<Compile Include="core\NewExportProcess.cs" />
|
||||
<Compile Include="core\NewImportProcess.cs" />
|
||||
<Compile Include="view\frmCommentChanges.cs" />
|
||||
<Compile Include="core\CsvImportProcess.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace dezentrale.model
|
||||
{
|
||||
public class ConfigEMail
|
||||
{
|
||||
[XmlAttribute] public string EMailName { get; set; } = "EMailName";
|
||||
[XmlAttribute] public string EMail { get; set; } = "user@example.com";
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{EMailName} <{EMail}>";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace dezentrale.model
|
||||
{
|
||||
public class ConfigVSMail
|
||||
{
|
||||
[XmlElement] public string VSName { get; set; } = "dezentrale Vorstand";
|
||||
[XmlElement] public string VSEmail { get; set; } = "vorstand@dezentrale.space";
|
||||
}
|
||||
}
|
|
@ -46,8 +46,9 @@ namespace dezentrale.model
|
|||
|
||||
|
||||
//db-wide configuration (in DB folder)
|
||||
[XmlElement("VS")] public ConfigVSMail VS { get; set; } = new ConfigVSMail();
|
||||
[XmlElement] public ConfigVSMail Schatzmeister { get; set; } = new ConfigVSMail();
|
||||
[XmlElement] public ConfigEMail VS { get; set; } = new ConfigEMail() { EMailName = "dezentrale Vorstand", EMail = "vorstand@dezentrale.space" };
|
||||
[XmlElement] public ConfigEMail Schatzmeister { get; set; } = new ConfigEMail() { EMailName = "Schatzmeister", EMail = "kasse@dezentrale.space" };
|
||||
[XmlElement] public ConfigEMail Schriftfuehrer { get; set; } = new ConfigEMail() { EMailName = "Schriftfuehrer", EMail = "vorstand@dezentrale.space" };
|
||||
|
||||
[XmlElement] public uint RegularPaymentAmount { get; set; } = 3200; //cents
|
||||
[XmlElement] public string RegularPaymentCurrency { get; set; } = "EUR";
|
||||
|
|
|
@ -52,7 +52,7 @@ namespace dezentrale.model
|
|||
{
|
||||
string[] addr = Program.config.Smtp.CcTo.Split(',', ';');
|
||||
foreach(string s in addr)
|
||||
message.CC.Add(new MailAddress(s));
|
||||
if(!string.IsNullOrEmpty(s)) message.CC.Add(new MailAddress(s));
|
||||
}
|
||||
|
||||
message.SubjectEncoding = Encoding.UTF8;
|
||||
|
@ -407,6 +407,24 @@ namespace dezentrale.model
|
|||
+ "Dies ist eine automatisch generierte E-Mail.\n",
|
||||
};
|
||||
}
|
||||
public static FormMail GenerateDisabledMemberGettingPayments2SM()
|
||||
{
|
||||
return new FormMail()
|
||||
{
|
||||
To = "schatzmeister <sm@example.com>", //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
|
||||
|
|
|
@ -23,7 +23,7 @@ namespace dezentrale.model
|
|||
|
||||
MembershipFee,
|
||||
MembershipPayment,
|
||||
MembershipDonation,
|
||||
Donation,
|
||||
|
||||
EMail,
|
||||
|
||||
|
|
|
@ -71,6 +71,7 @@ namespace dezentrale.model
|
|||
private bool paymentNotify = false;
|
||||
private DateTime memberFormDate;
|
||||
private DateTime reducedFeeValid;
|
||||
private int debtLevel = 0;
|
||||
|
||||
//This is a bit ugly but I didn't have a good idea how to solve it better.
|
||||
//The main goal is to track every change to every property.
|
||||
|
@ -112,11 +113,11 @@ namespace dezentrale.model
|
|||
[XmlElement] public DateTime MemberFormDate { get { return memberFormDate; } set { LogPropertyChange("MemberFormDate", memberFormDate, value); memberFormDate = value; } }
|
||||
|
||||
//internal management data
|
||||
[XmlElement] public int DebtLevel { get { return debtLevel; } set { LogPropertyChange("DebtLevel", debtLevel, value); debtLevel = value; } }
|
||||
[XmlElement] public DateTime GreetedDate { get; set; }
|
||||
[XmlElement] public DateTime LastPaymentProcessed { get; set; } = DateTime.Now;
|
||||
[XmlElement] public uint PaymentsTotal { get; set; }
|
||||
[XmlElement] public DateTime LastBalanceDegrade { get; set; } = DateTime.Now;
|
||||
[XmlElement] public int DebtLevel { get; set; } = 0;
|
||||
[XmlElement] public DateTime LastCronjobBalanceMail { get; set; } = DateTime.Now;
|
||||
[XmlElement] public DateTime LastCronjobReducedFeeMail { get; set; } = DateTime.Now;
|
||||
[XmlElement] public DateTime MvEventDate { get; set; }
|
||||
|
@ -160,9 +161,9 @@ namespace dezentrale.model
|
|||
else return number.CompareTo(other.Number);
|
||||
}
|
||||
|
||||
public bool SaveToFile(bool finishLog = true)
|
||||
public bool SaveToFile(string comment = null, bool finishLog = true)
|
||||
{
|
||||
if (finishLog) FinishLogEvent();
|
||||
if (finishLog) FinishLogEvent(comment);
|
||||
string completePath = System.IO.Path.Combine(Program.config.DbDirectory, GetFileName());
|
||||
Program.config.DbChangedSinceExport = true;
|
||||
Program.config.LastDbLocalChange = DateTime.Now;
|
||||
|
@ -174,23 +175,23 @@ namespace dezentrale.model
|
|||
|
||||
public bool CheckBankTransfer(BankTransfer t)
|
||||
{
|
||||
if (!evaluateAccountInCharge) return false;
|
||||
if (!bankAccountInCharge.Equals(t.IBAN))
|
||||
//on banktransfers, AccountInCharge is the receiver IBAN, we need the sender IBAN here
|
||||
return false;
|
||||
|
||||
if (string.IsNullOrEmpty(BankTransferRegEx))
|
||||
return true;
|
||||
if (!evaluateAccountInCharge) return false;
|
||||
|
||||
try
|
||||
{
|
||||
return Regex.IsMatch(t.TransferReason, BankTransferRegEx);
|
||||
{
|
||||
if (!string.IsNullOrEmpty(BankTransferRegEx))
|
||||
{
|
||||
if (Regex.IsMatch(t.TransferReason, BankTransferRegEx))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Member {this.Number:D3} invalid RegEx: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
|
||||
return bankAccountInCharge.Equals(t.IBAN);
|
||||
//on banktransfers, AccountInCharge is the receiver IBAN, we need the sender IBAN here
|
||||
}
|
||||
|
||||
private void PaymentAdjustBalance(Int64 amount, string user = null)
|
||||
|
@ -243,8 +244,8 @@ namespace dezentrale.model
|
|||
LogEvent.eEventType evt = LogEvent.eEventType.Generic;
|
||||
switch (t.TransferType)
|
||||
{
|
||||
case MoneyTransfer.eTransferType.MembershipDonation:
|
||||
evt = LogEvent.eEventType.MembershipDonation; break;
|
||||
case MoneyTransfer.eTransferType.Donation:
|
||||
evt = LogEvent.eEventType.Donation; break;
|
||||
case MoneyTransfer.eTransferType.MembershipFee:
|
||||
evt = LogEvent.eEventType.MembershipFee; break;
|
||||
case MoneyTransfer.eTransferType.MembershipPayment:
|
||||
|
@ -264,38 +265,47 @@ namespace dezentrale.model
|
|||
PaymentAdjustBalance(t.Amount);
|
||||
LastPaymentProcessed = DateTime.Now;
|
||||
|
||||
|
||||
//find out if we need to send a mail to Schatzmeister (i.e. amount is odd in respect to the monthly fee)
|
||||
Int64 months = t.Amount / (Int64)PaymentAmount;
|
||||
bool odd = months * (Int64)PaymentAmount != t.Amount;
|
||||
if (odd)
|
||||
bool odd = months * (Int64)PaymentAmount != t.Amount;
|
||||
|
||||
ConfigEMail smContact = Program.config.Schatzmeister;
|
||||
|
||||
FormMail fm = null;
|
||||
if (this.Status == eStatus.Deleted || this.Status == eStatus.Disabled)
|
||||
{
|
||||
Member sm = Program.members.Find(eRole.Schatzmeister);
|
||||
if (sm == null)
|
||||
Console.WriteLine("Member.ApplyMoneyTransfer(): Error - Schatzmeister account not found!");
|
||||
else
|
||||
fm = FormMail.GenerateDisabledMemberGettingPayments2SM();
|
||||
}
|
||||
else if (odd)
|
||||
{
|
||||
fm = new FormMail()
|
||||
{
|
||||
To = $"{smContact}",
|
||||
Subject = $"Schiefe Zahlung von Mitglied {Number} ({Nickname}, {t.AmountString} {t.Currency})",
|
||||
Body = "s. Betreff.\n"
|
||||
+ $"Type = {t.GetType()}\n"
|
||||
+ $"TransferAmount = {t.AmountString}\n"
|
||||
+ $"PaymentAmount = {PaymentAmountString } (monthly fee)\n"
|
||||
+ $"accountBalance = {AccountBalanceString} (new)\n"
|
||||
+ $"Next payment for this member is due at {PaymentDueMonth}\n"
|
||||
+ "\n\n--\n(automatische mail)"
|
||||
};
|
||||
}
|
||||
if (fm != null)
|
||||
{
|
||||
Console.WriteLine($"Member.ApplyMoneyTransfer(): sm={smContact}");
|
||||
|
||||
try
|
||||
{
|
||||
Console.WriteLine($"Member.ApplyMoneyTransfer(): sm={sm.Nickname}");
|
||||
FormMail fm = new FormMail()
|
||||
{
|
||||
To = $"{sm.EMailName} <{sm.EMail}>",
|
||||
Subject = $"Schiefe Zahlung von Mitglied {Number} ({Nickname}, {t.AmountString} {t.Currency})",
|
||||
Body = "s. Betreff.\n"
|
||||
+ $"Type = {t.GetType()}\n"
|
||||
+ $"TransferAmount = {t.AmountString}\n"
|
||||
+ $"PaymentAmount = {PaymentAmountString } (monthly fee)\n"
|
||||
+ $"accountBalance = {AccountBalanceString} (new)\n"
|
||||
+ $"Next payment for this member is due at {PaymentDueMonth}\n"
|
||||
+ "\n\n--\n(automatische mail)"
|
||||
};
|
||||
try
|
||||
{
|
||||
CurrentLog.SubEvents.Add(fm.Send());
|
||||
} catch(Exception ex)
|
||||
{
|
||||
CurrentLog.SubEvents.Add(new LogSubEvent() { Type = LogEvent.eEventType.Error, Topic = "Email notification error", Details = ex.Message, });
|
||||
}
|
||||
CurrentLog.SubEvents.Add(fm.Send());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
CurrentLog.SubEvents.Add(new LogSubEvent() { Type = LogEvent.eEventType.Error, Topic = "Email notification error", Details = ex.Message, });
|
||||
}
|
||||
}
|
||||
|
||||
if (paymentNotify)
|
||||
{
|
||||
FormMail notify = FormMail.GenerateMemberPaymentNotify(odd).ReplaceReflect(t);
|
||||
|
@ -310,7 +320,7 @@ namespace dezentrale.model
|
|||
}
|
||||
}
|
||||
|
||||
try { SaveToFile(false); }
|
||||
try { SaveToFile(null, false); }
|
||||
catch (Exception ex) { Console.WriteLine($"Error while saving member: {ex.Message}"); }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ namespace dezentrale.model
|
|||
{
|
||||
public class MemberImportExport
|
||||
{
|
||||
[XmlAttribute] public bool Enabled { get; set; } = false;
|
||||
[XmlElement] public string ZipFile { get; set; } = "fnord.zip";
|
||||
[XmlElement] public string ZipPassword { get; set; } = "";
|
||||
[XmlElement] public bool GpgEnabled { get; set; } = true;
|
||||
|
|
|
@ -6,7 +6,7 @@ namespace dezentrale.model
|
|||
{
|
||||
public MemberReport(bool memberList = false)
|
||||
{
|
||||
To = "{Nickname} <{EMail}>";
|
||||
To = "{EMailName} <{EMail}>";
|
||||
Subject = $"Automatic member statistics {DateTime.Now.ToString("yyyy-MM-dd")}";
|
||||
|
||||
int unGreetedMembers = 0;
|
||||
|
|
|
@ -45,8 +45,12 @@ namespace dezentrale.model
|
|||
});
|
||||
}
|
||||
}
|
||||
public void FinishLogEvent()
|
||||
public void FinishLogEvent(string comment = null)
|
||||
{
|
||||
if(CurrentLog != null && !string.IsNullOrEmpty(comment))
|
||||
{
|
||||
CurrentLog.Details = string.IsNullOrEmpty(CurrentLog.Details) ? comment : CurrentLog.Details + $"\n{comment}";
|
||||
}
|
||||
CurrentLog = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,11 +22,20 @@ namespace dezentrale.model.money
|
|||
[XmlElement] public string RecipientOrDebitor { get; set; } = "";
|
||||
[XmlElement] public string IBAN { get; set; } = "";
|
||||
[XmlElement] public string BIC { get; set; } = "";
|
||||
[XmlElement] public string Info { get; set; } = "";
|
||||
[XmlElement] public string Info { get; set; } = "";
|
||||
|
||||
//During the CSV import process, generated BankTransfer objects will hold CsvFile/Line for later
|
||||
//logging into member data / Main log (i.e. it is possible to track a MoneyTransfer from a
|
||||
//Member object to a line from a specific csv file)
|
||||
[XmlIgnore] public string CsvFile { get; set; } = null;
|
||||
[XmlIgnore] public int CsvLine { get; set; } = 0;
|
||||
|
||||
public BankTransfer() : base() { }
|
||||
public BankTransfer(List<string> csvHeadline, List<string> csvEntry) : base()
|
||||
{
|
||||
public BankTransfer(List<string> csvHeadline, List<string> csvEntry, string csvFile = "", int csvLineNumber = 0) : base()
|
||||
{
|
||||
CsvFile = csvFile;
|
||||
CsvLine = csvLineNumber;
|
||||
|
||||
int lc = csvEntry.Count;
|
||||
if (lc > csvHeadline.Count) lc = csvHeadline.Count;
|
||||
for (int i = 0; i < lc; i++)
|
||||
|
@ -58,7 +67,7 @@ namespace dezentrale.model.money
|
|||
case "Waehrung": Currency = csvEntry[i]; break;
|
||||
case "Info": Info = csvEntry[i]; break;
|
||||
default:
|
||||
throw new Exception($"invalid csv headline field: \"{csvHeadline[i]}\"");
|
||||
throw new Exception($"invalid csv headline field: \"{csvHeadline[i]}\" csvFile {csvFile} line {csvLineNumber}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace dezentrale.model.money
|
|||
{
|
||||
MembershipFee = LogEvent.eEventType.MembershipFee,
|
||||
MembershipPayment = LogEvent.eEventType.MembershipPayment,
|
||||
MembershipDonation = LogEvent.eEventType.MembershipDonation,
|
||||
Donation = LogEvent.eEventType.Donation,
|
||||
Unassigned,
|
||||
RunningCost,
|
||||
Ignored,
|
||||
|
@ -42,7 +42,8 @@ namespace dezentrale.model.money
|
|||
|
||||
public bool Equals(MoneyTransfer other) { return Equals(other, true); }
|
||||
public bool Equals(MoneyTransfer other, bool evaluateReason)
|
||||
{
|
||||
{
|
||||
#warning This doesn't respect the account ID and may lead to false positives.
|
||||
return this.ValutaDate.Equals(other.ValutaDate)
|
||||
&& (this.Amount == other.Amount)
|
||||
&& this.GetType().Equals(other.GetType())
|
||||
|
|
|
@ -157,7 +157,7 @@ namespace dezentrale.view
|
|||
|
||||
void CustomListView_MouseUp(object sender, MouseEventArgs e)
|
||||
{
|
||||
Console.WriteLine($"MouseUp(): MouseButtons={Control.MouseButtons}");
|
||||
//Console.WriteLine($"MouseUp(): MouseButtons={Control.MouseButtons}");
|
||||
if (resizeWhileMouseDown && (resizedWhileMouseDown != null))
|
||||
{
|
||||
//mono: Store new width.
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
using System;
|
||||
//using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
|
||||
|
||||
namespace dezentrale.view
|
||||
{
|
||||
public class frmCommentChanges : FormWithActionButtons
|
||||
{
|
||||
public string Comment { get; private set; } = "";
|
||||
|
||||
private TextBox tbComment;
|
||||
public frmCommentChanges(string captionEntity, string changes)
|
||||
{
|
||||
this.StartPosition = FormStartPosition.CenterParent;
|
||||
this.Size = new System.Drawing.Size(800, 600);
|
||||
this.Text = $"Comment changes to \"{captionEntity}\"";
|
||||
|
||||
|
||||
int w = this.ClientSize.Width;
|
||||
int h = this.ClientSize.Height - 35;
|
||||
this.Controls.Add(tbComment = new TextBox()
|
||||
{
|
||||
Location = new Point(groupOffset, 0 * line + tm + groupOffset),
|
||||
Size = new Size(w - 2 * groupOffset, h - 12 - tm),
|
||||
Multiline = true,
|
||||
ScrollBars = ScrollBars.Both,
|
||||
Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom,
|
||||
});
|
||||
|
||||
AddButton("Ok", btnOk_Click);
|
||||
}
|
||||
|
||||
private void btnOk_Click(object sender, EventArgs e)
|
||||
{
|
||||
Comment = tbComment.Text;
|
||||
this.Close();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -33,8 +33,13 @@ namespace dezentrale.view
|
|||
//Vorstand settings
|
||||
private TextBox tbVSName;
|
||||
private TextBox tbVSEmail;
|
||||
private TextBox tbSMName;
|
||||
private TextBox tbSMEmail;
|
||||
private TextBox tbSFName;
|
||||
private TextBox tbSFEmail;
|
||||
|
||||
//Import / Export settings
|
||||
private CheckBox cbIeEnabled;
|
||||
private TextBox tbIeZipFile;
|
||||
private TextBox tbIeZipPassword;
|
||||
private CheckBox cbIeGpgEnabled;
|
||||
|
@ -237,7 +242,7 @@ namespace dezentrale.view
|
|||
|
||||
gui.Controls.Add(new Label()
|
||||
{
|
||||
Text = "Name:",
|
||||
Text = "Vorstand:",
|
||||
Location = new Point(lm, 9 * line + tm + labelOffs),
|
||||
Size = new Size(110, labelHeight),
|
||||
TextAlign = ContentAlignment.BottomRight,
|
||||
|
@ -250,7 +255,7 @@ namespace dezentrale.view
|
|||
});
|
||||
gui.Controls.Add(new Label()
|
||||
{
|
||||
Text = "E-Mail:",
|
||||
Text = "VS-Mail:",
|
||||
Location = new Point(lm, 10 * line + tm + labelOffs),
|
||||
Size = new Size(110, labelHeight),
|
||||
TextAlign = ContentAlignment.BottomRight,
|
||||
|
@ -261,6 +266,60 @@ namespace dezentrale.view
|
|||
Width = 200,
|
||||
Anchor = AnchorStyles.Top | AnchorStyles.Left,
|
||||
});
|
||||
|
||||
gui.Controls.Add(new Label()
|
||||
{
|
||||
Text = "Schatzmeister:",
|
||||
Location = new Point(lm, 11 * line + tm + labelOffs),
|
||||
Size = new Size(110, labelHeight),
|
||||
TextAlign = ContentAlignment.BottomRight,
|
||||
});
|
||||
gui.Controls.Add(tbSMName = new TextBox()
|
||||
{
|
||||
Location = new Point(lm + 113, 11 * line + tm),
|
||||
Width = 200,
|
||||
Anchor = AnchorStyles.Top | AnchorStyles.Left,
|
||||
});
|
||||
gui.Controls.Add(new Label()
|
||||
{
|
||||
Text = "SM-Mail:",
|
||||
Location = new Point(lm, 12 * line + tm + labelOffs),
|
||||
Size = new Size(110, labelHeight),
|
||||
TextAlign = ContentAlignment.BottomRight,
|
||||
});
|
||||
gui.Controls.Add(tbSMEmail = new TextBox()
|
||||
{
|
||||
Location = new Point(lm + 113, 12 * line + tm),
|
||||
Width = 200,
|
||||
Anchor = AnchorStyles.Top | AnchorStyles.Left,
|
||||
});
|
||||
|
||||
gui.Controls.Add(new Label()
|
||||
{
|
||||
Text = "Schriftfuehrer:",
|
||||
Location = new Point(lm, 13 * line + tm + labelOffs),
|
||||
Size = new Size(110, labelHeight),
|
||||
TextAlign = ContentAlignment.BottomRight,
|
||||
});
|
||||
gui.Controls.Add(tbSFName = new TextBox()
|
||||
{
|
||||
Location = new Point(lm + 113, 13 * line + tm),
|
||||
Width = 200,
|
||||
Anchor = AnchorStyles.Top | AnchorStyles.Left,
|
||||
});
|
||||
gui.Controls.Add(new Label()
|
||||
{
|
||||
Text = "SF-Mail:",
|
||||
Location = new Point(lm, 14 * line + tm + labelOffs),
|
||||
Size = new Size(110, labelHeight),
|
||||
TextAlign = ContentAlignment.BottomRight,
|
||||
});
|
||||
gui.Controls.Add(tbSFEmail = new TextBox()
|
||||
{
|
||||
Location = new Point(lm + 113, 14 * line + tm),
|
||||
Width = 200,
|
||||
Anchor = AnchorStyles.Top | AnchorStyles.Left,
|
||||
});
|
||||
|
||||
cbSmtpEnabled.Checked = Program.config.Smtp.Enabled;
|
||||
tbSmtpHost.Text = Program.config.Smtp.Host;
|
||||
|
@ -271,8 +330,12 @@ namespace dezentrale.view
|
|||
tbSmtpPassword.Text = Program.config.Smtp.Password;
|
||||
tbSmtpCcTo.Text = Program.config.Smtp.CcTo;
|
||||
|
||||
tbVSName.Text = Program.config.VS.VSName;
|
||||
tbVSEmail.Text = Program.config.VS.VSEmail;
|
||||
tbVSName.Text = Program.config.VS.EMailName;
|
||||
tbVSEmail.Text = Program.config.VS.EMail;
|
||||
tbSMName.Text = Program.config.Schatzmeister.EMailName;
|
||||
tbSMEmail.Text = Program.config.Schatzmeister.EMail;
|
||||
tbSFName.Text = Program.config.Schriftfuehrer.EMailName;
|
||||
tbSFEmail.Text = Program.config.Schriftfuehrer.EMail;
|
||||
return gui;
|
||||
}
|
||||
public TabPage BuildMoneyTransfersGui()
|
||||
|
@ -286,16 +349,24 @@ namespace dezentrale.view
|
|||
{
|
||||
TabPage gui = new TabPage("Import / Export");
|
||||
|
||||
|
||||
gui.Controls.Add(cbIeEnabled = new CheckBox()
|
||||
{
|
||||
Text = "Enable Import/Export with the settings below",
|
||||
Location = new Point(lm + 113, 0 * line + tm),
|
||||
Width = 400,
|
||||
});
|
||||
|
||||
gui.Controls.Add(new Label()
|
||||
{
|
||||
Text = "Zip filename:",
|
||||
Location = new Point(lm, 0 * line + tm + labelOffs),
|
||||
Location = new Point(lm, 1 * line + tm + labelOffs),
|
||||
Size = new Size(110, labelHeight),
|
||||
TextAlign = ContentAlignment.BottomRight,
|
||||
});
|
||||
gui.Controls.Add(tbIeZipFile = new TextBox()
|
||||
{
|
||||
Location = new Point(lm + 113, 0 * line + tm),
|
||||
Location = new Point(lm + 113, 1 * line + tm),
|
||||
Width = 200,
|
||||
Anchor = AnchorStyles.Top | AnchorStyles.Left,
|
||||
});
|
||||
|
@ -303,14 +374,14 @@ namespace dezentrale.view
|
|||
gui.Controls.Add(new Label()
|
||||
{
|
||||
Text = "Zip password:",
|
||||
Location = new Point(lm, 1 * line + tm + labelOffs),
|
||||
Location = new Point(lm, 2 * line + tm + labelOffs),
|
||||
Size = new Size(110, labelHeight),
|
||||
TextAlign = ContentAlignment.BottomRight,
|
||||
});
|
||||
gui.Controls.Add(tbIeZipPassword = new TextBox()
|
||||
{
|
||||
PasswordChar = '*',
|
||||
Location = new Point(lm + 113, 1 * line + tm),
|
||||
Location = new Point(lm + 113, 2 * line + tm),
|
||||
Width = 200,
|
||||
Anchor = AnchorStyles.Top | AnchorStyles.Left,
|
||||
});
|
||||
|
@ -318,20 +389,20 @@ namespace dezentrale.view
|
|||
gui.Controls.Add(cbIeGpgEnabled = new CheckBox()
|
||||
{
|
||||
Text = "Enable file encryption with GPG (AES + password)",
|
||||
Location = new Point(lm + 113, 2 * line + tm),
|
||||
Location = new Point(lm + 113, 3 * line + tm),
|
||||
Width = 400,
|
||||
});
|
||||
|
||||
gui.Controls.Add(new Label()
|
||||
{
|
||||
Text = "Gpg filename:",
|
||||
Location = new Point(lm, 3 * line + tm + labelOffs),
|
||||
Location = new Point(lm, 4 * line + tm + labelOffs),
|
||||
Size = new Size(110, labelHeight),
|
||||
TextAlign = ContentAlignment.BottomRight,
|
||||
});
|
||||
gui.Controls.Add(tbIeGpgFile = new TextBox()
|
||||
{
|
||||
Location = new Point(lm + 113, 3 * line + tm),
|
||||
Location = new Point(lm + 113, 4 * line + tm),
|
||||
Width = 200,
|
||||
Anchor = AnchorStyles.Top | AnchorStyles.Left,
|
||||
});
|
||||
|
@ -339,48 +410,33 @@ namespace dezentrale.view
|
|||
gui.Controls.Add(new Label()
|
||||
{
|
||||
Text = "Gpg password:",
|
||||
Location = new Point(lm, 4 * line + tm + labelOffs),
|
||||
Location = new Point(lm, 5 * line + tm + labelOffs),
|
||||
Size = new Size(110, labelHeight),
|
||||
TextAlign = ContentAlignment.BottomRight,
|
||||
});
|
||||
gui.Controls.Add(tbIeGpgPassword = new TextBox()
|
||||
{
|
||||
PasswordChar = '*',
|
||||
Location = new Point(lm + 113, 4 * line + tm),
|
||||
Location = new Point(lm + 113, 5 * line + tm),
|
||||
Width = 200,
|
||||
Anchor = AnchorStyles.Top | AnchorStyles.Left,
|
||||
});
|
||||
gui.Controls.Add(cbIeHgEnabled = new CheckBox()
|
||||
{
|
||||
Text = "Enable data synchronisation over mercurial",
|
||||
Location = new Point(lm + 113, 5 * line + tm),
|
||||
Location = new Point(lm + 113, 6 * line + tm),
|
||||
Width = 400,
|
||||
});
|
||||
|
||||
gui.Controls.Add(new Label()
|
||||
{
|
||||
Text = "HG UserName:",
|
||||
Location = new Point(lm, 6 * line + tm + labelOffs),
|
||||
Location = new Point(lm, 7 * line + tm + labelOffs),
|
||||
Size = new Size(110, labelHeight),
|
||||
TextAlign = ContentAlignment.BottomRight,
|
||||
});
|
||||
gui.Controls.Add(tbIeHgUserName = new TextBox()
|
||||
{
|
||||
Location = new Point(lm + 113, 6 * line + tm),
|
||||
Width = 200,
|
||||
Anchor = AnchorStyles.Top | AnchorStyles.Left,
|
||||
});
|
||||
|
||||
gui.Controls.Add(new Label()
|
||||
{
|
||||
Text = "HG password:",
|
||||
Location = new Point(lm, 7 * line + tm + labelOffs),
|
||||
Size = new Size(110, labelHeight),
|
||||
TextAlign = ContentAlignment.BottomRight,
|
||||
});
|
||||
gui.Controls.Add(tbIeHgPassword = new TextBox()
|
||||
{
|
||||
PasswordChar = '*',
|
||||
Location = new Point(lm + 113, 7 * line + tm),
|
||||
Width = 200,
|
||||
Anchor = AnchorStyles.Top | AnchorStyles.Left,
|
||||
|
@ -388,18 +444,34 @@ namespace dezentrale.view
|
|||
|
||||
gui.Controls.Add(new Label()
|
||||
{
|
||||
Text = "HG URL:",
|
||||
Text = "HG password:",
|
||||
Location = new Point(lm, 8 * line + tm + labelOffs),
|
||||
Size = new Size(110, labelHeight),
|
||||
TextAlign = ContentAlignment.BottomRight,
|
||||
});
|
||||
gui.Controls.Add(tbIeHgPassword = new TextBox()
|
||||
{
|
||||
PasswordChar = '*',
|
||||
Location = new Point(lm + 113, 8 * line + tm),
|
||||
Width = 200,
|
||||
Anchor = AnchorStyles.Top | AnchorStyles.Left,
|
||||
});
|
||||
|
||||
gui.Controls.Add(new Label()
|
||||
{
|
||||
Text = "HG URL:",
|
||||
Location = new Point(lm, 9 * line + tm + labelOffs),
|
||||
Size = new Size(110, labelHeight),
|
||||
TextAlign = ContentAlignment.BottomRight,
|
||||
});
|
||||
gui.Controls.Add(tbIeHgURL = new TextBox()
|
||||
{
|
||||
Location = new Point(lm + 113, 8 * line + tm),
|
||||
Location = new Point(lm + 113, 9 * line + tm),
|
||||
Width = 400,
|
||||
Anchor = AnchorStyles.Top | AnchorStyles.Left,
|
||||
});
|
||||
|
||||
cbIeEnabled.Checked = Program.config.ImportExport.Enabled;
|
||||
tbIeZipFile.Text = Program.config.ImportExport.ZipFile;
|
||||
tbIeZipPassword.Text = Program.config.ImportExport.ZipPassword;
|
||||
cbIeGpgEnabled.Checked = Program.config.ImportExport.GpgEnabled;
|
||||
|
@ -472,12 +544,17 @@ namespace dezentrale.view
|
|||
Program.config.Smtp.Password = tbSmtpPassword.Text;
|
||||
Program.config.Smtp.CcTo = tbSmtpCcTo.Text;
|
||||
|
||||
Program.config.VS.VSName = tbVSName.Text;
|
||||
Program.config.VS.VSEmail = tbVSEmail.Text;
|
||||
Program.config.VS.EMailName = tbVSName.Text;
|
||||
Program.config.VS.EMail = tbVSEmail.Text;
|
||||
Program.config.Schatzmeister.EMailName = tbSMName.Text;
|
||||
Program.config.Schatzmeister.EMail = tbSMEmail.Text;
|
||||
Program.config.Schriftfuehrer.EMailName = tbSFName.Text;
|
||||
Program.config.Schriftfuehrer.EMail = tbSFEmail.Text;
|
||||
|
||||
//use MoneyTransferList for that, not Program.config
|
||||
//[XmlElement] public List<KeyValue> MoneyTransferRegEx { get; set; } = new List<KeyValue>();
|
||||
//use MoneyTransferList for that, not Program.config
|
||||
//[XmlElement] public List<KeyValue> MoneyTransferRegEx { get; set; } = new List<KeyValue>();
|
||||
|
||||
Program.config.ImportExport.Enabled = cbIeEnabled.Checked;
|
||||
Program.config.ImportExport.ZipFile = tbIeZipFile.Text;
|
||||
Program.config.ImportExport.ZipPassword = tbIeZipPassword.Text;
|
||||
Program.config.ImportExport.GpgEnabled = cbIeGpgEnabled.Checked;
|
||||
|
|
|
@ -388,7 +388,7 @@ namespace dezentrale.view
|
|||
Width = 100,
|
||||
Anchor = AnchorStyles.Top | AnchorStyles.Left,
|
||||
TextAlign = HorizontalAlignment.Right,
|
||||
ReadOnly = true,
|
||||
//ReadOnly = true,
|
||||
});
|
||||
parent.Controls.Add(new Label()
|
||||
{
|
||||
|
@ -695,9 +695,17 @@ namespace dezentrale.view
|
|||
member.BankTransferRegEx = tbBankTransferRegEx.Text;
|
||||
member.Remarks = tbRemarks.Text;
|
||||
|
||||
member.FinishLogEvent();
|
||||
//member.FinishLogEvent(); //implicit in SaveToFile()
|
||||
this.DialogResult = DialogResult.OK;
|
||||
member.SaveToFile();
|
||||
|
||||
string comment = null;
|
||||
if (!newMember)
|
||||
{
|
||||
frmCommentChanges commentChanges = new frmCommentChanges($"{member.Number:D3} ({ member.Nickname})", "");
|
||||
commentChanges.ShowDialog();
|
||||
comment = commentChanges.Comment;
|
||||
}
|
||||
member.SaveToFile(comment);
|
||||
|
||||
this.Close();
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ namespace dezentrale.view
|
|||
private LVMoneyTransfers mtv;
|
||||
private LvMv lstMv;
|
||||
|
||||
private MenuItem mnuFileExport, mnuFileImport;
|
||||
private void BuildMoneyTransfers(Control parent)
|
||||
{
|
||||
parent.Controls.Add(mtv = new LVMoneyTransfers() { Dock = DockStyle.Fill, });
|
||||
|
@ -31,7 +32,7 @@ namespace dezentrale.view
|
|||
this.Size = new Size(640, 480);
|
||||
this.FormClosing += (sender, e) =>
|
||||
{
|
||||
if(!enforceClosing && Program.config.DbChangedSinceExport)
|
||||
if(!enforceClosing && Program.config.DbChangedSinceExport && Program.config.ImportExport.Enabled)
|
||||
{
|
||||
DialogResult dr =
|
||||
MessageBox.Show("Database changed since last export.\r\n\r\n"
|
||||
|
@ -51,8 +52,8 @@ namespace dezentrale.view
|
|||
{ MenuItems = {
|
||||
new MenuItem("&Configuration...", mnuMain_File_Configuration) { Enabled = true },
|
||||
new MenuItem("-"),
|
||||
new MenuItem("&Export database", mnuMain_File_Export),
|
||||
new MenuItem("&Import database", mnuMain_File_Import),
|
||||
(mnuFileExport = new MenuItem("&Export database", mnuMain_File_Export)),
|
||||
(mnuFileImport = new MenuItem("&Import database", mnuMain_File_Import)),
|
||||
new MenuItem("-"),
|
||||
new MenuItem("&Quit", mnuMain_File_Quit),
|
||||
} },
|
||||
|
@ -88,6 +89,8 @@ namespace dezentrale.view
|
|||
}
|
||||
};
|
||||
|
||||
mnuFileImport.Enabled = mnuFileExport.Enabled = Program.config.ImportExport.Enabled;
|
||||
|
||||
TabPage tabMembers = new TabPage("Members");
|
||||
|
||||
tabMembers.Controls.Add(lstMembers = new LVMembers() { Dock = DockStyle.Fill });
|
||||
|
@ -129,32 +132,35 @@ namespace dezentrale.view
|
|||
lstMv.LoadFromList(Program.mvList.Entries);
|
||||
|
||||
//Check for needed import
|
||||
DateTime now = DateTime.Now;
|
||||
int totalHours = (int) now.Subtract(Program.config.LastDbImport).TotalHours;
|
||||
int totalDays = totalHours / 24;
|
||||
if (totalHours >= 8)
|
||||
if (Program.config.ImportExport.Enabled)
|
||||
{
|
||||
totalHours %= 24;
|
||||
string timeSpan = $"{totalDays} d, {totalHours} h";
|
||||
|
||||
if (Program.config.DbChangedSinceExport)
|
||||
DateTime now = DateTime.Now;
|
||||
int totalHours = (int) now.Subtract(Program.config.LastDbImport).TotalHours;
|
||||
int totalDays = totalHours / 24;
|
||||
if (totalHours >= 8)
|
||||
{
|
||||
MessageBox.Show( "Warning: There are local changes to DB since last export!\r\n"
|
||||
+ "Please check if there are changes on the server side and then\r\n"
|
||||
+ "- perform a manual backup-import-merge\r\n"
|
||||
+ "- or simply an export if there are no changes.\r\n\r\n"
|
||||
+ $"Last import was: {Program.config.LastDbImport}\r\n"
|
||||
+ $"Last export was: {Program.config.LastDbExport}\r\n"
|
||||
+ $"Last db change was {Program.config.LastDbLocalChange}\r\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (totalDays > 365) timeSpan = "too long";
|
||||
DialogResult dr = MessageBox.Show($"Last Db import was {timeSpan} ago.\r\nImport now?", "Import database", MessageBoxButtons.YesNo);
|
||||
if (dr == DialogResult.Yes)
|
||||
totalHours %= 24;
|
||||
string timeSpan = $"{totalDays} d, {totalHours} h";
|
||||
|
||||
if (Program.config.DbChangedSinceExport)
|
||||
{
|
||||
mnuMain_File_Import(null, null);
|
||||
MessageBox.Show( "Warning: There are local changes to DB since last export!\r\n"
|
||||
+ "Please check if there are changes on the server side and then\r\n"
|
||||
+ "- perform a manual backup-import-merge\r\n"
|
||||
+ "- or simply an export if there are no changes.\r\n\r\n"
|
||||
+ $"Last import was: {Program.config.LastDbImport}\r\n"
|
||||
+ $"Last export was: {Program.config.LastDbExport}\r\n"
|
||||
+ $"Last db change was {Program.config.LastDbLocalChange}\r\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (totalDays > 365) timeSpan = "too long";
|
||||
DialogResult dr = MessageBox.Show($"Last Db import was {timeSpan} ago.\r\nImport now?", "Import database", MessageBoxButtons.YesNo);
|
||||
if (dr == DialogResult.Yes)
|
||||
{
|
||||
mnuMain_File_Import(null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -165,8 +171,11 @@ namespace dezentrale.view
|
|||
frmConfig.ShowDialog();
|
||||
if (frmConfig.DialogResult == DialogResult.OK)
|
||||
{
|
||||
frmConfig.FillAndSaveConfig();
|
||||
if(frmConfig.KeylockCombiChanged && Program.config.Smtp.Enabled)
|
||||
frmConfig.FillAndSaveConfig();
|
||||
|
||||
mnuFileImport.Enabled = mnuFileExport.Enabled = Program.config.ImportExport.Enabled;
|
||||
|
||||
if (frmConfig.KeylockCombiChanged && Program.config.Smtp.Enabled)
|
||||
{
|
||||
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)
|
||||
|
@ -454,7 +463,19 @@ namespace dezentrale.view
|
|||
DialogResult dr = ofd.ShowDialog();
|
||||
//ofd.FilterIndex
|
||||
if (dr == DialogResult.OK)
|
||||
{
|
||||
lstMembers.SuspendLayout();
|
||||
ProcessCsv.ProcessCSV(ofd.FileName);
|
||||
foreach (Member m in Program.members.Entries) lstMembers.UpdateEntry(m);
|
||||
|
||||
if (Program.MoneyTransfersLoaded)
|
||||
{
|
||||
//This will enforce reloading the moneytransfer list
|
||||
Program.MoneyTransfersLoaded = false;
|
||||
mtv.LoadFromList(Program.MoneyTransfers.Entries);
|
||||
}
|
||||
lstMembers.ResumeLayout(false);
|
||||
}
|
||||
}
|
||||
private void mnuMain_Payments_Receipts(object sender, EventArgs e)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue