using Microsoft.EntityFrameworkCore; 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, string?, int)[] FieldNames = [ ("MgNr", "MgNr.", null, 12), ("Name1", "Name", null, 40), ("Name2", "Vorname", null, 40), ("Address", "Adresse", null, 60), ("Plz", "PLZ", null, 10), ("Locality", "Ort", null, 60), ("Shares", "GA", null, 10), ("DeliveryObligation", "Lieferpflicht", "kg", 22), ("DeliveryRight", "Lieferrecht", "kg", 22), ("WeightTotal", "Geliefert", "kg", 22), ("OverUnderDelivery", "Über-/Unterliefert", "kg|%", 34), ]; private static readonly (string, string, string?, int)[] FieldNamesRed = [ ("MgNr", "MgNr.", null, 12), ("Name1", "Name", null, 40), ("Name2", "Vorname", null, 40), ("Address", "Adresse", null, 60), ("Plz", "PLZ", null, 10), ("Locality", "Ort", null, 60), ("SharesRed", "GA", null, 10), ("DeliveryObligationRed", "Lieferpflicht", "kg", 22), ("DeliveryRightRed", "Lieferrecht", "kg", 22), ("WeightRed", "Geliefert", "kg", 22), ("OverUnderDeliveryRed", "Über-/Unterliefert", "kg|%", 34), ]; private static readonly (string, string, string?, int)[] FieldNamesWhite = [ ("MgNr", "MgNr.", null, 12), ("Name1", "Name", null, 40), ("Name2", "Vorname", null, 40), ("Address", "Adresse", null, 60), ("Plz", "PLZ", null, 10), ("Locality", "Ort", null, 60), ("SharesWhite", "GA", null, 10), ("DeliveryObligationWhite", "Lieferpflicht", "kg", 22), ("DeliveryRightWhite", "Lieferrecht", "kg", 22), ("WeightWhite", "Geliefert", "kg", 22), ("OverUnderDeliveryWhite", "Über-/Unterliefert", "kg|%", 34), ]; public OverUnderDeliveryData(IEnumerable rows, int year) : base($"Über-Unterlieferungen", $"Über- und Unterlieferungen laut gezeichneten Geschäftsanteilen {year}", rows, FieldNames) { } public OverUnderDeliveryData(IEnumerable rows, int year, string mode) : base($"Über-Unterlieferungen", $"Über- und Unterlieferungen laut gezeichneten Geschäftsanteilen {(mode == "R" ? "rot" : "weiß")} {year}", rows, mode == "R" ? FieldNamesRed : FieldNamesWhite) { } public static async Task ForSeason(DbSet table, int year) { var rows = await table.FromSql($""" SELECT m.mgnr, m.name AS name_1, COALESCE(m.prefix || ' ', '') || m.given_name || COALESCE(' ' || m.middle_names, '') || COALESCE(' ' || m.suffix, '') AS name_2, p.plz, o.name AS ort, m.address, m.shares, m.shares_red, m.shares_white, m.shares * COALESCE(s.min_kg_per_share, 0) AS min_kg, m.shares * COALESCE(s.max_kg_per_share, 0) AS max_kg, m.shares_red * COALESCE(s.min_kg_per_share_red, s.min_kg_per_share, 0) AS min_kg_red, m.shares_red * COALESCE(s.max_kg_per_share_red, s.max_kg_per_share, 0) AS max_kg_red, m.shares_white * COALESCE(s.min_kg_per_share_white, s.min_kg_per_share, 0) AS min_kg_white, m.shares_white * COALESCE(s.max_kg_per_share_white, s.max_kg_per_share, 0) AS max_kg_white, COALESCE(d.weight_total, 0) AS weight_total, COALESCE(d.weight_red, 0) AS weight_red, COALESCE(d.weight_white, 0) AS weight_white FROM season s, 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_stat_member d ON (d.year, d.mgnr) = (s.year, m.mgnr) WHERE s.year = {year} AND (m.active = TRUE OR d.weight_total > 0) ORDER BY 100.0 * weight_total / (max_kg + max_kg_red + max_kg_white), m.mgnr """).ToListAsync(); return new OverUnderDeliveryData(rows, year); } } [Keyless] public class OverUnderDeliveryRow { [Column("mgnr")] public int MgNr { get; set; } [Column("name_1")] public required string Name1 { get; set; } [Column("name_2")] public string? Name2 { get; set; } [Column("address")] public required string Address { get; set; } [Column("plz")] public int Plz { get; set; } [Column("ort")] public required string LocalityFull { get; set; } [NotMapped] public string Locality => LocalityFull.Split(",")[0]; [Column("shares")] public int Shares { get; set; } [Column("shares_red")] public int SharesRed { get; set; } [Column("shares_white")] public int SharesWhite { get; set; } [Column("min_kg")] public int DeliveryObligation { get; set; } [Column("max_kg")] public int DeliveryRight { get; set; } [NotMapped] public (int? Kg, double? Percent) OverUnderDelivery => WeightTotal < DeliveryObligation ? (WeightTotal - DeliveryObligation, WeightTotal * 100.0 / DeliveryObligation - 100.0) : WeightTotal > DeliveryRight ? (WeightTotal - DeliveryRight, WeightTotal * 100.0 / DeliveryRight - 100.0) : (null, null); [Column("min_kg_red")] public int DeliveryObligationRed { get; set; } [Column("max_kg_red")] public int DeliveryRightRed { get; set; } [NotMapped] public (int? Kg, double? Percent) OverUnderDeliveryRed => WeightRed < DeliveryObligationRed ? (WeightRed - DeliveryObligationRed, WeightRed * 100.0 / DeliveryObligationRed - 100.0) : WeightRed > DeliveryRightRed ? (WeightRed - DeliveryRightRed, WeightRed * 100.0 / DeliveryRightRed - 100.0) : (null, null); [Column("min_kg_white")] public int DeliveryObligationWhite { get; set; } [Column("max_kg_white")] public int DeliveryRightWhite { get; set; } [NotMapped] public (int? Kg, double? Percent) OverUnderDeliveryWhite => WeightWhite < DeliveryObligationWhite ? (WeightWhite - DeliveryObligationWhite, WeightWhite * 100.0 / DeliveryObligationWhite - 100.0) : WeightWhite > DeliveryRightWhite ? (WeightWhite - DeliveryRightWhite, WeightWhite * 100.0 / DeliveryRightWhite - 100.0) : (null, null); [Column("weight_total")] public int WeightTotal { get; set; } [Column("weight_red")] public int WeightRed { get; set; } [Column("weight_white")] public int WeightWhite { get; set; } } }