200827PX Added member filter for payment receipts (not finished yet), added sending pdf via E-Mail
This commit is contained in:
parent
dcf3b05fff
commit
852322578a
|
@ -17,6 +17,7 @@ namespace dezentrale.core
|
|||
|
||||
public interface IPaymentReceiptProcessData
|
||||
{
|
||||
List<Member> MemberList { get; set; }
|
||||
string DataTemplate { get; set; }
|
||||
IntermediateFormat DataFormat { get; set; }
|
||||
|
||||
|
@ -24,6 +25,8 @@ namespace dezentrale.core
|
|||
string FileNamePattern { get; set; }
|
||||
DateTime StartDate { get; set; }
|
||||
DateTime EndDate { get; set; }
|
||||
string StartDateString { get; }
|
||||
string EndDateString { get; }
|
||||
}
|
||||
|
||||
//In order to be able to ReplaceReflect, we need to have the SvgData and SvgFileName field separated in a class
|
||||
|
@ -66,7 +69,21 @@ namespace dezentrale.core
|
|||
uint step = 0;
|
||||
try
|
||||
{
|
||||
List<string> intermediateFiles = new List<string>();
|
||||
List<Member> memberList = data.MemberList ?? Program.members.Entries;
|
||||
|
||||
// In preparation to send E-Mail and combine multiple files into one mail later,
|
||||
// we're using a List of KVP with key = filename, value = member reference
|
||||
List<KeyValuePair<string, Member>> intermediateFiles = new List<KeyValuePair<string, Member>>();
|
||||
|
||||
string intermediateExt = "txt";
|
||||
string finalExt = ".pdf";
|
||||
switch (data.DataFormat)
|
||||
{
|
||||
case IntermediateFormat.Text: intermediateExt = ".txt"; finalExt = ".txt"; break;
|
||||
case IntermediateFormat.SvgInkscape092: intermediateExt = ".svg"; break;
|
||||
case IntermediateFormat.SvgInkscapeNew: intermediateExt = ".svg"; break;
|
||||
case IntermediateFormat.Latex: intermediateExt = ".tex"; break;
|
||||
}
|
||||
|
||||
LogTarget.StepStarted(step, "Loading source SVG template");
|
||||
IntermediateFile svgTemplate = new IntermediateFile(data.DataTemplate);
|
||||
|
@ -86,7 +103,7 @@ namespace dezentrale.core
|
|||
LogTarget.StepStarted(++step, "Processing all payments to generate temporary SVGs (main step)");
|
||||
foreach(MoneyTransfer mt in transfers)
|
||||
{
|
||||
Member m = Program.members.Find(mt.MemberNumber);
|
||||
Member m = memberList.Find(x => x.Number == mt.MemberNumber);
|
||||
if(m == null)
|
||||
{
|
||||
LogTarget.LogLine($"Cannot find member {mt.MemberNumber} referenced in MoneyTransfer {mt.Id} (from {mt.ValutaDate})", LogEvent.ELogLevel.Error, "PaymentReceiptProcess");
|
||||
|
@ -99,30 +116,49 @@ namespace dezentrale.core
|
|||
}
|
||||
IntermediateFile output = svgTemplate.ReplaceReflect(mt).ReplaceReflect(m);
|
||||
LogTarget.LogLine($"Generating file \"{output.FileName}\"", LogEvent.ELogLevel.Info, "PaymentReceiptProcess");
|
||||
File.WriteAllText(output.FileName, output.Data);
|
||||
intermediateFiles.Add(output.FileName);
|
||||
File.WriteAllText(Path.Combine(data.OutputDirectory, output.FileName + intermediateExt), output.Data);
|
||||
intermediateFiles.Add(new KeyValuePair<string,Member>(output.FileName,m));
|
||||
}
|
||||
|
||||
LogTarget.StepStarted(++step, "Converting intermediate files to PDF using Inkscape");
|
||||
foreach (string iFile in intermediateFiles)
|
||||
LogTarget.StepStarted(++step, "Converting intermediate files to PDF");
|
||||
foreach (KeyValuePair<string,Member> kvp in intermediateFiles)
|
||||
{
|
||||
switch(data.DataFormat)
|
||||
string sourceFile = Path.Combine(data.OutputDirectory, kvp.Key + intermediateExt);
|
||||
string pdf = Path.Combine(data.OutputDirectory, kvp.Key + finalExt);
|
||||
switch (data.DataFormat)
|
||||
{
|
||||
case IntermediateFormat.Text: break;
|
||||
case IntermediateFormat.Text:
|
||||
LogTarget.LogLine($"Skipping PDF generation for: \"{kvp.Key}{intermediateExt}\"", LogEvent.ELogLevel.Info, "PaymentReceiptProcess");
|
||||
break;
|
||||
case IntermediateFormat.SvgInkscape092:
|
||||
ImportExportBase.RunProcess("inkscape", $"{iFile} --export-pdf={iFile}.pdf", ".", LogTarget);
|
||||
ImportExportBase.RunProcess("inkscape", $"\"{sourceFile}\" --export-pdf={pdf}", ".", LogTarget);
|
||||
break;
|
||||
case IntermediateFormat.SvgInkscapeNew:
|
||||
ImportExportBase.RunProcess("inkscape", $"{iFile} --export-type=pdf --export-filename={iFile}.pdf", ".", LogTarget);
|
||||
ImportExportBase.RunProcess("inkscape", $"\"{sourceFile}\" --export-type=pdf --export-filename={pdf}", ".", LogTarget);
|
||||
break;
|
||||
case IntermediateFormat.Latex:
|
||||
ImportExportBase.RunProcess("pdflatex", $"{iFile}", ".", LogTarget);
|
||||
ImportExportBase.RunProcess("pdflatex", $"\"{sourceFile}\"", ".", LogTarget);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LogTarget.StepStarted(++step, "E-Mail the PDFs to the members");
|
||||
LogTarget.LogLine($"This step is still TODO", LogEvent.ELogLevel.Info, "PaymentReceiptProcess");
|
||||
FormMail receiptMail = FormMail.GenerateMemberPaymentReceipts().ReplaceReflect(data);
|
||||
foreach (Member m in memberList)
|
||||
{
|
||||
//gather entries per member
|
||||
List<string> outputs = new List<string>();
|
||||
foreach (KeyValuePair<string, Member> kvp in intermediateFiles)
|
||||
{
|
||||
if (m.Number == kvp.Value.Number) outputs.Add(Path.Combine(data.OutputDirectory, kvp.Key + finalExt));
|
||||
}
|
||||
|
||||
//send E-Mail
|
||||
m.StartLogEvent($"Payment receipts E-Mail ({data.StartDateString} ... {data.EndDateString})",LogEvent.eEventType.EMail, Program.config.LocalUser);
|
||||
LogSubEvent lse = receiptMail.Send(m, outputs);
|
||||
m.SaveToFile(true);
|
||||
}
|
||||
|
||||
LogTarget.StepCompleted(4, $"E-Mail the PDFs to the members", true);
|
||||
|
||||
|
|
|
@ -569,6 +569,30 @@ namespace dezentrale.model
|
|||
+ "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",
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -241,11 +241,16 @@ namespace dezentrale.view
|
|||
}
|
||||
private void mnuMain_Payments_Receipts(object sender, EventArgs e)
|
||||
{
|
||||
int year = DateTime.Now.Year - 1;
|
||||
frmPaymentReceipts receipts = new frmPaymentReceipts()
|
||||
{
|
||||
StartDate = new DateTime(2020, 01, 01),
|
||||
EndDate = new DateTime(2020, 12, 31),
|
||||
FileNamePattern = "Member{MemberNumber}-{ValutaDateString}-{AmountString}{Currency}"
|
||||
MemberList = new List<Member>() { Program.members.Find(4) },
|
||||
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="."
|
||||
};
|
||||
DialogResult dr = receipts.ShowDialog();
|
||||
if(dr == DialogResult.OK)
|
||||
|
|
|
@ -11,13 +11,15 @@ namespace dezentrale.view
|
|||
{
|
||||
public class frmPaymentReceipts : FormWithOkCancel, IPaymentReceiptProcessData
|
||||
{
|
||||
|
||||
public List<Member> MemberList { get; set; } = null;
|
||||
public string DataTemplate { get; set; } = "";
|
||||
public IntermediateFormat DataFormat { get; set; } = IntermediateFormat.Text;
|
||||
public string OutputDirectory { get; set; } = "";
|
||||
public string FileNamePattern { get; set; } = "{Number}-{Date}";
|
||||
public DateTime StartDate { get; set; }
|
||||
public DateTime EndDate { get; set; }
|
||||
public string StartDateString { get { return StartDate.ToShortDateString(); } }
|
||||
public string EndDateString { get { return EndDate .ToShortDateString(); } }
|
||||
|
||||
|
||||
private TextBox tbTemplate;
|
||||
|
@ -31,7 +33,8 @@ namespace dezentrale.view
|
|||
{
|
||||
DialogResult = DialogResult.Cancel;
|
||||
this.StartPosition = FormStartPosition.CenterParent;
|
||||
this.Size = new System.Drawing.Size(500, 400);
|
||||
this.Size = new System.Drawing.Size(483, 185);
|
||||
this.MinimumSize = new System.Drawing.Size(455, 185);
|
||||
this.Text = "Generate payment receipts";
|
||||
this.Controls.Add(new Label()
|
||||
{
|
||||
|
@ -43,13 +46,15 @@ namespace dezentrale.view
|
|||
this.Controls.Add(tbTemplate = new TextBox()
|
||||
{
|
||||
Location = new Point(lm + 113, 0 * line + tm),
|
||||
Width = 200,
|
||||
Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right,
|
||||
Width = 300,
|
||||
});
|
||||
Button btnBrowseTemplate;
|
||||
this.Controls.Add(btnBrowseTemplate = new Button()
|
||||
{
|
||||
Text = "...",
|
||||
Location = new Point(lm + 333, 0 * line + tm),
|
||||
Location = new Point(lm + 417, 0 * line + tm),
|
||||
Anchor = AnchorStyles.Top | AnchorStyles.Right,
|
||||
Width = 40,
|
||||
});
|
||||
btnBrowseTemplate.Click += btnBrowseTemplate_Click;
|
||||
|
@ -65,7 +70,8 @@ namespace dezentrale.view
|
|||
{
|
||||
DropDownStyle = ComboBoxStyle.DropDownList,
|
||||
Location = new Point(lm + 113, 1 * line + tm),
|
||||
Width = 200,
|
||||
Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right,
|
||||
Width = 345,
|
||||
});
|
||||
foreach (IntermediateFormat fmt in Enum.GetValues(typeof(IntermediateFormat)))
|
||||
cbDataFormat.Items.Add(fmt);
|
||||
|
@ -80,13 +86,15 @@ namespace dezentrale.view
|
|||
this.Controls.Add(tbOutputDirectory = new TextBox()
|
||||
{
|
||||
Location = new Point(lm + 113, 2 * line + tm),
|
||||
Width = 200,
|
||||
Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right,
|
||||
Width = 300,
|
||||
});
|
||||
Button btnBrowseOutputDir;
|
||||
this.Controls.Add(btnBrowseOutputDir = new Button()
|
||||
{
|
||||
Text = "...",
|
||||
Location = new Point(lm + 333, 2 * line + tm),
|
||||
Location = new Point(lm + 417, 2 * line + tm),
|
||||
Anchor = AnchorStyles.Top | AnchorStyles.Right,
|
||||
Width = 40,
|
||||
});
|
||||
btnBrowseOutputDir.Click += btnBrowseOutputDir_Click;
|
||||
|
@ -101,19 +109,65 @@ namespace dezentrale.view
|
|||
this.Controls.Add(tbFileNamePattern = new TextBox()
|
||||
{
|
||||
Location = new Point(lm + 113, 3 * line + tm),
|
||||
Width = 240,
|
||||
Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right,
|
||||
Width = 345,
|
||||
});
|
||||
|
||||
|
||||
this.Controls.Add(new Label()
|
||||
{
|
||||
Text = "Start date:",
|
||||
Location = new Point(lm, 4 * line + tm + labelOffs),
|
||||
Size = new Size(110, labelHeight),
|
||||
TextAlign = ContentAlignment.BottomRight,
|
||||
});
|
||||
this.Controls.Add(dtStartDate = new DateTimePicker()
|
||||
{
|
||||
Location = new Point(lm + 113, 4 * line + tm),
|
||||
Width = 100,
|
||||
Format = DateTimePickerFormat.Short,
|
||||
});
|
||||
this.Controls.Add(new Label()
|
||||
{
|
||||
Text = "00:00:00",
|
||||
Location = new Point(lm + 160, 4 * line + tm + labelOffs),
|
||||
Size = new Size(110, labelHeight),
|
||||
TextAlign = ContentAlignment.BottomRight,
|
||||
});
|
||||
|
||||
this.Controls.Add(new Label()
|
||||
{
|
||||
Text = "End date:",
|
||||
Location = new Point(lm, 5 * line + tm + labelOffs),
|
||||
Size = new Size(110, labelHeight),
|
||||
TextAlign = ContentAlignment.BottomRight,
|
||||
});
|
||||
this.Controls.Add(dtEndDate = new DateTimePicker()
|
||||
{
|
||||
Location = new Point(lm + 113, 5 * line + tm),
|
||||
Width = 100,
|
||||
Format = DateTimePickerFormat.Short,
|
||||
});
|
||||
this.Controls.Add(new Label()
|
||||
{
|
||||
Text = "23:59:59",
|
||||
Location = new Point(lm + 160, 5 * line + tm + labelOffs),
|
||||
Size = new Size(110, labelHeight),
|
||||
TextAlign = ContentAlignment.BottomRight,
|
||||
});
|
||||
|
||||
AddOkCancel(this, btnOK_Click, btnCancel_Click);
|
||||
|
||||
//We must run the filling of the data fields in the load event, as they
|
||||
//might have been changed after the constructor is executed
|
||||
this.Shown += (sender, e) =>
|
||||
this.Load += (sender, e) =>
|
||||
{
|
||||
tbTemplate.Text = DataTemplate;
|
||||
cbDataFormat.SelectedItem = DataFormat;
|
||||
tbOutputDirectory.Text = OutputDirectory;
|
||||
tbFileNamePattern.Text = FileNamePattern;
|
||||
dtStartDate.Value = StartDate;
|
||||
dtEndDate.Value = EndDate;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -140,6 +194,11 @@ namespace dezentrale.view
|
|||
private void btnOK_Click(object sender, EventArgs e)
|
||||
{
|
||||
DataTemplate = tbTemplate.Text;
|
||||
DataFormat = (IntermediateFormat) cbDataFormat.SelectedItem;
|
||||
OutputDirectory = tbOutputDirectory.Text;
|
||||
FileNamePattern = tbFileNamePattern.Text;
|
||||
StartDate = dtStartDate.Value;
|
||||
EndDate = dtEndDate.Value.AddSeconds(24*60*60 - 1);
|
||||
DialogResult = DialogResult.OK;
|
||||
this.Close();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue