From ad9f4d3a9a2d938cb182b37cf5eca6ba582dd7dc Mon Sep 17 00:00:00 2001 From: Lorenz Stechauner Date: Tue, 31 Oct 2023 22:21:24 +0100 Subject: [PATCH] Models: Remove DeliveryPartAttr --- Elwig/Documents/CreditNote.cshtml | 4 +- Elwig/Documents/DeliveryConfirmation.cshtml | 4 +- Elwig/Documents/DeliveryNote.cshtml | 4 +- Elwig/Helpers/AppDbContext.cs | 23 ---- Elwig/Helpers/AppDbUpdater.cs | 121 +++++++++++++++++++- Elwig/Helpers/Billing/Billing.cs | 4 +- Elwig/Helpers/NullItem.cs | 11 +- Elwig/Models/AreaComType.cs | 19 +-- Elwig/Models/DeliveryPart.cs | 15 +-- Elwig/Models/DeliveryPartAttr.cs | 25 ---- Elwig/Windows/DeliveryAdminWindow.xaml | 10 +- Elwig/Windows/DeliveryAdminWindow.xaml.cs | 36 +++--- 12 files changed, 172 insertions(+), 104 deletions(-) delete mode 100644 Elwig/Models/DeliveryPartAttr.cs diff --git a/Elwig/Documents/CreditNote.cshtml b/Elwig/Documents/CreditNote.cshtml index f6bf043..a841b3d 100644 --- a/Elwig/Documents/CreditNote.cshtml +++ b/Elwig/Documents/CreditNote.cshtml @@ -27,7 +27,7 @@ Lieferschein-Nr. Pos. Sorte - Attribut(e) + Attribut Gradation Zu-/Abschläge @Raw(string.Join("
", Model.BinNames)) @@ -65,7 +65,7 @@ @part.Delivery.LsNr @part.DPNr @part.Variant.Name - @string.Join(" / ", part.PartAttributes.Select(a => a.AttrId)) + @part.Attribute?.Name @($"{part.Oe:N0}") @($"{part.Kmw:N1}") @abs diff --git a/Elwig/Documents/DeliveryConfirmation.cshtml b/Elwig/Documents/DeliveryConfirmation.cshtml index fa3df41..fc3e2ac 100644 --- a/Elwig/Documents/DeliveryConfirmation.cshtml +++ b/Elwig/Documents/DeliveryConfirmation.cshtml @@ -24,7 +24,7 @@ Lieferschein-Nr. Pos. Sorte - Attribut(e) + Attribut Qualitätsstufe Gradation Flächenbindung @@ -56,7 +56,7 @@ @p.Delivery.LsNr @p.DPNr @p.Variant.Name - @p.AttributesString + @p.Attribute?.Name @p.Quality.Name @($"{p.Oe:N0}") @($"{p.Kmw:N1}") diff --git a/Elwig/Documents/DeliveryNote.cshtml b/Elwig/Documents/DeliveryNote.cshtml index 1c10201..7680ee5 100644 --- a/Elwig/Documents/DeliveryNote.cshtml +++ b/Elwig/Documents/DeliveryNote.cshtml @@ -21,7 +21,7 @@ Pos. Sorte - Attribut(e) + Attribut Qualitätsstufe Gradation Gewicht @@ -37,7 +37,7 @@ @part.DPNr @part.Variant.Name - @string.Join(" / ", part.Attributes) + @part.Attribute?.Name @part.Quality.Name @($"{part.Oe:N0}") @($"{part.Kmw:N1}") diff --git a/Elwig/Helpers/AppDbContext.cs b/Elwig/Helpers/AppDbContext.cs index 7db9138..f093bff 100644 --- a/Elwig/Helpers/AppDbContext.cs +++ b/Elwig/Helpers/AppDbContext.cs @@ -40,7 +40,6 @@ namespace Elwig.Helpers { public DbSet Modifiers { get; private set; } public DbSet Deliveries { get; private set; } public DbSet DeliveryParts { get; private set; } - public DbSet DeliveryPartAttributes { get; private set; } public DbSet DeliveryPartModifiers { get; private set; } public DbSet PaymentVariants { get; private set; } public DbSet MemberPayments { get; private set; } @@ -166,28 +165,6 @@ namespace Elwig.Helpers { .LastOrDefaultAsync(); } - public async Task UpdateDeliveryPartAttributes(DeliveryPart part, IEnumerable attributes) { - foreach (var a in WineAttributes) { - var attr = part.PartAttributes.Where(pa => pa.AttrId == a.AttrId).FirstOrDefault(); - if (attributes.Contains(a)) { - DeliveryPartAttr dpa = attr ?? this.CreateProxy(); - dpa.Year = part.Year; - dpa.DId = part.DId; - dpa.DPNr = part.DPNr; - dpa.AttrId = a.AttrId; - if (attr == null) { - await AddAsync(dpa); - } else { - Update(dpa); - } - } else { - if (attr != null) { - Remove(attr); - } - } - } - } - public async Task UpdateDeliveryPartModifiers(DeliveryPart part, IEnumerable modifiers) { foreach (var m in Modifiers.Where(m => m.Year == part.Year)) { var mod = part.PartModifiers.Where(pa => pa.ModId == m.ModId).FirstOrDefault(); diff --git a/Elwig/Helpers/AppDbUpdater.cs b/Elwig/Helpers/AppDbUpdater.cs index c3a9a99..fbe1f6b 100644 --- a/Elwig/Helpers/AppDbUpdater.cs +++ b/Elwig/Helpers/AppDbUpdater.cs @@ -4,11 +4,11 @@ using System; namespace Elwig.Helpers { public static class AppDbUpdater { - public static readonly int RequiredSchemaVersion = 4; + public static readonly int RequiredSchemaVersion = 5; private static int _versionOffset = 0; private static readonly Action[] _updaters = new[] { - UpdateDbSchema_1_To_2, UpdateDbSchema_2_To_3, UpdateDbSchema_3_To_4 + UpdateDbSchema_1_To_2, UpdateDbSchema_2_To_3, UpdateDbSchema_3_To_4, UpdateDbSchema_4_To_5 }; private static void ExecuteNonQuery(SqliteConnection cnx, string sql) { @@ -65,11 +65,14 @@ namespace Elwig.Helpers { } ExecuteNonQuery(cnx, "PRAGMA locking_mode = EXCLUSIVE"); + ExecuteNonQuery(cnx, "PRAGMA foreign_keys = OFF"); ExecuteNonQuery(cnx, "BEGIN EXCLUSIVE"); for (int i = fromVersion; i < toVersion; i++) { _updaters[i - 1](cnx); } + ExecuteNonQuery(cnx, "PRAGMA foreign_key_check"); ExecuteNonQuery(cnx, "COMMIT"); + ExecuteNonQuery(cnx, "PRAGMA foreign_keys = ON"); ExecuteNonQuery(cnx, "VACUUM"); ExecuteNonQuery(cnx, $"PRAGMA schema_version = {toVersion * 100 + _versionOffset}"); } @@ -213,5 +216,119 @@ namespace Elwig.Helpers { ORDER BY s.year, c.mgnr, LENGTH(c.vtrgid) DESC, c.vtrgid; """); } + + private static void UpdateDbSchema_4_To_5(SqliteConnection cnx) { + ExecuteNonQuery(cnx, """ + CREATE TABLE _area_commitment_type ( + vtrgid TEXT NOT NULL CHECK (vtrgid = sortid || COALESCE(attrid, '') || disc), + sortid TEXT NOT NULL, + attrid TEXT, + disc TEXT DEFAULT NULL CHECK (disc REGEXP '^[A-Z0-9]+$'), + + min_kg_per_ha INTEGER, + max_kg_per_ha INTEGER, + penalty_amount INTEGER, + + CONSTRAINT pk_area_commitment_type PRIMARY KEY (vtrgid), + CONSTRAINT sk_area_commitment_type_sort_attr UNIQUE (sortid, attrid, disc), + CONSTRAINT fk_area_commitment_type_wine_variety FOREIGN KEY (sortid) REFERENCES wine_variety (sortid) + ON UPDATE CASCADE + ON DELETE RESTRICT, + CONSTRAINT fk_area_commitment_type_wine_attribute FOREIGN KEY (attrid) REFERENCES wine_attribute (attrid) + ON UPDATE CASCADE + ON DELETE RESTRICT + ) STRICT; + """); + ExecuteNonQuery(cnx, """ + INSERT INTO _area_commitment_type (vtrgid, sortid, attrid, disc, min_kg_per_ha, max_kg_per_ha, penalty_amount) + SELECT vtrgid, sortid, attrid_1, disc, min_kg_per_ha, max_kg_per_ha, penalty_amount FROM area_commitment_type + """); + ExecuteNonQuery(cnx, "PRAGMA writable_schema = ON"); + ExecuteNonQuery(cnx, "DROP TABLE area_commitment_type"); + ExecuteNonQuery(cnx, "ALTER TABLE _area_commitment_type RENAME TO area_commitment_type"); + ExecuteNonQuery(cnx, "PRAGMA writable_schema = OFF"); + + ExecuteNonQuery(cnx, """ + ALTER TABLE delivery_part ADD COLUMN attrid TEXT DEFAULT NULL + REFERENCES wine_attribute (attrid) + ON UPDATE CASCADE + ON DELETE RESTRICT + """); + ExecuteNonQuery(cnx, """ + UPDATE delivery_part + SET attrid = (SELECT attrid + FROM delivery_part_attribute a + WHERE (delivery_part.year, delivery_part.did, delivery_part.dpnr) = (a.year, a.did, a.dpnr) + ORDER BY attrid DESC + LIMIT 1) + """); + ExecuteNonQuery(cnx, "DROP TRIGGER t_delivery_part_attribute_i_mtime_delivery_part"); + ExecuteNonQuery(cnx, "DROP TRIGGER t_delivery_part_attribute_u_mtime_delivery_part"); + ExecuteNonQuery(cnx, "DROP TRIGGER t_delivery_part_attribute_d_mtime_delivery_part"); + ExecuteNonQuery(cnx, "DROP TABLE delivery_part_attribute"); + + ExecuteNonQuery(cnx, "DROP VIEW v_delivery"); + ExecuteNonQuery(cnx, """ + CREATE VIEW v_delivery AS + SELECT p.year, p.did, p.dpnr, + d.date, d.time, d.zwstid, d.lnr, d.lsnr, + m.mgnr, m.family_name, m.given_name, + p.sortid, a.attrid, + p.weight, p.kmw, ROUND(p.kmw * (4.54 + 0.022 * p.kmw), 0) AS oe, p.qualid, + p.hkid, p.kgnr, p.rdnr, + p.gerebelt, p.gebunden, + p.qualid IN (SELECT l.qualid FROM wine_quality_level l WHERE NOT l.predicate AND (p.kmw >= l.min_kmw OR l.min_kmw IS NULL) ORDER BY l.min_kmw DESC LIMIT 1,100) AS abgewertet, + p.qualid NOT IN ('WEI', 'RSW', 'LDW') AS min_quw, + COALESCE(a.fill_lower_bins, 0) AS attribute_prio, + GROUP_CONCAT(o.modid) AS modifiers, + d.comment, p.comment AS part_comment + FROM delivery_part p + JOIN delivery d ON (d.year, d.did) = (p.year, p.did) + JOIN member m ON m.mgnr = d.mgnr + LEFT JOIN wine_attribute a ON a.attrid = p.attrid + LEFT JOIN delivery_part_modifier o ON (o.year, o.did, o.dpnr) = (p.year, p.did, p.dpnr) + GROUP BY p.year, p.did, p.dpnr + ORDER BY p.year, p.did, p.dpnr, o.modid; + """); + + ExecuteNonQuery(cnx, "DROP VIEW v_delivery_bin"); + ExecuteNonQuery(cnx, """ + CREATE VIEW v_delivery_bin AS + SELECT year, mgnr, + sortid || IIF(min_quw, COALESCE(attrid, ''), '_') AS bin, + SUM(weight) AS weight + FROM v_delivery + GROUP BY year, mgnr, bin + ORDER BY year, mgnr, LENGTH(bin) DESC, bin; + """); + + ExecuteNonQuery(cnx, "DROP VIEW v_stat_attr"); + ExecuteNonQuery(cnx, """ + CREATE VIEW v_stat_attr AS + SELECT year, attrid, + SUM(weight) as sum, + ROUND(SUM(kmw * weight) / SUM(weight), 2) AS kmw, + ROUND(SUM(oe * weight) / SUM(weight), 1) AS oe, + COUNT(DISTINCT did) AS lieferungen, + COUNT(DISTINCT mgnr) AS mitglieder + FROM v_delivery + GROUP BY year, attrid + ORDER BY year, attrid; + """); + + ExecuteNonQuery(cnx, "DROP VIEW v_stat_sort_attr"); + ExecuteNonQuery(cnx, """ + CREATE VIEW v_stat_sort_attr AS + SELECT year, sortid, attrid, + SUM(weight) as sum, + ROUND(SUM(kmw * weight) / SUM(weight), 2) AS kmw, + ROUND(SUM(oe * weight) / SUM(weight), 1) AS oe, + COUNT(DISTINCT did) AS lieferungen, + COUNT(DISTINCT mgnr) AS mitglieder + FROM v_delivery + GROUP BY year, sortid, attrid + ORDER BY year, sortid, attrid; + """); + } } } diff --git a/Elwig/Helpers/Billing/Billing.cs b/Elwig/Helpers/Billing/Billing.cs index ff97ac7..0698e7d 100644 --- a/Elwig/Helpers/Billing/Billing.cs +++ b/Elwig/Helpers/Billing/Billing.cs @@ -11,14 +11,14 @@ namespace Elwig.Helpers.Billing { protected readonly AppDbContext Context; protected readonly Dictionary Attributes; protected readonly Dictionary Modifiers; - protected readonly Dictionary AreaComTypes; + protected readonly Dictionary AreaComTypes; public Billing(int year) { Year = year; Context = new AppDbContext(); Attributes = Context.WineAttributes.ToDictionary(a => a.AttrId, a => a.Name); Modifiers = Context.Modifiers.Where(m => m.Year == Year).ToDictionary(m => m.ModId, m => (m.Abs, m.Rel)); - AreaComTypes = Context.AreaCommitmentTypes.ToDictionary(v => v.VtrgId, v => (v.SortId, v.AttrId1, v.AttrId2, v.Discriminator, v.MinKgPerHa, v.MaxKgPerHa, v.PenaltyAmount)); + AreaComTypes = Context.AreaCommitmentTypes.ToDictionary(v => v.VtrgId, v => (v.SortId, v.AttrId, v.Discriminator, v.MinKgPerHa, v.MaxKgPerHa, v.PenaltyAmount)); } public async Task FinishSeason() { diff --git a/Elwig/Helpers/NullItem.cs b/Elwig/Helpers/NullItem.cs index 9ac9f61..81f8cae 100644 --- a/Elwig/Helpers/NullItem.cs +++ b/Elwig/Helpers/NullItem.cs @@ -1,5 +1,14 @@ namespace Elwig.Helpers { public class NullItem { - public static string Name => "- Keine Angabe -"; + + public string Name { get; private set; } + + public NullItem(string name = "- Keine Angabe -") { + Name = name; + } + + public override string ToString() { + return Name; + } } } diff --git a/Elwig/Models/AreaComType.cs b/Elwig/Models/AreaComType.cs index ce532de..c9e411b 100644 --- a/Elwig/Models/AreaComType.cs +++ b/Elwig/Models/AreaComType.cs @@ -4,7 +4,7 @@ using System.ComponentModel.DataAnnotations.Schema; using IndexAttribute = Microsoft.EntityFrameworkCore.IndexAttribute; namespace Elwig.Models { - [Table("area_commitment_type"), PrimaryKey("VtrgId"), Index("SortId", "AttrId1", "AttrId2", "Discriminator")] + [Table("area_commitment_type"), PrimaryKey("VtrgId"), Index("SortId", "AttrId", "Discriminator")] public class AreaComType { [Column("vtrgid")] public string VtrgId { get; set; } @@ -12,11 +12,8 @@ namespace Elwig.Models { [Column("sortid")] public string SortId { get; set; } - [Column("attrid_1")] - public string? AttrId1 { get; set; } - - [Column("attrid_2")] - public string? AttrId2 { get; set; } + [Column("attrid")] + public string? AttrId { get; set; } [Column("disc")] public string? Discriminator { get; set; } @@ -39,14 +36,10 @@ namespace Elwig.Models { [ForeignKey("SortId")] public virtual WineVar WineVar { get; private set; } - [ForeignKey("AttrId1")] - public virtual WineAttr? WineAttr1 { get; private set; } - - [ForeignKey("AttrId2")] - public virtual WineAttr? WineAttr2 { get; private set; } + [ForeignKey("AttrId")] + public virtual WineAttr? WineAttr { get; private set; } [NotMapped] - public string DisplayName => WineVar.Name + (WineAttr1 != null ? $" {WineAttr1.Name}" : "") + - (WineAttr2 != null ? $" {WineAttr2.Name}" : "") + (Discriminator != null ? $" ({Discriminator})" : ""); + public string DisplayName => WineVar.Name + (WineAttr != null ? $" {WineAttr.Name}" : "") + (Discriminator != null ? $" ({Discriminator})" : ""); } } diff --git a/Elwig/Models/DeliveryPart.cs b/Elwig/Models/DeliveryPart.cs index d74015a..3554e17 100644 --- a/Elwig/Models/DeliveryPart.cs +++ b/Elwig/Models/DeliveryPart.cs @@ -25,6 +25,12 @@ namespace Elwig.Models { [ForeignKey("SortId")] public virtual WineVar Variant { get; private set; } + [Column("attrid")] + public string? AttrId { get; set; } + + [ForeignKey("AttrId")] + public virtual WineAttr? Attribute { get; private set; } + [Column("weight")] public int Weight { get; set; } @@ -96,15 +102,6 @@ namespace Elwig.Models { [Column("comment")] public string? Comment { get; set; } - [InverseProperty("Part")] - public virtual ISet PartAttributes { get; private set; } - - [NotMapped] - public IEnumerable Attributes => PartAttributes.Select(a => a.Attr); - - [NotMapped] - public string AttributesString => string.Join(" / ", Attributes); - [InverseProperty("Part")] public virtual ISet PartModifiers { get; private set; } diff --git a/Elwig/Models/DeliveryPartAttr.cs b/Elwig/Models/DeliveryPartAttr.cs deleted file mode 100644 index 5e3e611..0000000 --- a/Elwig/Models/DeliveryPartAttr.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using System.ComponentModel.DataAnnotations.Schema; - -namespace Elwig.Models { - [Table("delivery_part_attribute"), PrimaryKey("Year", "DId", "DPNr", "AttrId")] - public class DeliveryPartAttr { - [Column("year")] - public int Year { get; set; } - - [Column("did")] - public int DId { get; set; } - - [Column("dpnr")] - public int DPNr { get; set; } - - [ForeignKey("Year, DId, DPNr")] - public virtual DeliveryPart Part { get; private set; } - - [Column("attrid")] - public string AttrId { get; set; } - - [ForeignKey("AttrId")] - public virtual WineAttr Attr { get; private set; } - } -} diff --git a/Elwig/Windows/DeliveryAdminWindow.xaml b/Elwig/Windows/DeliveryAdminWindow.xaml index 72f7d2a..5c0ddd9 100644 --- a/Elwig/Windows/DeliveryAdminWindow.xaml +++ b/Elwig/Windows/DeliveryAdminWindow.xaml @@ -271,10 +271,10 @@ ItemTemplate="{StaticResource WineVarietyTemplate}" TextSearch.TextPath="Name" SelectionChanged="WineVarietyInput_SelectionChanged" KeyUp="Input_KeyUp"/> -