183 lines
9.3 KiB
C#
183 lines
9.3 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? payment = null, int? area = null,
|
|
bool isGa = false, bool showPayment = false, bool showArea = false
|
|
) {
|
|
payment ??= delivery;
|
|
var baseline = showPayment ? 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>{(baseline < obligation ? $"<b>{obligation - baseline:N0}</b>" : "-")}</td>" +
|
|
$"<td>{(baseline >= obligation && 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>{delivery: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.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>";
|
|
}
|
|
}
|
|
}
|