Dtos: Add more DTOs
This commit is contained in:
@ -9,6 +9,7 @@ using Microsoft.Extensions.Logging;
|
|||||||
using Microsoft.Data.Sqlite;
|
using Microsoft.Data.Sqlite;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Elwig.Models.Dtos;
|
||||||
|
|
||||||
namespace Elwig.Helpers {
|
namespace Elwig.Helpers {
|
||||||
public class AppDbContext : DbContext {
|
public class AppDbContext : DbContext {
|
||||||
@ -45,6 +46,10 @@ namespace Elwig.Helpers {
|
|||||||
public DbSet<PaymentMember> MemberPayments { get; private set; }
|
public DbSet<PaymentMember> MemberPayments { get; private set; }
|
||||||
public DbSet<Credit> Credits { get; private set; }
|
public DbSet<Credit> Credits { get; private set; }
|
||||||
|
|
||||||
|
public DbSet<OverUnderDeliveryRow> OverUnderDeliveryRows { get; private set; }
|
||||||
|
public DbSet<AreaComUnderDeliveryRowSingle> AreaComUnderDeliveryRows { get; private set; }
|
||||||
|
public DbSet<MemberDeliveryPerVariantRowSingle> MemberDeliveryPerVariantRows { 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);
|
||||||
public DateTime SavedLastWriteTime { get; private set; }
|
public DateTime SavedLastWriteTime { get; private set; }
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
using Elwig.Models.Dtos;
|
using Elwig.Models.Dtos;
|
||||||
using ScottPlot;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Data.Entity.Core.Common.CommandTrees.ExpressionBuilder;
|
using System.Data.Entity.Core.Common.CommandTrees.ExpressionBuilder;
|
||||||
@ -20,7 +19,7 @@ namespace Elwig.Helpers.Export {
|
|||||||
FileName = filename;
|
FileName = filename;
|
||||||
File.Delete(filename);
|
File.Delete(filename);
|
||||||
ZipArchive = ZipFile.Open(FileName, ZipArchiveMode.Create);
|
ZipArchive = ZipFile.Open(FileName, ZipArchiveMode.Create);
|
||||||
_tables = new List<string>();
|
_tables = new();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose() {
|
public void Dispose() {
|
||||||
@ -90,6 +89,19 @@ namespace Elwig.Helpers.Export {
|
|||||||
<style:style style:name="default" style:family="table-cell">
|
<style:style style:name="default" style:family="table-cell">
|
||||||
<style:table-cell-properties style:vertical-align="top"/>
|
<style:table-cell-properties style:vertical-align="top"/>
|
||||||
</style:style>
|
</style:style>
|
||||||
|
|
||||||
|
""");
|
||||||
|
|
||||||
|
for (int i = 1; i <= 100; i++) {
|
||||||
|
await Content.WriteAsync($"""
|
||||||
|
<style:style style:name="colw{i}" style:family="table-column">
|
||||||
|
<style:table-column-properties style:column-width="{i}mm"/>
|
||||||
|
</style:style>
|
||||||
|
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
|
||||||
|
await Content.WriteAsync("""
|
||||||
<style:style style:name="header" style:family="table-cell" style:parent-style-name="default">
|
<style:style style:name="header" style:family="table-cell" style:parent-style-name="default">
|
||||||
<style:table-cell-properties style:text-align-source="fix" style:repeat-content="false"/>
|
<style:table-cell-properties style:text-align-source="fix" style:repeat-content="false"/>
|
||||||
<style:paragraph-properties fo:text-align="center"/>
|
<style:paragraph-properties fo:text-align="center"/>
|
||||||
@ -163,9 +175,12 @@ namespace Elwig.Helpers.Export {
|
|||||||
if (Content == null) return;
|
if (Content == null) return;
|
||||||
var totalSpan = table.ColumnSpans.Sum();
|
var totalSpan = table.ColumnSpans.Sum();
|
||||||
|
|
||||||
_tables.Add(table.FullName);
|
_tables.Add(table.Name);
|
||||||
|
await Content.WriteAsync($" <table:table table:name=\"{table.Name}\" table:default-cell-style-name=\"default\">\r\n");
|
||||||
|
foreach (var w in table.ColumnWidths) {
|
||||||
|
await Content.WriteAsync(" <table:table-column" + (w != null ? $" table:style-name=\"colw{w}\"" : "") + "/>\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
await Content.WriteAsync($" <table:table table:name=\"{table.FullName}\" table:default-cell-style-name=\"default\">\r\n");
|
|
||||||
await Content.WriteAsync(
|
await Content.WriteAsync(
|
||||||
$" <table:table-row>\r\n" +
|
$" <table:table-row>\r\n" +
|
||||||
FormatCell(table.FullName, colSpan: totalSpan, style: "header") +
|
FormatCell(table.FullName, colSpan: totalSpan, style: "header") +
|
||||||
|
109
Elwig/Models/Dtos/AreaComUnderDeliveyData.cs
Normal file
109
Elwig/Models/Dtos/AreaComUnderDeliveyData.cs
Normal file
@ -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<AreaComUnderDeliveryRow> {
|
||||||
|
|
||||||
|
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<AreaComUnderDeliveryRow> rows, int year) :
|
||||||
|
base($"Unterlieferungen FB", $"Unterlieferungen laut Flächenbindungen {year}", rows, FieldNames) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<AreaComUnderDeliveryData> ForSeason(DbSet<AreaComUnderDeliveryRowSingle> table, int year) {
|
||||||
|
return new AreaComUnderDeliveryData(
|
||||||
|
(await FromDbSet(table, year)).GroupBy(
|
||||||
|
r => r.MgNr,
|
||||||
|
(k, g) => new AreaComUnderDeliveryRow(g)
|
||||||
|
), year);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task<IEnumerable<AreaComUnderDeliveryRowSingle>> FromDbSet(DbSet<AreaComUnderDeliveryRowSingle> 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<AreaComUnderDeliveryRowSingle> 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; }
|
||||||
|
}
|
||||||
|
}
|
@ -17,15 +17,16 @@ namespace Elwig.Models.Dtos {
|
|||||||
public IEnumerable<Type?> ColumnTypes => ColumnDefs.Select(m => m.Item2);
|
public IEnumerable<Type?> ColumnTypes => ColumnDefs.Select(m => m.Item2);
|
||||||
public IEnumerable<Type?> ColumnFlatTypes { get; private set; }
|
public IEnumerable<Type?> ColumnFlatTypes { get; private set; }
|
||||||
public IEnumerable<int> ColumnSpans { get; private set; }
|
public IEnumerable<int> ColumnSpans { get; private set; }
|
||||||
|
public IEnumerable<int?> ColumnWidths { get; private set; }
|
||||||
|
|
||||||
private readonly PropertyInfo[] _properties;
|
private readonly PropertyInfo[] _properties;
|
||||||
private readonly FieldInfo[] _fields;
|
private readonly FieldInfo[] _fields;
|
||||||
private readonly (string, PropertyInfo?, FieldInfo?)[] _map;
|
private readonly (string, PropertyInfo?, FieldInfo?)[] _map;
|
||||||
|
|
||||||
public DataTable(string name, string fullName, IEnumerable<T> rows, IEnumerable<(string, string)>? colNames = null) {
|
public DataTable(string name, string fullName, IEnumerable<T> rows, IEnumerable<(string, string, int?)>? colNames = null) {
|
||||||
_fields = typeof(T).GetFields();
|
_fields = typeof(T).GetFields();
|
||||||
_properties = typeof(T).GetProperties();
|
_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();
|
_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;
|
Name = name;
|
||||||
FullName = fullName;
|
FullName = fullName;
|
||||||
@ -41,10 +42,28 @@ namespace Elwig.Models.Dtos {
|
|||||||
return type != null && type.IsValueType && type.Name.StartsWith("ValueTuple") ? type.GetFields().Length :
|
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;
|
type != null && elType != null && type.IsArray && elType.IsValueType && elType.Name.StartsWith("ValueTuple") ? elType.GetFields().Length : 1;
|
||||||
}).ToList();
|
}).ToList();
|
||||||
|
ColumnWidths = colNames.Select(c => c.Item3).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public DataTable(string name, string fullName, IEnumerable<T> rows, IEnumerable<(string, string)>? colNames = null) :
|
||||||
|
this(name, fullName, rows, colNames?.Select(c => (c.Item1, c.Item2, (int?)null))) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public DataTable(string name, IEnumerable<T> rows, IEnumerable<(string, string)>? colNames = null) :
|
public DataTable(string name, IEnumerable<T> rows, IEnumerable<(string, string)>? colNames = null) :
|
||||||
this(name, name, rows, colNames) { }
|
this(name, name, rows, colNames) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public DataTable(string name, IEnumerable<T> rows, IEnumerable<(string, string, int?)>? colNames = null) :
|
||||||
|
this(name, name, rows, colNames) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public DataTable(string name, IEnumerable<T> rows, IEnumerable<(string, string, int)>? colNames = null) :
|
||||||
|
this(name, name, rows, colNames) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public DataTable(string name, string fullName, IEnumerable<T> 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) {
|
protected IEnumerable<(string, object?)> GetNamedRowData(T row) {
|
||||||
return _map.Select(i => (i.Item1, i.Item2?.GetValue(row) ?? i.Item3?.GetValue(row)));
|
return _map.Select(i => (i.Item1, i.Item2?.GetValue(row) ?? i.Item3?.GetValue(row)));
|
||||||
|
@ -7,7 +7,7 @@ using System.Threading.Tasks;
|
|||||||
namespace Elwig.Models.Dtos {
|
namespace Elwig.Models.Dtos {
|
||||||
public class DeliveryConfirmationData : DataTable<DeliveryConfirmationRow> {
|
public class DeliveryConfirmationData : DataTable<DeliveryConfirmationRow> {
|
||||||
|
|
||||||
private static readonly (string, string)[] _fieldNames = new[] {
|
private static readonly (string, string)[] FieldNames = new[] {
|
||||||
("LsNr", "LsNr."),
|
("LsNr", "LsNr."),
|
||||||
("DPNr", "Pos."),
|
("DPNr", "Pos."),
|
||||||
("Variant", "Sorte"),
|
("Variant", "Sorte"),
|
||||||
@ -20,24 +20,24 @@ namespace Elwig.Models.Dtos {
|
|||||||
("Weight", "Gewicht"),
|
("Weight", "Gewicht"),
|
||||||
};
|
};
|
||||||
|
|
||||||
public int MgNr { get; private set; }
|
private readonly int MgNr;
|
||||||
|
|
||||||
private DeliveryConfirmationData(IEnumerable<DeliveryConfirmationRow> rows, int mgnr) :
|
private DeliveryConfirmationData(IEnumerable<DeliveryConfirmationRow> rows, int year, Member m) :
|
||||||
base("Anl.-Best.", "Anlieferungsbestätigung", rows, _fieldNames) {
|
base($"Anlieferungsbestätigung", $"Anlieferungsbestätigung {year} – {m.AdministrativeName}", rows, FieldNames) {
|
||||||
MgNr = mgnr;
|
MgNr = m.MgNr;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<IDictionary<int, DeliveryConfirmationData>> ForSeason(DbSet<DeliveryPart> table, int year) {
|
public static async Task<IDictionary<int, DeliveryConfirmationData>> ForSeason(DbSet<DeliveryPart> table, int year) {
|
||||||
return (await FromDbSet(table, year))
|
return (await FromDbSet(table, year))
|
||||||
.GroupBy(
|
.GroupBy(
|
||||||
p => p.Delivery.MgNr,
|
p => p.Delivery.Member,
|
||||||
p => new DeliveryConfirmationRow(p),
|
p => new DeliveryConfirmationRow(p),
|
||||||
(k, g) => new DeliveryConfirmationData(g, k)
|
(k, g) => new DeliveryConfirmationData(g, year, k)
|
||||||
).ToDictionary(d => d.MgNr, d => d);
|
).ToDictionary(d => d.MgNr, d => d);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<DeliveryConfirmationData> ForMember(DbSet<DeliveryPart> table, int year, int mgnr) {
|
public static async Task<DeliveryConfirmationData> ForMember(DbSet<DeliveryPart> table, int year, Member m) {
|
||||||
return new DeliveryConfirmationData((await FromDbSet(table, year, mgnr)).Select(p => new DeliveryConfirmationRow(p)), mgnr);
|
return new DeliveryConfirmationData((await FromDbSet(table, year, m.MgNr)).Select(p => new DeliveryConfirmationRow(p)), year, m);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<IEnumerable<DeliveryPart>> FromDbSet(DbSet<DeliveryPart> table, int? year = null, int? mgnr = null) {
|
private static async Task<IEnumerable<DeliveryPart>> FromDbSet(DbSet<DeliveryPart> table, int? year = null, int? mgnr = null) {
|
||||||
@ -66,7 +66,6 @@ namespace Elwig.Models.Dtos {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public class DeliveryConfirmationRow {
|
public class DeliveryConfirmationRow {
|
||||||
|
|
||||||
public string LsNr;
|
public string LsNr;
|
||||||
public int DPNr;
|
public int DPNr;
|
||||||
public string Variant;
|
public string Variant;
|
||||||
|
118
Elwig/Models/Dtos/MemberDeliveryPerVariantData.cs
Normal file
118
Elwig/Models/Dtos/MemberDeliveryPerVariantData.cs
Normal file
@ -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<MemberDeliveryPerVariantRow> {
|
||||||
|
|
||||||
|
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<MemberDeliveryPerVariantRow> rows, int year) :
|
||||||
|
base($"Liefermengen", $"Liefermengen pro Mitglied, Sorte und Attribut {year}", rows, FieldNames) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<MemberDeliveryPerVariantData> ForSeason(DbSet<MemberDeliveryPerVariantRowSingle> table, int year) {
|
||||||
|
return new MemberDeliveryPerVariantData(
|
||||||
|
(await FromDbSet(table, year)).GroupBy(
|
||||||
|
r => r.MgNr,
|
||||||
|
(k, g) => new MemberDeliveryPerVariantRow(g)
|
||||||
|
), year);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task<IEnumerable<MemberDeliveryPerVariantRowSingle>> FromDbSet(DbSet<MemberDeliveryPerVariantRowSingle> 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<MemberDeliveryPerVariantRowSingle> 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; }
|
||||||
|
}
|
||||||
|
}
|
81
Elwig/Models/Dtos/OverUnderDeliveryData.cs
Normal file
81
Elwig/Models/Dtos/OverUnderDeliveryData.cs
Normal file
@ -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<OverUnderDeliveryRow> {
|
||||||
|
|
||||||
|
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<OverUnderDeliveryRow> rows, int year) :
|
||||||
|
base($"Über-Unterlieferungen", $"Über- und Unterlieferungen laut gezeichneten Geschäftsanteilen {year}", rows, FieldNames) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<OverUnderDeliveryData> ForSeason(DbSet<OverUnderDeliveryRow> 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;
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +1,10 @@
|
|||||||
using Elwig.Dialogs;
|
using Elwig.Dialogs;
|
||||||
using Elwig.Helpers;
|
using Elwig.Helpers;
|
||||||
using Elwig.Helpers.Billing;
|
using Elwig.Helpers.Billing;
|
||||||
|
using Elwig.Helpers.Export;
|
||||||
|
using Elwig.Models.Dtos;
|
||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
@ -59,137 +59,23 @@ namespace Elwig.Windows {
|
|||||||
if (SeasonInput.Value is not int year)
|
if (SeasonInput.Value is not int year)
|
||||||
return;
|
return;
|
||||||
var d = new SaveFileDialog() {
|
var d = new SaveFileDialog() {
|
||||||
FileName = $"Über-Unterlieferungen-{year}.csv",
|
FileName = $"Über-Unterlieferungen-{year}.ods",
|
||||||
DefaultExt = "csv",
|
DefaultExt = "ods",
|
||||||
Filter = "CSV-Datei (*.csv)|*.csv",
|
Filter = "OpenDocument Format Spreadsheet (*.ods)|*.ods",
|
||||||
Title = $"Über-/Unterlieferungen {year} speichern unter - Elwig"
|
Title = $"Über-/Unterlieferungen {year} speichern unter - Elwig"
|
||||||
};
|
};
|
||||||
if (d.ShowDialog() == false)
|
if (d.ShowDialog() == false)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Mouse.OverrideCursor = Cursors.AppStarting;
|
Mouse.OverrideCursor = Cursors.AppStarting;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
using var file = new StreamWriter(d.FileName, false, Encoding.Latin1);
|
using var ods = new OdsFile(d.FileName);
|
||||||
using var cnx = await AppDbContext.ConnectAsync();
|
await ods.AddTable(await OverUnderDeliveryData.ForSeason(Context.OverUnderDeliveryRows, year));
|
||||||
await file.WriteLineAsync($"Auswertungen {year};;;;;;;;;;;");
|
await ods.AddTable(await AreaComUnderDeliveryData.ForSeason(Context.AreaComUnderDeliveryRows, year));
|
||||||
|
await ods.AddTable(await MemberDeliveryPerVariantData.ForSeason(Context.MemberDeliveryPerVariantRows, 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 : "")}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception exc) {
|
} catch (Exception exc) {
|
||||||
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
Mouse.OverrideCursor = null;
|
Mouse.OverrideCursor = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user