[#58] PaymentVariantSummary: Add 'attributslos gebunden' columns
All checks were successful
Test / Run tests (push) Successful in 1m45s

This commit is contained in:
2025-05-23 15:39:44 +02:00
parent 0f3ce39f35
commit d71abdf2fd
4 changed files with 64 additions and 37 deletions

View File

@ -111,8 +111,8 @@
<td class="number"><span class="fleft">@Model.CurrencySymbol</span>@($"{Math.Abs(payed):N2}")</td> <td class="number"><span class="fleft">@Model.CurrencySymbol</span>@($"{Math.Abs(payed):N2}")</td>
@{ @{
var weiRows = Model.Data.Rows.Where(r => r.QualityLevel == "Wein"); var weiRows = Model.Data.Rows.Where(r => r.QualityLevel == "Wein");
var minWei = weiRows.Min(r => r.Ungeb.Price); var minWei = weiRows.Min(r => r.Ungeb.MinPrice);
var maxWei = weiRows.Max(r => r.Ungeb.Price); var maxWei = weiRows.Max(r => r.Ungeb.MaxPrice);
} }
<th class="lborder tborder">Preis (abgewertet):</th> <th class="lborder tborder">Preis (abgewertet):</th>
<td colspan="2" class="center tborder">@(minWei != maxWei ? $"{minWei:N4}{maxWei:N4}" : $"{minWei:N4}") @Model.CurrencySymbol/kg</td> <td colspan="2" class="center tborder">@(minWei != maxWei ? $"{minWei:N4}{maxWei:N4}" : $"{minWei:N4}") @Model.CurrencySymbol/kg</td>
@ -123,8 +123,8 @@
<td class="number tborder"><span class="fleft">@Model.CurrencySymbol</span>@($"{netSum:N2}")</td> <td class="number tborder"><span class="fleft">@Model.CurrencySymbol</span>@($"{netSum:N2}")</td>
@{ @{
var quwRows = Model.Data.Rows.Where(r => r.QualityLevel != "Wein"); var quwRows = Model.Data.Rows.Where(r => r.QualityLevel != "Wein");
var minPrice = quwRows.Min(r => r.Ungeb.Price); var minPrice = quwRows.Min(r => r.Ungeb.MinPrice);
var maxPrice = quwRows.Max(r => r.Ungeb.Price); var maxPrice = quwRows.Max(r => r.Ungeb.MaxPrice);
} }
<th class="lborder">Preis (ungeb., nicht abgew.):</th> <th class="lborder">Preis (ungeb., nicht abgew.):</th>
<td colspan="2" class="center">@(minPrice != maxPrice ? $"{minPrice:N4}{maxPrice:N4}" : $"{minPrice:N4}") @Model.CurrencySymbol/kg</td> <td colspan="2" class="center">@(minPrice != maxPrice ? $"{minPrice:N4}{maxPrice:N4}" : $"{minPrice:N4}") @Model.CurrencySymbol/kg</td>
@ -135,8 +135,8 @@
<td class="number"><span class="fleft">@Model.CurrencySymbol</span>@($"{Math.Abs(vat):N2}")</td> <td class="number"><span class="fleft">@Model.CurrencySymbol</span>@($"{Math.Abs(vat):N2}")</td>
@{ @{
var gebRows = Model.Data.Rows var gebRows = Model.Data.Rows
.Where(r => r.Geb.Price != null && r.Ungeb.Price != null) .Where(r => r.Geb.MaxPrice != null && r.Ungeb.MinPrice != null)
.Select(r => r.Geb.Price - r.Ungeb.Price); .Select(r => r.Geb.MaxPrice - r.Ungeb.MinPrice);
var minGeb = gebRows.Min(); var minGeb = gebRows.Min();
var maxGeb = gebRows.Max(); var maxGeb = gebRows.Max();
} }
@ -219,19 +219,22 @@
</table> </table>
<table class="payment-variant-data"> <table class="payment-variant-data">
<colgroup> <colgroup>
<col style="width: 30mm;"/>
<col style="width: 20mm;"/>
<col style="width: 25mm;"/>
<col style="width: 20mm;"/>
<col style="width: 25mm;"/>
<col style="width: 20mm;"/>
<col style="width: 25mm;"/> <col style="width: 25mm;"/>
<col style="width: 19mm;"/>
<col style="width: 18mm;"/>
<col style="width: 15mm;"/>
<col style="width: 18mm;"/>
<col style="width: 15mm;"/>
<col style="width: 18mm;"/>
<col style="width: 15mm;"/>
<col style="width: 22mm;"/>
</colgroup> </colgroup>
<thead> <thead>
<tr> <tr>
<th rowspan="2" style="text-align: left;">Qualitätsstufe</th> <th rowspan="2" style="text-align: left;">Qualitätsstufe</th>
<th>Gradation</th> <th>Gradation</th>
<th colspan="2">ungebunden</th> <th colspan="2">ungebunden</th>
<th colspan="2">attributlos gebunden</th>
<th colspan="2">gebunden</th> <th colspan="2">gebunden</th>
<th>Gesamt</th> <th>Gesamt</th>
</tr> </tr>
@ -241,6 +244,8 @@
<th>[@(Model.CurrencySymbol)/kg]</th> <th>[@(Model.CurrencySymbol)/kg]</th>
<th>[kg]</th> <th>[kg]</th>
<th>[@(Model.CurrencySymbol)/kg]</th> <th>[@(Model.CurrencySymbol)/kg]</th>
<th>[kg]</th>
<th>[@(Model.CurrencySymbol)/kg]</th>
<th>[@(Model.CurrencySymbol)]</th> <th>[@(Model.CurrencySymbol)]</th>
</tr> </tr>
</thead> </thead>
@ -258,6 +263,8 @@
<th colspan="2">@hdr</th> <th colspan="2">@hdr</th>
<td class="number">@($"{rows.Sum(r => r.Ungeb.Weight):N0}")</td> <td class="number">@($"{rows.Sum(r => r.Ungeb.Weight):N0}")</td>
<td></td> <td></td>
<td class="number">@($"{rows.Sum(r => r.LowGeb.Weight):N0}")</td>
<td></td>
<td class="number">@($"{rows.Sum(r => r.Geb.Weight):N0}")</td> <td class="number">@($"{rows.Sum(r => r.Geb.Weight):N0}")</td>
<td></td> <td></td>
<td class="number">@($"{rows.Sum(r => r.Amount):N2}")</td> <td class="number">@($"{rows.Sum(r => r.Amount):N2}")</td>
@ -267,9 +274,11 @@
<td>@(row.QualityLevel)</td> <td>@(row.QualityLevel)</td>
<td class="center">@($"{row.Oe:N0}")</td> <td class="center">@($"{row.Oe:N0}")</td>
<td class="number">@(row.Ungeb.Weight != 0 ? $"{row.Ungeb.Weight:N0}" : "-")</td> <td class="number">@(row.Ungeb.Weight != 0 ? $"{row.Ungeb.Weight:N0}" : "-")</td>
<td class="number">@(row.Ungeb.Price != null ? $"{row.Ungeb.Price:N4}" : "-")</td> <td class="number">@(row.Ungeb.MaxPrice != null ? $"{row.Ungeb.MaxPrice:N4}" : "-")</td>
<td class="number">@(row.LowGeb.Weight != 0 ? $"{row.LowGeb.Weight:N0}" : "-")</td>
<td class="number">@(row.LowGeb.MaxPrice != null ? $"{row.LowGeb.MaxPrice:N4}" : "-")</td>
<td class="number">@(row.Geb.Weight != 0 ? $"{row.Geb.Weight:N0}" : "-")</td> <td class="number">@(row.Geb.Weight != 0 ? $"{row.Geb.Weight:N0}" : "-")</td>
<td class="number">@(row.Geb.Price != null ? $"{row.Geb.Price:N4}" : "-")</td> <td class="number">@(row.Geb.MaxPrice != null ? $"{row.Geb.MaxPrice:N4}" : "-")</td>
<td class="number">@($"{row.Amount:N2}")</td> <td class="number">@($"{row.Amount:N2}")</td>
</tr> </tr>
lastHdr = hdr; lastHdr = hdr;

View File

@ -317,7 +317,7 @@ namespace Elwig.Helpers.Export {
c = $"<{ct} office:value-type=\"string\" calcext:value-type=\"string\"{add}><text:p>{SecurityElement.Escape(data.ToString())}</text:p></{ct}>"; c = $"<{ct} office:value-type=\"string\" calcext:value-type=\"string\"{add}><text:p>{SecurityElement.Escape(data.ToString())}</text:p></{ct}>";
} }
return $" {c}\r\n" + (colSpan > 1 ? $" <table:covered-table-cell table:number-rows-repeated=\"{colSpan - 1}\"/>\r\n" : ""); return $" {c}\r\n" + (colSpan > 1 ? $" <table:covered-table-cell table:number-columns-repeated=\"{colSpan - 1}\"/>\r\n" : "");
} }
} }
} }

