From 486655d071282c511a7fa857975b40d1cc43e096 Mon Sep 17 00:00:00 2001 From: Lorenz Stechauner Date: Wed, 15 Nov 2023 16:40:17 +0100 Subject: [PATCH] Dtos: Add more DTOs --- Elwig/Helpers/AppDbContext.cs | 5 + Elwig/Helpers/Export/Ods.cs | 23 ++- Elwig/Models/Dtos/AreaComUnderDeliveyData.cs | 109 +++++++++++++++ Elwig/Models/Dtos/DataTable.cs | 25 +++- Elwig/Models/Dtos/DeliveryConfirmationData.cs | 19 ++- .../Dtos/MemberDeliveryPerVariantData.cs | 118 ++++++++++++++++ Elwig/Models/Dtos/OverUnderDeliveryData.cs | 81 +++++++++++ Elwig/Windows/SeasonFinishWindow.xaml.cs | 132 ++---------------- 8 files changed, 372 insertions(+), 140 deletions(-) create mode 100644 Elwig/Models/Dtos/AreaComUnderDeliveyData.cs create mode 100644 Elwig/Models/Dtos/MemberDeliveryPerVariantData.cs create mode 100644 Elwig/Models/Dtos/OverUnderDeliveryData.cs diff --git a/Elwig/Helpers/AppDbContext.cs b/Elwig/Helpers/AppDbContext.cs index 860ac2f..8f000a0 100644 --- a/Elwig/Helpers/AppDbContext.cs +++ b/Elwig/Helpers/AppDbContext.cs @@ -9,6 +9,7 @@ using Microsoft.Extensions.Logging; using Microsoft.Data.Sqlite; using System.Text.RegularExpressions; using System.Collections.Generic; +using Elwig.Models.Dtos; namespace Elwig.Helpers { public class AppDbContext : DbContext { @@ -45,6 +46,10 @@ namespace Elwig.Helpers { public DbSet MemberPayments { get; private set; } public DbSet Credits { get; private set; } + public DbSet OverUnderDeliveryRows { get; private set; } + public DbSet AreaComUnderDeliveryRows { get; private set; } + public DbSet MemberDeliveryPerVariantRows { get; private set; } + private readonly StreamWriter? LogFile = null; public static DateTime LastWriteTime => File.GetLastWriteTime(App.Config.DatabaseFile); public DateTime SavedLastWriteTime { get; private set; } diff --git a/Elwig/Helpers/Export/Ods.cs b/Elwig/Helpers/Export/Ods.cs index cc30d36..db32f26 100644 --- a/Elwig/Helpers/Export/Ods.cs +++ b/Elwig/Helpers/Export/Ods.cs @@ -1,5 +1,4 @@ using Elwig.Models.Dtos; -using ScottPlot; using System; using System.Collections.Generic; using System.Data.Entity.Core.Common.CommandTrees.ExpressionBuilder; @@ -20,7 +19,7 @@ namespace Elwig.Helpers.Export { FileName = filename; File.Delete(filename); ZipArchive = ZipFile.Open(FileName, ZipArchiveMode.Create); - _tables = new List(); + _tables = new(); } public void Dispose() { @@ -90,6 +89,19 @@ namespace Elwig.Helpers.Export { + + """); + + for (int i = 1; i <= 100; i++) { + await Content.WriteAsync($""" + + + + + """); + } + + await Content.WriteAsync(""" @@ -163,9 +175,12 @@ namespace Elwig.Helpers.Export { if (Content == null) return; var totalSpan = table.ColumnSpans.Sum(); - _tables.Add(table.FullName); + _tables.Add(table.Name); + await Content.WriteAsync($" \r\n"); + foreach (var w in table.ColumnWidths) { + await Content.WriteAsync(" \r\n"); + } - await Content.WriteAsync($" \r\n"); await Content.WriteAsync( $" \r\n" + FormatCell(table.FullName, colSpan: totalSpan, style: "header") + diff --git a/Elwig/Models/Dtos/AreaComUnderDeliveyData.cs b/Elwig/Models/Dtos/AreaComUnderDeliveyData.cs new file mode 100644 index 0000000..9382797 --- /dev/null +++ b/Elwig/Models/Dtos/AreaComUnderDeliveyData.cs @@ -0,0 +1,109 @@ +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Threading.Tasks; + +namespace Elwig.Models.Dtos { + public class AreaComUnderDeliveryData : DataTable { + + private static readonly (string, string, int)[] FieldNames = new[] { + ("MgNr", "MgNr.", 12), + ("Name", "Name", 40), + ("GivenName", "Vorname", 40), + ("Address", "Adresse", 60), + ("Plz", "PLZ", 10), + ("Locality", "Ort", 60), + ("VtrgIds", "Vertrag", 14), + ("Areas", "Fläche", 16), + ("DeliveryObligations", "Lieferpflicht", 22), + ("Weights", "Geliefert", 22), + ("UnderDeliveries", "Unterliefert", 22), + ("Percents", "Prozent", 16), + }; + + public AreaComUnderDeliveryData(IEnumerable rows, int year) : + base($"Unterlieferungen FB", $"Unterlieferungen laut Flächenbindungen {year}", rows, FieldNames) { + } + + public static async Task ForSeason(DbSet table, int year) { + return new AreaComUnderDeliveryData( + (await FromDbSet(table, year)).GroupBy( + r => r.MgNr, + (k, g) => new AreaComUnderDeliveryRow(g) + ), year); + } + + private static async Task> FromDbSet(DbSet table, int year) { + return await table.FromSqlRaw($""" + SELECT m.mgnr, m.family_name, m.given_name, p.plz, o.name AS ort, m.address, + c.bucket, c.area, u.min_kg, u.weight + FROM member m + LEFT JOIN AT_plz_dest p ON p.id = m.postal_dest + LEFT JOIN AT_ort o ON o.okz = p.okz + LEFT JOIN v_area_commitment_bucket_strict c ON c.mgnr = m.mgnr AND c.year = {year} + JOIN v_under_delivery u ON (u.mgnr, u.bucket, u.year) = (m.mgnr, c.bucket, c.year) + WHERE m.active = 1 + ORDER BY m.mgnr, c.bucket + """).ToListAsync(); + } + } + + public class AreaComUnderDeliveryRow { + public int MgNr; + public string Name; + public string GivenName; + public string Address; + public int Plz; + public string Locality; + public string[] VtrgIds; + public int[] Areas; + public int[] DeliveryObligations; + public int[] Weights; + public int?[] UnderDeliveries => Weights.Zip(DeliveryObligations) + .Select(v => v.First < v.Second ? (int?)v.First - v.Second : null) + .ToArray(); + public double?[] Percents => Weights.Zip(DeliveryObligations) + .Select(v => v.First < v.Second ? (double?)Math.Round(v.First * 100.0 / v.Second - 100.0, 1) : null) + .ToArray(); + + public AreaComUnderDeliveryRow(IEnumerable rows) { + var f = rows.First(); + MgNr = f.MgNr; + Name = f.Name; + GivenName = f.GivenName; + Address = f.Address; + Plz = f.Plz; + Locality = f.Locality.Split(",")[0]; + VtrgIds = rows.Select(r => r.VtrgId).ToArray(); + Areas = rows.Select(r => r.Area).ToArray(); + DeliveryObligations = rows.Select(r => r.DeliveryObligation).ToArray(); + Weights = rows.Select(r => r.Weight).ToArray(); + } + } + + [Keyless] + public class AreaComUnderDeliveryRowSingle { + [Column("mgnr")] + public int MgNr { get; set; } + [Column("family_name")] + public string Name { get; set; } + [Column("given_name")] + public string GivenName { get; set; } + [Column("address")] + public string Address { get; set; } + [Column("plz")] + public int Plz { get; set; } + [Column("ort")] + public string Locality { get; set; } + [Column("bucket")] + public string VtrgId { get; set; } + [Column("area")] + public int Area { get; set; } + [Column("min_kg")] + public int DeliveryObligation { get; set; } + [Column("weight")] + public int Weight { get; set; } + } +} diff --git a/Elwig/Models/Dtos/DataTable.cs b/Elwig/Models/Dtos/DataTable.cs index 876abd5..2bc3841 100644 --- a/Elwig/Models/Dtos/DataTable.cs +++ b/Elwig/Models/Dtos/DataTable.cs @@ -17,15 +17,16 @@ namespace Elwig.Models.Dtos { public IEnumerable ColumnTypes => ColumnDefs.Select(m => m.Item2); public IEnumerable ColumnFlatTypes { get; private set; } public IEnumerable ColumnSpans { get; private set; } + public IEnumerable ColumnWidths { get; private set; } private readonly PropertyInfo[] _properties; private readonly FieldInfo[] _fields; private readonly (string, PropertyInfo?, FieldInfo?)[] _map; - public DataTable(string name, string fullName, IEnumerable rows, IEnumerable<(string, string)>? colNames = null) { + public DataTable(string name, string fullName, IEnumerable rows, IEnumerable<(string, string, int?)>? colNames = null) { _fields = typeof(T).GetFields(); _properties = typeof(T).GetProperties(); - colNames ??= _properties.Select(p => p.Name).Union(_fields.Select(f => f.Name)).Select(i => (i, i)).ToList(); + colNames ??= _properties.Select(p => p.Name).Union(_fields.Select(f => f.Name)).Select(i => (i, i, (int?)null)).ToList(); _map = colNames.Select(n => (n.Item2, _properties.FirstOrDefault(p => p?.Name == n.Item1, null), _fields.FirstOrDefault(f => f?.Name == n.Item1, null))).ToArray(); Name = name; FullName = fullName; @@ -41,10 +42,28 @@ namespace Elwig.Models.Dtos { return type != null && type.IsValueType && type.Name.StartsWith("ValueTuple") ? type.GetFields().Length : type != null && elType != null && type.IsArray && elType.IsValueType && elType.Name.StartsWith("ValueTuple") ? elType.GetFields().Length : 1; }).ToList(); + ColumnWidths = colNames.Select(c => c.Item3).ToList(); + } + + public DataTable(string name, string fullName, IEnumerable rows, IEnumerable<(string, string)>? colNames = null) : + this(name, fullName, rows, colNames?.Select(c => (c.Item1, c.Item2, (int?)null))) { } public DataTable(string name, IEnumerable rows, IEnumerable<(string, string)>? colNames = null) : - this(name, name, rows, colNames) { } + this(name, name, rows, colNames) { + } + + public DataTable(string name, IEnumerable rows, IEnumerable<(string, string, int?)>? colNames = null) : + this(name, name, rows, colNames) { + } + + public DataTable(string name, IEnumerable rows, IEnumerable<(string, string, int)>? colNames = null) : + this(name, name, rows, colNames) { + } + + public DataTable(string name, string fullName, IEnumerable rows, IEnumerable<(string, string, int)>? colNames = null) : + this(name, fullName, rows, colNames?.Select(c => (c.Item1, c.Item2, (int?)c.Item3))) { + } protected IEnumerable<(string, object?)> GetNamedRowData(T row) { return _map.Select(i => (i.Item1, i.Item2?.GetValue(row) ?? i.Item3?.GetValue(row))); diff --git a/Elwig/Models/Dtos/DeliveryConfirmationData.cs b/Elwig/Models/Dtos/DeliveryConfirmationData.cs index b645eba..b9be339 100644 --- a/Elwig/Models/Dtos/DeliveryConfirmationData.cs +++ b/Elwig/Models/Dtos/DeliveryConfirmationData.cs @@ -7,7 +7,7 @@ using System.Threading.Tasks; namespace Elwig.Models.Dtos { public class DeliveryConfirmationData : DataTable { - private static readonly (string, string)[] _fieldNames = new[] { + private static readonly (string, string)[] FieldNames = new[] { ("LsNr", "LsNr."), ("DPNr", "Pos."), ("Variant", "Sorte"), @@ -20,24 +20,24 @@ namespace Elwig.Models.Dtos { ("Weight", "Gewicht"), }; - public int MgNr { get; private set; } + private readonly int MgNr; - private DeliveryConfirmationData(IEnumerable rows, int mgnr) : - base("Anl.-Best.", "Anlieferungsbestätigung", rows, _fieldNames) { - MgNr = mgnr; + private DeliveryConfirmationData(IEnumerable rows, int year, Member m) : + base($"Anlieferungsbestätigung", $"Anlieferungsbestätigung {year} – {m.AdministrativeName}", rows, FieldNames) { + MgNr = m.MgNr; } public static async Task> ForSeason(DbSet table, int year) { return (await FromDbSet(table, year)) .GroupBy( - p => p.Delivery.MgNr, + p => p.Delivery.Member, p => new DeliveryConfirmationRow(p), - (k, g) => new DeliveryConfirmationData(g, k) + (k, g) => new DeliveryConfirmationData(g, year, 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)).Select(p => new DeliveryConfirmationRow(p)), mgnr); + public static async Task ForMember(DbSet table, int year, Member m) { + return new DeliveryConfirmationData((await FromDbSet(table, year, m.MgNr)).Select(p => new DeliveryConfirmationRow(p)), year, m); } private static async Task> FromDbSet(DbSet table, int? year = null, int? mgnr = null) { @@ -66,7 +66,6 @@ namespace Elwig.Models.Dtos { } public class DeliveryConfirmationRow { - public string LsNr; public int DPNr; public string Variant; diff --git a/Elwig/Models/Dtos/MemberDeliveryPerVariantData.cs b/Elwig/Models/Dtos/MemberDeliveryPerVariantData.cs new file mode 100644 index 0000000..aa6f4b1 --- /dev/null +++ b/Elwig/Models/Dtos/MemberDeliveryPerVariantData.cs @@ -0,0 +1,118 @@ +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Threading.Tasks; + +namespace Elwig.Models.Dtos { + public class MemberDeliveryPerVariantData : DataTable { + + private static readonly (string, string, int)[] FieldNames = new[] { + ("MgNr", "MgNr.", 12), + ("Name", "Name", 40), + ("GivenName", "Vorname", 40), + ("Address", "Adresse", 60), + ("Plz", "PLZ", 10), + ("Locality", "Ort", 60), + ("SortIds", "Sorte", 12), + ("AttrIds", "Attribut", 16), + ("Weights", "Geliefert", 22), + ("Areas", "Fläche", 22), + ("Yields", "Ertrag", 22), + }; + + + public MemberDeliveryPerVariantData(IEnumerable rows, int year) : + base($"Liefermengen", $"Liefermengen pro Mitglied, Sorte und Attribut {year}", rows, FieldNames) { + } + + public static async Task ForSeason(DbSet table, int year) { + return new MemberDeliveryPerVariantData( + (await FromDbSet(table, year)).GroupBy( + r => r.MgNr, + (k, g) => new MemberDeliveryPerVariantRow(g) + ), year); + } + + private static async Task> FromDbSet(DbSet table, int year) { + return await table.FromSqlRaw($""" + SELECT m.mgnr, m.family_name, m.given_name, p.plz, o.name AS ort, m.address, + v.bucket, v.weight, v.area + FROM ( + SELECT c.year AS year, + c.mgnr AS mgnr, + c.bucket AS bucket, + COALESCE(d.weight, 0) AS weight, + COALESCE(c.area, 0) AS area + FROM v_area_commitment_bucket_strict c + LEFT JOIN v_delivery_bucket_strict d ON (d.year, d.mgnr, d.bucket) = (c.year, c.mgnr, c.bucket) + WHERE c.year = {year} + UNION + SELECT d.year, + d.mgnr, + d.bucket, + COALESCE(d.weight, 0), + COALESCE(c.area, 0) + FROM v_delivery_bucket_strict d + LEFT JOIN v_area_commitment_bucket_strict c ON (c.year, c.mgnr, c.bucket) = (d.year, d.mgnr, d.bucket) + WHERE d.year = {year} + ) v + LEFT JOIN member m ON m.mgnr = v.mgnr + LEFT JOIN AT_plz_dest p ON p.id = m.postal_dest + LEFT JOIN AT_ort o ON o.okz = p.okz + ORDER BY m.mgnr, v.bucket + """).ToListAsync(); + } + } + + public class MemberDeliveryPerVariantRow { + public int MgNr; + public string Name; + public string GivenName; + public string Address; + public int Plz; + public string Locality; + public string[] SortIds; + public string[] AttrIds; + public int[] Areas; + public int[] Weights; + public int?[] Yields => Weights.Zip(Areas).Select(i => i.Second > 0 ? (int?)i.First * 10_000 / i.Second : null).ToArray(); + + public MemberDeliveryPerVariantRow(IEnumerable rows) { + var f = rows.First(); + MgNr = f.MgNr; + Name = f.Name; + GivenName = f.GivenName; + Address = f.Address; + Plz = f.Plz; + Locality = f.Locality.Split(",")[0]; + SortIds = rows.Select(r => r.VtrgId[..2]).ToArray(); + AttrIds = rows.Select(r => r.VtrgId[2..]).ToArray(); + Areas = rows.Select(r => r.Area).ToArray(); + Weights = rows.Select(r => r.Weight).ToArray(); + } + } + + [Keyless] + public class MemberDeliveryPerVariantRowSingle { + [Column("mgnr")] + public int MgNr { get; set; } + [Column("family_name")] + public string Name { get; set; } + [Column("given_name")] + public string GivenName { get; set; } + [Column("address")] + public string Address { get; set; } + [Column("plz")] + public int Plz { get; set; } + [Column("ort")] + public string Locality { get; set; } + [Column("bucket")] + public string VtrgId { get; set; } + [Column("area")] + public int Area { get; set; } + [Column("weight")] + public int Weight { get; set; } + } +} diff --git a/Elwig/Models/Dtos/OverUnderDeliveryData.cs b/Elwig/Models/Dtos/OverUnderDeliveryData.cs new file mode 100644 index 0000000..ba320ef --- /dev/null +++ b/Elwig/Models/Dtos/OverUnderDeliveryData.cs @@ -0,0 +1,81 @@ +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.Threading.Tasks; + +namespace Elwig.Models.Dtos { + public class OverUnderDeliveryData : DataTable { + + private static readonly (string, string, int)[] FieldNames = new[] { + ("MgNr", "MgNr.", 12), + ("Name", "Name", 40), + ("GivenName", "Vorname", 40), + ("Address", "Adresse", 60), + ("Plz", "PLZ", 10), + ("Locality", "Ort", 60), + ("BusinessShares", "GA", 10), + ("DeliveryObligation", "Lieferpflicht", 22), + ("DeliveryRight", "Lieferrecht", 22), + ("Weight", "Geliefert", 22), + ("OverUnderDelivery", "Über-/Unterliefert", 35), + ("Percent", "Prozent", 16), + }; + + public OverUnderDeliveryData(IEnumerable rows, int year) : + base($"Über-Unterlieferungen", $"Über- und Unterlieferungen laut gezeichneten Geschäftsanteilen {year}", rows, FieldNames) { + } + + public static async Task ForSeason(DbSet table, int year) { + var rows = await table.FromSqlRaw($""" + SELECT m.mgnr, m.family_name, m.given_name, p.plz, o.name AS ort, m.address, m.business_shares, + m.business_shares * s.min_kg_per_bs AS min_kg, + m.business_shares * s.max_kg_per_bs AS max_kg, + COALESCE(SUM(d.weight), 0) AS sum + FROM member m + LEFT JOIN AT_plz_dest p ON p.id = m.postal_dest + LEFT JOIN AT_ort o ON o.okz = p.okz + LEFT JOIN season s ON s.year = {year} + LEFT JOIN v_delivery d ON d.mgnr = m.mgnr AND d.year = s.year + WHERE m.active = 1 + GROUP BY d.year, m.mgnr + ORDER BY 100.0 * sum / max_kg, m.mgnr; + """).ToListAsync(); + return new OverUnderDeliveryData(rows, year); + } + } + + [Keyless] + public class OverUnderDeliveryRow { + [Column("mgnr")] + public int MgNr { get; set; } + [Column("family_name")] + public string Name { get; set; } + [Column("given_name")] + public string GivenName { get; set; } + [Column("address")] + public string Address { get; set; } + [Column("plz")] + public int Plz { get; set; } + [Column("ort")] + public string LocalityFull { get; set; } + [NotMapped] + public string Locality => LocalityFull.Split(",")[0]; + [Column("business_shares")] + public int BusinessShares { get; set; } + [Column("min_kg")] + public int DeliveryObligation { get; set; } + [Column("max_kg")] + public int DeliveryRight { get; set; } + [Column("sum")] + public int Weight { get; set; } + [NotMapped] + public int? OverUnderDelivery => + Weight < DeliveryObligation ? Weight - DeliveryObligation : + Weight > DeliveryRight ? Weight - DeliveryRight : null; + [NotMapped] + public double? Percent => + Weight < DeliveryObligation ? Math.Round(Weight * 100.0 / DeliveryObligation - 100.0, 1) : + Weight > DeliveryRight ? Math.Round(Weight * 100.0 / DeliveryRight - 100, 1) : null; + } +} diff --git a/Elwig/Windows/SeasonFinishWindow.xaml.cs b/Elwig/Windows/SeasonFinishWindow.xaml.cs index 63298d7..9c29f2a 100644 --- a/Elwig/Windows/SeasonFinishWindow.xaml.cs +++ b/Elwig/Windows/SeasonFinishWindow.xaml.cs @@ -1,10 +1,10 @@ using Elwig.Dialogs; using Elwig.Helpers; using Elwig.Helpers.Billing; +using Elwig.Helpers.Export; +using Elwig.Models.Dtos; using Microsoft.Win32; using System; -using System.IO; -using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Input; @@ -59,137 +59,23 @@ namespace Elwig.Windows { if (SeasonInput.Value is not int year) return; var d = new SaveFileDialog() { - FileName = $"Über-Unterlieferungen-{year}.csv", - DefaultExt = "csv", - Filter = "CSV-Datei (*.csv)|*.csv", + FileName = $"Über-Unterlieferungen-{year}.ods", + DefaultExt = "ods", + Filter = "OpenDocument Format Spreadsheet (*.ods)|*.ods", Title = $"Über-/Unterlieferungen {year} speichern unter - Elwig" }; if (d.ShowDialog() == false) return; Mouse.OverrideCursor = Cursors.AppStarting; - try { - using var file = new StreamWriter(d.FileName, false, Encoding.Latin1); - using var cnx = await AppDbContext.ConnectAsync(); - await file.WriteLineAsync($"Auswertungen {year};;;;;;;;;;;"); - - await file.WriteLineAsync($";;;;;;;;;;;"); - await file.WriteLineAsync($"Über-/Unterlieferungen lt. gez. GA;;;;;;;;;;;"); - await file.WriteLineAsync($"MgNr;Name;Vorname;Adresse;PLZ;Ort;GA;Lieferpflicht;Lieferrecht;Geliefert;Über-/Unterliefert;Prozent"); - using (var cmd = cnx.CreateCommand()) { - cmd.CommandText = $""" - SELECT m.mgnr, m.family_name, m.given_name, p.plz, o.name, m.address, m.business_shares, - m.business_shares * s.min_kg_per_bs AS min_kg, - m.business_shares * s.max_kg_per_bs AS max_kg, - COALESCE(SUM(d.weight), 0) AS sum - FROM member m - LEFT JOIN AT_plz_dest p ON p.id = m.postal_dest - LEFT JOIN AT_ort o ON o.okz = p.okz - LEFT JOIN season s ON s.year = {year} - LEFT JOIN v_delivery d ON d.mgnr = m.mgnr AND d.year = s.year - WHERE m.active = 1 - GROUP BY d.year, m.mgnr - ORDER BY sum = 0 DESC, 100.0 * sum / max_kg, m.mgnr; - """; - using var reader = await cmd.ExecuteReaderAsync(); - while (await reader.ReadAsync()) { - var mgnr = reader.GetInt32(0); - var familyName = reader.GetString(1); - var givenName = reader.GetString(2); - var plz = reader.GetInt32(3); - var ort = reader.GetString(4).Split(',')[0]; - var addr = reader.GetString(5); - var ga = reader.GetInt32(6); - var minKg = reader.GetInt32(7); - var maxKg = reader.GetInt32(8); - var sum = reader.GetInt32(9); - var s1 = sum < minKg ? $"{sum - minKg}" : sum > maxKg ? $"{sum - maxKg}" : ""; - var s2 = sum < minKg ? $"{sum * 100.0 / minKg - 100.0:0.0}" : sum > maxKg ? $"{sum * 100.0 / maxKg - 100:0.0}" : ""; - await file.WriteLineAsync($"{mgnr};{familyName};{givenName};{addr};{plz};{ort};{ga};{minKg};{maxKg};{sum};{s1};{s2}"); - } - } - - await file.WriteLineAsync($";;;;;;;;;;;"); - await file.WriteLineAsync($"Unterlieferungen lt. Flächenbindungen;;;;;;;;;;;"); - await file.WriteLineAsync($"MgNr;Name;Vorname;Adresse;PLZ;Ort;Vertrag;Fläche;Lieferpflicht;Geliefert;Unterliefert;Prozent"); - using (var cmd = cnx.CreateCommand()) { - cmd.CommandText = $""" - SELECT m.mgnr, m.family_name, m.given_name, p.plz, o.name, m.address, - c.bucket, c.area, u.min_kg, u.weight - FROM member m - LEFT JOIN AT_plz_dest p ON p.id = m.postal_dest - LEFT JOIN AT_ort o ON o.okz = p.okz - LEFT JOIN v_area_commitment_bucket_strict c ON c.mgnr = m.mgnr AND c.year = {year} - JOIN v_under_delivery u ON (u.mgnr, u.bucket, u.year) = (m.mgnr, c.bucket, c.year) - WHERE m.active = 1 - ORDER BY m.mgnr, c.bucket - """; - using var reader = await cmd.ExecuteReaderAsync(); - while (await reader.ReadAsync()) { - var mgnr = reader.GetInt32(0); - var familyName = reader.GetString(1); - var givenName = reader.GetString(2); - var plz = reader.GetInt32(3); - var ort = reader.GetString(4).Split(',')[0]; - var addr = reader.GetString(5); - var id = reader.GetString(6); - var area = reader.GetInt32(7); - var minKg = reader.GetInt32(8); - var sum = reader.GetInt32(9); - await file.WriteLineAsync($"{mgnr};{familyName};{givenName};{addr};{plz};{ort};{id};{area};{minKg};{sum};{sum - minKg};{sum * 100.0 / minKg - 100.0:0.0}"); - } - } - - await file.WriteLineAsync($";;;;;;;;;;;"); - await file.WriteLineAsync($"Lieferungen pro Mitglied und Sorte;;;;;;;;;;;"); - await file.WriteLineAsync($"MgNr;Name;Vorname;Adresse;PLZ;Ort;Sorte;Attribut;Geliefert;Fläche;Ertrag"); - using (var cmd = cnx.CreateCommand()) { - cmd.CommandText = $""" - SELECT m.mgnr, m.family_name, m.given_name, p.plz, o.name, m.address, - v.bucket, v.weight, v.area - FROM ( - SELECT c.year AS year, - c.mgnr AS mgnr, - c.bucket AS bucket, - COALESCE(d.weight, 0) AS weight, - COALESCE(c.area, 0) AS area - FROM v_area_commitment_bucket_strict c - LEFT JOIN v_delivery_bucket_strict d ON (d.year, d.mgnr, d.bucket) = (c.year, c.mgnr, c.bucket) - WHERE c.year = {year} - UNION - SELECT d.year, - d.mgnr, - d.bucket, - COALESCE(d.weight, 0), - COALESCE(c.area, 0) - FROM v_delivery_bucket_strict d - LEFT JOIN v_area_commitment_bucket_strict c ON (c.year, c.mgnr, c.bucket) = (d.year, d.mgnr, d.bucket) - WHERE d.year = {year} - ) v - LEFT JOIN member m ON m.mgnr = v.mgnr - LEFT JOIN AT_plz_dest p ON p.id = m.postal_dest - LEFT JOIN AT_ort o ON o.okz = p.okz - ORDER BY m.mgnr, v.bucket - """; - using var reader = await cmd.ExecuteReaderAsync(); - while (await reader.ReadAsync()) { - var mgnr = reader.GetInt32(0); - var familyName = reader.GetString(1); - var givenName = reader.GetString(2); - var plz = reader.GetInt32(3); - var ort = reader.GetString(4).Split(',')[0]; - var addr = reader.GetString(5); - var id = reader.GetString(6); - var sum = reader.GetInt32(7); - var area = reader.GetInt32(8); - await file.WriteLineAsync($"{mgnr};{familyName};{givenName};{addr};{plz};{ort};{id[..2]};{id[2..]};{sum};{area};{(area > 0 ? sum * 10000 / area : "")}"); - } - } + using var ods = new OdsFile(d.FileName); + await ods.AddTable(await OverUnderDeliveryData.ForSeason(Context.OverUnderDeliveryRows, year)); + await ods.AddTable(await AreaComUnderDeliveryData.ForSeason(Context.AreaComUnderDeliveryRows, year)); + await ods.AddTable(await MemberDeliveryPerVariantData.ForSeason(Context.MemberDeliveryPerVariantRows, year)); } catch (Exception exc) { MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); } - Mouse.OverrideCursor = null; }