dmdb/Program.cs

330 lines
13 KiB
C#
Raw Normal View History

2019-05-15 16:42:43 +00:00
using System;
using System.Collections.Generic;
using System.IO;
using System.Windows.Forms;
2019-05-15 16:42:43 +00:00
using dezentrale.model;
using dezentrale.model.money;
using dezentrale.view;
2019-05-15 16:42:43 +00:00
/*
TODO
----
- Documentation
- ErrorLog for all errors
- frmMain: Menu option to miss an MV for selected/checked users
- FormMail: Add mail for automatic member type setting to "Foerdermitglied"
- FormMail: Use manual type changing
- FormMail: Cronjob found unassigned MoneyTransfers
- Configuration window: MoneyTransferRegEx
- Bug: Generating testdata doesn't remove old xml files, thus the memberlist will be mixed after next restart
- CronjobConfig
- CustomListView: implement generic filtering
*/
2019-05-15 16:42:43 +00:00
namespace dezentrale
{
public class Program
{
public static uint VersionNumber { get; private set; } = 0x19111000;
2019-05-15 16:42:43 +00:00
public static string VersionString { get; private set; } = $"{VersionNumber:x}";
public static string AppData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
public static string DmDirectory = Path.Combine(AppData, "dezentrale-members");
public static string ConfigFile = Path.Combine(DmDirectory, "configuration.xml");
public static Configuration config = new Configuration();
public static MemberList members = new MemberList();
public static bool MoneyTransfersLoaded { get { return moneyTransfers != null; } }
private static MoneyTransferList moneyTransfers = null;
public static MoneyTransferList MoneyTransfers
{
get
{
if (moneyTransfers != null) return moneyTransfers;
return moneyTransfers = MoneyTransferList.LoadFromFile();
}
}
2019-05-15 16:42:43 +00:00
public enum eMode
{
CommandLine = 0,
Gui = 1,
Cronjob = 2,
Export = 3,
Import = 4,
BankImport = 5,
2019-05-15 16:42:43 +00:00
}
public static eMode ProgramMode = eMode.Gui;
private static string csvInput = null;
2019-05-15 16:42:43 +00:00
[STAThread]
2019-05-15 16:42:43 +00:00
static int Main(string[] args)
{
bool printHelp = false;
Console.WriteLine($"dezentrale-members, Version {VersionString}");
Console.WriteLine($"Working directory: {DmDirectory}");
2019-05-15 16:42:43 +00:00
List<string> clArgs = new List<string>();
foreach (string argIt in args)
2019-05-15 16:42:43 +00:00
{
string argn;
string argv;
if (argIt.Contains("="))
{
argn = argIt.Substring(0, argIt.IndexOf('='));
argv = argIt.Substring(argIt.IndexOf('=') + 1);
}
else
2019-05-15 16:42:43 +00:00
{
argn = argIt;
argv = "";
}
if (argn.StartsWith("-", StringComparison.InvariantCulture)) argn = argn.Substring(1);
if (argn.StartsWith("/", StringComparison.InvariantCulture) || argn.StartsWith("-", StringComparison.InvariantCulture)) argn = argn.Substring(1);
switch (argn.ToLower())
2019-05-15 16:42:43 +00:00
{
case "help": printHelp = true; break;
2019-05-15 16:42:43 +00:00
case "mode":
switch (argv.ToLower())
2019-05-15 16:42:43 +00:00
{
case "cl": ProgramMode = eMode.CommandLine; break;
case "gui": ProgramMode = eMode.Gui; break;
2019-05-15 16:42:43 +00:00
case "cronjob":
case "auto": ProgramMode = eMode.Cronjob; break;
case "export": ProgramMode = eMode.Export; break;
case "import": ProgramMode = eMode.Import; break;
case "bankimport": ProgramMode = eMode.BankImport; break;
2019-05-15 16:42:43 +00:00
default:
Console.WriteLine("Invalid mode.");
printHelp = true;
break;
}
Console.WriteLine($"Setting Mode to {ProgramMode}");
break;
case "csvinput":
csvInput = argv;
2019-05-15 16:42:43 +00:00
break;
default:
Console.WriteLine($"Invalid command({argn})");
printHelp = true;
break;
}
}
if (printHelp)
{
Console.WriteLine("command line arguments:");
Console.WriteLine("--help Display this help message");
Console.WriteLine("--mode=<mode> Starts the program in given mode. Supported modes are:");
Console.WriteLine(" cl (default) Manual/interactive use from command line.");
Console.WriteLine(" gui Start in GUI mode (not implemented yet)");
Console.WriteLine(" auto, cronjob Check and perform pending required membership actions");
Console.WriteLine();
return 1;
}
try { Directory.CreateDirectory(DmDirectory); }
catch (Exception ex) { Console.WriteLine($"Error while creating data directory:\n{ex.Message}"); return 1; }
try
{
config = (Configuration)XmlData.LoadFromFile(ConfigFile, typeof(Configuration));
}
catch (FileNotFoundException)
{
config.DbDirectory = Path.Combine(DmDirectory, Configuration.DefaultDbDirectory);
XmlData.SaveToFile(ConfigFile, config); Console.WriteLine("Created new configuration file.");
}
catch (Exception ex)
{
Console.WriteLine("Error while accessing program data:");
Console.WriteLine(ex.Message);
return 1;
}
try { Directory.CreateDirectory(config.DbDirectory); }
catch (Exception ex) { Console.WriteLine($"Error while creating member data directory:\n{ex.Message}"); return 1; }
2019-05-15 16:42:43 +00:00
try
{
string[] memberFiles = Directory.GetFiles(config.DbDirectory, "member-*.xml");
//foreach (string s in memberFiles) Console.WriteLine(s);
members = MemberList.LoadFromFiles(memberFiles);
Console.WriteLine($"Loaded {members.Entries.Count} member entries");
}
catch (Exception ex)
{
Console.WriteLine("Error while loading member files:");
Console.WriteLine(ex.Message);
return 1;
}
2019-05-15 16:42:43 +00:00
switch (ProgramMode)
{
case eMode.Gui:
frmMain w = new frmMain();
Application.Run(w);
break;
case eMode.CommandLine:
Console.WriteLine("Not implemented yet");
break;
case eMode.Cronjob:
Cronjob.Run();
break;
case eMode.Export:
if (!config.ImportExport.Export(config.DbDirectory, DmDirectory)) return 1;
if (!config.ImportExport.VerifyExport(config.DbDirectory, DmDirectory)) return 1;
break;
case eMode.Import:
if (!config.ImportExport.Import(config.DbDirectory, DmDirectory))
return 1;
break;
case eMode.BankImport:
if (string.IsNullOrEmpty(csvInput))
{
Console.WriteLine("You must provide an input file by using --csvinput=<file>");
return 1;
}
if (!ProcessCSV(csvInput))
return 1;
break;
}
2019-05-15 16:42:43 +00:00
return 0;
}
public static bool ProcessCSV(string fileName)
{
CsvFile csv = new CsvFile();
csv.FieldSeparator = ';';
try
{
List<BankTransfer> tmpList = new List<BankTransfer>();
csv.ReadFile(fileName);
List<string> headlineFields = null;
List<Member> changedMembers = new List<Member>();
foreach (List<string> l in csv.FileContents)
{
if (headlineFields == null)
{
//The first line is expected to have the headline field first, describing the contents
headlineFields = l;
continue;
}
BankTransfer bt = new BankTransfer(headlineFields, l);
MoneyTransfer duplicate = MoneyTransfers.FindEqualEntry(bt);
if (duplicate != null)
{
Console.WriteLine("Duplicate MoneyTransfer found");
Console.WriteLine($"ValutaDate: {bt.ValutaDate}, Amount = {bt.AmountString} {bt.Currency}, Reason = \"{bt.TransferReason.Replace('\r','\\').Replace('\n','\\')}\"");
} else
{
MoneyTransfers.AddEntry(bt);
tmpList.Add(bt);
}
}
//try to assign transfers to the members
foreach (BankTransfer bt in tmpList)
{
if (bt.Amount < 0)
{
bt.TransferType = MoneyTransfer.eTransferType.RunningCost;
Console.WriteLine($"{bt.Id}: Amount = {bt.AmountString} --> RunningCost");
continue;
}
foreach (Member m in members.Entries)
{
if (m.CheckBankTransfer(bt))
{
bt.TransferType = MoneyTransfer.eTransferType.MembershipPayment;
changedMembers.Add(m);
m.StartLogEvent("Incoming bank transfer", LogEvent.eEventType.MembershipPayment, "automatic");
m.ApplyMoneyTransfer(bt);
bt.AssignFixed = true;
break; //this is important. We don't want to assign this to multiple members.
}
}
}
//Store bank transfer list
Console.WriteLine("ProcessCSV(): Storing money transfers...");
MoneyTransfers.Entries.Sort();
if (!MoneyTransfers.SaveToFile())
return false;
bool ret = true;
/*
//automaticly saved in ApplyMoneyTransfer()
foreach (Member m in changedMembers)
{
if (m.CurrentLog != null)
{
Console.Write($"ProcessCSV(): Storing {m.GetFileName()}... ");
try
{
if (!m.SaveToFile()) return false;
Console.WriteLine("OK");
} catch(Exception ex2)
{
Console.WriteLine($"ERROR: {ex2.Message}");
ret = false;
}
}
}*/
//TBD: mail to schatzmeister if there are unassigned transfers
return ret;
}
catch (Exception ex)
{
Console.WriteLine($"Error while processing csv file \"{fileName}\":");
Console.WriteLine(ex.Message);
return false;
}
}
public static string PadLeft(string input, uint totalLength)
{
if (input.Length < totalLength)
return new string(' ', (int)(totalLength - input.Length)) + input;
else
return input;
}
//TBD: This is an utility function and should reside in an extra class
public static string Int64FPToString(Int64 value)
{
//float fValue = ((float) value) / 100;
//return $"{fValue:0.00}";
Int64 intPart = value / 100;
Int64 decPart = (intPart < 0 ? -1 : 1) * (value % 100);
return $"{intPart},{decPart:D2}";
}
//TBD: This is an utility function and should reside in an extra class
public static Int64 StringToInt64FP(string value)
{
if (value == null) return 0;
if (!value.Contains(".") && !value.Contains(","))
{
return Convert.ToInt64(value) * 100;
}
int i = value.IndexOf('.');
if (i < 0) i = value.IndexOf(',');
string intPart = value.Substring(0, i);
string decPart = value.Substring(i + 1);
Int64 ip64 = Convert.ToInt64(intPart);
return (ip64 * 100) + (ip64 > 0 ? Convert.ToInt64(decPart) : -Convert.ToInt64(decPart));
}
2019-05-15 16:42:43 +00:00
}
}