DeliveryConfirmation: Add Statistics table
This commit is contained in:
@ -93,7 +93,60 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<!-- TODO add Gesamtlieferung tabelle -->
|
<table class="delivery-confirmation-stats">
|
||||||
|
<colgroup>
|
||||||
|
<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.Year</b> per @($"{Model.Date:dd.MM.yyyy}") [kg]</th>
|
||||||
|
<th>Lieferpflicht</th>
|
||||||
|
<th>Lieferrecht</th>
|
||||||
|
<th>Unterliefert<br/>(bzgl. Zuget.)</th>
|
||||||
|
<th>Noch zu liefern<br/>(bzgl. Gelft.)</th>
|
||||||
|
<th>Überliefert<br/>(bzgl. Gelft.)</th>
|
||||||
|
<th>Zugeteilt</th>
|
||||||
|
<th>Geliefert</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@{
|
||||||
|
string FormatRow(int obligation, int right, int sum, int? payment = null) {
|
||||||
|
var isGa = payment == null;
|
||||||
|
payment ??= sum;
|
||||||
|
return $"<td>{obligation:N0}</td>" +
|
||||||
|
$"<td>{right:N0}</td>" +
|
||||||
|
$"<td>{(payment < obligation ? $"<b>{obligation - payment:N0}\x3c/b>" : "-")}</td>" +
|
||||||
|
$"<td>{(sum >= obligation && sum <= right ? $"{right - sum:N0}" : "-")}</td>" +
|
||||||
|
$"<td>{(obligation == 0 && right == 0 ? "-" : (sum > right ? ((isGa ? "<b>" : "") + $"{sum - right:N0}" + (isGa ? "</b>" : "")) : "-"))}</td>" +
|
||||||
|
$"<td>{(obligation == 0 && right == 0 ? "-" : $"{payment:N0}")}</td>" +
|
||||||
|
$"<td>{sum:N0}</td>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<tr>
|
||||||
|
<th>Gesamtlieferung lt. gez. GA</th>
|
||||||
|
@Raw(FormatRow(Model.Member.DeliveryObligation, Model.Member.DeliveryRight, Model.Member.Deliveries.Where(d => d.Year == Model.Year).Sum(d => d.Weight)))
|
||||||
|
</tr>
|
||||||
|
<tr class="subheading">
|
||||||
|
<th>Flächenbindungen:</th>
|
||||||
|
</tr>
|
||||||
|
@foreach (var (id, (name, right, obligation, sum, payment)) in Model.MemberBins.OrderBy(b => b.Key)) {
|
||||||
|
if (right > 0 || obligation > 0 || sum > 0) {
|
||||||
|
<tr>
|
||||||
|
<th>@name</th>
|
||||||
|
@Raw(FormatRow(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>
|
||||||
|
@ -10,6 +10,7 @@ namespace Elwig.Documents {
|
|||||||
public int Year;
|
public int Year;
|
||||||
public IEnumerable<DeliveryPart> Deliveries;
|
public IEnumerable<DeliveryPart> Deliveries;
|
||||||
public string? Text = App.Client.TextDeliveryConfirmation;
|
public string? Text = App.Client.TextDeliveryConfirmation;
|
||||||
|
public Dictionary<string, (string, int, int, int, int)> MemberBins;
|
||||||
|
|
||||||
public DeliveryConfirmation(AppDbContext ctx, int year, Member m) :
|
public DeliveryConfirmation(AppDbContext ctx, int year, Member m) :
|
||||||
base($"Anlieferungsbestätigung {year} – {((IAddress?)m.BillingAddress ?? m).Name}", m) {
|
base($"Anlieferungsbestätigung {year} – {((IAddress?)m.BillingAddress ?? m).Name}", m) {
|
||||||
@ -29,6 +30,7 @@ namespace Elwig.Documents {
|
|||||||
v.kmw DESC, v.lsnr, v.dpnr
|
v.kmw DESC, v.lsnr, v.dpnr
|
||||||
""")
|
""")
|
||||||
.ToList();
|
.ToList();
|
||||||
|
MemberBins = ctx.GetMemberBins(Year, m.MgNr).GetAwaiter().GetResult();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,8 +76,7 @@
|
|||||||
<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) {
|
||||||
<div id="delivery-stats">
|
<table class="delivery-note-stats @(Model.DisplayStats > 2 ? "expanded" : "")">
|
||||||
<table class="delivery-stats @(Model.DisplayStats > 2 ? "expanded" : "")">
|
|
||||||
<colgroup>
|
<colgroup>
|
||||||
<col style="width: 45mm;"/>
|
<col style="width: 45mm;"/>
|
||||||
<col style="width: 20mm;"/>
|
<col style="width: 20mm;"/>
|
||||||
@ -109,7 +108,7 @@
|
|||||||
$"<td>{sum:N0}</td>";
|
$"<td>{sum:N0}</td>";
|
||||||
}
|
}
|
||||||
var sortids = Model.Delivery.Parts.Select(p => p.SortId).ToList();
|
var sortids = Model.Delivery.Parts.Select(p => p.SortId).ToList();
|
||||||
var bins = Model.MemberBins.GroupBy(b => b.Item1[..2]).ToDictionary(g => g.Key, g => g.Count());
|
var bins = Model.MemberBins.GroupBy(b => b.Key[..2]).ToDictionary(g => g.Key, g => g.Count());
|
||||||
}
|
}
|
||||||
<tr>
|
<tr>
|
||||||
<th>Gesamtlieferung lt. gez. GA</th>
|
<th>Gesamtlieferung lt. gez. GA</th>
|
||||||
@ -119,7 +118,7 @@
|
|||||||
<tr class="subheading">
|
<tr class="subheading">
|
||||||
<th>Flächenbindungen:</th>
|
<th>Flächenbindungen:</th>
|
||||||
</tr>
|
</tr>
|
||||||
@foreach (var (id, name, right, obligation, sum) in Model.MemberBins.OrderBy(b => b.Item1)) {
|
@foreach (var (id, (name, right, obligation, sum, _)) in Model.MemberBins.OrderBy(b => b.Key)) {
|
||||||
if (right > 0 || obligation > 0 || (sum > 0 && bins[id[..2]] > 1 && !id.EndsWith('_'))) {
|
if (right > 0 || obligation > 0 || (sum > 0 && bins[id[..2]] > 1 && !id.EndsWith('_'))) {
|
||||||
<tr class="@(sortids.Contains(id[..2]) ? "" : "optional")">
|
<tr class="@(sortids.Contains(id[..2]) ? "" : "optional")">
|
||||||
<th>@name</th>
|
<th>@name</th>
|
||||||
@ -130,7 +129,6 @@
|
|||||||
}
|
}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
|
||||||
}
|
}
|
||||||
</main>
|
</main>
|
||||||
@for (int i = 0; i < 2; i++) {
|
@for (int i = 0; i < 2; i++) {
|
||||||
|
@ -7,7 +7,7 @@ namespace Elwig.Documents {
|
|||||||
|
|
||||||
public Delivery Delivery;
|
public Delivery Delivery;
|
||||||
public string? Text;
|
public string? Text;
|
||||||
public IEnumerable<(string, string, int, int, int)> MemberBins;
|
public Dictionary<string, (string, int, int, int, int)> MemberBins;
|
||||||
|
|
||||||
// 0 - none
|
// 0 - none
|
||||||
// 1 - GA only
|
// 1 - GA only
|
||||||
@ -27,7 +27,7 @@ namespace Elwig.Documents {
|
|||||||
$"</tbody></table>";
|
$"</tbody></table>";
|
||||||
Text = App.Client.TextDeliveryNote;
|
Text = App.Client.TextDeliveryNote;
|
||||||
DocumentId = d.LsNr;
|
DocumentId = d.LsNr;
|
||||||
MemberBins = ctx.GetMemberBins(d.Member, d.Year).GetAwaiter().GetResult();
|
MemberBins = ctx.GetMemberBins(d.Year, d.Member.MgNr).GetAwaiter().GetResult();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
|
|
||||||
table.delivery-confirmation {
|
table.delivery-confirmation {
|
||||||
font-size: 10pt;
|
font-size: 10pt;
|
||||||
|
margin-bottom: 5mm;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.delivery-confirmation thead {
|
table.delivery-confirmation thead {
|
||||||
@ -68,3 +69,38 @@ table.delivery-confirmation tr.sum {
|
|||||||
table.delivery-confirmation tr.sum td {
|
table.delivery-confirmation tr.sum td {
|
||||||
padding-top: 1mm;
|
padding-top: 1mm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
table.delivery-confirmation-stats {
|
||||||
|
font-size: 10pt;
|
||||||
|
break-inside: avoid;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.delivery-confirmation-stats th,
|
||||||
|
table.delivery-confirmation-stats td {
|
||||||
|
padding: 0.125mm 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
@ -52,45 +52,45 @@ table.delivery tr.sum td {
|
|||||||
padding-top: 1mm;
|
padding-top: 1mm;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.delivery-stats {
|
table.delivery-note-stats {
|
||||||
font-size: 8pt;
|
font-size: 8pt;
|
||||||
break-inside: avoid;
|
break-inside: avoid;
|
||||||
break-after: avoid;
|
break-after: avoid;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.delivery-stats th,
|
table.delivery-note-stats th,
|
||||||
table.delivery-stats td {
|
table.delivery-note-stats td {
|
||||||
padding: 0.125mm 0;
|
padding: 0.125mm 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.delivery-stats:not(.expanded) tr.optional {
|
table.delivery-note-stats:not(.expanded) tr.optional {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.delivery-stats tr.subheading th {
|
table.delivery-note-stats tr.subheading th {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.delivery-stats.expanded tr.subheading:not(:has(~ tr)),
|
table.delivery-note-stats.expanded tr.subheading:not(:has(~ tr)),
|
||||||
table.delivery-stats tr.subheading:not(:has(~ tr:not(.optional))) {
|
table.delivery-note-stats tr.subheading:not(:has(~ tr:not(.optional))) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.delivery-stats thead th {
|
table.delivery-note-stats thead th {
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.delivery-stats thead th:first-child {
|
table.delivery-note-stats thead th:first-child {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.delivery-stats td {
|
table.delivery-note-stats td {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.delivery-stats tbody th {
|
table.delivery-note-stats tbody th {
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
|
@ -53,6 +53,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, int>>> _memberDeliveryBins = new();
|
||||||
|
private readonly Dictionary<int, Dictionary<int, Dictionary<string, int>>> _memberPaymentBins = new();
|
||||||
|
|
||||||
public AppDbContext() {
|
public AppDbContext() {
|
||||||
if (App.Config.DatabaseLog != null) {
|
if (App.Config.DatabaseLog != null) {
|
||||||
try {
|
try {
|
||||||
@ -206,26 +210,111 @@ namespace Elwig.Helpers {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<(string, string, int, int, int)>> GetMemberBins(Member m, int year) {
|
private async Task FetchMemberRightsAndObligations(int year, SqliteConnection? cnx = null) {
|
||||||
using var cnx = await ConnectAsync();
|
var ownCnx = cnx == null;
|
||||||
var (rights, obligations) = await Billing.Billing.GetMemberRightsObligations(cnx, year, m.MgNr);
|
cnx ??= await ConnectAsync();
|
||||||
var bins = await Billing.Billing.GetMemberBinWeights(m.MgNr, year, cnx);
|
var bins = new Dictionary<int, Dictionary<string, (int, int)>>();
|
||||||
|
using (var cmd = cnx.CreateCommand()) {
|
||||||
var list = new List<(string, string, int, int, int)>();
|
cmd.CommandText = $"""
|
||||||
foreach (var id in rights.Keys.Union(obligations.Keys).Union(bins.Keys)) {
|
SELECT mgnr, t.vtrgid,
|
||||||
var s = await WineVarieties.FindAsync(id[..2]);
|
ROUND(SUM(COALESCE(area * min_kg_per_ha, 0)) / 10000.0) AS min_kg,
|
||||||
var attrIds = id[2..];
|
ROUND(SUM(COALESCE(area * max_kg_per_ha, 0)) / 10000.0) AS max_kg
|
||||||
var a = await WineAttributes.Where(a => attrIds.Contains(a.AttrId)).ToListAsync();
|
FROM area_commitment c
|
||||||
var name = (s?.Name ?? "") + (a.Count > 0 ? $" ({string.Join(" / ", a.Select(a => a.Name))})" : "");
|
JOIN area_commitment_type t ON t.vtrgid = c.vtrgid
|
||||||
list.Add((
|
WHERE (year_from IS NULL OR year_from <= {year}) AND
|
||||||
id, name,
|
(year_to IS NULL OR year_to >= {year})
|
||||||
rights.TryGetValue(id, out var v1) ? v1 : 0,
|
GROUP BY mgnr, t.vtrgid
|
||||||
obligations.TryGetValue(id, out var v2) ? v2 : 0,
|
ORDER BY LENGTH(t.vtrgid) DESC, t.vtrgid
|
||||||
bins.TryGetValue(id, out var v3) ? v3 : 0
|
""";
|
||||||
));
|
using var reader = await cmd.ExecuteReaderAsync();
|
||||||
|
while (await reader.ReadAsync()) {
|
||||||
|
var mgnr = reader.GetInt32(0);
|
||||||
|
var vtrgid = reader.GetString(1);
|
||||||
|
if (!bins.ContainsKey(mgnr)) bins[mgnr] = new();
|
||||||
|
bins[mgnr][vtrgid] = (reader.GetInt32(3), reader.GetInt32(2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ownCnx) await cnx.DisposeAsync();
|
||||||
|
_memberRightsAndObligations[year] = bins;
|
||||||
}
|
}
|
||||||
|
|
||||||
return list;
|
private async Task FetchMemberDeliveryBins(int year, SqliteConnection? cnx = null) {
|
||||||
|
var ownCnx = cnx == null;
|
||||||
|
cnx ??= await ConnectAsync();
|
||||||
|
var bins = new Dictionary<int, Dictionary<string, int>>();
|
||||||
|
using (var cmd = cnx.CreateCommand()) {
|
||||||
|
cmd.CommandText = $"SELECT mgnr, bin, weight FROM v_delivery_bin WHERE year = {year}";
|
||||||
|
using var reader = await cmd.ExecuteReaderAsync();
|
||||||
|
while (await reader.ReadAsync()) {
|
||||||
|
var mgnr = reader.GetInt32(0);
|
||||||
|
var bin = reader.GetString(1);
|
||||||
|
if (!bins.ContainsKey(mgnr)) bins[mgnr] = new();
|
||||||
|
bins[mgnr][bin] = reader.GetInt32(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ownCnx) await cnx.DisposeAsync();
|
||||||
|
_memberDeliveryBins[year] = bins;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task FetchMemberPaymentBins(int year, SqliteConnection? cnx = null) {
|
||||||
|
var ownCnx = cnx == null;
|
||||||
|
cnx ??= await ConnectAsync();
|
||||||
|
var bins = new Dictionary<int, Dictionary<string, int>>();
|
||||||
|
using (var cmd = cnx.CreateCommand()) {
|
||||||
|
cmd.CommandText = $"SELECT mgnr, bin, weight FROM v_payment_bin WHERE year = {year}";
|
||||||
|
using var reader = await cmd.ExecuteReaderAsync();
|
||||||
|
while (await reader.ReadAsync()) {
|
||||||
|
var mgnr = reader.GetInt32(0);
|
||||||
|
var bin = reader.GetString(1);
|
||||||
|
if (!bins.ContainsKey(mgnr)) bins[mgnr] = new();
|
||||||
|
bins[mgnr][bin] = reader.GetInt32(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ownCnx) await cnx.DisposeAsync();
|
||||||
|
_memberPaymentBins[year] = bins;
|
||||||
|
}
|
||||||
|
|
||||||
|
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>> GetMemberDeliveryBins(int year, int mgnr, SqliteConnection? cnx = null) {
|
||||||
|
if (!_memberDeliveryBins.ContainsKey(year))
|
||||||
|
await FetchMemberDeliveryBins(year, cnx);
|
||||||
|
return _memberDeliveryBins[year].GetValueOrDefault(mgnr, new());
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Dictionary<string, int>> GetMemberPaymentBins(int year, int mgnr, SqliteConnection? cnx = null) {
|
||||||
|
if (!_memberPaymentBins.ContainsKey(year))
|
||||||
|
await FetchMemberPaymentBins(year, cnx);
|
||||||
|
return _memberPaymentBins[year].GetValueOrDefault(mgnr, new());
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Dictionary<string, (string, int, int, int, int)>> GetMemberBins(int year, int mgnr, SqliteConnection? cnx = null) {
|
||||||
|
var ownCnx = cnx == null;
|
||||||
|
cnx ??= await ConnectAsync();
|
||||||
|
var rightsAndObligations = await GetMemberRightsAndObligations(year, mgnr, cnx);
|
||||||
|
var deliveryBins = await GetMemberDeliveryBins(year, mgnr, cnx);
|
||||||
|
var paymentBins = await GetMemberPaymentBins(year, mgnr, cnx);
|
||||||
|
if (ownCnx) await cnx.DisposeAsync();
|
||||||
|
|
||||||
|
var bins = new Dictionary<string, (string, int, int, int, int)>();
|
||||||
|
foreach (var id in rightsAndObligations.Keys.Union(deliveryBins.Keys).Union(paymentBins.Keys)) {
|
||||||
|
var variety = await WineVarieties.FindAsync(id[..2]);
|
||||||
|
var attrIds = id[2..];
|
||||||
|
var attrs = await WineAttributes.Where(a => attrIds.Contains(a.AttrId)).ToListAsync();
|
||||||
|
var name = (variety?.Name ?? "") + (attrs.Count > 0 ? $" ({string.Join(" / ", attrs.Select(a => a.Name))})" : "");
|
||||||
|
bins[id] = (
|
||||||
|
name,
|
||||||
|
rightsAndObligations.GetValueOrDefault(id).Item1,
|
||||||
|
rightsAndObligations.GetValueOrDefault(id).Item2,
|
||||||
|
deliveryBins.GetValueOrDefault(id),
|
||||||
|
paymentBins.GetValueOrDefault(id)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return bins;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ namespace Elwig.Helpers.Billing {
|
|||||||
var attrVals = Context.WineAttributes.ToDictionary(a => a.AttrId, a => a.FillLowerBins);
|
var attrVals = Context.WineAttributes.ToDictionary(a => a.AttrId, a => a.FillLowerBins);
|
||||||
var attrForced = attrVals.Where(a => a.Value == 0).Select(a => a.Key).ToArray();
|
var attrForced = attrVals.Where(a => a.Value == 0).Select(a => a.Key).ToArray();
|
||||||
using var cnx = await AppDbContext.ConnectAsync();
|
using var cnx = await AppDbContext.ConnectAsync();
|
||||||
var memberOblRig = await GetMemberRightsObligations(cnx, Year);
|
await Context.GetMemberRightsAndObligations(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?)>();
|
||||||
@ -68,19 +68,15 @@ namespace Elwig.Helpers.Billing {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int lastMgNr = 0;
|
int lastMgNr = 0;
|
||||||
Dictionary<string, int>? rights = null;
|
Dictionary<string, (int, int)>? rightsAndObligations = null;
|
||||||
Dictionary<string, int>? obligations = null;
|
|
||||||
Dictionary<string, int> used = new();
|
Dictionary<string, int> used = new();
|
||||||
foreach (var (mgnr, did, dpnr, sortid, weight, kmw, qualid, attributes, modifiers, gebunden) in deliveries) {
|
foreach (var (mgnr, did, dpnr, sortid, weight, kmw, qualid, attributes, modifiers, gebunden) in deliveries) {
|
||||||
if (lastMgNr != mgnr) {
|
if (lastMgNr != mgnr) {
|
||||||
var or = memberOblRig.GetValueOrDefault(mgnr, (new(), new()));
|
rightsAndObligations = await Context.GetMemberRightsAndObligations(Year, mgnr);
|
||||||
rights = or.Item2;
|
|
||||||
obligations = or.Item1;
|
|
||||||
used = new();
|
used = new();
|
||||||
}
|
}
|
||||||
if ((honorGebunden && gebunden == false) ||
|
if ((honorGebunden && gebunden == false) ||
|
||||||
obligations == null || rights == null ||
|
rightsAndObligations == null || rightsAndObligations.Count == 0 ||
|
||||||
obligations.Count == 0 || rights.Count == 0 ||
|
|
||||||
qualid == "WEI" || qualid == "RSW" || qualid == "LDW")
|
qualid == "WEI" || qualid == "RSW" || qualid == "LDW")
|
||||||
{
|
{
|
||||||
// Explizit als ungebunden markiert,
|
// Explizit als ungebunden markiert,
|
||||||
@ -98,7 +94,7 @@ namespace Elwig.Helpers.Billing {
|
|||||||
foreach (var p in Utils.Permutate(attributes, attributes.Intersect(attrForced))) {
|
foreach (var p in Utils.Permutate(attributes, attributes.Intersect(attrForced))) {
|
||||||
var c = p.Count();
|
var c = p.Count();
|
||||||
var key = sortid + string.Join("", p);
|
var key = sortid + string.Join("", p);
|
||||||
if (rights.ContainsKey(key) && obligations.ContainsKey(key)) {
|
if (rightsAndObligations.ContainsKey(key)) {
|
||||||
int i = 4;
|
int i = 4;
|
||||||
if (c == 1) {
|
if (c == 1) {
|
||||||
i = (p.ElementAt(0) == attributes[0]) ? 2 : 3;
|
i = (p.ElementAt(0) == attributes[0]) ? 2 : 3;
|
||||||
@ -106,8 +102,8 @@ namespace Elwig.Helpers.Billing {
|
|||||||
i = 1;
|
i = 1;
|
||||||
}
|
}
|
||||||
var u = used.GetValueOrDefault(key, 0);
|
var u = used.GetValueOrDefault(key, 0);
|
||||||
var vr = Math.Max(0, Math.Min(rights[key] - u, w));
|
var vr = Math.Max(0, Math.Min(rightsAndObligations[key].Item1 - u, w));
|
||||||
var vo = Math.Max(0, Math.Min(obligations[key] - u, w));
|
var vo = Math.Max(0, Math.Min(rightsAndObligations[key].Item2 - u, w));
|
||||||
var v = (c == 0 || p.Select(a => attrVals[a]).Min() == 2) ? vr : vo;
|
var v = (c == 0 || p.Select(a => attrVals[a]).Min() == 2) ? vr : vo;
|
||||||
used[key] = u + v;
|
used[key] = u + v;
|
||||||
inserts.Add((did, dpnr, i, key[2..], v));
|
inserts.Add((did, dpnr, i, key[2..], v));
|
||||||
@ -131,58 +127,5 @@ namespace Elwig.Helpers.Billing {
|
|||||||
|
|
||||||
// TODO add second round to avoid under deliveries
|
// TODO add second round to avoid under deliveries
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<Dictionary<int, (Dictionary<string, int>, Dictionary<string, int>)>> GetMemberRightsObligations(SqliteConnection cnx, int year, int? mgnr = null) {
|
|
||||||
var members = new Dictionary<int, (Dictionary<string, int>, Dictionary<string, int>)>();
|
|
||||||
|
|
||||||
using var cmd = cnx.CreateCommand();
|
|
||||||
cmd.CommandText = $"""
|
|
||||||
SELECT mgnr, t.vtrgid,
|
|
||||||
SUM(COALESCE(area * min_kg_per_ha, 0)) / 10000 AS min_kg,
|
|
||||||
SUM(COALESCE(area * max_kg_per_ha, 0)) / 10000 AS max_kg
|
|
||||||
FROM area_commitment c
|
|
||||||
JOIN area_commitment_type t ON t.vtrgid = c.vtrgid
|
|
||||||
WHERE ({(mgnr == null ? "NULL" : mgnr)} IS NULL OR mgnr = {(mgnr == null ? "NULL" : mgnr)}) AND
|
|
||||||
(year_from IS NULL OR year_from <= {year}) AND
|
|
||||||
(year_to IS NULL OR year_to >= {year})
|
|
||||||
GROUP BY mgnr, t.vtrgid
|
|
||||||
ORDER BY LENGTH(t.vtrgid) DESC, t.vtrgid
|
|
||||||
""";
|
|
||||||
|
|
||||||
var reader = await cmd.ExecuteReaderAsync();
|
|
||||||
while (await reader.ReadAsync()) {
|
|
||||||
var m = reader.GetInt32(0);
|
|
||||||
var vtrgid = reader.GetString(1);
|
|
||||||
if (!members.ContainsKey(m)) members[m] = (new(), new());
|
|
||||||
members[m].Item1[vtrgid] = reader.GetInt32(2);
|
|
||||||
members[m].Item2[vtrgid] = reader.GetInt32(3);
|
|
||||||
}
|
|
||||||
|
|
||||||
return members;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task<(Dictionary<string, int>, Dictionary<string, int>)> GetMemberRightsObligations(SqliteConnection cnx, int year, int mgnr) {
|
|
||||||
var members = await GetMemberRightsObligations(cnx, year, (int?)mgnr);
|
|
||||||
return members.GetValueOrDefault(mgnr, (new(), new()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task<Dictionary<string, int>> GetMemberBinWeights(int mgnr, int year, SqliteConnection cnx) {
|
|
||||||
var bins = new Dictionary<string, int>();
|
|
||||||
|
|
||||||
using var cmd = cnx.CreateCommand();
|
|
||||||
cmd.CommandText = $"""
|
|
||||||
SELECT bin, weight
|
|
||||||
FROM v_delivery_bin
|
|
||||||
WHERE (year, mgnr) = ({year}, {mgnr})
|
|
||||||
""";
|
|
||||||
|
|
||||||
var reader = await cmd.ExecuteReaderAsync();
|
|
||||||
while (await reader.ReadAsync()) {
|
|
||||||
var bin = reader.GetString(0);
|
|
||||||
bins[bin] = reader.GetInt32(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return bins;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user