Documents: Add Letterhead
This commit is contained in:
@ -2,11 +2,15 @@ using System;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Elwig.Helpers;
|
using Elwig.Helpers;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Elwig.Documents {
|
namespace Elwig.Documents {
|
||||||
public abstract class Document : IDisposable {
|
public abstract partial class Document : IDisposable {
|
||||||
|
|
||||||
private TempFile? PdfFile = null;
|
private TempFile? _pdfFile = null;
|
||||||
|
private string? _renderedHtml = null;
|
||||||
|
|
||||||
public bool ShowFoldMarks = App.Config.Debug;
|
public bool ShowFoldMarks = App.Config.Debug;
|
||||||
|
|
||||||
@ -35,17 +39,56 @@ namespace Elwig.Documents {
|
|||||||
Date = DateTime.Today;
|
Date = DateTime.Today;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[GeneratedRegex(@"</body>.*?</footer>\s*</div>", RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.Compiled)]
|
||||||
|
private static partial Regex GeneratedDocumentHeaderRegex();
|
||||||
|
private static readonly Regex DocumentHeaderRegex = GeneratedDocumentHeaderRegex();
|
||||||
|
|
||||||
|
[GeneratedRegex(@"<style>.*?/style>", RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.Compiled)]
|
||||||
|
private static partial Regex GeneratedHtmlStyleRegex();
|
||||||
|
private static readonly Regex HtmlStyleRegex = GeneratedHtmlStyleRegex();
|
||||||
|
|
||||||
|
[GeneratedRegex(@"<link[^>]*>", RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.Compiled)]
|
||||||
|
private static partial Regex GeneratedHtmlLinkRegex();
|
||||||
|
private static readonly Regex HtmlLinkRegex = GeneratedHtmlLinkRegex();
|
||||||
|
|
||||||
~Document() {
|
~Document() {
|
||||||
Dispose();
|
Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose() {
|
public void Dispose() {
|
||||||
PdfFile?.Dispose();
|
_pdfFile?.Dispose();
|
||||||
PdfFile = null;
|
_pdfFile = null;
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task<string> Render() {
|
public static async Task<Document> Merge(IEnumerable<Document> docs) {
|
||||||
|
string html = "";
|
||||||
|
var styles = new List<string>();
|
||||||
|
foreach (var d in docs) {
|
||||||
|
var h = await d.Render();
|
||||||
|
var s = HtmlStyleRegex.Matches(h).Select(m => m.Value).ToList();
|
||||||
|
var l = HtmlLinkRegex.Matches(h).Select(m => m.Value).ToList();
|
||||||
|
if (s.All(styles.Contains)) {
|
||||||
|
h = HtmlStyleRegex.Replace(h, "");
|
||||||
|
} else {
|
||||||
|
styles.AddRange(s);
|
||||||
|
}
|
||||||
|
if (l.All(styles.Contains)) {
|
||||||
|
h = HtmlLinkRegex.Replace(h, "");
|
||||||
|
} else {
|
||||||
|
styles.AddRange(l);
|
||||||
|
}
|
||||||
|
html += h;
|
||||||
|
}
|
||||||
|
html = DocumentHeaderRegex.Replace(html, "<div class='document-break'/>");
|
||||||
|
return new InternalDocument("Mehrere Dokumente") {
|
||||||
|
_renderedHtml = html,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<string> Render() {
|
||||||
|
if (_renderedHtml != null)
|
||||||
|
return _renderedHtml;
|
||||||
string name;
|
string name;
|
||||||
if (this is BusinessLetter) {
|
if (this is BusinessLetter) {
|
||||||
name = "BusinessLetter";
|
name = "BusinessLetter";
|
||||||
@ -55,14 +98,17 @@ namespace Elwig.Documents {
|
|||||||
name = "CreditNote";
|
name = "CreditNote";
|
||||||
} else if (this is DeliveryJournal) {
|
} else if (this is DeliveryJournal) {
|
||||||
name = "DeliveryJournal";
|
name = "DeliveryJournal";
|
||||||
|
} else if (this is Letterhead) {
|
||||||
|
name = "Letterhead";
|
||||||
} else {
|
} else {
|
||||||
throw new InvalidOperationException("Invalid document object");
|
throw new InvalidOperationException("Invalid document object");
|
||||||
}
|
}
|
||||||
return Render(name);
|
return await Render(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task<string> Render(string name) {
|
private async Task<string> Render(string name) {
|
||||||
return Html.CompileRenderAsync(name, this);
|
_renderedHtml = await Html.CompileRenderAsync(name, this);
|
||||||
|
return _renderedHtml;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Generate() {
|
public async Task Generate() {
|
||||||
@ -71,22 +117,26 @@ namespace Elwig.Documents {
|
|||||||
await File.WriteAllTextAsync(tmpHtml.FilePath, await Render(), Utils.UTF8);
|
await File.WriteAllTextAsync(tmpHtml.FilePath, await Render(), Utils.UTF8);
|
||||||
await Pdf.Convert(tmpHtml.FilePath, pdf.FilePath);
|
await Pdf.Convert(tmpHtml.FilePath, pdf.FilePath);
|
||||||
}
|
}
|
||||||
PdfFile = pdf;
|
_pdfFile = pdf;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SaveTo(string pdfPath) {
|
public void SaveTo(string pdfPath) {
|
||||||
if (PdfFile == null) throw new InvalidOperationException("Pdf file has not been generated yet");
|
if (_pdfFile == null) throw new InvalidOperationException("Pdf file has not been generated yet");
|
||||||
File.Copy(PdfFile.FilePath, pdfPath);
|
File.Copy(_pdfFile.FilePath, pdfPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Print(int copies = 1) {
|
public async Task Print(int copies = 1) {
|
||||||
if (PdfFile == null) throw new InvalidOperationException("Pdf file has not been generated yet");
|
if (_pdfFile == null) throw new InvalidOperationException("Pdf file has not been generated yet");
|
||||||
await Pdf.Print(PdfFile.FilePath, copies);
|
await Pdf.Print(_pdfFile.FilePath, copies);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Show() {
|
public void Show() {
|
||||||
if (PdfFile == null) throw new InvalidOperationException("Pdf file has not been generated yet");
|
if (_pdfFile == null) throw new InvalidOperationException("Pdf file has not been generated yet");
|
||||||
Pdf.Show(PdfFile.NewReference(), Title);
|
Pdf.Show(_pdfFile.NewReference(), Title);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class InternalDocument : Document {
|
||||||
|
public InternalDocument(string title) : base(title) { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ namespace Elwig.Documents {
|
|||||||
await e.CompileTemplateAsync("DeliveryNote");
|
await e.CompileTemplateAsync("DeliveryNote");
|
||||||
await e.CompileTemplateAsync("CreditNote");
|
await e.CompileTemplateAsync("CreditNote");
|
||||||
await e.CompileTemplateAsync("DeliveryJournal");
|
await e.CompileTemplateAsync("DeliveryJournal");
|
||||||
|
await e.CompileTemplateAsync("Letterhead");
|
||||||
|
|
||||||
Engine = e;
|
Engine = e;
|
||||||
evtHandler();
|
evtHandler();
|
||||||
|
9
Elwig/Documents/Letterhead.cshtml
Normal file
9
Elwig/Documents/Letterhead.cshtml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
@using RazorLight
|
||||||
|
@inherits TemplatePage<Elwig.Documents.Letterhead>
|
||||||
|
@model Elwig.Documents.Letterhead
|
||||||
|
@{ Layout = "BusinessDocument"; }
|
||||||
|
<style>
|
||||||
|
header, .footer-wrapper {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
</style>
|
9
Elwig/Documents/Letterhead.cshtml.cs
Normal file
9
Elwig/Documents/Letterhead.cshtml.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
using Elwig.Models;
|
||||||
|
|
||||||
|
namespace Elwig.Documents {
|
||||||
|
public class Letterhead : BusinessDocument {
|
||||||
|
public Letterhead(Member m) : base($"Briefkopf {m.Name}", m, true) {
|
||||||
|
Aside = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -20,6 +20,9 @@
|
|||||||
hr.page-break {
|
hr.page-break {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
.document-break {
|
||||||
|
break-before: page;
|
||||||
|
}
|
||||||
|
|
||||||
@page {
|
@page {
|
||||||
size: A4;
|
size: A4;
|
||||||
|
@ -10,6 +10,7 @@ using Elwig.Models;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
using Elwig.Documents;
|
||||||
|
|
||||||
namespace Elwig.Windows {
|
namespace Elwig.Windows {
|
||||||
public partial class MemberAdminWindow : AdministrationWindow {
|
public partial class MemberAdminWindow : AdministrationWindow {
|
||||||
@ -269,6 +270,25 @@ namespace Elwig.Windows {
|
|||||||
Utils.MailTo(((Member)MemberList.SelectedItem).EmailAddresses.Select(a => a.Address));
|
Utils.MailTo(((Member)MemberList.SelectedItem).EmailAddresses.Select(a => a.Address));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async void Menu_Print_Letterheads_MgNr_Click(object sender, RoutedEventArgs evt) {
|
||||||
|
using var d = await Document.Merge(Context.Members
|
||||||
|
.Where(m => m.IsActive)
|
||||||
|
.OrderBy(m => m.MgNr)
|
||||||
|
.Select(m => new Letterhead(m)));
|
||||||
|
await d.Generate();
|
||||||
|
d.Show();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void Menu_Print_Letterheads_Name_Click(object sender, RoutedEventArgs evt) {
|
||||||
|
using var d = await Document.Merge(Context.Members
|
||||||
|
.Where(m => m.IsActive)
|
||||||
|
.OrderBy(m => m.FamilyName)
|
||||||
|
.ThenBy(m => m.GivenName)
|
||||||
|
.Select(m => new Letterhead(m)));
|
||||||
|
await d.Generate();
|
||||||
|
d.Show();
|
||||||
|
}
|
||||||
|
|
||||||
private void FocusSearchInput(object sender, RoutedEventArgs evt) {
|
private void FocusSearchInput(object sender, RoutedEventArgs evt) {
|
||||||
if (!IsEditing && !IsCreating) {
|
if (!IsEditing && !IsCreating) {
|
||||||
SearchInput.Focus();
|
SearchInput.Focus();
|
||||||
|
Reference in New Issue
Block a user