View File

@ -18,8 +18,9 @@ namespace Elwig.Models.Dtos {
("Cultivation", "Bewirt.", null, 20), ("Cultivation", "Bewirt.", null, 20),
("QualityLevel", "Qualitätsstufe", null, 30), ("QualityLevel", "Qualitätsstufe", null, 30),
("Oe", "Gradation", "°Oe", 20), ("Oe", "Gradation", "°Oe", 20),
("Ungeb", "ungebunden", "kg|€/kg", 40), ("Ungeb", "ungebunden", "kg|€/kg|€/kg", 60),
("Geb", "gebunden", "kg|€/kg", 40), ("LowGeb", "attributlos gebunden", "kg|€/kg|€/kg", 60),
("Geb", "gebunden", "kg|€/kg|€/kg", 60),
("Amount", "Gesamt", "€", 25), ("Amount", "Gesamt", "€", 25),
]; ];
@ -30,8 +31,9 @@ namespace Elwig.Models.Dtos {
string? Cultivation, string? Cultivation,
string QualityLevel, string QualityLevel,
double Oe, double Oe,
(int Weight, decimal? Price) Ungeb, (int Weight, decimal? MinPrice, decimal? MaxPrice) Ungeb,
(int Weight, decimal? Price) Geb, (int Weight, decimal? MinPrice, decimal? MaxPrice) LowGeb,
(int Weight, decimal? MinPrice, decimal? MaxPrice) Geb,
decimal Amount decimal Amount
); );
@ -42,8 +44,9 @@ namespace Elwig.Models.Dtos {
public static async Task<PaymentVariantSummaryData> ForPaymentVariant(PaymentVar v, DbSet<PaymentVariantSummaryRow> table) { public static async Task<PaymentVariantSummaryData> ForPaymentVariant(PaymentVar v, DbSet<PaymentVariantSummaryRow> table) {
return new(v, (await FromDbSet(table, v.Year, v.AvNr)) return new(v, (await FromDbSet(table, v.Year, v.AvNr))
.Select(r => new PaymentRow(r.Type, r.Variety, r.Attribute, r.Cultivation, r.QualityLevel, r.Oe, .Select(r => new PaymentRow(r.Type, r.Variety, r.Attribute, r.Cultivation, r.QualityLevel, r.Oe,
(r.WeightUngeb, r.PriceUngeb != null ? Utils.DecFromDb(r.PriceUngeb.Value, v.Season.Precision) : null), (r.WeightUngeb, r.MinPriceUngeb != null ? Utils.DecFromDb(r.MinPriceUngeb.Value, v.Season.Precision) : null, r.MaxPriceUngeb != null ? Utils.DecFromDb(r.MaxPriceUngeb.Value, v.Season.Precision) : null),
(r.WeightGeb, r.PriceGeb != null ? Utils.DecFromDb(r.PriceGeb.Value, v.Season.Precision) : null), (r.WeightLowGeb, r.MinPriceLowGeb != null ? Utils.DecFromDb(r.MinPriceLowGeb.Value, v.Season.Precision) : null, r.MaxPriceLowGeb != null ? Utils.DecFromDb(r.MaxPriceLowGeb.Value, v.Season.Precision) : null),
(r.WeightGeb, r.MinPriceGeb != null ? Utils.DecFromDb(r.MinPriceGeb.Value, v.Season.Precision) : null, r.MaxPriceGeb != null ? Utils.DecFromDb(r.MaxPriceGeb.Value, v.Season.Precision) : null),
Utils.DecFromDb(r.Amount, v.Season.Precision))) Utils.DecFromDb(r.Amount, v.Season.Precision)))
.ToArray()); .ToArray());
} }
@ -57,19 +60,23 @@ namespace Elwig.Models.Dtos {
q.name AS quality_level, q.name AS quality_level,
ROUND(kmw * (4.54 + 0.022 * kmw)) AS oe, ROUND(kmw * (4.54 + 0.022 * kmw)) AS oe,
SUM(IIF(w.discr = '_', w.value, 0)) AS weight_ungeb, SUM(IIF(w.discr = '_', w.value, 0)) AS weight_ungeb,
MAX(IIF(w.discr = '_', b.price, NULL)) AS price_ungeb, MIN(IIF(w.discr = '_', b.price, NULL)) AS min_price_ungeb,
SUM(IIF(w.discr != '_', w.value, 0)) AS weight_geb, MAX(IIF(w.discr = '_', b.price, NULL)) AS max_price_ungeb,
MAX(IIF(w.discr != '_', b.price, NULL)) AS price_geb, SUM(IIF(w.discr NOT IN (COALESCE(p.attrid, ''), '_'), w.value, 0)) AS weight_lowgeb,
MIN(IIF(w.discr NOT IN (COALESCE(p.attrid, ''), '_'), b.price, NULL)) AS min_price_lowgeb,
MAX(IIF(w.discr NOT IN (COALESCE(p.attrid, ''), '_'), b.price, NULL)) AS max_price_lowgeb,
SUM(IIF(w.discr = COALESCE(p.attrid, ''), w.value, 0)) AS weight_geb,
MIN(IIF(w.discr = COALESCE(p.attrid, ''), b.price, NULL)) AS min_price_geb,
MAX(IIF(w.discr = COALESCE(p.attrid, ''), b.price, NULL)) AS max_price_geb,
SUM(b.amount) AS amount SUM(b.amount) AS amount
FROM payment_delivery_part_bucket b FROM payment_delivery_part_bucket b
LEFT JOIN delivery_part_bucket w ON (w.year, w.did, w.dpnr, w.bktnr) = (b.year, b.did, b.dpnr, b.bktnr) LEFT JOIN delivery_part_bucket w ON (w.year, w.did, w.dpnr, w.bktnr) = (b.year, b.did, b.dpnr, b.bktnr)
LEFT JOIN delivery_part p ON (p.year, p.did, p.dpnr) = (b.year, b.did, b.dpnr) LEFT JOIN delivery_part p ON (p.year, p.did, p.dpnr) = (b.year, b.did, b.dpnr)
LEFT JOIN delivery d ON (d.year, d.did) = (p.year, p.did)
LEFT JOIN wine_variety v ON v.sortid = p.sortid LEFT JOIN wine_variety v ON v.sortid = p.sortid
LEFT JOIN wine_attribute a ON a.attrid = p.attrid LEFT JOIN wine_attribute a ON a.attrid = p.attrid
LEFT JOIN wine_cultivation c ON c.cultid = p.cultid LEFT JOIN wine_cultivation c ON c.cultid = p.cultid
LEFT JOIN wine_quality_level q ON q.qualid = p.qualid LEFT JOIN wine_quality_level q ON q.qualid = p.qualid
WHERE d.year = {year} AND b.avnr = {avnr} WHERE p.year = {year} AND b.avnr = {avnr}
GROUP BY variety, attribute, cultivation, q.min_kmw, oe GROUP BY variety, attribute, cultivation, q.min_kmw, oe
ORDER BY variety, attribute, cultivation, q.min_kmw, oe ORDER BY variety, attribute, cultivation, q.min_kmw, oe
""").ToListAsync(); """).ToListAsync();
@ -92,12 +99,22 @@ namespace Elwig.Models.Dtos {
public double Oe { get; set; } public double Oe { get; set; }
[Column("weight_ungeb")] [Column("weight_ungeb")]
public int WeightUngeb { get; set; } public int WeightUngeb { get; set; }
[Column("price_ungeb")] [Column("min_price_ungeb")]
public long? PriceUngeb { get; set; } public long? MinPriceUngeb { get; set; }
[Column("max_price_ungeb")]
public long? MaxPriceUngeb { get; set; }
[Column("weight_lowgeb")]
public int WeightLowGeb { get; set; }
[Column("min_price_lowgeb")]
public long? MinPriceLowGeb { get; set; }
[Column("max_price_lowgeb")]
public long? MaxPriceLowGeb { get; set; }
[Column("weight_geb")] [Column("weight_geb")]
public int WeightGeb { get; set; } public int WeightGeb { get; set; }
[Column("price_geb")] [Column("min_price_geb")]
public long? PriceGeb { get; set; } public long? MinPriceGeb { get; set; }
[Column("max_price_geb")]
public long? MaxPriceGeb { get; set; }
[Column("amount")] [Column("amount")]
public long Amount { get; set; } public long Amount { get; set; }
} }

