From 9478f2a1ab3c13e45b06c2687fc4b84936408bf4 Mon Sep 17 00:00:00 2001
From: Lorenz Stechauner <lorenz.stechauner@necronda.net>
Date: Fri, 28 Jun 2024 21:07:55 +0200
Subject: [PATCH] [#49] PaymentVariantSummary: Add modifier statistics

---
 Elwig/Documents/PaymentVariantSummary.cs     |  8 +++-
 Elwig/Documents/PaymentVariantSummary.cshtml | 39 ++++++++++++++++++++
 Elwig/Helpers/AppDbContext.cs                | 30 +++++++++++++++
 Elwig/Helpers/AppDbUpdater.cs                |  2 +-
 Elwig/Resources/Sql/22-23.sql                | 15 ++++++++
 Tests/fetch-resources.bat                    |  2 +-
 6 files changed, 93 insertions(+), 3 deletions(-)
 create mode 100644 Elwig/Resources/Sql/22-23.sql

diff --git a/Elwig/Documents/PaymentVariantSummary.cs b/Elwig/Documents/PaymentVariantSummary.cs
index 0c39a11..8818958 100644
--- a/Elwig/Documents/PaymentVariantSummary.cs
+++ b/Elwig/Documents/PaymentVariantSummary.cs
@@ -1,6 +1,8 @@
-using Elwig.Helpers.Billing;
+using Elwig.Helpers;
+using Elwig.Helpers.Billing;
 using Elwig.Models.Dtos;
 using Elwig.Models.Entities;
+using System.Collections.Generic;
 using System.Linq;
 
 namespace Elwig.Documents {
@@ -15,6 +17,8 @@ namespace Elwig.Documents {
         public int MemberNum;
         public int DeliveryNum;
         public int DeliveryPartNum;
+        public List<ModifierStat> ModifierStat;
+        public Dictionary<string, Modifier> Modifiers;
 
         public PaymentVariantSummary(PaymentVar v, PaymentVariantSummaryData data) :
             base($"{Name} {v.Year} - {v.Name}") {
@@ -25,6 +29,8 @@ namespace Elwig.Documents {
             MemberNum = v.Credits.Count;
             DeliveryNum = v.DeliveryPartPayments.DistinctBy(p => p.DeliveryPart.Delivery).Count();
             DeliveryPartNum = v.DeliveryPartPayments.Count;
+            ModifierStat = AppDbContext.GetModifierStats(v.Year, v.AvNr).GetAwaiter().GetResult();
+            Modifiers = v.Season.Modifiers.ToDictionary(m => m.ModId);
         }
     }
 }
diff --git a/Elwig/Documents/PaymentVariantSummary.cshtml b/Elwig/Documents/PaymentVariantSummary.cshtml
index 43c4b14..0e8833f 100644
--- a/Elwig/Documents/PaymentVariantSummary.cshtml
+++ b/Elwig/Documents/PaymentVariantSummary.cshtml
@@ -167,6 +167,45 @@
             </tr>
         </tbody>
     </table>
+    <table class="payment-variant border">
+        <colgroup>
+            <col style="width: 35mm;"/>
+            <col style="width: 30mm;"/>
+            <col style="width: 25mm;"/>
+            <col style="width: 25mm;"/>
+            <col style="width: 25mm;"/>
+            <col style="width: 25mm;"/>
+        </colgroup>
+        <thead>
+            <tr>
+                <th rowspan="2">Name</th>
+                <th rowspan="2">Zu-/Abschlag</th>
+                <th>Lieferungen</th>
+                <th>Minimum</th>
+                <th>Maximum</th>
+                <th>Betrag</th>
+            </tr>
+            <tr>
+                <th>[#]</th>
+                <th>[@Model.CurrencySymbol]</th>
+                <th>[@Model.CurrencySymbol]</th>
+                <th>[@Model.CurrencySymbol]</th>
+            </tr>
+        </thead>
+        <tbody>
+            @foreach (var m in Model.ModifierStat) {
+                var mod = Model.Modifiers[m.ModId];
+                <tr>
+                    <th>@mod.Name</th>
+                    <td class="number">@mod.ValueStr</td>
+                    <td class="number">@($"{m.Count:N0}")</td>
+                    <td class="number">@($"{m.Min:N2}")</td>
+                    <td class="number">@($"{m.Max:N2}")</td>
+                    <td class="number">@($"{m.Sum:N2}")</td>
+                </tr>
+            }
+        </tbody>
+    </table>
     <table class="payment-variant-data">
         <colgroup>
             <col style="width: 30mm;"/>
diff --git a/Elwig/Helpers/AppDbContext.cs b/Elwig/Helpers/AppDbContext.cs
index d7cac24..449e418 100644
--- a/Elwig/Helpers/AppDbContext.cs
+++ b/Elwig/Helpers/AppDbContext.cs
@@ -19,6 +19,7 @@ namespace Elwig.Helpers {
     public record struct UnderDelivery(int Weight, int Diff);
     public record struct MemberBucket(string Name, int Area, int Obligation, int Right, int Delivery, int DeliveryStrict, int Payment);
     public record struct MemberStat(string Variety, string Discr, int Weight);
+    public record struct ModifierStat(string ModId, string Name, int Count, decimal? Min, decimal? Max, decimal Sum);
 
     public class AppDbContext : DbContext {
 
@@ -437,5 +438,34 @@ namespace Elwig.Helpers {
             if (ownCnx) await cnx.DisposeAsync();
             return list;
         }
+
+        public static async Task<List<ModifierStat>> GetModifierStats(int year, int avnr, SqliteConnection? cnx = null) {
+            var ownCnx = cnx == null;
+            cnx ??= await ConnectAsync();
+            var list = new List<ModifierStat>();
+            using (var cmd = cnx.CreateCommand()) {
+                cmd.CommandText = $"""
+                    SELECT m.modid, m.name, m.count, m.min, m.max, m.sum, s.precision
+                    FROM v_stat_modifier m
+                        JOIN season s ON s.year = m.year
+                    WHERE m.year = {year} AND m.avnr = {avnr}
+                    """;
+                using var reader = await cmd.ExecuteReaderAsync();
+                while (await reader.ReadAsync()) {
+                    var prec = (byte)reader.GetInt16(6);
+                    long? min = reader.IsDBNull(3) ? null : reader.GetInt64(3);
+                    long? max = reader.IsDBNull(4) ? null : reader.GetInt64(4);
+                    var sum = reader.GetInt64(5);
+                    if (min != null && max != null && Math.Abs((long)min) > Math.Abs((long)max))
+                        (min, max) = (max, min);
+                    list.Add(new(reader.GetString(0), reader.GetString(1), reader.GetInt32(2),
+                        min == null ? null : Utils.DecFromDb((long)min, prec),
+                        max == null ? null : Utils.DecFromDb((long)max, prec),
+                        Utils.DecFromDb(sum, prec)));
+                }
+            }
+            if (ownCnx) await cnx.DisposeAsync();
+            return list;
+        }
     }
 }
diff --git a/Elwig/Helpers/AppDbUpdater.cs b/Elwig/Helpers/AppDbUpdater.cs
index dd7a737..6c3d86f 100644
--- a/Elwig/Helpers/AppDbUpdater.cs
+++ b/Elwig/Helpers/AppDbUpdater.cs
@@ -9,7 +9,7 @@ namespace Elwig.Helpers {
     public static class AppDbUpdater {
 
         // Don't forget to update value in Tests/fetch-resources.bat!
-        public static readonly int RequiredSchemaVersion = 22;
+        public static readonly int RequiredSchemaVersion = 23;
 
         private static int VersionOffset = 0;
 
diff --git a/Elwig/Resources/Sql/22-23.sql b/Elwig/Resources/Sql/22-23.sql
new file mode 100644
index 0000000..162c27c
--- /dev/null
+++ b/Elwig/Resources/Sql/22-23.sql
@@ -0,0 +1,15 @@
+-- schema version 20 to 21
+
+CREATE VIEW v_stat_modifier AS
+SELECT v.year, v.avnr, m.modid, m.name, m.abs, m.rel,
+       COUNT(*) AS count,
+       MIN(IIF(p.net_amount = 0 AND m.abs IS NULL, NULL, ROUND(COALESCE(d.weight * m.abs, 0) + COALESCE(p.net_amount * m.rel, 0)))) AS min,
+       MAX(IIF(p.net_amount = 0 AND m.abs IS NULL, NULL, ROUND(COALESCE(d.weight * m.abs, 0) + COALESCE(p.net_amount * m.rel, 0)))) AS max,
+       SUM(ROUND(COALESCE(d.weight * m.abs, 0) + COALESCE(p.net_amount * m.rel, 0))) AS sum
+FROM payment_variant v
+    JOIN modifier m ON m.year = v.year
+    JOIN delivery_part d ON d.year = v.year
+    JOIN delivery_part_modifier x ON (x.year, x.did, x.dpnr, x.modid) = (d.year, d.did, d.dpnr, m.modid)
+    LEFT JOIN payment_delivery_part p ON (p.year, p.did, p.dpnr, p.avnr) = (d.year, d.did, d.dpnr, v.avnr)
+GROUP BY v.year, v.avnr, m.modid
+ORDER BY v.year, v.avnr, m.ordering;
diff --git a/Tests/fetch-resources.bat b/Tests/fetch-resources.bat
index eb7707e..2f43848 100644
--- a/Tests/fetch-resources.bat
+++ b/Tests/fetch-resources.bat
@@ -1 +1 @@
-curl --fail -s -L "https://elwig.at/files/create.sql?v=22" -u "elwig:ganzGeheim123!" -o "Resources\Sql\Create.sql"
+curl --fail -s -L "https://elwig.at/files/create.sql?v=23" -u "elwig:ganzGeheim123!" -o "Resources\Sql\Create.sql"