Compare commits

..

14 Commits

Author SHA1 Message Date
lorenz.stechauner 781077e5e3 [#25] Documents: Fix page breaking 2023-12-20 01:39:26 +01:00
lorenz.stechauner 16d429e9e4 DeliveryConfirmation: Keep last two tables together on page 2023-12-19 22:04:34 +01:00
lorenz.stechauner 18600a44da Document: Add mailto: and http: hrefs to footer 2023-12-19 20:48:01 +01:00
lorenz.stechauner 9c46974bd7 [#23] DeliveryConfirmation: Add Sortenaufteilung table 2023-12-19 20:48:01 +01:00
lorenz.stechauner 480f99234c AppDbContext: Remove support for multiple attributes in buckets 2023-12-19 19:31:35 +01:00
lorenz.stechauner 8811ca25ce [#17][#23] BusinessDocument: Remove enum RowMode 2023-12-19 18:11:02 +01:00
lorenz.stechauner 161bf31a62 [#17][#23] Documents: Unify table stylings 2023-12-19 18:10:31 +01:00
lorenz.stechauner ae00fd2c31 [#22] DeliveryConfirmation: Fix wrong border 2023-12-18 21:01:15 +01:00
lorenz.stechauner 2c48c89cfa Installer/config.ini: Comment out branch 2023-12-18 12:20:05 +01:00
lorenz.stechauner de5e62de50 MemberAdminWindow: Rename ...Memberdata... to ...MemberDataSheet... 2023-12-02 17:30:04 +01:00
lorenz.stechauner 0eed426559 [#21] AdministrationWindow: Temporarily fix UnitTextBox/TextBox casting error 2023-12-02 14:00:22 +01:00
lorenz.stechauner 03a9a3793a Config: Use Microsoft's INI implementation instead of a 3rd party's 2023-12-02 13:04:50 +01:00
lorenz.stechauner 7528764ff3 Update project to .NET 8 2023-12-02 12:28:16 +01:00
lorenz.stechauner 3576a066fe AppDbContext: Use records instead of unnamed tuples for buckets 2023-11-30 17:29:01 +01:00
28 changed files with 460 additions and 561 deletions
+124
View File
@@ -1,5 +1,7 @@
using Elwig.Helpers; using Elwig.Helpers;
using Elwig.Models.Entities; using Elwig.Models.Entities;
using System.Collections.Generic;
using System.Linq;
namespace Elwig.Documents { namespace Elwig.Documents {
public abstract class BusinessDocument : Document { public abstract class BusinessDocument : Document {
@@ -32,5 +34,127 @@ namespace Elwig.Documents {
return (addr is BillingAddr ? $"{addr.Name}\n" : "") + $"{Member.AdministrativeName}\n{addr.Address}\n{plz?.Plz} {plz?.Ort.Name.Split(",")[0]}\n{addr.PostalDest.Country.Name}"; return (addr is BillingAddr ? $"{addr.Name}\n" : "") + $"{Member.AdministrativeName}\n{addr.Address}\n{plz?.Plz} {plz?.Ort.Name.Split(",")[0]}\n{addr.PostalDest.Country.Name}";
} }
} }
private static string GetColGroup(IEnumerable<double> cols) {
return "<colgroup>\n" + string.Join("\n", cols.Select(g => $"<col style=\"width: {g}mm;\"/>")) + "\n</colgroup>\n";
}
public static string PrintSortenaufteilung(Dictionary<string, MemberBucket> buckets) {
List<string> attributes = ["_", ""];
List<string> names = ["kein Qual.Wein", "ohne Attribut"];
List<(string, string)> bucketAttrs = [
.. buckets
.Where(b => b.Key.Length > 2 && b.Key[2] != '_' && b.Value.DeliveryStrict > 0)
.Select(b => (b.Key[2..], b.Value.Name.Split("(")[1][..^1]))
.Distinct()
.OrderBy(v => v.Item1)
];
names.AddRange(bucketAttrs.Select(b => b.Item2));
names.Add("Gesamt");
attributes.AddRange(bucketAttrs.Select(b => b.Item1));
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", buckets
.GroupBy(b => (b.Key[..2], b.Value.Name.Split("(")[0].Trim()))
.Where(g => g.Sum(a => a.Value.DeliveryStrict) > 0)
.OrderBy(g => g.Key.Item1)
.Select(g => {
var dict = g.ToDictionary(a => a.Key[2..], a => a.Value);
var vals = attributes.Select(a => dict.TryGetValue(a, out MemberBucket value) ? value.DeliveryStrict : 0).ToList();
return $"<tr><th>{g.Key.Item2}</th>" + string.Join("", vals.Select(v => "<td class=\"number\">" + (v == 0 ? "-" : $"{v:N0}") + "</td>")) +
$"<td class=\"number\">{dict.Values.Select(v => v.DeliveryStrict).Sum():N0}</td></tr>";
})
);
var totalDict = buckets.GroupBy(b => b.Key[2..]).ToDictionary(g => g.Key, g => g.Sum(a => a.Value.DeliveryStrict));
var totals = attributes.Select(a => totalDict.TryGetValue(a, out int value) ? value : 0);
tbl += "<tr class=\"sum\"><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, bool isGa = false, bool showPayment = false) {
payment ??= delivery;
var baseline = showPayment ? payment : delivery;
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) {
return FormatRow(bucket.Obligation, bucket.Right, bucket.Delivery, bucket.Payment, isGa, showPayment);
}
public string PrintBucketTable(Season season, Dictionary<string, MemberBucket> buckets, bool includePayment = false, bool isTiny = false, IEnumerable<string>? filter = null) {
string tbl = GetColGroup(includePayment ? [45, 17, 17, 17, 19, 16, 17, 17] : [45, 20, 20, 20, 20, 20, 20]);
tbl += $"""
<thead>
<tr>
<th><b>Lese {season.Year}</b> per {Date:dd.MM.yyyy} [kg]</th>
<th>Lieferpflicht</th>
<th>Lieferrecht</th>
<th>Unterliefert</th>
<th>Noch lieferbar</th>
<th>Überliefert</th>
{(includePayment ? "<th>Zugeteilt</th>" : "")}
<th>Geliefert</th>
</tr>
</thead>
""";
var mBuckets = buckets
.Where(b => (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,
Member.Deliveries.Where(d => d.Year == season.Year).Sum(d => d.Weight),
isGa: true, showPayment: includePayment
)}</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)}</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)}</tr>";
}
}
tbl += "\n</tbody>\n";
return $"<table class=\"buckets {(isTiny ? "tiny" : "small")} number cohere\">\n" + tbl + "\n</table>";
}
} }
} }
+1 -1
View File
@@ -1,5 +1,5 @@
.address-wrapper, aside, main { .address-wrapper, aside {
overflow: hidden; overflow: hidden;
} }
-52
View File
@@ -1,49 +1,5 @@
table.credit {
font-size: 10pt;
}
table.credit th,
table.credit td {
padding: 0 0.25mm;
}
table.credit thead {
font-size: 8pt
}
table.credit thead th {
font-weight: normal;
font-style: italic;
vertical-align: bottom;
}
table.credit td {
vertical-align: top;
}
table.credit .oe,
table.credit .kmw {
text-align: center;
}
table.credit .dpnr {
text-align: center;
}
table.credit .amount,
table.credit .weight,
table.credit .price {
text-align: right;
}
table.credit .rel,
table.credit .abs {
text-align: center;
}
table.credit .amount.sum { table.credit .amount.sum {
vertical-align: bottom;
padding-bottom: 1mm; padding-bottom: 1mm;
} }
@@ -59,11 +15,3 @@ table.credit tbody tr.first td {
table.credit tbody tr.last td { table.credit tbody tr.last td {
padding-bottom: 1mm; padding-bottom: 1mm;
} }
table.credit tbody tr.new {
border-top: 0.5pt solid black;
}
table.credit .small {
font-size: 8pt;
}
+1 -1
View File
@@ -10,7 +10,7 @@ namespace Elwig.Documents {
public Season Season; public Season Season;
public DeliveryConfirmationData Data; public DeliveryConfirmationData Data;
public string? Text = App.Client.TextDeliveryConfirmation; public string? Text = App.Client.TextDeliveryConfirmation;
public Dictionary<string, (string, int, int, int, int)> MemberBuckets; public Dictionary<string, MemberBucket> MemberBuckets;
public DeliveryConfirmation(AppDbContext ctx, int year, Member m, DeliveryConfirmationData data) : public DeliveryConfirmation(AppDbContext ctx, int year, Member m, DeliveryConfirmationData data) :
base($"Anlieferungsbestätigung {year}", m) { base($"Anlieferungsbestätigung {year}", m) {
+18 -95
View File
@@ -1,3 +1,4 @@
@using Elwig.Documents
@using RazorLight @using RazorLight
@inherits TemplatePage<Elwig.Documents.DeliveryConfirmation> @inherits TemplatePage<Elwig.Documents.DeliveryConfirmation>
@model Elwig.Documents.DeliveryConfirmation @model Elwig.Documents.DeliveryConfirmation
@@ -22,7 +23,7 @@
<thead> <thead>
<tr> <tr>
<th rowspan="2" style="text-align: left;">Lieferschein-Nr.</th> <th rowspan="2" style="text-align: left;">Lieferschein-Nr.</th>
<th rowspan="2">Pos.</th> <th rowspan="2" class="narrow">Pos.</th>
<th rowspan="2" style="text-align: left;">Sorte</th> <th rowspan="2" style="text-align: left;">Sorte</th>
<th rowspan="2" style="text-align: left;">Attribut</th> <th rowspan="2" style="text-align: left;">Attribut</th>
<th rowspan="2" style="text-align: left;">Qualitätsstufe</th> <th rowspan="2" style="text-align: left;">Qualitätsstufe</th>
@@ -32,11 +33,11 @@
<th>Davon<br/>abzuwerten</th> <th>Davon<br/>abzuwerten</th>
</tr> </tr>
<tr> <tr>
<th>[°Oe]</th> <th class="unit">[°Oe]</th>
<th>[°KMW]</th> <th class="unit narrow">[°KMW]</th>
<th colspan="2">[kg]</th> <th class="unit"colspan="2">[kg]</th>
<th>[kg]</th> <th class="unit">[kg]</th>
<th>[kg]</th> <th class="unit">[kg]</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@@ -54,121 +55,43 @@
<td class="small">@p.Variant</td> <td class="small">@p.Variant</td>
<td class="small">@p.Attribute</td> <td class="small">@p.Attribute</td>
<td class="small">@p.QualityLevel</td> <td class="small">@p.QualityLevel</td>
<td rowspan="@rows" class="grad">@($"{p.Gradation.Oe:N0}")</td> <td rowspan="@rows" class="center">@($"{p.Gradation.Oe:N0}")</td>
<td rowspan="@rows" class="grad">@($"{p.Gradation.Kmw:N1}")</td> <td rowspan="@rows" class="center">@($"{p.Gradation.Kmw:N1}")</td>
} }
@if (i > 0 && i <= p.Modifiers.Length) { @if (i > 0 && i <= p.Modifiers.Length) {
<td colspan="3" class="mod">@(p.Modifiers[i - 1])</td> <td colspan="3" class="small mod">@(p.Modifiers[i - 1])</td>
} else if (i > 0) { } else if (i > 0) {
<td colspan="3"></td> <td colspan="3"></td>
} }
@if (i < p.Buckets.Length) { @if (i < p.Buckets.Length) {
var bucket = p.Buckets[i]; var bucket = p.Buckets[i];
<td class="geb">@bucket.Name:</td> <td class="small">@bucket.Name:</td>
<td class="weight">@($"{bucket.Value:N0}")</td> <td class="number">@($"{bucket.Value:N0}")</td>
} else { } else {
<td colspan="2"></td> <td colspan="2"></td>
} }
@if (i == p.Buckets.Length - 1) { @if (i == p.Buckets.Length - 1) {
<td class="weight">@($"{p.Weight:N0}")</td> <td class="number">@($"{p.Weight:N0}")</td>
} else { } else {
<td></td> <td></td>
} }
@if (first) { @if (first) {
<td rowspan="@rows" class="weight"></td> <td rowspan="@rows" class="number"></td>
first = false; first = false;
} }
</tr> </tr>
lastVariant = p.Variant;
} }
lastVariant = p.Variant;
} }
<tr class="sum"> <tr class="sum">
<td colspan="8">Gesamt:</td> <td colspan="8">Gesamt:</td>
<td colspan="2" class="weight">@($"{Model.Data.Rows.Sum(p => p.Weight):N0}")</td> <td colspan="2" class="number">@($"{Model.Data.Rows.Sum(p => p.Weight):N0}")</td>
<td></td> <td></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
<table class="delivery-confirmation-stats"> @Raw(BusinessDocument.PrintSortenaufteilung(Model.MemberBuckets))
<colgroup> @Raw(Model.PrintBucketTable(Model.Season, Model.MemberBuckets, includePayment: true))
<col style="width: 45mm;"/>
<col style="width: 17mm;"/>
<col style="width: 17mm;"/>
<col style="width: 17mm;"/>
<col style="width: 19mm;"/>
<col style="width: 16mm;"/>
<col style="width: 17mm;"/>
<col style="width: 17mm;"/>
</colgroup>
<thead>
<tr>
<th><b>Lese @Model.Season.Year</b> per @($"{Model.Date:dd.MM.yyyy}") [kg]</th>
<th>Lieferpflicht</th>
<th>Lieferrecht</th>
<th>Unterliefert</th>
<th>Noch lieferbar</th>
<th>Überliefert</th>
<th>Zugeteilt</th>
<th>Geliefert</th>
</tr>
</thead>
<tbody>
@{
string FormatRow(int mode, int obligation, int right, int sum, int? payment = null) {
var isGa = mode == 0;
payment ??= sum;
return $"<td>{(mode == 1 ? "" : obligation == 0 ? "-" : $"{obligation:N0}")}</td>" +
$"<td>{(mode == 1 ? "" : right == 0 ? "-" : $"{right:N0}")}</td>" +
$"<td>{(mode == 1 ? "" : payment < obligation ? $"<b>{obligation - payment:N0}\x3c/b>" : "-")}</td>" +
$"<td>{(mode == 1 ? "" : payment >= obligation && sum <= right ? $"{right - sum:N0}" : "-")}</td>" +
$"<td>{(mode == 1 ? "" : obligation == 0 && right == 0 ? "-" : (sum > right ? ((isGa ? "<b>" : "") + $"{sum - right:N0}" + (isGa ? "</b>" : "")) : "-"))}</td>" +
$"<td>{(mode != 2 ? "" : obligation == 0 && right == 0 ? "-" : $"{payment:N0}")}</td>" +
$"<td>{sum:N0}</td>";
}
var mBuckets = Model.MemberBuckets.Where(b => b.Value.Item2 > 0 || b.Value.Item3 > 0 || b.Value.Item4 > 0).ToList();
var fbVars = mBuckets.Where(b => b.Value.Item2 > 0 || b.Value.Item3 > 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.Item1);
var vtr = mBuckets.Where(b => fbVars.Contains(b.Key) && b.Key.Length > 2).OrderBy(b => b.Value.Item1);
var rem = mBuckets.Where(b => !fbVars.Contains(b.Key)).OrderBy(b => b.Value.Item1);
}
<tr>
<th>Gesamtlieferung lt. gez. GA</th>
@Raw(FormatRow(
0,
Model.Member.BusinessShares * Model.Season.MinKgPerBusinessShare,
Model.Member.BusinessShares * Model.Season.MaxKgPerBusinessShare,
Model.Member.Deliveries.Where(d => d.Year == Model.Season.Year).Sum(d => d.Weight)
))
</tr>
@if (rem.Any()) {
<tr class="subheading"><th colspan="8">Sortenaufteilung:</th></tr>
}
@foreach (var (id, (name, right, obligation, sum, payment)) in rem) {
<tr>
<th>@name</th>
@Raw(FormatRow(1, obligation, right, sum, payment))
</tr>
}
@if (fbs.Any()){
<tr class="subheading"><th colspan="8">Flächenbindungen:</th></tr>
}
@foreach (var (id, (name, right, obligation, sum, payment)) in fbs) {
<tr>
<th>@name</th>
@Raw(FormatRow(2, obligation, right, sum, payment))
</tr>
}
@if (vtr.Any()) {
<tr class="subheading"><th colspan="8">Verträge:</th></tr>
}
@foreach (var (id, (name, right, obligation, sum, payment)) in vtr) {
<tr>
<th>@name</th>
@Raw(FormatRow(2, obligation, right, sum, payment))
</tr>
}
</tbody>
</table>
<div class="text" style="margin-top: 2em;"> <div class="text" style="margin-top: 2em;">
@if (Model.Text != null) { @if (Model.Text != null) {
<p class="comment" style="white-space: pre-wrap; break-inside: avoid;">@Model.Text</p> <p class="comment" style="white-space: pre-wrap; break-inside: avoid;">@Model.Text</p>
+4 -85
View File
@@ -1,52 +1,8 @@
table.delivery-confirmation {
font-size: 10pt;
margin-bottom: 5mm;
}
table.delivery-confirmation thead {
font-size: 8pt;
}
table.delivery-confirmation thead th {
font-weight: normal;
font-style: italic;
}
table.delivery-confirmation td {
overflow: hidden;
white-space: nowrap;
}
table.delivery-confirmation td[rowspan] {
vertical-align: top;
}
table.delivery-confirmation .weight {
text-align: right;
}
table.delivery-confirmation .grad {
text-align: center;
}
table.delivery-confirmation .geb {
font-size: 8pt;
}
table.delivery-confirmation .mod { table.delivery-confirmation .mod {
font-size: 8pt;
padding-left: 5mm; padding-left: 5mm;
} }
table.delivery-confirmation .small {
font-size: 8pt;
}
table.delivery-confirmation tr.new td {
border-top: 0.5pt solid black;
}
table.delivery-confirmation tr:not(.first) { table.delivery-confirmation tr:not(.first) {
break-before: avoid; break-before: avoid;
} }
@@ -60,9 +16,6 @@ table.delivery-confirmation tr.trailing td {
} }
table.delivery-confirmation tr.sum { table.delivery-confirmation tr.sum {
border-top: 0.5pt solid black;
break-before: avoid;
font-weight: bold;
font-size: 12pt; font-size: 12pt;
} }
@@ -70,44 +23,10 @@ table.delivery-confirmation tr.sum td {
padding-top: 1mm; padding-top: 1mm;
} }
table.delivery-confirmation-stats { table.sortenaufteilung {
font-size: 10pt; break-after: avoid;
break-inside: avoid;
} }
table.delivery-confirmation-stats th, table.buckets {
table.delivery-confirmation-stats td { break-before: avoid;
padding: 0.125mm 0;
overflow: hidden;
white-space: nowrap;
}
table.delivery-confirmation-stats tr.subheading th {
text-align: left;
}
table.delivery-confirmation-stats thead th {
font-weight: normal;
font-style: italic;
text-align: right;
font-size: 8pt;
}
table.delivery-confirmation-stats thead th:first-child {
text-align: left;
}
table.delivery-confirmation-stats td {
text-align: right;
}
table.delivery-confirmation-stats tbody th {
font-weight: normal;
font-style: italic;
text-align: left;
}
table.delivery-confirmation-stats tr.subheading th {
font-weight: bold;
border-top: 0.5pt solid black;
} }
+17 -17
View File
@@ -10,9 +10,9 @@
<colgroup> <colgroup>
<col style="width: 25mm;"/> <col style="width: 25mm;"/>
<col style="width: 5mm;"/> <col style="width: 5mm;"/>
<col style="width: 17mm;"/> <col style="width: 15mm;"/>
<col style="width: 10mm;"/>
<col style="width: 8mm;"/> <col style="width: 8mm;"/>
<col style="width: 12mm;"/>
<col style="width: 38mm;"/> <col style="width: 38mm;"/>
<col style="width: 28mm;"/> <col style="width: 28mm;"/>
<col style="width: 10mm;"/> <col style="width: 10mm;"/>
@@ -22,7 +22,7 @@
<thead> <thead>
<tr> <tr>
<th rowspan="2" style="text-align: left;">Lieferschein-Nr.</th> <th rowspan="2" style="text-align: left;">Lieferschein-Nr.</th>
<th rowspan="2">Pos.</th> <th rowspan="2" class="narrow">Pos.</th>
<th rowspan="2">Datum</th> <th rowspan="2">Datum</th>
<th rowspan="2">Zeit</th> <th rowspan="2">Zeit</th>
<th colspan="2" rowspan="2" style="text-align: left;">Mitglied</th> <th colspan="2" rowspan="2" style="text-align: left;">Mitglied</th>
@@ -31,9 +31,9 @@
<th>Gewicht</th> <th>Gewicht</th>
</tr> </tr>
<tr> <tr>
<th>[°Oe]</th> <th class="unit">[°Oe]</th>
<th>[°KMW]</th> <th class="unit narrow">[°KMW]</th>
<th>[kg]</th> <th class="unit">[kg]</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@@ -41,14 +41,14 @@
<tr> <tr>
<td>@p.Delivery.LsNr</td> <td>@p.Delivery.LsNr</td>
<td>@p.DPNr</td> <td>@p.DPNr</td>
<td>@($"{p.Delivery.Date:dd.MM.yyyy}")</td> <td class="small">@($"{p.Delivery.Date:dd.MM.yyyy}")</td>
<td>@($"{p.Delivery.Time:HH:mm}")</td> <td class="small">@($"{p.Delivery.Time:HH:mm}")</td>
<td class="mgnr">@p.Delivery.Member.MgNr</td> <td class="number">@p.Delivery.Member.MgNr</td>
<td>@p.Delivery.Member.AdministrativeName</td> <td class="small">@p.Delivery.Member.AdministrativeName</td>
<td>@p.Variant.Name</td> <td class="small">@p.Variant.Name</td>
<td class="grad">@($"{p.Oe:N0}")</td> <td class="center">@($"{p.Oe:N0}")</td>
<td class="grad">@($"{p.Kmw:N1}")</td> <td class="center">@($"{p.Kmw:N1}")</td>
<td class="weight">@($"{p.Weight:N0}")</td> <td class="number">@($"{p.Weight:N0}")</td>
</tr> </tr>
} }
<tr class="sum"> <tr class="sum">
@@ -58,9 +58,9 @@
} }
<td colspan="2">Gesamt:</td> <td colspan="2">Gesamt:</td>
<td colspan="5">(Teil-)Lieferungen: @($"{Model.Deliveries.DistinctBy(p => p.Delivery).Count():N0}") (@($"{Model.Deliveries.Count():N0}"))</td> <td colspan="5">(Teil-)Lieferungen: @($"{Model.Deliveries.DistinctBy(p => p.Delivery).Count():N0}") (@($"{Model.Deliveries.Count():N0}"))</td>
<td class="grad">@($"{oe:N0}")</td> <td class="center">@($"{oe:N0}")</td>
<td class="grad">@($"{kmw:N1}")</td> <td class="center">@($"{kmw:N1}")</td>
<td class="weight">@($"{Model.Deliveries.Sum(p => p.Weight):N0}")</td> <td class="number">@($"{Model.Deliveries.Sum(p => p.Weight):N0}")</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
-35
View File
@@ -10,38 +10,3 @@ h2 {
font-size: 14pt; font-size: 14pt;
margin-top: 2mm; margin-top: 2mm;
} }
table.journal {
font-size: 10pt;
}
table.journal thead {
font-size: 8pt;
}
table.journal th {
font-weight: normal;
font-style: italic;
}
table.journal td {
overflow: hidden;
white-space: nowrap;
}
table.journal .mgnr,
table.journal .weight {
text-align: right;
}
table.journal .grad {
text-align: center;
}
table.journal tr.sum {
font-weight: bold;
}
table.journal tr.sum td {
border-top: 0.5pt solid black;
}
+1 -1
View File
@@ -7,7 +7,7 @@ namespace Elwig.Documents {
public Delivery Delivery; public Delivery Delivery;
public string? Text; public string? Text;
public Dictionary<string, (string, int, int, int, int)> MemberBuckets; public Dictionary<string, MemberBucket> MemberBuckets;
// 0 - none // 0 - none
// 1 - GA only // 1 - GA only
+18 -69
View File
@@ -5,7 +5,7 @@
<link rel="stylesheet" href="file:///@Raw(Model.DataPath)\resources\DeliveryNote.css" /> <link rel="stylesheet" href="file:///@Raw(Model.DataPath)\resources\DeliveryNote.css" />
<main> <main>
<h1>@Model.Title</h1> <h1>@Model.Title</h1>
<table class="delivery"> <table class="delivery large">
<colgroup> <colgroup>
<col style="width: 10.00mm;"/> <col style="width: 10.00mm;"/>
<col style="width: 21.25mm;"/> <col style="width: 21.25mm;"/>
@@ -19,7 +19,7 @@
</colgroup> </colgroup>
<thead> <thead>
<tr> <tr>
<th class="main" rowspan="2" style="text-align: center;">Pos.</th> <th class="main center narrow" rowspan="2">Pos.</th>
<th class="main" rowspan="2" colspan="2">Sorte</th> <th class="main" rowspan="2" colspan="2">Sorte</th>
<th class="main" rowspan="2" colspan="2">Attribut</th> <th class="main" rowspan="2" colspan="2">Attribut</th>
<th class="main" rowspan="2">Qualitätsstufe</th> <th class="main" rowspan="2">Qualitätsstufe</th>
@@ -27,21 +27,21 @@
<th>Gewicht</th> <th>Gewicht</th>
</tr> </tr>
<tr> <tr>
<th style="font-size: 8pt;">[°Oe]</th> <th class="unit">[°Oe]</th>
<th style="font-size: 8pt;">[°KMW]</th> <th class="unit narrow">[°KMW]</th>
<th style="font-size: 8pt;">[kg]</th> <th class="unit">[kg]</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@foreach (var part in Model.Delivery.Parts.OrderBy(p => p.DPNr)) { @foreach (var part in Model.Delivery.Parts.OrderBy(p => p.DPNr)) {
<tr class="main"> <tr class="main">
<td style="text-align: center;">@part.DPNr</td> <td class="center">@part.DPNr</td>
<td colspan="2">@part.Variant.Name</td> <td colspan="2">@part.Variant.Name</td>
<td colspan="2">@part.Attribute?.Name</td> <td colspan="2">@part.Attribute?.Name</td>
<td>@part.Quality.Name</td> <td>@part.Quality.Name</td>
<td class="narrow" style="text-align: center;">@($"{part.Oe:N0}")</td> <td class="center">@($"{part.Oe:N0}")</td>
<td class="narrow" style="text-align: center;">@($"{part.Kmw:N1}")</td> <td class="center">@($"{part.Kmw:N1}")</td>
<td class="narrow" style="text-align: right;">@($"{part.Weight:N0}")</td> <td class="number">@($"{part.Weight:N0}")</td>
</tr> </tr>
<tr><td></td><td colspan="5" style="white-space: pre;"><i>Herkunft:</i> @part.OriginString</td></tr> <tr><td></td><td colspan="5" style="white-space: pre;"><i>Herkunft:</i> @part.OriginString</td></tr>
@if (part.Modifiers.Count() > 0) { @if (part.Modifiers.Count() > 0) {
@@ -65,9 +65,9 @@
@if (Model.Delivery.Parts.Count() > 1) { @if (Model.Delivery.Parts.Count() > 1) {
<tr class="main sum"> <tr class="main sum">
<td colspan="6">Gesamt:</td> <td colspan="6">Gesamt:</td>
<td style="text-align: center;">@($"{Model.Delivery.Oe:N0}")</td> <td class="center">@($"{Model.Delivery.Oe:N0}")</td>
<td style="text-align: center;">@($"{Model.Delivery.Kmw:N1}")</td> <td class="center">@($"{Model.Delivery.Kmw:N1}")</td>
<td style="text-align: right;">@($"{Model.Delivery.Weight:N0}")</td> <td class="number">@($"{Model.Delivery.Weight:N0}")</td>
</tr> </tr>
} }
</tbody> </tbody>
@@ -76,63 +76,12 @@
<p class="comment">Amerkung zur Lieferung: @Model.Delivery.Comment</p> <p class="comment">Amerkung zur Lieferung: @Model.Delivery.Comment</p>
} }
@if (Model.DisplayStats > 0) { @if (Model.DisplayStats > 0) {
<table class="delivery-note-stats @(Model.DisplayStats > 2 ? "expanded" : "")"> @Raw(Model.PrintBucketTable(
<colgroup> Model.Delivery.Season, Model.MemberBuckets, isTiny: true,
<col style="width: 45mm;"/> filter: Model.DisplayStats > 2 ? null :
<col style="width: 20mm;"/> Model.DisplayStats == 1 ? new List<string>() :
<col style="width: 20mm;"/> Model.Delivery.Parts.Select(p => p.SortId).Distinct().ToList()
<col style="width: 20mm;"/> ))
<col style="width: 20mm;"/>
<col style="width: 20mm;"/>
<col style="width: 20mm;"/>
</colgroup>
<thead>
<tr>
<th><b>Lese @Model.Delivery.Year</b> per @($"{Model.Date:dd.MM.yyyy}") [kg]</th>
<th>Lieferpflicht</th>
<th>Lieferrecht</th>
<th>Unterliefert</th>
<th>Noch lieferbar</th>
<th>Überliefert</th>
<th>Geliefert</th>
</tr>
</thead>
<tbody>
@{
string FormatRow(int obligation, int right, int sum) {
return $"<td>{obligation:N0}</td>" +
$"<td>{right:N0}</td>" +
$"<td>{(sum < obligation ? $"{obligation - sum:N0}" : "-")}</td>" +
$"<td>{(sum >= obligation && sum <= right ? $"{right - sum:N0}" : "-")}</td>" +
$"<td>{(sum > right ? $"{sum - right:N0}" : "-")}</td>" +
$"<td>{sum:N0}</td>";
}
var sortids = Model.Delivery.Parts.Select(p => p.SortId).ToList();
var buckets = Model.MemberBuckets.GroupBy(b => b.Key[..2]).ToDictionary(g => g.Key, g => g.Count());
}
<tr>
<th>Gesamtlieferung lt. gez. GA</th>
@Raw(FormatRow(
Model.Member.BusinessShares * Model.Delivery.Season.MinKgPerBusinessShare,
Model.Member.BusinessShares * Model.Delivery.Season.MaxKgPerBusinessShare,
Model.Member.Deliveries.Where(d => d.Year == Model.Delivery.Year).Sum(d => d.Weight)
))
</tr>
@if (Model.DisplayStats > 1) {
<tr class="subheading">
<th>Flächenbindungen:</th>
</tr>
@foreach (var (id, (name, right, obligation, sum, _)) in Model.MemberBuckets.OrderBy(b => b.Key)) {
if (right > 0 || obligation > 0 || (sum > 0 && buckets[id[..2]] > 1 && !id.EndsWith('_'))) {
<tr class="@(sortids.Contains(id[..2]) ? "" : "optional")">
<th>@name</th>
@Raw(FormatRow(obligation, right, sum))
</tr>
}
}
}
</tbody>
</table>
} }
</main> </main>
@for (int i = 0; i < 2; i++) { @for (int i = 0; i < 2; i++) {
-51
View File
@@ -11,12 +11,6 @@ table.delivery tr:not(.main) {
break-before: avoid; break-before: avoid;
} }
table.delivery th {
font-weight: normal;
font-style: italic;
font-size: 10pt;
}
table.delivery th.main { table.delivery th.main {
text-align: left; text-align: left;
} }
@@ -43,55 +37,10 @@ table.delivery tr.tight:has(+ tr:not(.tight)) td {
padding-bottom: 0.5mm !important; padding-bottom: 0.5mm !important;
} }
table.delivery tr.sum {
border-top: 0.5pt solid black;
break-before: avoid;
}
table.delivery tr.sum td { table.delivery tr.sum td {
padding-top: 1mm; padding-top: 1mm;
} }
table.delivery-note-stats { table.delivery-note-stats {
font-size: 8pt;
break-inside: avoid;
break-after: avoid; break-after: avoid;
} }
table.delivery-note-stats th,
table.delivery-note-stats td {
padding: 0.125mm 0;
}
table.delivery-note-stats:not(.expanded) tr.optional {
display: none;
}
table.delivery-note-stats tr.subheading th {
text-align: left;
}
table.delivery-note-stats.expanded tr.subheading:not(:has(~ tr)),
table.delivery-note-stats tr.subheading:not(:has(~ tr:not(.optional))) {
display: none;
}
table.delivery-note-stats thead th {
font-weight: normal;
font-style: italic;
text-align: right;
}
table.delivery-note-stats thead th:first-child {
text-align: left;
}
table.delivery-note-stats td {
text-align: right;
}
table.delivery-note-stats tbody th {
font-weight: normal;
font-style: italic;
text-align: left;
}
+5
View File
@@ -68,4 +68,9 @@ hr.page-break {
.page::after { .page::after {
content: "Seite " counter(page) " von " counter(pages) !important; content: "Seite " counter(page) " von " counter(pages) !important;
} }
a {
text-decoration: inherit;
color: inherit;
}
} }
+113
View File
@@ -0,0 +1,113 @@
main table {
border-collapse: collapse;
margin-bottom: 10mm;
font-size: 10pt;
}
main table.large {font-size: 12pt;}
main table.tiny {
font-size: 8pt;
margin-bottom: 5mm;
}
main table tr {
break-inside: avoid;
}
main table th,
main table td {
overflow: hidden;
white-space: nowrap;
vertical-align: middle;
padding: 0.5mm 1mm;
font-weight: normal;
}
main table.small th,
main table.small td,
main table.tiny th,
main table.tiny td {
padding: 0.125mm 0.125mm;
}
main table td[rowspan] {
vertical-align: top;
}
main table thead {
font-size: 8pt;
}
main table.large thead {
font-size: 10pt;
}
main table th {
font-style: italic;
}
main table tbody {
}
main table tbody .small {
font-size: 8pt;
}
main table.number td,
main table.number th {
padding-left: 0;
padding-right: 0;
}
main table.number thead th,
main table.number td,
main table tbody td.number {
text-align: right;
}
main table.center tbody td,
main table tbody td.center {
text-align: center;
}
main table tbody th {
text-align: left;
}
main table.cohere {
break-inside: avoid;
}
main table tr.subheading th {
text-align: left;
font-weight: bold;
font-size: 10pt;
}
main table.small tr.subheading th,
main table.tiny tr.subheading th {
font-size: 8pt;
}
main table.number thead tr:first-child th:first-child {
text-align: left;
}
main table tr.sum td {
font-weight: bold;
}
main table tr.sum,
main table tr.new,
main table tr.border {
border-top: 0.5pt solid black;
}
main table tr.sum {
break-before: avoid;
}
main table th.unit {
font-size: 8pt;
}
main table th.narrow {
padding-left: 0;
padding-right: 0;
}
+3 -1
View File
@@ -33,7 +33,9 @@ namespace Elwig.Documents {
Footer = Utils.GenerateFooter("<br/>", " \u00b7 ") Footer = Utils.GenerateFooter("<br/>", " \u00b7 ")
.Item(c.NameFull).NextLine() .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.Address).Item($"{c.Plz} {c.Ort}").Item("Österreich").Item("Tel.", c.PhoneNr).Item("Fax", c.FaxNr).NextLine()
.Item(c.EmailAddress).Item(c.Website).Item("Betriebs-Nr.", c.LfbisNr).Item("UID", c.UstIdNr).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) .Item("BIC", c.Bic).Item("IBAN", c.Iban)
.ToString(); .ToString();
Date = DateTime.Today; Date = DateTime.Today;
+1
View File
@@ -9,6 +9,7 @@
<meta charset="UTF-8"/> <meta charset="UTF-8"/>
<link rel="stylesheet" href="file:///@Raw(Model.DataPath)\resources\Document.css"/> <link rel="stylesheet" href="file:///@Raw(Model.DataPath)\resources\Document.css"/>
<link rel="stylesheet" href="file:///@Raw(Model.DataPath)\resources\Document.Page.css"/> <link rel="stylesheet" href="file:///@Raw(Model.DataPath)\resources\Document.Page.css"/>
<link rel="stylesheet" href="file:///@Raw(Model.DataPath)\resources\Document.Table.css"/>
@if (Model.DoubleSided) { @if (Model.DoubleSided) {
<style> <style>
@@page :left { @@page :left {
+1 -3
View File
@@ -8,14 +8,12 @@ namespace Elwig.Documents {
public Season Season; public Season Season;
public int Year = Utils.CurrentYear; public int Year = Utils.CurrentYear;
public Dictionary<string, (string, int, int, int, int)> MemberBuckets; public Dictionary<string, MemberBucket> MemberBuckets;
public Dictionary<string, int> BucketAreas;
public MemberDataSheet(Member m, AppDbContext ctx) : base($"Stammdatenblatt {m.AdministrativeName}", m) { public MemberDataSheet(Member m, AppDbContext ctx) : base($"Stammdatenblatt {m.AdministrativeName}", m) {
DocumentId = $"Stammdatenblatt {m.MgNr}"; DocumentId = $"Stammdatenblatt {m.MgNr}";
Season = ctx.Seasons.Find(Year) ?? throw new ArgumentException("invalid season"); Season = ctx.Seasons.Find(Year) ?? throw new ArgumentException("invalid season");
MemberBuckets = ctx.GetMemberBuckets(Year, m.MgNr).GetAwaiter().GetResult(); MemberBuckets = ctx.GetMemberBuckets(Year, m.MgNr).GetAwaiter().GetResult();
BucketAreas = ctx.GetMemberBucketAreas(Year, m.MgNr).GetAwaiter().GetResult();
} }
} }
} }
+11 -11
View File
@@ -259,10 +259,10 @@
$"<td>{(mode == 1 ? "" : obligation == 0 ? "-" : $"{obligation:N0}")}</td>" + $"<td>{(mode == 1 ? "" : obligation == 0 ? "-" : $"{obligation:N0}")}</td>" +
$"<td>{(mode == 1 ? "" : right == 0 ? "-" : $"{right:N0}")}</td>"; $"<td>{(mode == 1 ? "" : right == 0 ? "-" : $"{right:N0}")}</td>";
} }
var mBuckets = Model.MemberBuckets.Where(b => b.Value.Item2 > 0 || b.Value.Item3 > 0 || b.Value.Item4 > 0).ToList(); var mBuckets = Model.MemberBuckets.Where(b => b.Value.Right > 0 || b.Value.Obligation > 0 || b.Value.Delivery > 0).ToList();
var fbVars = mBuckets.Where(b => b.Value.Item2 > 0 || b.Value.Item3 > 0).Select(b => b.Key.Replace("_", "")).Order().ToArray(); 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.Item1); 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.Item1); var vtr = mBuckets.Where(b => fbVars.Contains(b.Key) && b.Key.Length > 2).OrderBy(b => b.Value.Name);
} }
<tr> <tr>
<th>Laut gezeichneten GA</th> <th>Laut gezeichneten GA</th>
@@ -271,24 +271,24 @@
0, 0,
Model.Member.BusinessShares * Model.Season.MinKgPerBusinessShare, Model.Member.BusinessShares * Model.Season.MinKgPerBusinessShare,
Model.Member.BusinessShares * Model.Season.MaxKgPerBusinessShare Model.Member.BusinessShares * Model.Season.MaxKgPerBusinessShare
)) ))
</tr> </tr>
@if (fbs.Any()) { @if (fbs.Any()) {
<tr class="subheading"><th colspan="8">Flächenbindungen:</th></tr> <tr class="subheading"><th colspan="8">Flächenbindungen:</th></tr>
} }
@foreach (var (id, (name, right, obligation, _, _)) in fbs) { @foreach (var (id, b) in fbs) {
<tr> <tr>
<th>@name</th> <th>@b.Name</th>
@Raw(FormatRow(2, Model.BucketAreas[id], obligation, right)) @Raw(FormatRow(2, b.Area, b.Obligation, b.Right))
</tr> </tr>
} }
@if (vtr.Any()) { @if (vtr.Any()) {
<tr class="subheading"><th colspan="8">Verträge:</th></tr> <tr class="subheading"><th colspan="8">Verträge:</th></tr>
} }
@foreach (var (id, (name, right, obligation, _, _)) in vtr) { @foreach (var (id, b) in vtr) {
<tr> <tr>
<th>@name</th> <th>@b.Name</th>
@Raw(FormatRow(2, Model.BucketAreas[id], obligation, right)) @Raw(FormatRow(2, b.Area, b.Obligation, b.Right))
</tr> </tr>
} }
</tbody> </tbody>
+9 -9
View File
@@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<TargetFramework>net7.0-windows</TargetFramework> <TargetFramework>net8.0-windows</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<UseWPF>true</UseWPF> <UseWPF>true</UseWPF>
<PreserveCompilationContext>true</PreserveCompilationContext> <PreserveCompilationContext>true</PreserveCompilationContext>
@@ -22,16 +22,16 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Extended.Wpf.Toolkit" Version="4.5.1" /> <PackageReference Include="Extended.Wpf.Toolkit" Version="4.5.1" />
<PackageReference Include="ini-parser" Version="2.5.2" /> <PackageReference Include="LinqKit" Version="1.2.5" />
<PackageReference Include="LinqKit" Version="1.2.4" /> <PackageReference Include="Microsoft.AspNetCore.Razor.Language" Version="6.0.25" />
<PackageReference Include="Microsoft.AspNetCore.Razor.Language" Version="6.0.24" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="8.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="7.0.13" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.13" /> <PackageReference Include="Microsoft.Extensions.Configuration.Ini" Version="8.0.0" />
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.2088.41" /> <PackageReference Include="Microsoft.Web.WebView2" Version="1.0.2151.40" />
<PackageReference Include="RazorLight" Version="2.3.1" /> <PackageReference Include="RazorLight" Version="2.3.1" />
<PackageReference Include="ScottPlot.WPF" Version="4.1.68" /> <PackageReference Include="ScottPlot.WPF" Version="4.1.68" />
<PackageReference Include="System.IO.Ports" Version="7.0.0" /> <PackageReference Include="System.IO.Ports" Version="8.0.0" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="7.0.0" /> <PackageReference Include="System.Text.Encoding.CodePages" Version="8.0.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>
+50 -48
View File
@@ -12,6 +12,10 @@ using System.Collections.Generic;
using Elwig.Models.Dtos; using Elwig.Models.Dtos;
namespace Elwig.Helpers { namespace Elwig.Helpers {
public record struct AreaComBucket(int Area, int Obligation, int Right);
public record struct MemberBucket(string Name, int Area, int Obligation, int Right, int Delivery, int DeliveryStrict, int Payment);
public class AppDbContext : DbContext { public class AppDbContext : DbContext {
public DbSet<Country> Countries { get; private set; } public DbSet<Country> Countries { get; private set; }
@@ -60,10 +64,10 @@ namespace Elwig.Helpers {
public static string ConnectionString => $"Data Source=\"{App.Config.DatabaseFile}\"; Foreign Keys=True; Mode=ReadWrite; Cache=Default"; public static string ConnectionString => $"Data Source=\"{App.Config.DatabaseFile}\"; Foreign Keys=True; Mode=ReadWrite; Cache=Default";
private readonly Dictionary<int, Dictionary<int, Dictionary<string, (int, int)>>> _memberRightsAndObligations = new(); private readonly Dictionary<int, Dictionary<int, Dictionary<string, AreaComBucket>>> _memberAreaCommitmentBuckets = new();
private readonly Dictionary<int, Dictionary<int, Dictionary<string, int>>> _memberDeliveryBuckets = new(); private readonly Dictionary<int, Dictionary<int, Dictionary<string, int>>> _memberDeliveryBuckets = new();
private readonly Dictionary<int, Dictionary<int, Dictionary<string, int>>> _memberDeliveryBucketsStrict = new();
private readonly Dictionary<int, Dictionary<int, Dictionary<string, int>>> _memberPaymentBuckets = new(); private readonly Dictionary<int, Dictionary<int, Dictionary<string, int>>> _memberPaymentBuckets = new();
private readonly Dictionary<int, Dictionary<int, Dictionary<string, int>>> _memberBucketAreas = new();
public AppDbContext() { public AppDbContext() {
if (App.Config.DatabaseLog != null) { if (App.Config.DatabaseLog != null) {
@@ -203,22 +207,22 @@ namespace Elwig.Helpers {
} }
} }
private async Task FetchMemberRightsAndObligations(int year, SqliteConnection? cnx = null) { private async Task FetchMemberAreaCommitmentBuckets(int year, SqliteConnection? cnx = null) {
var ownCnx = cnx == null; var ownCnx = cnx == null;
cnx ??= await ConnectAsync(); cnx ??= await ConnectAsync();
var buckets = new Dictionary<int, Dictionary<string, (int, int)>>(); var buckets = new Dictionary<int, Dictionary<string, AreaComBucket>>();
using (var cmd = cnx.CreateCommand()) { using (var cmd = cnx.CreateCommand()) {
cmd.CommandText = $"SELECT mgnr, bucket, min_kg, max_kg FROM v_area_commitment_bucket WHERE year = {year}"; cmd.CommandText = $"SELECT mgnr, bucket, area, min_kg, max_kg FROM v_area_commitment_bucket WHERE year = {year}";
using var reader = await cmd.ExecuteReaderAsync(); using var reader = await cmd.ExecuteReaderAsync();
while (await reader.ReadAsync()) { while (await reader.ReadAsync()) {
var mgnr = reader.GetInt32(0); var mgnr = reader.GetInt32(0);
var vtrgid = reader.GetString(1); var vtrgid = reader.GetString(1);
if (!buckets.ContainsKey(mgnr)) buckets[mgnr] = new(); if (!buckets.ContainsKey(mgnr)) buckets[mgnr] = new();
buckets[mgnr][vtrgid] = (reader.GetInt32(3), reader.GetInt32(2)); buckets[mgnr][vtrgid] = new(reader.GetInt32(2), reader.GetInt32(3), reader.GetInt32(4));
} }
} }
if (ownCnx) await cnx.DisposeAsync(); if (ownCnx) await cnx.DisposeAsync();
_memberRightsAndObligations[year] = buckets; _memberAreaCommitmentBuckets[year] = buckets;
} }
private async Task FetchMemberDeliveryBuckets(int year, SqliteConnection? cnx = null) { private async Task FetchMemberDeliveryBuckets(int year, SqliteConnection? cnx = null) {
@@ -239,6 +243,24 @@ namespace Elwig.Helpers {
_memberDeliveryBuckets[year] = buckets; _memberDeliveryBuckets[year] = buckets;
} }
private async Task FetchMemberDeliveryBucketsStrict(int year, SqliteConnection? cnx = null) {
var ownCnx = cnx == null;
cnx ??= await ConnectAsync();
var buckets = new Dictionary<int, Dictionary<string, int>>();
using (var cmd = cnx.CreateCommand()) {
cmd.CommandText = $"SELECT mgnr, bucket, weight FROM v_delivery_bucket_strict WHERE year = {year}";
using var reader = await cmd.ExecuteReaderAsync();
while (await reader.ReadAsync()) {
var mgnr = reader.GetInt32(0);
var bucket = reader.GetString(1);
if (!buckets.ContainsKey(mgnr)) buckets[mgnr] = new();
buckets[mgnr][bucket] = reader.GetInt32(2);
}
}
if (ownCnx) await cnx.DisposeAsync();
_memberDeliveryBucketsStrict[year] = buckets;
}
private async Task FetchMemberPaymentBuckets(int year, SqliteConnection? cnx = null) { private async Task FetchMemberPaymentBuckets(int year, SqliteConnection? cnx = null) {
var ownCnx = cnx == null; var ownCnx = cnx == null;
cnx ??= await ConnectAsync(); cnx ??= await ConnectAsync();
@@ -257,32 +279,10 @@ namespace Elwig.Helpers {
_memberPaymentBuckets[year] = buckets; _memberPaymentBuckets[year] = buckets;
} }
private async Task FetchMemberBucketAreas(int year, SqliteConnection? cnx = null) { public async Task<Dictionary<string, AreaComBucket>> GetMemberAreaCommitmentBuckets(int year, int mgnr, SqliteConnection? cnx = null) {
var ownCnx = cnx == null; if (!_memberAreaCommitmentBuckets.ContainsKey(year))
cnx ??= await ConnectAsync(); await FetchMemberAreaCommitmentBuckets(year, cnx);
var buckets = new Dictionary<int, Dictionary<string, int>>(); return _memberAreaCommitmentBuckets[year].GetValueOrDefault(mgnr, new());
using (var cmd = cnx.CreateCommand()) {
cmd.CommandText = $"SELECT mgnr, bucket, area FROM v_area_commitment_bucket_strict WHERE year = {year}";
using var reader = await cmd.ExecuteReaderAsync();
while (await reader.ReadAsync()) {
var mgnr = reader.GetInt32(0);
var bucket = reader.GetString(1);
var v = reader.GetInt32(2);
if (!buckets.ContainsKey(mgnr)) buckets[mgnr] = new();
buckets[mgnr][bucket] = v;
if (bucket.Length > 2) {
buckets[mgnr][bucket[..2]] = buckets[mgnr].GetValueOrDefault(bucket[..2], 0) + v;
}
}
}
if (ownCnx) await cnx.DisposeAsync();
_memberBucketAreas[year] = buckets;
}
public async Task<Dictionary<string, (int, int)>> GetMemberRightsAndObligations(int year, int mgnr, SqliteConnection? cnx = null) {
if (!_memberRightsAndObligations.ContainsKey(year))
await FetchMemberRightsAndObligations(year, cnx);
return _memberRightsAndObligations[year].GetValueOrDefault(mgnr, new());
} }
public async Task<Dictionary<string, int>> GetMemberDeliveryBuckets(int year, int mgnr, SqliteConnection? cnx = null) { public async Task<Dictionary<string, int>> GetMemberDeliveryBuckets(int year, int mgnr, SqliteConnection? cnx = null) {
@@ -291,37 +291,39 @@ namespace Elwig.Helpers {
return _memberDeliveryBuckets[year].GetValueOrDefault(mgnr, new()); return _memberDeliveryBuckets[year].GetValueOrDefault(mgnr, new());
} }
public async Task<Dictionary<string, int>> GetMemberDeliveryBucketsStrict(int year, int mgnr, SqliteConnection? cnx = null) {
if (!_memberDeliveryBucketsStrict.ContainsKey(year))
await FetchMemberDeliveryBucketsStrict(year, cnx);
return _memberDeliveryBucketsStrict[year].GetValueOrDefault(mgnr, new());
}
public async Task<Dictionary<string, int>> GetMemberPaymentBuckets(int year, int mgnr, SqliteConnection? cnx = null) { public async Task<Dictionary<string, int>> GetMemberPaymentBuckets(int year, int mgnr, SqliteConnection? cnx = null) {
if (!_memberPaymentBuckets.ContainsKey(year)) if (!_memberPaymentBuckets.ContainsKey(year))
await FetchMemberPaymentBuckets(year, cnx); await FetchMemberPaymentBuckets(year, cnx);
return _memberPaymentBuckets[year].GetValueOrDefault(mgnr, new()); return _memberPaymentBuckets[year].GetValueOrDefault(mgnr, new());
} }
public async Task<Dictionary<string, int>> GetMemberBucketAreas(int year, int mgnr, SqliteConnection? cnx = null) { public async Task<Dictionary<string, MemberBucket>> GetMemberBuckets(int year, int mgnr, SqliteConnection? cnx = null) {
if (!_memberBucketAreas.ContainsKey(year))
await FetchMemberBucketAreas(year, cnx);
return _memberBucketAreas[year].GetValueOrDefault(mgnr, new());
}
public async Task<Dictionary<string, (string, int, int, int, int)>> GetMemberBuckets(int year, int mgnr, SqliteConnection? cnx = null) {
var ownCnx = cnx == null; var ownCnx = cnx == null;
cnx ??= await ConnectAsync(); cnx ??= await ConnectAsync();
var rightsAndObligations = await GetMemberRightsAndObligations(year, mgnr, cnx); var rightsAndObligations = await GetMemberAreaCommitmentBuckets(year, mgnr, cnx);
var deliveryBuckets = await GetMemberDeliveryBuckets(year, mgnr, cnx); var deliveryBuckets = await GetMemberDeliveryBuckets(year, mgnr, cnx);
var deliveryBucketsStrict = await GetMemberDeliveryBucketsStrict(year, mgnr, cnx);
var paymentBuckets = await GetMemberPaymentBuckets(year, mgnr, cnx); var paymentBuckets = await GetMemberPaymentBuckets(year, mgnr, cnx);
if (ownCnx) await cnx.DisposeAsync(); if (ownCnx) await cnx.DisposeAsync();
var buckets = new Dictionary<string, (string, int, int, int, int)>(); var buckets = new Dictionary<string, MemberBucket>();
foreach (var id in rightsAndObligations.Keys.Union(deliveryBuckets.Keys).Union(paymentBuckets.Keys)) { foreach (var id in rightsAndObligations.Keys.Union(deliveryBuckets.Keys).Union(paymentBuckets.Keys)) {
var variety = await WineVarieties.FindAsync(id[..2]); var variety = await WineVarieties.FindAsync(id[..2]);
var attrIds = id[2..]; var attribute = await WineAttributes.FindAsync(id[2..]);
var attrs = await WineAttributes.Where(a => attrIds.Contains(a.AttrId)).ToListAsync(); var name = (variety?.Name ?? "") + (id[2..] == "_" ? " (kein Qual.Wein)" : attribute != null ? $" ({attribute})" : "");
var name = (variety?.Name ?? "") + (attrIds == "_" ? " (kein Qual.Wein)" : attrs.Count > 0 ? $" ({string.Join(" / ", attrs.Select(a => a.Name))})" : ""); buckets[id] = new(
buckets[id] = (
name, name,
rightsAndObligations.GetValueOrDefault(id).Item1, rightsAndObligations.GetValueOrDefault(id).Area,
rightsAndObligations.GetValueOrDefault(id).Item2, rightsAndObligations.GetValueOrDefault(id).Obligation,
rightsAndObligations.GetValueOrDefault(id).Right,
deliveryBuckets.GetValueOrDefault(id), deliveryBuckets.GetValueOrDefault(id),
deliveryBucketsStrict.GetValueOrDefault(id),
paymentBuckets.GetValueOrDefault(id) paymentBuckets.GetValueOrDefault(id)
); );
} }
+23 -1
View File
@@ -5,12 +5,13 @@ using System.Windows;
namespace Elwig.Helpers { namespace Elwig.Helpers {
public static class AppDbUpdater { public static class AppDbUpdater {
public static readonly int RequiredSchemaVersion = 9; public static readonly int RequiredSchemaVersion = 10;
private static int _versionOffset = 0; private static int _versionOffset = 0;
private static readonly Action<SqliteConnection>[] _updaters = new[] { private static readonly Action<SqliteConnection>[] _updaters = new[] {
UpdateDbSchema_1_To_2, UpdateDbSchema_2_To_3, UpdateDbSchema_3_To_4, UpdateDbSchema_4_To_5, UpdateDbSchema_1_To_2, UpdateDbSchema_2_To_3, UpdateDbSchema_3_To_4, UpdateDbSchema_4_To_5,
UpdateDbSchema_5_To_6, UpdateDBSchema_6_To_7, UpdateDbSchema_7_To_8, UpdateDbSchema_8_To_9, UpdateDbSchema_5_To_6, UpdateDBSchema_6_To_7, UpdateDbSchema_7_To_8, UpdateDbSchema_8_To_9,
UpdateDbSchema_9_To_10,
}; };
private static void ExecuteNonQuery(SqliteConnection cnx, string sql) { private static void ExecuteNonQuery(SqliteConnection cnx, string sql) {
@@ -714,5 +715,26 @@ namespace Elwig.Helpers {
END; END;
"""); """);
} }
private static void UpdateDbSchema_9_To_10(SqliteConnection cnx) {
ExecuteNonQuery(cnx, "UPDATE wine_quality_level SET min_kmw = 10.6 WHERE qualid = 'RSW'");
ExecuteNonQuery(cnx, "DROP VIEW v_area_commitment_bucket");
ExecuteNonQuery(cnx, """
CREATE VIEW v_area_commitment_bucket AS
SELECT year, mgnr, bucket, area, min_kg, max_kg
FROM v_area_commitment_bucket_strict
WHERE attrid IS NOT NULL
UNION ALL
SELECT b.year, b.mgnr, b.sortid,
SUM(b.area) AS area,
SUM(b.min_kg) AS min_kg,
SUM(b.upper_max_kg) AS max_kg
FROM v_area_commitment_bucket_strict b
LEFT JOIN wine_attribute a ON a.attrid = b.attrid
WHERE a.strict IS NULL OR a.strict = FALSE
GROUP BY b.year, b.mgnr, b.sortid
ORDER BY year, mgnr, bucket;
""");
}
} }
} }
+5 -5
View File
@@ -41,7 +41,7 @@ namespace Elwig.Helpers.Billing {
var attrVals = Context.WineAttributes.ToDictionary(a => a.AttrId, a => (a.IsStrict, a.FillLower)); var attrVals = Context.WineAttributes.ToDictionary(a => a.AttrId, a => (a.IsStrict, a.FillLower));
var attrForced = attrVals.Where(a => a.Value.IsStrict && a.Value.FillLower == 0).Select(a => a.Key).ToArray(); var attrForced = attrVals.Where(a => a.Value.IsStrict && a.Value.FillLower == 0).Select(a => a.Key).ToArray();
using var cnx = await AppDbContext.ConnectAsync(); using var cnx = await AppDbContext.ConnectAsync();
await Context.GetMemberRightsAndObligations(Year, 0, cnx); await Context.GetMemberAreaCommitmentBuckets(Year, 0, cnx);
var inserts = new List<(int, int, int, string, int)>(); var inserts = new List<(int, int, int, string, int)>();
var deliveries = new List<(int, int, int, string, int, double, string, string?, string[], bool?)>(); var deliveries = new List<(int, int, int, string, int, double, string, string?, string[], bool?)>();
@@ -66,11 +66,11 @@ namespace Elwig.Helpers.Billing {
} }
int lastMgNr = 0; int lastMgNr = 0;
Dictionary<string, (int, int)>? rightsAndObligations = null; Dictionary<string, AreaComBucket>? rightsAndObligations = null;
Dictionary<string, int> used = new(); Dictionary<string, int> used = new();
foreach (var (mgnr, did, dpnr, sortid, weight, kmw, qualid, attrid, modifiers, gebunden) in deliveries) { foreach (var (mgnr, did, dpnr, sortid, weight, kmw, qualid, attrid, modifiers, gebunden) in deliveries) {
if (lastMgNr != mgnr) { if (lastMgNr != mgnr) {
rightsAndObligations = await Context.GetMemberRightsAndObligations(Year, mgnr); rightsAndObligations = await Context.GetMemberAreaCommitmentBuckets(Year, mgnr);
used = new(); used = new();
} }
if ((honorGebunden && gebunden == false) || if ((honorGebunden && gebunden == false) ||
@@ -94,8 +94,8 @@ namespace Elwig.Helpers.Billing {
if (rightsAndObligations.ContainsKey(key)) { if (rightsAndObligations.ContainsKey(key)) {
int i = (c == 0) ? 1 : 2; int i = (c == 0) ? 1 : 2;
var u = used.GetValueOrDefault(key, 0); var u = used.GetValueOrDefault(key, 0);
var vr = Math.Max(0, Math.Min(rightsAndObligations[key].Item1 - u, w)); var vr = Math.Max(0, Math.Min(rightsAndObligations[key].Right - u, w));
var vo = Math.Max(0, Math.Min(rightsAndObligations[key].Item2 - u, w)); var vo = Math.Max(0, Math.Min(rightsAndObligations[key].Obligation - u, w));
var v = (attributes.Length == c || attributes.Select(a => !attrVals[a].IsStrict ? 2 : attrVals[a].FillLower).Min() == 2) ? vr : vo; var v = (attributes.Length == c || attributes.Select(a => !attrVals[a].IsStrict ? 2 : attrVals[a].FillLower).Min() == 2) ? vr : vo;
used[key] = u + v; used[key] = u + v;
if (key.Length > 2 && !isStrict) used[key[..2]] = used.GetValueOrDefault(key[..2], 0) + v; if (key.Length > 2 && !isStrict) used[key[..2]] = used.GetValueOrDefault(key[..2], 0) + v;
+17 -50
View File
@@ -1,8 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using IniParser; using Microsoft.Extensions.Configuration;
using IniParser.Model;
namespace Elwig.Helpers { namespace Elwig.Helpers {
public class Config { public class Config {
@@ -13,7 +12,8 @@ namespace Elwig.Helpers {
public string? DatabaseLog = null; public string? DatabaseLog = null;
public string? Branch = null; public string? Branch = null;
public IList<string?[]> Scales; public IList<string?[]> Scales;
private readonly List<string?[]> ScaleList = new(); private readonly List<string?[]> ScaleList = [];
private static readonly string[] trueValues = ["1", "true", "yes", "on"];
public Config(string filename) { public Config(string filename) {
FileName = filename; FileName = filename;
@@ -22,57 +22,24 @@ namespace Elwig.Helpers {
} }
public void Read() { public void Read() {
var parser = new FileIniDataParser(); var config = new ConfigurationBuilder().AddIniFile(FileName).Build();
IniData? ini = null;
try {
ini = parser.ReadFile(FileName, Utils.UTF8);
} catch {}
if (ini == null || !ini.TryGetKey("database.file", out string db)) { DatabaseFile = Utils.GetAbsolutePath(config["database:file"] ?? "database.sqlite3", App.DataPath);
DatabaseFile = App.DataPath + "database.sqlite3"; var log = config["database:log"];
} else if (db.Length > 1 && (db[1] == ':' || db[0] == '/' || db[0] == '\\')) { DatabaseLog = log != null ? Utils.GetAbsolutePath(log, App.DataPath) : null;
DatabaseFile = db; Branch = config["general:branch"];
} else { Debug = trueValues.Contains(config["general:debug"]?.ToLower());
DatabaseFile = App.DataPath + db;
}
if (ini == null || !ini.TryGetKey("database.log", out string log)) {
DatabaseLog = null;
} else if (log.Length > 1 && (log[1] == ':' || log[0] == '/' || log[0] == '\\')) {
DatabaseLog = log;
} else {
DatabaseLog = App.DataPath + log;
}
if (ini == null || !ini.TryGetKey("general.branch", out string branch)) {
Branch = null;
} else {
Branch = branch;
}
if (ini == null || !ini.TryGetKey("general.debug", out string debug)) {
Debug = false;
} else {
debug = debug.ToLower();
Debug = debug == "1" || debug == "true" || debug == "yes" || debug == "on";
}
var scales = config.AsEnumerable().Where(i => i.Key.StartsWith("scale.")).GroupBy(i => i.Key.Split(':')[0][6..]).Select(i => i.Key);
ScaleList.Clear(); ScaleList.Clear();
Scales = ScaleList; Scales = ScaleList;
if (ini != null) { foreach (var s in scales) {
foreach (var s in ini.Sections.Where(s => s.SectionName.StartsWith("scale."))) { string? scaleLog = config[$"scale.{s}:log"];
string? scaleLog = null; if (scaleLog != null) scaleLog = Utils.GetAbsolutePath(scaleLog, App.DataPath);
if (s.Keys["log"] != null) { ScaleList.Add([
scaleLog = s.Keys["log"]; s, config[$"scale.{s}:type"], config[$"scale.{s}:model"], config[$"scale.{s}:connection"],
if (scaleLog.Length <= 1 || (scaleLog[1] != ':' && scaleLog[0] != '/' && scaleLog[0] != '\\')) { config[$"scale.{s}:empty"], config[$"scale.{s}:filling"], config[$"scale.{s}:limit"], scaleLog
scaleLog = App.DataPath + scaleLog; ]);
}
}
ScaleList.Add(new string?[] {
s.SectionName[6..], s.Keys["type"], s.Keys["model"], s.Keys["connection"],
s.Keys["empty"], s.Keys["filling"], s.Keys["limit"], scaleLog
});
}
} }
} }
+5
View File
@@ -11,6 +11,7 @@ using Elwig.Dialogs;
using System.Text; using System.Text;
using System.Numerics; using System.Numerics;
using Elwig.Models.Entities; using Elwig.Models.Entities;
using System.IO;
namespace Elwig.Helpers { namespace Elwig.Helpers {
public static partial class Utils { public static partial class Utils {
@@ -345,5 +346,9 @@ namespace Elwig.Helpers {
} }
return output.OrderByDescending(l => l.Count()); return output.OrderByDescending(l => l.Count());
} }
public static string GetAbsolutePath(string path, string basePath) {
return (path.Length > 1 && (path[1] == ':' || path[0] == '/' || path[0] == '\\')) ? Path.Combine(basePath, path) : path;
}
} }
} }
+7 -4
View File
@@ -427,8 +427,9 @@ namespace Elwig.Windows {
} }
protected void TextBox_TextChanged(object sender, RoutedEventArgs? evt) { protected void TextBox_TextChanged(object sender, RoutedEventArgs? evt) {
var input = (TextBox)sender; var input = (Control)sender;
if (SenderIsRequired(input) && input.Text.Length == 0) { var tb = input as TextBox ?? (input as UnitTextBox)?.TextBox;
if (SenderIsRequired(input) && tb?.Text.Length == 0) {
ValidateInput(input, false); ValidateInput(input, false);
ControlUtils.SetInputInvalid(input); ControlUtils.SetInputInvalid(input);
} else { } else {
@@ -472,11 +473,13 @@ namespace Elwig.Windows {
} }
protected void IntegerInput_TextChanged(object sender, TextChangedEventArgs evt) { protected void IntegerInput_TextChanged(object sender, TextChangedEventArgs evt) {
InputTextChanged((TextBox)sender, Validator.CheckInteger); // FIXME
InputTextChanged((sender as UnitTextBox)?.TextBox ?? (TextBox)sender, Validator.CheckInteger);
} }
protected void DecimalInput_TextChanged(object sender, TextChangedEventArgs evt) { protected void DecimalInput_TextChanged(object sender, TextChangedEventArgs evt) {
InputTextChanged((TextBox)sender, Validator.CheckDecimal); // FIXME
InputTextChanged((sender as UnitTextBox)?.TextBox ?? (TextBox)sender, Validator.CheckDecimal);
} }
protected void PartialDateInput_TextChanged(object sender, TextChangedEventArgs evt) { protected void PartialDateInput_TextChanged(object sender, TextChangedEventArgs evt) {
+6 -3
View File
@@ -1,4 +1,5 @@
<local:AdministrationWindow x:Class="Elwig.Windows.MemberAdminWindow" <local:AdministrationWindow
x:Class="Elwig.Windows.MemberAdminWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
@@ -53,8 +54,10 @@
<MenuItem Header="Drucken"> <MenuItem Header="Drucken">
<MenuItem x:Name="Menu_Print_Letterhead" Header="Briefkopf drucken" <MenuItem x:Name="Menu_Print_Letterhead" Header="Briefkopf drucken"
Click="Menu_Print_Letterhead_Click"/> Click="Menu_Print_Letterhead_Click"/>
<MenuItem x:Name="Menu_Show_Memberdata" Header="Stammdatenblatt anzeigen" Click="Menu_Show_Memberdata_Click"/> <MenuItem x:Name="Menu_Show_MemberDataSheet" Header="Stammdatenblatt anzeigen" IsEnabled="False" Tag="Print"
<MenuItem x:Name="Menu_Print_Memberdata" Header="Stammdatenblatt drucken" Click="Menu_Print_Memberdata_Click"/> Click="Menu_Show_MemberDataSheet_Click"/>
<MenuItem x:Name="Menu_Print_MemberDataSheet" Header="Stammdatenblatt drucken" IsEnabled="False" Tag="Print"
Click="Menu_Print_MemberDataSheet_Click"/>
<MenuItem Header="Briefköpfe drucken"> <MenuItem Header="Briefköpfe drucken">
<MenuItem x:Name="Menu_Print_Letterheads_MgNr" Header="nach MgNr. sortiert" IsEnabled="False" Tag="Print" <MenuItem x:Name="Menu_Print_Letterheads_MgNr" Header="nach MgNr. sortiert" IsEnabled="False" Tag="Print"
Click="Menu_Print_Letterheads_MgNr_Click"/> Click="Menu_Print_Letterheads_MgNr_Click"/>
+18 -17
View File
@@ -15,29 +15,29 @@ using Elwig.Documents;
namespace Elwig.Windows { namespace Elwig.Windows {
public partial class MemberAdminWindow : AdministrationWindow { public partial class MemberAdminWindow : AdministrationWindow {
private List<string> TextFilter = new(); private List<string> TextFilter = [];
private readonly RoutedCommand CtrlF = new(); private readonly RoutedCommand CtrlF = new();
private readonly (ComboBox, TextBox, TextBox)[] PhoneNrInputs; private readonly (ComboBox, TextBox, TextBox)[] PhoneNrInputs;
private static ObservableCollection<KeyValuePair<string, string>> PhoneNrTypes { get; set; } = new() { private static ObservableCollection<KeyValuePair<string, string>> PhoneNrTypes { get; set; } = [
new("landline", "Tel.-Nr. (Festnetz)"), new("landline", "Tel.-Nr. (Festnetz)"),
new("mobile", "Tel.-Nr. (mobil)"), new("mobile", "Tel.-Nr. (mobil)"),
new("fax", "Fax-Nr."), new("fax", "Fax-Nr."),
}; ];
public MemberAdminWindow() { public MemberAdminWindow() {
InitializeComponent(); InitializeComponent();
CtrlF.InputGestures.Add(new KeyGesture(Key.F, ModifierKeys.Control)); CtrlF.InputGestures.Add(new KeyGesture(Key.F, ModifierKeys.Control));
CommandBindings.Add(new CommandBinding(CtrlF, FocusSearchInput)); CommandBindings.Add(new CommandBinding(CtrlF, FocusSearchInput));
ExemptInputs = new Control[] { ExemptInputs = [
SearchInput, ActiveMemberInput, MemberList, SearchInput, ActiveMemberInput, MemberList,
}; ];
RequiredInputs = new Control[] { RequiredInputs = [
MgNrInput, GivenNameInput, FamilyNameInput, MgNrInput, GivenNameInput, FamilyNameInput,
AddressInput, PlzInput, OrtInput, BillingOrtInput, AddressInput, PlzInput, OrtInput, BillingOrtInput,
BusinessSharesInput, BranchInput, DefaultKgInput BusinessSharesInput, BranchInput, DefaultKgInput
}; ];
PhoneNrInputs = new (ComboBox, TextBox, TextBox)[] { PhoneNrInputs = [
(PhoneNr1TypeInput, PhoneNr1Input, PhoneNr1CommentInput), (PhoneNr1TypeInput, PhoneNr1Input, PhoneNr1CommentInput),
(PhoneNr2TypeInput, PhoneNr2Input, PhoneNr2CommentInput), (PhoneNr2TypeInput, PhoneNr2Input, PhoneNr2CommentInput),
(PhoneNr3TypeInput, PhoneNr3Input, PhoneNr3CommentInput), (PhoneNr3TypeInput, PhoneNr3Input, PhoneNr3CommentInput),
@@ -47,7 +47,7 @@ namespace Elwig.Windows {
(PhoneNr7TypeInput, PhoneNr7Input, PhoneNr7CommentInput), (PhoneNr7TypeInput, PhoneNr7Input, PhoneNr7CommentInput),
(PhoneNr8TypeInput, PhoneNr8Input, PhoneNr8CommentInput), (PhoneNr8TypeInput, PhoneNr8Input, PhoneNr8CommentInput),
(PhoneNr9TypeInput, PhoneNr9Input, PhoneNr9CommentInput), (PhoneNr9TypeInput, PhoneNr9Input, PhoneNr9CommentInput),
}; ];
foreach (var input in PhoneNrInputs) input.Item1.ItemsSource = PhoneNrTypes; foreach (var input in PhoneNrInputs) input.Item1.ItemsSource = PhoneNrTypes;
InitializeDelayTimer(SearchInput, SearchInput_TextChanged); InitializeDelayTimer(SearchInput, SearchInput_TextChanged);
@@ -57,8 +57,9 @@ namespace Elwig.Windows {
private void Window_Loaded(object sender, RoutedEventArgs evt) { private void Window_Loaded(object sender, RoutedEventArgs evt) {
Menu_Print_Letterheads_MgNr.IsEnabled = App.IsPrintingReady; Menu_Print_Letterheads_MgNr.IsEnabled = App.IsPrintingReady;
Menu_Print_Letterheads_Name.IsEnabled = App.IsPrintingReady; Menu_Print_Letterheads_Name.IsEnabled = App.IsPrintingReady;
Menu_Show_Memberdata.IsEnabled = App.IsPrintingReady; Menu_Print_Letterheads_Plz.IsEnabled = App.IsPrintingReady;
Menu_Print_Memberdata.IsEnabled = App.IsPrintingReady; Menu_Show_MemberDataSheet.IsEnabled = App.IsPrintingReady;
Menu_Print_MemberDataSheet.IsEnabled = App.IsPrintingReady;
ActiveMemberInput.IsChecked = true; ActiveMemberInput.IsChecked = true;
UpdatePhoneNrInputVisibility(); UpdatePhoneNrInputVisibility();
@@ -339,7 +340,7 @@ namespace Elwig.Windows {
await PrintLetterheads(2); await PrintLetterheads(2);
} }
private async void Menu_Print_Memberdata_Click(object sender, RoutedEventArgs evt) { private async void Menu_Print_MemberDataSheet_Click(object sender, RoutedEventArgs evt) {
if (MemberList.SelectedItem is not Member m) if (MemberList.SelectedItem is not Member m)
return; return;
Mouse.OverrideCursor = Cursors.AppStarting; Mouse.OverrideCursor = Cursors.AppStarting;
@@ -353,7 +354,7 @@ namespace Elwig.Windows {
} }
} }
private async void Menu_Show_Memberdata_Click(object sender, RoutedEventArgs evt) { private async void Menu_Show_MemberDataSheet_Click(object sender, RoutedEventArgs evt) {
if (MemberList.SelectedItem is not Member m) if (MemberList.SelectedItem is not Member m)
return; return;
Mouse.OverrideCursor = Cursors.AppStarting; Mouse.OverrideCursor = Cursors.AppStarting;
@@ -649,8 +650,8 @@ namespace Elwig.Windows {
Menu_Member_SendEmail.IsEnabled = m.EmailAddresses.Count > 0; Menu_Member_SendEmail.IsEnabled = m.EmailAddresses.Count > 0;
Menu_Print_Letterhead.IsEnabled = true; Menu_Print_Letterhead.IsEnabled = true;
Menu_Show_Memberdata.IsEnabled = true; Menu_Show_MemberDataSheet.IsEnabled = true;
Menu_Print_Memberdata.IsEnabled = true; Menu_Print_MemberDataSheet.IsEnabled = true;
FinishInputFilling(); FinishInputFilling();
} }
@@ -658,8 +659,8 @@ namespace Elwig.Windows {
new protected void ClearInputs(bool validate = false) { new protected void ClearInputs(bool validate = false) {
Menu_Member_SendEmail.IsEnabled = false; Menu_Member_SendEmail.IsEnabled = false;
Menu_Print_Letterhead.IsEnabled = false; Menu_Print_Letterhead.IsEnabled = false;
Menu_Show_Memberdata.IsEnabled = false; Menu_Show_MemberDataSheet.IsEnabled = false;
Menu_Print_Memberdata.IsEnabled = false; Menu_Print_MemberDataSheet.IsEnabled = false;
StatusDeliveriesLastSeason.Text = $"Lieferungen ({Utils.CurrentLastSeason - 1}): -"; StatusDeliveriesLastSeason.Text = $"Lieferungen ({Utils.CurrentLastSeason - 1}): -";
StatusDeliveriesThisSeason.Text = $"Lieferungen ({Utils.CurrentLastSeason}): -"; StatusDeliveriesThisSeason.Text = $"Lieferungen ({Utils.CurrentLastSeason}): -";
StatusAreaCommitment.Text = "Gebundene Fläche: -"; StatusAreaCommitment.Text = "Gebundene Fläche: -";
+1 -1
View File
@@ -1,7 +1,7 @@
[general] [general]
; Only needed, if more than one branch is stored in database ; Only needed, if more than one branch is stored in database
branch = Zweigstelle ;branch = Zweigstelle
;debug = true ;debug = true
[database] [database]
+1 -1
View File
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net7.0-windows</TargetFramework> <TargetFramework>net8.0-windows</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>