183 lines
		
	
	
		
			9.4 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			183 lines
		
	
	
		
			9.4 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
using Elwig.Helpers;
 | 
						|
using Elwig.Models;
 | 
						|
using Elwig.Models.Entities;
 | 
						|
using System.Collections.Generic;
 | 
						|
using System.Globalization;
 | 
						|
using System.Linq;
 | 
						|
 | 
						|
namespace Elwig.Documents {
 | 
						|
    public abstract class BusinessDocument : Document {
 | 
						|
 | 
						|
        public Member Member;
 | 
						|
        public string? Location;
 | 
						|
        public bool IncludeSender = false;
 | 
						|
        public bool UseBillingAddress = false;
 | 
						|
        public bool ShowDateAndLocation = false;
 | 
						|
        public string Aside;
 | 
						|
 | 
						|
        public BusinessDocument(string title, Member m, bool includeSender = false) : base(title) {
 | 
						|
            Member = m;
 | 
						|
            Location = App.BranchLocation;
 | 
						|
            IncludeSender = includeSender;
 | 
						|
            var uid = (m.UstIdNr ?? "-") + (m.IsBuchführend ? "" : " <i>(pauschaliert)</i>");
 | 
						|
            Aside = $"<table><colgroup><col span='1' style='width: 22.5mm;'/><col span='1' style='width: 42.5mm;'/></colgroup>" +
 | 
						|
                $"<thead><tr><th colspan='2'>Mitglied</th></tr></thead><tbody>" +
 | 
						|
                $"<tr><th>Mitglieds-Nr.:</th><td>{m.MgNr}</td></tr>" +
 | 
						|
                $"<tr><th>Betriebs-Nr.:</th><td>{m.LfbisNr}</td></tr>" +
 | 
						|
                $"<tr><th>UID:</th><td>{uid}</td></tr>" +
 | 
						|
                $"</tbody></table>";
 | 
						|
        }
 | 
						|
 | 
						|
        public string Address {
 | 
						|
            get {
 | 
						|
                IAddress addr = (Member.BillingAddress != null && UseBillingAddress) ? Member.BillingAddress : Member;
 | 
						|
                var plz = addr.PostalDest.AtPlz;
 | 
						|
                return string.Join("\n", ((string?[])[Member.BillingAddress?.FullName, Member.AdministrativeName, Member.ForTheAttentionOf, addr.Address, $"{plz?.Plz} {plz?.Ort.Name.Split(",")[0]}", addr.PostalDest.Country.Name]).Where(s => !string.IsNullOrWhiteSpace(s)));
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        private static string GetColGroup(IEnumerable<double> cols) {
 | 
						|
            return "<colgroup>\n" + string.Join("\n", cols.Select(g => $"<col style=\"width: {g.ToString(CultureInfo.InvariantCulture)}mm;\"/>")) + "\n</colgroup>\n";
 | 
						|
        }
 | 
						|
 | 
						|
        public static string PrintSortenaufteilung(List<MemberStat> stats) {
 | 
						|
            List<string> discrs = [""];
 | 
						|
            List<string> names = ["ohne Attr./Bewirt."];
 | 
						|
            List<string> bucketAttrs = [
 | 
						|
                .. stats
 | 
						|
                .Select(s => s.Discr)
 | 
						|
                .Distinct()
 | 
						|
                .Where(s => s.Length > 0)
 | 
						|
                .Order()
 | 
						|
            ];
 | 
						|
            names.AddRange(bucketAttrs);
 | 
						|
            names.Add("Gesamt");
 | 
						|
            discrs.AddRange(bucketAttrs);
 | 
						|
 | 
						|
            List<double> cols = [40];
 | 
						|
            cols.AddRange(names.Select(_ => 125.0 / names.Count));
 | 
						|
            string tbl = GetColGroup(cols);
 | 
						|
            tbl += "<thead><tr>" +
 | 
						|
                $"<th><b>Sortenaufteilung</b> [kg]</th>" +
 | 
						|
                string.Join("", names.Select(c => $"<th>{c}</th>")) +
 | 
						|
                "</tr></thead>";
 | 
						|
 | 
						|
            tbl += string.Join("\n", stats
 | 
						|
                .GroupBy(b => b.Variety)
 | 
						|
                .OrderBy(b => b.Key)
 | 
						|
                .Select(g => {
 | 
						|
                    var dict = g.ToDictionary(a => a.Discr, a => a.Weight);
 | 
						|
                    var vals = discrs.Select(a => dict.GetValueOrDefault(a, 0)).ToList();
 | 
						|
                    return $"<tr><th>{g.Key}</th>" + string.Join("", vals.Select(v => "<td class=\"number\">" + (v == 0 ? "-" : $"{v:N0}") + "</td>")) +
 | 
						|
                        $"<td class=\"number\">{dict.Values.Sum():N0}</td></tr>";
 | 
						|
                })
 | 
						|
            );
 | 
						|
            var totalDict = stats.GroupBy(s => s.Discr).ToDictionary(g => g.Key, g => g.Sum(a => a.Weight));
 | 
						|
            var totals = discrs.Select(a => totalDict.TryGetValue(a, out int value) ? value : 0);
 | 
						|
            tbl += "<tr class=\"sum bold\"><td></td>" + string.Join("", totals.Select(v => $"<td class=\"number\">{v:N0}</td>")) +
 | 
						|
                $"<td class=\"number\">{totalDict.Values.Sum():N0}</td></tr>";
 | 
						|
 | 
						|
            return "<table class=\"sortenaufteilung small number cohere\">" + tbl + "</table>";
 | 
						|
        }
 | 
						|
 | 
						|
        private static string FormatRow(
 | 
						|
            int obligation, int right, int delivery, int? totalDelivery = null, int? payment = null, int? area = null,
 | 
						|
            bool isGa = false, bool showPayment = false, bool showArea = false
 | 
						|
        ) {
 | 
						|
            totalDelivery ??= delivery;
 | 
						|
            payment ??= delivery;
 | 
						|
 | 
						|
            if (showArea) {
 | 
						|
                return $"<td>{(area == null ? "" : $"{area:N0}")}</td>" +
 | 
						|
                    $"<td>{obligation:N0}</td>" +
 | 
						|
                    $"<td>{right:N0}</td>";
 | 
						|
            }
 | 
						|
 | 
						|
            return $"<td>{(obligation == 0 ? "-" : $"{obligation:N0}")}</td>" +
 | 
						|
                $"<td>{(right == 0 ? "-" : $"{right:N0}")}</td>" +
 | 
						|
                $"<td>{(totalDelivery < obligation ? $"<b>{obligation - totalDelivery:N0}</b>" : "-")}</td>" +
 | 
						|
                $"<td>{(delivery <= right ? $"{right - delivery:N0}" : "-")}</td>" +
 | 
						|
                $"<td>{(obligation == 0 && right == 0 ? "-" : (delivery > right ? ((isGa ? "<b>" : "") + $"{delivery - right:N0}" + (isGa ? "</b>" : "")) : "-"))}</td>" +
 | 
						|
                (showPayment ? $"<td>{(isGa ? "" : obligation == 0 && right == 0 ? "-" : $"{payment:N0}")}</td>" : "") +
 | 
						|
                $"<td>{totalDelivery:N0}</td>";
 | 
						|
        }
 | 
						|
 | 
						|
        private static string FormatRow(MemberBucket bucket, bool isGa = false, bool showPayment = false, bool showArea = false) {
 | 
						|
            return FormatRow(bucket.Obligation, bucket.Right, bucket.Delivery, bucket.DeliveryTotal, bucket.Payment, bucket.Area, isGa, showPayment, showArea);
 | 
						|
        }
 | 
						|
 | 
						|
        public string PrintBucketTable(
 | 
						|
            Season season, Dictionary<string, MemberBucket> buckets,
 | 
						|
            bool includeDelivery = true, bool includePayment = false,
 | 
						|
            bool isTiny = false, IEnumerable<string>? filter = null
 | 
						|
        ) {
 | 
						|
            includePayment = includePayment && includeDelivery;
 | 
						|
            string tbl = GetColGroup(!includeDelivery ? [105, 20, 20, 20] : includePayment ? [45, 17, 17, 17, 19, 16, 17, 17] : [45, 20, 20, 20, 20, 20, 20]);
 | 
						|
            tbl += $"""
 | 
						|
                <thead>
 | 
						|
                    <tr>
 | 
						|
                        <th{(!includeDelivery ? " rowspan=\"2\"" : "")}>
 | 
						|
                            <b>{(includeDelivery ? "Lese " + season.Year : "Zusammengefasste Flächenbindungen")}</b>
 | 
						|
                            per {Date:dd.MM.yyyy} {(includeDelivery ? "[kg]" : "")}
 | 
						|
                        </th>
 | 
						|
                        {(!includeDelivery ? "<th>Fläche</th>" : "")}
 | 
						|
                        <th>Lieferpflicht</th>
 | 
						|
                        <th>Lieferrecht</th>
 | 
						|
                        {(includeDelivery ? "<th>Unterliefert</th>" : "")}
 | 
						|
                        {(includeDelivery ? "<th>Noch lieferbar</th>" : "")}
 | 
						|
                        {(includeDelivery ? "<th>Überliefert</th>" : "")}
 | 
						|
                        {(includePayment ? "<th>Zugeteilt</th>" : "")}
 | 
						|
                        {(includeDelivery ? "<th>Geliefert</th>" : "")}
 | 
						|
                    </tr>
 | 
						|
                    {(!includeDelivery ? "<tr><th class=\"unit\">[m²]</th><th class=\"unit\">[kg]</th><th class=\"unit\">[kg]</th></tr>" : "")}
 | 
						|
                </thead>
 | 
						|
                """;
 | 
						|
 | 
						|
            var mBuckets = buckets
 | 
						|
                .Where(b => ((!includeDelivery && b.Value.Area > 0) ||
 | 
						|
                             (includeDelivery && (b.Value.Right > 0 || b.Value.Obligation > 0 || b.Value.Delivery > 0))) &&
 | 
						|
                            (filter == null || filter.Contains(b.Key[..2])))
 | 
						|
                .ToList();
 | 
						|
            var fbVars = mBuckets
 | 
						|
                .Where(b => b.Value.Right > 0 || b.Value.Obligation > 0)
 | 
						|
                .Select(b => b.Key.Replace("_", ""))
 | 
						|
                .Order()
 | 
						|
                .ToArray();
 | 
						|
            var fbs = mBuckets
 | 
						|
                .Where(b => fbVars.Contains(b.Key) && b.Key.Length == 2)
 | 
						|
                .OrderBy(b => b.Value.Name);
 | 
						|
            var vtr = mBuckets
 | 
						|
                .Where(b => fbVars.Contains(b.Key) && b.Key.Length > 2)
 | 
						|
                .OrderBy(b => b.Value.Name);
 | 
						|
            var rem = mBuckets
 | 
						|
                .Where(b => !fbVars.Contains(b.Key))
 | 
						|
                .OrderBy(b => b.Value.Name);
 | 
						|
 | 
						|
            tbl += "\n<tbody>\n";
 | 
						|
            tbl += $"<tr><th>Gesamtlieferung lt. gez. GA</th>{FormatRow(
 | 
						|
                    Member.BusinessShares * season.MinKgPerBusinessShare,
 | 
						|
                    Member.BusinessShares * season.MaxKgPerBusinessShare,
 | 
						|
                    season.Deliveries.Where(d => d.MgNr == Member.MgNr).Sum(d => d.Weight),
 | 
						|
                    isGa: true, showPayment: includePayment, showArea: !includeDelivery
 | 
						|
                )}</tr>";
 | 
						|
            if (fbs.Any()) {
 | 
						|
                tbl += $"<tr class=\"subheading{(filter == null ? " border" : "")}\"><th colspan=\"{(includePayment ? 8 : 7)}\">" +
 | 
						|
                    $"Flächenbindungen{(vtr.Any() ? " (inkl. Verträge)" : "")}:</th></tr>";
 | 
						|
                foreach (var (id, b) in fbs) {
 | 
						|
                    tbl += $"<tr><th>{b.Name}</th>{FormatRow(b, showPayment: includePayment, showArea: !includeDelivery)}</tr>";
 | 
						|
                }
 | 
						|
            }
 | 
						|
            if (vtr.Any()) {
 | 
						|
                tbl += $"<tr class=\"subheading{(filter == null ? " border" : "")}\"><th colspan=\"{(includePayment ? 8 : 7)}\">" +
 | 
						|
                    "Verträge:</th></tr>";
 | 
						|
                foreach (var (id, b) in vtr) {
 | 
						|
                    tbl += $"<tr><th>{b.Name}</th>{FormatRow(b, showPayment: includePayment, showArea: !includeDelivery)}</tr>";
 | 
						|
                }
 | 
						|
            }
 | 
						|
            tbl += "\n</tbody>\n";
 | 
						|
 | 
						|
            return $"<table class=\"buckets {(isTiny ? "tiny" : "small")} number cohere\">\n" + tbl + "\n</table>";
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 |