188 lines
7.5 KiB
C#
188 lines
7.5 KiB
C#
using System;
|
|
using System.Threading.Tasks;
|
|
using System.IO;
|
|
using Elwig.Helpers;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Elwig.Helpers.Printing;
|
|
using MimeKit;
|
|
|
|
namespace Elwig.Documents {
|
|
public abstract partial class Document : IDisposable {
|
|
|
|
public static string Name => "Dokument";
|
|
|
|
protected static readonly double GenerationProportion = 0.125;
|
|
|
|
protected TempFile? _pdfFile = null;
|
|
protected string? _pdfPath;
|
|
protected string? PdfPath => _pdfPath ?? _pdfFile?.FilePath;
|
|
public int? TotalPages { get; private set; }
|
|
public int? Pages => TotalPages / (DoublePaged ? 2 : 1);
|
|
|
|
public bool ShowFoldMarks = App.Config.Debug;
|
|
public bool DoublePaged = false;
|
|
|
|
public string DataPath;
|
|
public int CurrentNextSeason;
|
|
public string? DocumentId;
|
|
public string Title;
|
|
public string Author;
|
|
public string Header;
|
|
public string Footer;
|
|
public DateOnly Date;
|
|
|
|
public Document(string title) {
|
|
var c = App.Client;
|
|
DataPath = App.DataPath;
|
|
CurrentNextSeason = Utils.CurrentNextSeason;
|
|
Title = title;
|
|
Author = c.NameFull;
|
|
Header = $"<div class='name'>{c.Name}</div><div class='suffix'>{c.NameSuffix}</div><div class='type'>{c.NameTypeFull}</div>";
|
|
Footer = Utils.GenerateFooter("<br/>", " \u00b7 ")
|
|
.Item(c.NameFull).NextLine()
|
|
.Item(c.Address).Item($"{c.Plz} {c.Ort}").Item("Österreich").Item("Tel.", c.PhoneNr).Item("Fax", c.FaxNr).NextLine()
|
|
.Item(c.EmailAddress != null ? $"<a href=\"mailto:{c.Name} {c.NameSuffix} <{c.EmailAddress}>\">{c.EmailAddress}</a>" : null)
|
|
.Item(c.Website != null ? $"<a href=\"http://{c.Website}/\">{c.Website}</a>" : null)
|
|
.Item("Betriebs-Nr.", c.LfbisNr).Item("UID", c.UstIdNr).NextLine()
|
|
.Item("BIC", c.Bic).Item("IBAN", c.Iban)
|
|
.ToString();
|
|
Date = DateOnly.FromDateTime(Utils.Today);
|
|
}
|
|
|
|
~Document() {
|
|
Dispose();
|
|
}
|
|
|
|
public void Dispose() {
|
|
_pdfFile?.Dispose();
|
|
_pdfFile = null;
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
public static Document Merge(IEnumerable<Document> docs) {
|
|
return new MergedDocument(docs);
|
|
}
|
|
|
|
public static Document FromPdf(string path) {
|
|
return new PdfDocument(path);
|
|
}
|
|
|
|
private async Task<string> Render() {
|
|
string name;
|
|
if (this is BusinessLetter) {
|
|
name = "BusinessLetter";
|
|
} else if (this is DeliveryNote) {
|
|
name = "DeliveryNote";
|
|
} else if (this is CreditNote) {
|
|
name = "CreditNote";
|
|
} else if (this is DeliveryJournal) {
|
|
name = "DeliveryJournal";
|
|
} else if (this is DeliveryDepreciationList) {
|
|
name = "DeliveryDepreciationList";
|
|
} else if (this is Letterhead) {
|
|
name = "Letterhead";
|
|
} else if (this is DeliveryConfirmation) {
|
|
name = "DeliveryConfirmation";
|
|
} else if (this is MemberDataSheet) {
|
|
name = "MemberDataSheet";
|
|
} else if (this is MemberList) {
|
|
name = "MemberList";
|
|
} else if (this is WineQualityStatistics) {
|
|
name = "WineQualityStatistics";
|
|
} else if (this is PaymentVariantSummary) {
|
|
name = "PaymentVariantSummary";
|
|
} else if (this is DeliveryAncmtList) {
|
|
name = "DeliveryAncmtList";
|
|
} else {
|
|
throw new InvalidOperationException("Invalid document object");
|
|
}
|
|
return await Render(name);
|
|
}
|
|
|
|
private async Task<string> Render(string name) {
|
|
return await Html.CompileRenderAsync(name, this); ;
|
|
}
|
|
|
|
public async Task Generate(IProgress<double>? progress = null) {
|
|
if (_pdfFile != null)
|
|
return;
|
|
progress?.Report(0.0);
|
|
if (this is PdfDocument) {
|
|
// nothing to do
|
|
} else if (this is MergedDocument m) {
|
|
var pdf = new TempFile("pdf");
|
|
var tmpHtmls = new List<TempFile>();
|
|
var tmpFiles = new List<string>();
|
|
var n = m.Documents.Count();
|
|
int i = 0;
|
|
foreach (var doc in m.Documents) {
|
|
if (doc is PdfDocument) {
|
|
tmpFiles.Add(doc.PdfPath!);
|
|
continue;
|
|
}
|
|
var tmpHtml = new TempFile("html");
|
|
await File.WriteAllTextAsync(tmpHtml.FilePath, await doc.Render(), Utils.UTF8);
|
|
tmpHtmls.Add(tmpHtml);
|
|
tmpFiles.Add((doc is Letterhead ? "#" : "") + tmpHtml.FileName);
|
|
i++;
|
|
progress?.Report(GenerationProportion * 100 * i / n);
|
|
}
|
|
progress?.Report(GenerationProportion * 100);
|
|
var pages = await Pdf.Convert(tmpFiles, pdf.FileName, DoublePaged, new Progress<double>(v => progress?.Report(GenerationProportion * 100 + v * (1 - GenerationProportion))));
|
|
TotalPages = pages.Pages;
|
|
foreach (var tmp in tmpHtmls) {
|
|
tmp.Dispose();
|
|
}
|
|
_pdfFile = pdf;
|
|
} else {
|
|
var pdf = new TempFile("pdf");
|
|
using (var tmpHtml = new TempFile("html")) {
|
|
await File.WriteAllTextAsync(tmpHtml.FilePath, await Render(), Utils.UTF8);
|
|
progress?.Report(50.0);
|
|
var pages = await Pdf.Convert(tmpHtml.FilePath, pdf.FilePath, DoublePaged);
|
|
TotalPages = pages.Pages;
|
|
}
|
|
_pdfFile = pdf;
|
|
}
|
|
progress?.Report(100.0);
|
|
}
|
|
|
|
public void SaveTo(string pdfPath) {
|
|
if (PdfPath == null) throw new InvalidOperationException("Pdf file has not been generated yet");
|
|
File.Copy(PdfPath, pdfPath, true);
|
|
}
|
|
|
|
public async Task Print(int copies = 1) {
|
|
if (PdfPath == null) throw new InvalidOperationException("Pdf file has not been generated yet");
|
|
await Pdf.Print(PdfPath, copies, DoublePaged);
|
|
}
|
|
|
|
public void Show() {
|
|
if (_pdfFile == null) throw new InvalidOperationException("Pdf file has not been generated yet");
|
|
Pdf.Show(_pdfFile.NewReference(), Title + (this is BusinessDocument b ? $" - {b.Member.FullName}" : ""));
|
|
}
|
|
|
|
public MimePart AsEmailAttachment(string filename) {
|
|
if (PdfPath == null) throw new InvalidOperationException("Pdf file has not been generated yet");
|
|
return new("application", "pdf") {
|
|
Content = new MimeContent(File.OpenRead(PdfPath)),
|
|
ContentDisposition = new ContentDisposition(ContentDisposition.Attachment),
|
|
ContentTransferEncoding = ContentEncoding.Base64,
|
|
FileName = filename
|
|
};
|
|
}
|
|
|
|
private class MergedDocument(IEnumerable<Document> docs) : Document("Mehrere Dokumente") {
|
|
public IEnumerable<Document> Documents = docs;
|
|
}
|
|
|
|
private class PdfDocument : Document {
|
|
public PdfDocument(string pdfPath) :
|
|
base(Path.GetFileNameWithoutExtension(pdfPath)) {
|
|
_pdfPath = pdfPath;
|
|
}
|
|
}
|
|
}
|
|
}
|