From 2cdde606447e51e095b550cc7d0be93dc538ae06 Mon Sep 17 00:00:00 2001 From: Lorenz Stechauner Date: Sun, 12 Nov 2023 19:38:36 +0100 Subject: [PATCH] Models: Add Dtos/ --- Elwig/Documents/DeliveryConfirmation.cs | 16 +--- Elwig/Documents/DeliveryConfirmation.cshtml | 38 ++++---- Elwig/Models/Dtos/DataTable.cs | 45 +++++++++ Elwig/Models/Dtos/DeliveryConfirmationData.cs | 95 +++++++++++++++++++ .../DeliveryConfirmationsWindow.xaml.cs | 13 +-- 5 files changed, 164 insertions(+), 43 deletions(-) create mode 100644 Elwig/Models/Dtos/DataTable.cs create mode 100644 Elwig/Models/Dtos/DeliveryConfirmationData.cs diff --git a/Elwig/Documents/DeliveryConfirmation.cs b/Elwig/Documents/DeliveryConfirmation.cs index a8aa8e6..4fa1947 100644 --- a/Elwig/Documents/DeliveryConfirmation.cs +++ b/Elwig/Documents/DeliveryConfirmation.cs @@ -1,33 +1,25 @@ using Elwig.Helpers; +using Elwig.Models.Dtos; using Elwig.Models.Entities; -using Microsoft.EntityFrameworkCore; using System; using System.Collections.Generic; -using System.Linq; namespace Elwig.Documents { public class DeliveryConfirmation : BusinessDocument { public Season Season; - public IEnumerable Deliveries; + public DeliveryConfirmationData Data; public string? Text = App.Client.TextDeliveryConfirmation; public Dictionary MemberBuckets; - public DeliveryConfirmation(AppDbContext ctx, int year, Member m, IEnumerable? deliveries = null) : + public DeliveryConfirmation(AppDbContext ctx, int year, Member m, DeliveryConfirmationData data) : base($"Anlieferungsbestätigung {year}", m) { Season = ctx.Seasons.Find(year) ?? throw new ArgumentException("invalid season"); ShowDateAndLocation = true; UseBillingAddress = true; IncludeSender = true; DocumentId = $"Anl.-Best. {Season.Year}/{m.MgNr}"; - Deliveries = deliveries ?? ctx.DeliveryParts.FromSqlRaw($""" - SELECT p.* - FROM v_delivery v - JOIN delivery_part p ON (p.year, p.did, p.dpnr) = (v.year, v.did, v.dpnr) - WHERE (v.year, v.mgnr) = ({Season.Year}, {m.MgNr}) - ORDER BY v.sortid, v.abgewertet ASC, v.attribute_prio DESC, COALESCE(v.attrid, '~'), v.kmw DESC, v.lsnr, v.dpnr - """) - .ToList(); + Data = data; MemberBuckets = ctx.GetMemberBuckets(Season.Year, m.MgNr).GetAwaiter().GetResult(); } } diff --git a/Elwig/Documents/DeliveryConfirmation.cshtml b/Elwig/Documents/DeliveryConfirmation.cshtml index 405bc50..b11bdf3 100644 --- a/Elwig/Documents/DeliveryConfirmation.cshtml +++ b/Elwig/Documents/DeliveryConfirmation.cshtml @@ -41,39 +41,35 @@ @{ - var lastSortId = ""; + var lastVariant = ""; } - @foreach (var p in Model.Deliveries) { - var buckets = p.Buckets.Where(b => b.Value > 0).OrderByDescending(b => b.BktNr).ToArray(); - var rowsBuckets = buckets.Length; - var mods = p.Modifiers.Select(m => m.Name).ToArray(); - var rowsMod = mods.Length + 1; - var rows = Math.Max(rowsBuckets, rowsMod); + @foreach (var p in Model.Data.Rows) { + var rows = Math.Max(p.Buckets.Length, p.Modifiers.Length + 1); var first = true; @for (int i = 0; i < rows; i++) { - i + 1 ? "trailing" : "")"> + i + 1 ? "trailing" : "")"> @if (first) { - @p.Delivery.LsNr + @p.LsNr @p.DPNr - @p.Variant.Name - @p.Attribute?.Name - @p.Quality.Name + @p.Variant + @p.Attribute + @p.QualityLevel @($"{p.Oe:N0}") @($"{p.Kmw:N1}") } - @if (i > 0 && i <= mods.Length) { - @(mods[i - 1]) + @if (i > 0 && i <= p.Modifiers.Length) { + @(p.Modifiers[i - 1]) } else if (i > 0) { } - @if (i < buckets.Length) { - var bucket = buckets[i]; - @(bucket.Discr == "_" ? "ungeb." : $"geb. {p.SortId}{bucket.Discr}"): - @($"{bucket.Value:N0}") + @if (i < p.Buckets.Length) { + var bucket = p.Buckets[i]; + @bucket.Item1: + @($"{bucket.Item2:N0}") } else { } - @if (i == buckets.Length - 1) { + @if (i == p.Buckets.Length - 1) { @($"{p.Weight:N0}") } else { @@ -83,12 +79,12 @@ first = false; } - lastSortId = p.SortId; + lastVariant = p.Variant; } } Gesamt: - @($"{Model.Deliveries.Sum(p => p.Weight):N0}") + @($"{Model.Data.Rows.Sum(p => p.Weight):N0}") diff --git a/Elwig/Models/Dtos/DataTable.cs b/Elwig/Models/Dtos/DataTable.cs new file mode 100644 index 0000000..b594490 --- /dev/null +++ b/Elwig/Models/Dtos/DataTable.cs @@ -0,0 +1,45 @@ +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace Elwig.Models.Dtos { + public class DataTable { + + public string Name { get; set; } + public string FullName { get; set; } + public IEnumerable Rows { get; private set; } + public int RowNum => Rows.Count(); + public IEnumerable ColumnNames => _fieldMap.Select(m => m.Item2); + public int ColNum => ColumnNames.Count(); + private readonly FieldInfo[] _fields; + private readonly (FieldInfo, string)[] _fieldMap; + + public DataTable(string name, string fullName, IEnumerable rows, IEnumerable<(string, string)>? colNames = null) { + _fields = typeof(T).GetFields(); + var dict = colNames?.ToDictionary(n => n.Item1, n => n.Item2); + _fieldMap = (dict == null ? _fields.Select(f => (f, f.Name)) : _fields.Select(f => (f, dict[f.Name]))).ToArray(); + Name = name; + FullName = fullName; + Rows = rows; + } + + public DataTable(string name, IEnumerable rows, IEnumerable<(string, string)>? colNames = null) : + this(name, name, rows, colNames) { } + + protected IEnumerable<(string, object?)> GetNamedRowData(T row) { + return _fieldMap.Select(i => (i.Item2, i.Item1.GetValue(row))); + } + + protected IEnumerable GetRowData(T row) { + return GetNamedRowData(row).Select(i => i.Item2); + } + + public IEnumerable> GetData() { + return Rows.Select(GetRowData); + } + + public IEnumerable> GetNamedData() { + return Rows.Select(GetNamedRowData); + } + } +} diff --git a/Elwig/Models/Dtos/DeliveryConfirmationData.cs b/Elwig/Models/Dtos/DeliveryConfirmationData.cs new file mode 100644 index 0000000..3177b14 --- /dev/null +++ b/Elwig/Models/Dtos/DeliveryConfirmationData.cs @@ -0,0 +1,95 @@ +using Elwig.Models.Entities; +using Microsoft.EntityFrameworkCore; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Elwig.Models.Dtos { + public class DeliveryConfirmationData : DataTable { + + private static readonly (string, string)[] _fields = new[] { + ("LsNr", "LsNr."), + ("DPNr", "Pos."), + ("Variant", "Sorte"), + ("Attribute", "Attribut"), + ("Modifiers", "Zu-/Abschläge"), + ("QualityLevel", "Qualitätsstufe"), + ("GradationOe", "°Oe"), + ("GradationKmw", "°KMW"), + ("Commitment", "Flächenbindung"), + ("Weight", "Gewicht"), + }; + + public int MgNr { get; private set; } + + private DeliveryConfirmationData(IEnumerable rows, int mgnr) : + base("Anl.-Best.", "Anlieferungsbestätigung", rows, _fields) { + MgNr = mgnr; + } + + public static async Task> ForSeason(DbSet table, int year) { + return (await FromDbSet(table, year).ToListAsync()) + .GroupBy( + p => p.Delivery.MgNr, + p => new DeliveryConfirmationRow(p), + (k, g) => new DeliveryConfirmationData(g, k) + ).ToDictionary(d => d.MgNr, d => d); + } + + public static async Task ForMember(DbSet table, int year, int mgnr) { + return new DeliveryConfirmationData((await FromDbSet(table, year, mgnr).ToListAsync()).Select(p => new DeliveryConfirmationRow(p)), mgnr); + } + + private static IQueryable FromDbSet(DbSet table, int? year = null, int? mgnr = null) { + var y = year?.ToString() ?? "NULL"; + var m = mgnr?.ToString() ?? "NULL"; + return table.FromSqlRaw($""" + SELECT p.* + FROM v_delivery v + JOIN delivery_part p ON (p.year, p.did, p.dpnr) = (v.year, v.did, v.dpnr) + WHERE (p.year = {y} OR {y} IS NULL) AND (v.mgnr = {m} OR {m} IS NULL) + ORDER BY p.year, v.mgnr, v.sortid, v.abgewertet ASC, v.attribute_prio DESC, COALESCE(v.attrid, '~'), v.kmw DESC, v.lsnr, v.dpnr + """) + .Include(p => p.Delivery) + .Include(p => p.Variant) + .Include(p => p.Attribute) + .Include(p => p.Quality) + .Include(p => p.Buckets) + .Include(p => p.PartModifiers).ThenInclude(m => m.Modifier); + } + } + + public class DeliveryConfirmationRow { + + public string LsNr { get; set; } + public int DPNr { get; set; } + public string Variant { get; set; } + public string? Attribute { get; set; } + public string QualityLevel { get; set; } + public double Oe { get; set; } + public double Kmw { get; set; } + public string[] Modifiers { get; set; } + public int Weight { get; set; } + public (string, int)[] Buckets { get; set; } + + public DeliveryConfirmationRow(DeliveryPart p) { + var d = p.Delivery; + LsNr = d.LsNr; + DPNr = p.DPNr; + Variant = p.Variant.Name; + Attribute = p.Attribute?.Name; + QualityLevel = p.Quality.Name; + Oe = p.Oe; + Kmw = p.Kmw; + Modifiers = p.Modifiers + .Select(m => m.Name) + .ToArray(); + Weight = p.Weight; + Buckets = p.Buckets + .Where(b => b.Value > 0) + .OrderByDescending(b => b.BktNr) + .Select(b => (b.Discr == "_" ? "ungeb." : $"geb. {p.SortId}{b.Discr}", b.Value)) + .ToArray(); + } + } +} diff --git a/Elwig/Windows/DeliveryConfirmationsWindow.xaml.cs b/Elwig/Windows/DeliveryConfirmationsWindow.xaml.cs index 20cd128..992bba3 100644 --- a/Elwig/Windows/DeliveryConfirmationsWindow.xaml.cs +++ b/Elwig/Windows/DeliveryConfirmationsWindow.xaml.cs @@ -1,4 +1,5 @@ using Elwig.Documents; +using Elwig.Models.Dtos; using Elwig.Models.Entities; using Elwig.Windows; using Microsoft.EntityFrameworkCore; @@ -84,17 +85,9 @@ namespace Elwig.Dialogs { list = list.Where((_, n) => n % 10 == r); } - var deliveries = await Context.DeliveryParts.FromSqlRaw($""" - SELECT p.* - FROM v_delivery v - JOIN delivery_part p ON (p.year, p.did, p.dpnr) = (v.year, v.did, v.dpnr) - WHERE v.year = {Year} - ORDER BY v.sortid, v.abgewertet ASC, v.attribute_prio DESC, COALESCE(v.attrid, '~'), v.kmw DESC, v.lsnr, v.dpnr - """) - .ToListAsync(); - + var data = await DeliveryConfirmationData.ForSeason(Context.DeliveryParts, Year); using var doc = Document.Merge(list.Select(m => - new DeliveryConfirmation(Context, Year, m, deliveries.Where(d => d.Delivery.MgNr == m.MgNr).ToList()) { + new DeliveryConfirmation(Context, Year, m, data[m.MgNr]) { //DoubleSided = true } ));