View File

@ -12,16 +12,17 @@ namespace Tests.DocumentTests {
var v = (await ctx.PaymentVariants.FindAsync(2020, 1))!; var v = (await ctx.PaymentVariants.FindAsync(2020, 1))!;
var data = await PaymentVariantSummaryData.ForPaymentVariant(v, ctx.PaymentVariantSummaryRows); var data = await PaymentVariantSummaryData.ForPaymentVariant(v, ctx.PaymentVariantSummaryRows);
using var doc = new PaymentVariantSummary(v, data); using var doc = new PaymentVariantSummary(v, data);
var text = await Utils.GeneratePdfText(doc); var text = await Utils.GeneratePdfText(doc, true);
var table = Utils.ExtractTable(text);
Assert.Multiple(() => { Assert.Multiple(() => {
Assert.That(text, Contains.Substring("Auszahlungsvariante")); Assert.That(text, Contains.Substring("Auszahlungsvariante"));
Assert.That(text, Contains.Substring(v.Name)); Assert.That(text, Contains.Substring(v.Name));
Assert.That(text, Contains.Substring(""" Assert.That(table.Skip(17).ToArray(), Is.EqualTo(new string[][] {
Gradation ungebunden gebunden Gesamt [ "Gradation", "ungebunden", "attributlos gebunden", "gebunden", "Gesamt" ],
[°Oe] [kg] [/kg] [kg] [/kg] [] [ "[°Oe]", "[kg]", "[/kg]", "[kg]", "[/kg]", "[kg]", "[/kg]", "[]" ],
Grüner Veltliner 3 219 0 1 609,50 ["Grüner Veltliner", "3 219", "0", "0", "1 609,50"],
Qualitätswein 73 3 219 0,5000 - - 1 609,50 ["Qualitätswein", "73", "3 219", "0,5000", "-", "-", "-", "-", "1 609,50"]
""")); }));
}); });
} }
} }