using Elwig.Helpers.Billing; using Elwig.Models.Entities; 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 CreditNoteDeliveryData : DataTable { private static readonly (string, string, string?)[] FieldNames = [ ("", "", null), // TODO ]; private readonly int Year; private readonly int? TgNr; private readonly int? AvNr; private readonly int? MgNr; private CreditNoteDeliveryData(IEnumerable rows, int year, int? tgnr, int? avnr = null, int? mgnr = null) : base($"Traubengutschrift {year}/{tgnr}", rows, FieldNames) { Year = year; TgNr = tgnr; AvNr = avnr; MgNr = mgnr; } public static async Task> ForPaymentVariant(DbSet table, DbSet seasons, int year, int avnr) { var variant = (await seasons.FindAsync(year))?.PaymentVariants.Where(v => v.AvNr == avnr).SingleOrDefault(); BillingData? varData = null; try { varData = variant != null ? BillingData.FromJson(variant.Data) : null; } catch { } return (await FromDbSet(table, year, avnr)) .GroupBy( r => new { r.Year, r.AvNr, r.MgNr, r.TgNr, r.DId, r.DPNr }, (k, g) => new CreditNoteDeliveryRow(g, seasons, varData?.NetWeightModifier ?? 0.0, varData?.GrossWeightModifier ?? 0.0)) .GroupBy( r => new { r.Year, r.AvNr, r.MgNr, r.TgNr }, (k, g) => new CreditNoteDeliveryData(g, k.Year, k.TgNr, mgnr: k.MgNr)) .ToDictionary(d => d.MgNr ?? 0); } private static async Task> FromDbSet(DbSet table, int? year = null, int? avnr = null, int? mgnr = null) { var y = year?.ToString() ?? "NULL"; var v = avnr?.ToString() ?? "NULL"; var m = mgnr?.ToString() ?? "NULL"; return await table.FromSqlRaw($""" SELECT d.year, c.tgnr, v.avnr, d.mgnr, d.did, d.lsnr, d.dpnr, d.weight, d.modifiers, b.bktnr, d.sortid, b.discr, b.value, pb.price, pb.amount, p.net_amount, p.amount AS total_amount, s.name AS variety, a.name AS attribute, c.name AS cultivation, q.qualid AS qualid, q.name AS quality_level, d.oe, d.kmw, d.net_weight FROM v_delivery d JOIN wine_variety s ON s.sortid = d.sortid LEFT JOIN wine_attribute a ON a.attrid = d.attrid LEFT JOIN wine_cultivation c ON c.cultid = d.cultid JOIN wine_quality_level q ON q.qualid = d.qualid LEFT JOIN delivery_part_bucket b ON (b.year, b.did, b.dpnr) = (d.year, d.did, d.dpnr) LEFT JOIN payment_variant v ON v.year = d.year LEFT JOIN payment_delivery_part p ON (p.year, p.did, p.dpnr, p.avnr) = (d.year, d.did, d.dpnr, v.avnr) LEFT JOIN payment_delivery_part_bucket pb ON (pb.year, pb.did, pb.dpnr, pb.bktnr, pb.avnr) = (b.year, b.did, b.dpnr, b.bktnr, v.avnr) LEFT JOIN credit c ON (c.year, c.avnr, c.mgnr) = (d.year, v.avnr, d.mgnr) WHERE b.value > 0 AND (d.year = {y} OR {y} IS NULL) AND (v.avnr = {v} OR {v} IS NULL) AND (d.mgnr = {m} OR {m} IS NULL) ORDER BY d.year, v.avnr, d.mgnr, d.lsnr, d.dpnr """).ToListAsync(); } } public class CreditNoteDeliveryRow { public int Year; public int? TgNr; public int? AvNr; public int MgNr; public string LsNr; public int DPNr; public string Variety; public string? Attribute; public string? Cultivation; public string[] Modifiers; public string QualId; public string QualityLevel; public (double Oe, double Kmw) Gradation; public (string Name, int Value, decimal? Price, decimal? Amount)[] Buckets; public decimal? TotalModifiers; public decimal? Amount; public double WeighingModifier; public CreditNoteDeliveryRow(IEnumerable rows, DbSet seasons, double netWeightModifier, double grossWeightModifier) { var f = rows.First(); Year = f.Year; TgNr = f.TgNr; AvNr = f.AvNr; MgNr = f.MgNr; var season = seasons.Find(Year); LsNr = f.LsNr; DPNr = f.DPNr; Variety = f.Variety; Attribute = f.Attribute; Cultivation = f.Cultivation; var modifiers = (IEnumerable)(f.Modifiers ?? "").Split(',') .Select(m => season?.Modifiers.FirstOrDefault(s => s.ModId == m)) .Where(m => m != null) .OrderBy(m => m.Ordering) .ToList(); Modifiers = modifiers.Select(m => m.Name).ToArray(); QualId = f.QualId; QualityLevel = f.QualityLevel; Gradation = (f.Oe, f.Kmw); Buckets = rows .Where(b => b.Value > 0) .OrderByDescending(b => b.BktNr) .Select(b => (b.Discr == "_" ? "ungeb." : $"geb. {f.SortId}{b.Discr}", b.Value, b.Price != null ? season?.DecFromDb((long)b.Price) : null, b.Amount != null ? season?.DecFromDb((long)b.Amount) : null)) .ToArray(); WeighingModifier = f.NetWeight ? netWeightModifier : grossWeightModifier; Amount = f.TotalAmount != null ? season?.DecFromDb((long)f.TotalAmount) : null; var netAmount = f.NetAmount != null ? season?.DecFromDb((long)f.NetAmount) : null; var amt = netAmount * (decimal)(1.0 + WeighingModifier); TotalModifiers = Amount - (amt != null ? Math.Round((decimal)amt, season?.Precision ?? 0) : null); } } [Keyless] public class CreditNoteDeliveryRowSingle { [Column("year")] public int Year { get; set; } [Column("tgnr")] public int? TgNr { get; set; } [Column("avnr")] public int? AvNr { get; set; } [Column("mgnr")] public int MgNr { get; set; } [Column("did")] public int DId { get; set; } [Column("lsnr")] public required string LsNr { get; set; } [Column("dpnr")] public int DPNr { get; set; } [Column("weight")] public int Weight { get; set; } [Column("modifiers")] public string? Modifiers { get; set; } [Column("bktnr")] public int BktNr { get; set; } [Column("sortid")] public required string SortId { get; set; } [Column("discr")] public required string Discr { get; set; } [Column("value")] public int Value { get; set; } [Column("price")] public long? Price { get; set; } [Column("amount")] public long? Amount { get; set; } [Column("net_amount")] public long? NetAmount { get; set; } [Column("total_amount")] public long? TotalAmount { 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("qualid")] public required string QualId { get; set; } [Column("quality_level")] public required string QualityLevel { get; set; } [Column("oe")] public double Oe { get; set; } [Column("kmw")] public double Kmw { get; set; } [Column("net_weight")] public bool NetWeight { get; set; } } }