dmdb/view/frmMain.cs

646 lines
28 KiB
C#

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using dezentrale.core;
using dezentrale.model;
using dezentrale.model.money;
namespace dezentrale.view
{
public class frmMain : Form
{
private LVMembers lstMembers;
private LVMoneyTransfers mtv;
private LvMv lstMv;
private MenuItem mnuFileExport, mnuFileImport;
private void BuildMoneyTransfers(Control parent)
{
parent.Controls.Add(mtv = new LVMoneyTransfers() { Dock = DockStyle.Fill, });
if (Program.MoneyTransfersLoaded) mtv.LoadFromList(Program.MoneyTransfers.Entries);
else mtv.LoadRequest += (sender, e) => { e.Transfers = Program.MoneyTransfers.Entries; };
}
private bool enforceClosing = false;
public frmMain()
{
this.SuspendLayout();
this.Text = $"dezentrale-members Version {Program.VersionString}";
this.StartPosition = FormStartPosition.CenterScreen;
this.Size = new Size(640, 480);
this.FormClosing += (sender, e) =>
{
if(!enforceClosing && Program.config.DbChangedSinceExport && Program.config.ImportExport.Enabled)
{
DialogResult dr =
MessageBox.Show("Database changed since last export.\r\n\r\n"
+$"Last Export: {Program.config.LastDbExport}\r\n"
+$"Last Change: {Program.config.LastDbLocalChange}\r\n\r\n"
+"Really quit without exporting?",
"Quit witout export?", MessageBoxButtons.YesNo);
if(dr == DialogResult.No)
e.Cancel = true;
}
};
this.Menu = new MainMenu()
{
MenuItems =
{
new MenuItem("File")
{ MenuItems = {
new MenuItem("&Configuration...", mnuMain_File_Configuration) { Enabled = true },
new MenuItem("-"),
(mnuFileExport = new MenuItem("&Export database", mnuMain_File_Export)),
(mnuFileImport = new MenuItem("&Import database", mnuMain_File_Import)),
new MenuItem("-"),
new MenuItem("&Quit", mnuMain_File_Quit),
} },
new MenuItem("Members")
{ MenuItems = {
new MenuItem("&Add new member", mnuMain_Members_Add),
new MenuItem("&Cronjob all", lstMembers_CronjobAll),
new MenuItem("-"),
#if DEBUG
new MenuItem("Generate &Testdata", mnuMain_Members_Generate_Testdata),
new MenuItem("-"),
#endif
new MenuItem("Show numeric &info", lstMembers_mnuMain_Members_ShowInfo),
new MenuItem("Export &CSV (selected)", lstMembers_mnuMain_Members_CSV_selected),
new MenuItem("Export &CSV (all)", lstMembers_mnuMain_Members_CSV_all),
} },
new MenuItem("MV")
{ MenuItems = {
new MenuItem("&New MV...", lstMv_New), //Todo: Do we even need this here?
new MenuItem("&Edit selected MV...", lstMv_Edit), //Todo: Do we even need this here?
new MenuItem("&Cancel/Remove selected MV...", lstMv_CancelSelected), //Todo: Do we even need this here?
} },
new MenuItem("Payments")
{ MenuItems = {
new MenuItem("&Add new MoneyTransfer", mnuMain_Payments_Add) { Enabled = true },
new MenuItem("Process CSV...", mnuMain_Payments_ProcessCSV),
new MenuItem("Generate payment receipts...", mnuMain_Payments_Receipts),
} },
new MenuItem("Help")
{ MenuItems = {
new MenuItem("&About", mnuMain_Help_About),
} }
}
};
mnuFileImport.Enabled = mnuFileExport.Enabled = Program.config.ImportExport.Enabled;
TabPage tabMembers = new TabPage("Members");
tabMembers.Controls.Add(lstMembers = new LVMembers() { Dock = DockStyle.Fill });
//lstMembers.AddMenuItem("Add new member", lstMembers_Add);
lstMembers.AddMenuItem("Edit selected member", lstMembers_Edit);
lstMembers.AddMenuItem("Delete selected member", lstMembers_Delete);
lstMembers.AddMenuItem("Add cash payment to member", lstMembers_AddCashTransfer);
lstMembers.AddMenuItem("-", null);
lstMembers.AddMenuItem("Cronjob selected member", lstMembers_CronjobSelected);
//lstMembers.AddMenuItem("Cronjob checked ones", lstMembers_CronjobChecked);
lstMembers.AddMenuItem("Cronjob all", lstMembers_CronjobAll);
lstMembers.AddMenuItem("-", null);
lstMembers.AddMenuItem("Send test mail to member", lstMembers_TestMail);
lstMembers.AddMenuItem("Send account status mail to member", lstMembers_AccountStatusMail);
//TBD: "Selected users missed an MV"
//lstMembers.AddMenuItem("Main Settings", null);
lstMembers.DoubleClick += lstMembers_Edit;
TabPage tabMvList = new TabPage("MvList");
tabMvList.Controls.Add(lstMv = new LvMv() { Dock = DockStyle.Fill, });
lstMv.AddMenuItem("New MV...", lstMv_New);
lstMv.AddMenuItem("Edit selected MV", lstMv_Edit);
lstMv.AddMenuItem("Cancel/Remove selected MV...", lstMv_CancelSelected);
TabPage tabMoneyTransfers = new TabPage("MoneyTransfers");
BuildMoneyTransfers(tabMoneyTransfers);
this.Controls.Add(new TabControl()
{
Dock = DockStyle.Fill,
TabPages = { tabMembers, tabMvList, tabMoneyTransfers },
});
this.ResumeLayout(false);
//Fill list with data from members
lstMembers.LoadFromList(Program.members.Entries);
//Fill mv list with data from mv
lstMv.LoadFromList(Program.mvList.Entries);
//Check for needed import
if (Program.config.ImportExport.Enabled)
{
DateTime now = DateTime.Now;
int totalHours = (int) now.Subtract(Program.config.LastDbImport).TotalHours;
int totalDays = totalHours / 24;
if (totalHours >= 8)
{
totalHours %= 24;
string timeSpan = $"{totalDays} d, {totalHours} h";
if (Program.config.DbChangedSinceExport)
{
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);
}
}
}
}
}
private void mnuMain_File_Configuration(object sender, EventArgs e)
{
frmConfiguration frmConfig = new frmConfiguration();
frmConfig.ShowDialog();
if (frmConfig.DialogResult == DialogResult.OK)
{
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)
{
FormMail keylockChanged = FormMail.GenerateKeylockChanged().ReplaceReflect(Program.config);
foreach (Member m in Program.members.Entries)
{
if (m.Status != Member.eStatus.Active) continue;
m.StartLogEvent("New keylock code", LogEvent.eEventType.EMail);
m.CurrentLog.SubEvents.Add(keylockChanged.Send(m));
m.SaveToFile();
}
}
}
}
}
private void mnuMain_File_Export(object sender, EventArgs e)
{
if(!Program.config.DbChangedSinceExport)
{
DialogResult dr = MessageBox.Show( "There were no changes to the local DB, exporting may not be necessary.\r\n"
+ "Really proceed with export?", "Database export", MessageBoxButtons.YesNo);
if (dr == DialogResult.No) return;
}
ExportProcess export = new ExportProcess()
{
ImportExportSettings = Program.config.ImportExport,
MemberDir = Program.config.DbDirectory,
OutputDir = Program.DmDirectory,
};
frmProcessWithLog frmExport = new frmProcessWithLog(export, false);
frmExport.ShowDialog();
}
private void mnuMain_File_Import(object sender, EventArgs e)
{
DialogResult dr;
if (Program.config.DbChangedSinceExport)
dr = MessageBox.Show( "There were changes to the local DB which WILL BE LOST on import!\r\n"
+ $"Last export: {Program.config.LastDbExport}\r\n"
+ $"Last change: {Program.config.LastDbLocalChange}\r\n"
+ "Really proceed with import?", "Overwrite local version of the database?", MessageBoxButtons.YesNo);
else
dr = MessageBox.Show("Warning\nImporting database from external source will overwrite all\nlocal changes! Really import?", "Overwrite local version of the database?", MessageBoxButtons.YesNo);
if(dr == DialogResult.Yes)
{
ImportProcess import = new ImportProcess()
{
ImportExportSettings = Program.config.ImportExport,
MemberDir = Program.config.DbDirectory,
InputDir = Program.DmDirectory,
};
frmProcessWithLog frmImport = new frmProcessWithLog(import, true);
dr = frmImport.ShowDialog();
if (dr == DialogResult.Yes)
{
if (Program.LoadFiles() != 0)
{
MessageBox.Show("Error while loading imported files.\nProgram will close now.");
this.Close();
}
lstMembers.LoadFromList(Program.members.Entries);
lstMv.LoadFromList(Program.mvList.Entries);
mtv.ClearList();
}
}
}
private void mnuMain_File_Quit(object sender, EventArgs e)
{
this.Close();
}
private void mnuMain_Members_Add(object sender, EventArgs e)
{
Member m = Program.members.CreateMember(false);
frmEditEntry edit = new frmEditEntry(m, true);
edit.ShowDialog();
if (edit.DialogResult == DialogResult.OK)
{
//the edit window already updated the data in the member object
//but it is not added to the data list yet.
Program.members.Entries.Add(m);
List<Member> toSave = new List<Member>() { m };
MemberList.SaveToFiles(toSave);
lstMembers.AddEntry(m);
}
}
private void lstMv_New(object sender, EventArgs e)
{
DialogResult res = MessageBox.Show("This will create a new MV and store it in MV list.\n", "Create new MV?", MessageBoxButtons.YesNo);
if (res == DialogResult.Yes)
{
frmMv newMv = new frmMv();
Program.mvList.Entries.Add(newMv.mv);
Program.mvList.SaveToFile();
newMv.ShowDialog();
Program.mvList.SaveToFile();
lstMv.AddEntry(newMv.mv);
}
}
private void lstMv_Edit(object sender, EventArgs e)
{
Mv mv = lstMv.GetFirstSelectedItem();
if (mv == null)
{
MessageBox.Show("No MV entry selected");
} else
{
frmMv editMv = new frmMv(mv);
editMv.ShowDialog();
Program.mvList.SaveToFile();
lstMv.UpdateEntry(editMv.mv);
}
//if(newMv.DialogResult == DialogResult.OK)
//lstMv.AddEntry(newMv.GetMv());
//This process runs in two steps: First, the GUI will ask the user about all details,
//Second, there will be a @ref BackgroundProcess launched that prepares and sends the e-mails.
/* frmMvInvitation mvInvitation = new frmMvInvitation();
DialogResult dr = mvInvitation.ShowDialog();
if (dr == DialogResult.Cancel) return;
{
//prepare member list
List<Member> lm;
switch(mvInvitation.InvitationGroup)
{
case MvInvitationGroup.AllActiveMembers:
lm = new List<Member>();
foreach (Member m in Program.members.Entries)
if (m.Status == Member.eStatus.Active) lm.Add(m);
break;
case MvInvitationGroup.AllMembers:
lm = Program.members.Entries;
break;
case MvInvitationGroup.AllSelectedFromMainWindow:
lm = lstMembers.GetSelectedItems();
break;
default:
MessageBox.Show($"Invalid MvInvitationGroup selected (mvInvitation.InvitationGroup)");
return;
}
MvInvitationProcess inv = new MvInvitationProcess(mvInvitation, lm);
frmProcessWithLog frmInv = new frmProcessWithLog(inv, true);
dr = frmInv.ShowDialog();
}
*/
}
private void lstMv_CancelSelected(object sender, EventArgs e)
{
Mv mv = lstMv.GetFirstSelectedItem();
if (mv == null)
{
MessageBox.Show("No MV entry selected");
} else if(mv.Status == Mv.MvStatus.Cancelled)
{
MessageBox.Show("MV is already cancelled");
} else if(mv.Status == Mv.MvStatus.Ended)
{
MessageBox.Show("MV is finished and cannot be cancelled.");
} else
{
DialogResult res;
if (mv.Status == Mv.MvStatus.InPreparation)
{
res = MessageBox.Show("MV is in preparation state, do you also want to delete it completely?", "Also delete MV?", MessageBoxButtons.YesNoCancel);
} else
{
res = MessageBox.Show("Do you really want to cancel this MV?", "Cancel MV?", MessageBoxButtons.OKCancel);
}
switch(res)
{
case DialogResult.Yes: //Delete MV
//mv.Status = Mv.MvStatus.InPreparation
lstMv.RemoveEntry(mv);
Program.mvList.Entries.Remove(mv);
Program.mvList.SaveToFile();
break;
case DialogResult.No: //Set status to Cancelled
case DialogResult.OK:
//Send cancellation mails?
if (mv.Status != Mv.MvStatus.InPreparation)
{
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);
foreach (MvInvitedMember mvi in mv.Members)
{
if (!mvi.Invited) continue;
mvi.Member.StartLogEvent("MV cancelled", LogEvent.eEventType.EMail);
mvi.Member.CurrentLog.SubEvents.Add(fm.Send(mvi.Member));
mvi.Member.SaveToFile();
}
}
}
mv.Status = Mv.MvStatus.Cancelled;
lstMv.UpdateEntry(mv);
Program.mvList.SaveToFile();
break;
default:
case DialogResult.Cancel: //Do nothing
break;
}
}
}
#if DEBUG
private void mnuMain_Members_Generate_Testdata(object sender, EventArgs e)
{
if (Program.members.Entries.Count > 0)
{
DialogResult dr = MessageBox.Show(this, $"Generating testdata will overwrite the current member list.\nUse this on a test system only!\n Really overwrite current member list?", "Really overwrite list?", MessageBoxButtons.YesNo);
if (dr == DialogResult.No) return;
}
Program.members.GenerateTestData();
lstMembers.LoadFromList(Program.members.Entries);
}
#endif
private void lstMembers_mnuMain_Members_ShowInfo(object sender, EventArgs e)
{
MessageBox.Show(new MemberReport().Body);
}
private void MemberCsvExport(List<Member> list)
{
frmExportCsv<Member> frmCsv = new frmExportCsv<Member>(list)
{
SelectedProperties = Program.config.MemberCsvExportFields,
};
frmCsv.ShowDialog();
Program.config.MemberCsvExportFields = frmCsv.SelectedProperties;
XmlData.SaveToFile(Program.ConfigFile, Program.config);
}
private void lstMembers_mnuMain_Members_CSV_selected(object sender, EventArgs e)
{
MemberCsvExport(lstMembers.GetSelectedItems());
}
private void lstMembers_mnuMain_Members_CSV_all(object sender, EventArgs e)
{
MemberCsvExport(Program.members.Entries);
}
private void mnuMain_Payments_Add(object sender, EventArgs e)
{
frmMoneyTransfer addMoney = new frmMoneyTransfer();
addMoney.ShowDialog();
DialogResult dr = addMoney.DialogResult;
if (dr == DialogResult.OK)
{
try
{
MoneyTransfer mt = addMoney.FillMoneyTransfer();
if (mt.MemberNumber != 0)
{
Member m = Program.members.Find(mt.MemberNumber);
m.ApplyMoneyTransfer(mt);
mt.AssignFixed = true;
//m.SaveToFile(); //automaticly saved in ApplyMoneyTransfer()
}
Program.MoneyTransfers.AddEntry(mt);
Program.MoneyTransfers.SaveToFile();
} catch(Exception ex)
{
MessageBox.Show($"Error while storing MoneyTransfer: {ex.Message}");
}
}
}
private void mnuMain_Payments_ProcessCSV(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog()
{
Filter = "Spaßkasse-CSV-Dateien (*.csv)|*.csv;*.CSV|Alle Dateien (*.*)|*.*",
};
DialogResult dr = ofd.ShowDialog();
//ofd.FilterIndex
if (dr == DialogResult.OK)
{
lstMembers.SuspendLayout();
CsvImportProcess csvImport = new CsvImportProcess()
{
FileName = ofd.FileName,
};
frmProcessWithLog frmCsvImport = new frmProcessWithLog(csvImport, true);
dr = frmCsvImport.ShowDialog();
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)
{
int year = DateTime.Now.Year - 1;
List<Member> sel = lstMembers.GetSelectedItems();
frmPaymentReceipts receipts = new frmPaymentReceipts()
{
//Defaults that will be edited by the user
MemberList = (sel != null && sel.Count > 0) ? sel : null,
DataTemplate = "dezentrale-beitragsquittung-template.svg",
DataFormat = IntermediateFormat.SvgInkscape092,
StartDate = new DateTime(year, 01, 01),
EndDate = new DateTime(year, 12, 31),
FileNamePattern = "Member{MemberNumber}-{ValutaDateString}-{AmountString}{Currency}",
OutputDirectory=".",
SendEmail = false
};
DialogResult dr = receipts.ShowDialog();
if(dr == DialogResult.OK)
{
PaymentReceiptProcess rec = new PaymentReceiptProcess(receipts);
frmProcessWithLog frmRec = new frmProcessWithLog(rec, true);
dr = frmRec.ShowDialog();
}
}
private void mnuMain_Help_About(object sender, EventArgs e)
{
MessageBox.Show("mnuMain_Help_About");
}
private void CronjobMember(Member m)
{
if (m != null)
{
Cronjob.Run(m);
lstMembers.UpdateEntry(m);
}
}
private void lstMembers_CronjobSelected(object sender, EventArgs e)
{
Member m = lstMembers.GetFirstSelectedItem();
CronjobMember(m);
}
private void lstMembers_CronjobChecked(object sender, EventArgs e)
{
lstMembers.SuspendLayout();
foreach (Member m in lstMembers.GetCheckedItems()) CronjobMember(m);
lstMembers.ResumeLayout(false);
}
private void lstMembers_CronjobAll(object sender, EventArgs e)
{
lstMembers.SuspendLayout();
//foreach (Member m in Program.members.Entries) CronjobMember(m);
Cronjob.Run();
foreach (Member m in Program.members.Entries) lstMembers.UpdateEntry(m);
lstMembers.ResumeLayout(false);
}
private bool SendMail(FormMail mail, Member m)
{
try
{
if (m == null) return true;
mail.Send(m);
} catch(Exception ex)
{
string msg = ex.Message;
while (ex.InnerException != null)
{
ex = ex.InnerException;
msg += "\r\n" + ex.Message;
}
MessageBox.Show($"Cannot send mail:\r\n{msg}");
}
return true;
}
private void lstMembers_TestMail(object sender, EventArgs e)
{
Member m = lstMembers.GetFirstSelectedItem();
FormMail testMail = FormMail.GenerateTestmail();
SendMail(testMail, m);
}
private void lstMembers_AccountStatusMail(object sender, EventArgs e)
{
Member m = lstMembers.GetFirstSelectedItem();
FormMail statusMail = FormMail.GenerateSingleMemberStatusReport();
SendMail(statusMail, m);
}
private void lstMembers_Edit(object sender, EventArgs e)
{
Member m = lstMembers.GetFirstSelectedItem();
if (m != null)
{
frmEditEntry edit = new frmEditEntry(m);
bool mtvLoadedOld = Program.MoneyTransfersLoaded;
edit.ShowDialog();
if (!mtvLoadedOld && Program.MoneyTransfersLoaded) mtv.LoadFromList(Program.MoneyTransfers.Entries);
if (edit.DialogResult == DialogResult.OK)
{
//the edit window already updated the data in the member object
lstMembers.UpdateEntry(m);
}
}
}
private void lstMembers_Delete(object sender, EventArgs e)
{
Member m = lstMembers.GetFirstSelectedItem();
if (m != null)
{
DialogResult dr = MessageBox.Show(this, $"Deleting a member cannot be undone!\nDo you really want to delete member {m.Number:D3} ({m.Nickname})?", "Really delete member?", MessageBoxButtons.YesNo);
if(dr == DialogResult.Yes)
{
try
{
if (!Program.members.Remove(m)) throw new Exception($"Program.members.Remove({m}) returned false.");
} catch(Exception ex)
{
MessageBox.Show($"Cannot remove member:\n{ex.Message}");
return;
}
lstMembers.RemoveEntry(m);
}
}
}
private void lstMembers_AddCashTransfer(object sender, EventArgs e)
{
Member m = lstMembers.GetFirstSelectedItem();
if (m != null)
{
//MoneyTransfer ct = new CashTransfer();
CashTransfer ct = new CashTransfer();
ct.MemberNumber = m.Number;
ct.TransferType = MoneyTransfer.eTransferType.MembershipPayment;
ct.AssignFixed = true;
frmMoneyTransfer addMoney = new frmMoneyTransfer(ct);
addMoney.ShowDialog();
DialogResult dr = addMoney.DialogResult;
if (dr == DialogResult.OK)
{
addMoney.FillMoneyTransfer();
//MoneyTransfer mt = addMoney.GetMoneyTransfer();
m.ApplyMoneyTransfer(ct);
//m.SaveToFile(); //automaticly saved in ApplyMoneyTransfer()
//ct.AssignFixed = true;
Program.MoneyTransfers.AddEntry(ct);
Program.MoneyTransfers.SaveToFile();
lstMembers.UpdateEntry(m);
}
}
}
}
}