188 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			188 lines
		
	
	
		
			7.6 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 DocumentsPath;
 | 
						|
        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;
 | 
						|
            DocumentsPath = App.DocumentsPath;
 | 
						|
            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("Bio-KSt.", c.OrganicAuthority).NextLine()
 | 
						|
                .Item("UID", c.UstIdNr).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;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 |