[#32] Documents: Add PaymentVariantSummary
This commit is contained in:
@ -88,6 +88,8 @@ namespace Elwig.Documents {
|
|||||||
name = "MemberList";
|
name = "MemberList";
|
||||||
} else if (this is WineQualityStatistics) {
|
} else if (this is WineQualityStatistics) {
|
||||||
name = "WineQualityStatistics";
|
name = "WineQualityStatistics";
|
||||||
|
} else if (this is PaymentVariantSummary) {
|
||||||
|
name = "PaymentVariantSummary";
|
||||||
} else {
|
} else {
|
||||||
throw new InvalidOperationException("Invalid document object");
|
throw new InvalidOperationException("Invalid document object");
|
||||||
}
|
}
|
||||||
|
19
Elwig/Documents/PaymentVariantSummary.cs
Normal file
19
Elwig/Documents/PaymentVariantSummary.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
using Elwig.Models.Dtos;
|
||||||
|
using Elwig.Models.Entities;
|
||||||
|
|
||||||
|
namespace Elwig.Documents {
|
||||||
|
public class PaymentVariantSummary : Document {
|
||||||
|
|
||||||
|
public new static string Name => "Auszahlungsvariante";
|
||||||
|
|
||||||
|
public PaymentVariantSummaryData Data;
|
||||||
|
public PaymentVar Variant;
|
||||||
|
public string CurrencySymbol;
|
||||||
|
|
||||||
|
public PaymentVariantSummary(PaymentVar v, PaymentVariantSummaryData data) : base(v.Name) {
|
||||||
|
Variant = v;
|
||||||
|
Data = data;
|
||||||
|
CurrencySymbol = v.Season.Currency.Symbol ?? v.Season.Currency.Code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
70
Elwig/Documents/PaymentVariantSummary.cshtml
Normal file
70
Elwig/Documents/PaymentVariantSummary.cshtml
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
@using RazorLight
|
||||||
|
@using Elwig.Helpers
|
||||||
|
@inherits TemplatePage<Elwig.Documents.PaymentVariantSummary>
|
||||||
|
@model Elwig.Documents.PaymentVariantSummary
|
||||||
|
@{ Layout = "Document"; }
|
||||||
|
<link rel="stylesheet" href="file:///@Raw(Model.DataPath)\resources\PaymentVariantSummary.css" />
|
||||||
|
<main>
|
||||||
|
<h1>Auszahlungsvariante</h1>
|
||||||
|
<h2>@Model.Variant.Name</h2>
|
||||||
|
<!-- TODO -->
|
||||||
|
<table class="payment-variant">
|
||||||
|
<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;"/>
|
||||||
|
</colgroup>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th rowspan="2" style="text-align: left;">Qualitätsstufe</th>
|
||||||
|
<th>Gradation</th>
|
||||||
|
<th colspan="2">ungebunden</th>
|
||||||
|
<th colspan="2">gebunden</th>
|
||||||
|
<th>Gesamt</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>[@(true ? "°Oe" : "°KMW")]</th>
|
||||||
|
<th>[kg]</th>
|
||||||
|
<th>[@(Model.CurrencySymbol)/kg]</th>
|
||||||
|
<th>[kg]</th>
|
||||||
|
<th>[@(Model.CurrencySymbol)/kg]</th>
|
||||||
|
<th>[@(Model.CurrencySymbol)]</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@{
|
||||||
|
string? lastHdr = null;
|
||||||
|
}
|
||||||
|
@foreach (var row in Model.Data.Rows) {
|
||||||
|
var hdr = $"{row.Variety}{(row.Attribute != null ? " / " : "")}{row.Attribute}{(row.Cultivation != null ? " / " : "")}{row.Cultivation}";
|
||||||
|
if (lastHdr != hdr) {
|
||||||
|
var rows = Model.Data.Rows
|
||||||
|
.Where(r => r.Variety == row.Variety && r.Attribute == row.Attribute && r.Cultivation == row.Cultivation)
|
||||||
|
.ToList();
|
||||||
|
<tr class="subheading @(hdr != lastHdr && lastHdr != null ? "new" : "")">
|
||||||
|
<th colspan="2">@hdr</th>
|
||||||
|
<td class="number">@($"{rows.Sum(r => r.WeightUngeb):N0}")</td>
|
||||||
|
<td></td>
|
||||||
|
<td class="number">@($"{rows.Sum(r => r.WeightGeb):N0}")</td>
|
||||||
|
<td></td>
|
||||||
|
<td class="number">@($"{rows.Sum(r => r.Amount):N2}")</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
<tr>
|
||||||
|
<td>@(row.QualityLevel)</td>
|
||||||
|
<td class="center">@($"{row.Oe:N0}")</td>
|
||||||
|
<td class="number">@(row.WeightUngeb != 0 ? $"{row.WeightUngeb:N0}" : "-")</td>
|
||||||
|
<td class="number">@(row.PriceUngeb != null ? $"{row.PriceUngeb:N4}" : "-")</td>
|
||||||
|
<td class="number">@(row.WeightGeb != 0 ? $"{row.WeightGeb:N0}" : "-")</td>
|
||||||
|
<td class="number">@(row.PriceGeb != null ? $"{row.PriceGeb:N4}" : "-")</td>
|
||||||
|
<td class="number">@($"{row.Amount:N2}")</td>
|
||||||
|
</tr>
|
||||||
|
lastHdr = hdr;
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</main>
|
17
Elwig/Documents/PaymentVariantSummary.css
Normal file
17
Elwig/Documents/PaymentVariantSummary.css
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
|
||||||
|
h1 {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 24pt;
|
||||||
|
margin-top: 10mm;
|
||||||
|
margin-bottom: 2mm;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 14pt;
|
||||||
|
margin-top: 2mm;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.payment-variant {
|
||||||
|
break-before: page;
|
||||||
|
}
|
@ -65,6 +65,7 @@ namespace Elwig.Helpers {
|
|||||||
public DbSet<CreditNoteDeliveryRowSingle> CreditNoteDeliveryRows { get; private set; }
|
public DbSet<CreditNoteDeliveryRowSingle> CreditNoteDeliveryRows { get; private set; }
|
||||||
public DbSet<CreditNoteRowSingle> CreditNoteRows { get; private set; }
|
public DbSet<CreditNoteRowSingle> CreditNoteRows { get; private set; }
|
||||||
public DbSet<WeightBreakdownRow> WeightBreakDownRows { get; private set; }
|
public DbSet<WeightBreakdownRow> WeightBreakDownRows { get; private set; }
|
||||||
|
public DbSet<PaymentVariantSummaryRow> PaymentVariantSummaryRows { get; private set; }
|
||||||
|
|
||||||
private readonly StreamWriter? LogFile = null;
|
private readonly StreamWriter? LogFile = null;
|
||||||
public static DateTime LastWriteTime => File.GetLastWriteTime(App.Config.DatabaseFile);
|
public static DateTime LastWriteTime => File.GetLastWriteTime(App.Config.DatabaseFile);
|
||||||
|
83
Elwig/Models/Dtos/PaymentVariantSummaryData.cs
Normal file
83
Elwig/Models/Dtos/PaymentVariantSummaryData.cs
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
using Elwig.Helpers;
|
||||||
|
using Elwig.Models.Entities;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using System.Data.Entity.Core.Common.CommandTrees.ExpressionBuilder;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Elwig.Models.Dtos {
|
||||||
|
public class PaymentVariantSummaryData {
|
||||||
|
|
||||||
|
public record struct PaymentRow(string Type, string Variety, string? Attribute, string? Cultivation, string QualityLevel, double Oe, int WeightUngeb, decimal? PriceUngeb, int WeightGeb, decimal? PriceGeb, decimal Amount);
|
||||||
|
|
||||||
|
public PaymentRow[] Rows;
|
||||||
|
|
||||||
|
public PaymentVariantSummaryData(PaymentRow[] rows) {
|
||||||
|
Rows = rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<PaymentVariantSummaryData> ForPaymentVariant(PaymentVar v, DbSet<PaymentVariantSummaryRow> table) {
|
||||||
|
return new((await FromDbSet(table, v.Year, v.AvNr))
|
||||||
|
.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.WeightGeb, r.PriceGeb != null ? Utils.DecFromDb(r.PriceGeb.Value, v.Season.Precision) : null,
|
||||||
|
Utils.DecFromDb(r.Amount, v.Season.Precision)))
|
||||||
|
.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task<IEnumerable<PaymentVariantSummaryRow>> FromDbSet(DbSet<PaymentVariantSummaryRow> table, int year, int avnr) {
|
||||||
|
return await table.FromSqlRaw($"""
|
||||||
|
SELECT v.type AS type,
|
||||||
|
v.name AS variety,
|
||||||
|
a.name AS attribute,
|
||||||
|
c.name AS cultivation,
|
||||||
|
q.name AS quality_level,
|
||||||
|
ROUND(kmw * (4.54 + 0.022 * kmw)) AS oe,
|
||||||
|
SUM(IIF(w.discr = '_', w.value, 0)) AS weight_ungeb,
|
||||||
|
MAX(IIF(w.discr = '_', b.price, NULL)) AS price_ungeb,
|
||||||
|
SUM(IIF(w.discr != '_', w.value, 0)) AS weight_geb,
|
||||||
|
MAX(IIF(w.discr != '_', b.price, NULL)) AS price_geb,
|
||||||
|
SUM(b.amount) AS amount
|
||||||
|
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 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_attribute a ON a.attrid = p.attrid
|
||||||
|
LEFT JOIN wine_cultivation c ON c.cultid = p.cultid
|
||||||
|
LEFT JOIN wine_quality_level q ON q.qualid = p.qualid
|
||||||
|
WHERE d.year = {year} AND b.avnr = {avnr}
|
||||||
|
GROUP BY variety, attribute, cultivation, q.min_kmw, oe
|
||||||
|
ORDER BY variety, attribute, cultivation, q.min_kmw, oe
|
||||||
|
""").ToListAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Keyless]
|
||||||
|
public class PaymentVariantSummaryRow {
|
||||||
|
[Column("type")]
|
||||||
|
public required string Type { get; set; }
|
||||||
|
[Column("variety")]
|
||||||
|
public required string Variety { get; set; }
|
||||||
|
[Column("attribute")]
|
||||||
|
public string? Attribute { get; set; }
|
||||||
|
[Column("cultivation")]
|
||||||
|
public string? Cultivation { get; set; }
|
||||||
|
[Column("quality_level")]
|
||||||
|
public required string QualityLevel { get; set; }
|
||||||
|
[Column("oe")]
|
||||||
|
public double Oe { get; set; }
|
||||||
|
[Column("weight_ungeb")]
|
||||||
|
public int WeightUngeb { get; set; }
|
||||||
|
[Column("price_ungeb")]
|
||||||
|
public long? PriceUngeb { get; set; }
|
||||||
|
[Column("weight_geb")]
|
||||||
|
public int WeightGeb { get; set; }
|
||||||
|
[Column("price_geb")]
|
||||||
|
public long? PriceGeb { get; set; }
|
||||||
|
[Column("amount")]
|
||||||
|
public long Amount { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -19,7 +19,7 @@ namespace Elwig.Models.Dtos {
|
|||||||
Sections = sections;
|
Sections = sections;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static QualitySection[] GetQualitySections(IEnumerable<QualityRow> rows) {
|
private static QualitySection[] GetSections(IEnumerable<QualityRow> rows) {
|
||||||
var data = new List<QualitySection>();
|
var data = new List<QualitySection>();
|
||||||
var currentQual = new Dictionary<double, (double AvgKmw, int Num, int Weight)>();
|
var currentQual = new Dictionary<double, (double AvgKmw, int Num, int Weight)>();
|
||||||
var current = new Dictionary<string, (double, double, int, int)[]>();
|
var current = new Dictionary<string, (double, double, int, int)[]>();
|
||||||
@ -88,7 +88,7 @@ namespace Elwig.Models.Dtos {
|
|||||||
.Select(r => new QualityRow(r.Key.Variety, r.Key.Attribute, r.Key.Cultivation, r.Key.Type, r.Key.QualId, r.AvgKmw, r.Key.Grad, r.Num, r.Weight))
|
.Select(r => new QualityRow(r.Key.Variety, r.Key.Attribute, r.Key.Cultivation, r.Key.Type, r.Key.QualId, r.AvgKmw, r.Key.Grad, r.Num, r.Weight))
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
var data = GetQualitySections(rows);
|
var data = GetSections(rows);
|
||||||
if (data.Length <= 1)
|
if (data.Length <= 1)
|
||||||
return new(data);
|
return new(data);
|
||||||
|
|
||||||
@ -105,7 +105,7 @@ namespace Elwig.Models.Dtos {
|
|||||||
.ThenBy(g => g.QualId)
|
.ThenBy(g => g.QualId)
|
||||||
.ThenBy(g => g.Grad)
|
.ThenBy(g => g.Grad)
|
||||||
.ToList();
|
.ToList();
|
||||||
var typeData = GetQualitySections(typeRows);
|
var typeData = GetSections(typeRows);
|
||||||
if (typeData.Length <= 1)
|
if (typeData.Length <= 1)
|
||||||
return new([.. typeData, .. data]);
|
return new([.. typeData, .. data]);
|
||||||
|
|
||||||
@ -121,7 +121,7 @@ namespace Elwig.Models.Dtos {
|
|||||||
.OrderBy(g => g.QualId)
|
.OrderBy(g => g.QualId)
|
||||||
.ThenBy(g => g.Grad)
|
.ThenBy(g => g.Grad)
|
||||||
.ToList();
|
.ToList();
|
||||||
var totalData = GetQualitySections(totalRows);
|
var totalData = GetSections(totalRows);
|
||||||
return new([.. totalData, .. typeData, .. data]) { UseOe = mode == 0 };
|
return new([.. totalData, .. typeData, .. data]) { UseOe = mode == 0 };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user