129 lines
5.8 KiB
C#
129 lines
5.8 KiB
C#
using Elwig.Models.Entities;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Data.Entity.Core.Common.CommandTrees.ExpressionBuilder;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace Elwig.Models.Dtos {
|
|
public class WineQualityStatisticsData {
|
|
|
|
public record struct QualityRow(string? Variety, string? Attribute, string? Cultivation, string? Type, string QualId, double AvgKmw, double Grad, int Num, int Weight);
|
|
public record struct QualitySection(string Name, string? Type, Dictionary<string, (double Grad, double AvgKmw, int Num, int Weight)[]> Data);
|
|
|
|
public bool UseOe = true;
|
|
public QualitySection[] Sections;
|
|
|
|
public WineQualityStatisticsData(QualitySection[] sections) {
|
|
Sections = sections;
|
|
}
|
|
|
|
private static QualitySection[] GetSections(IEnumerable<QualityRow> rows) {
|
|
var data = new List<QualitySection>();
|
|
var currentQual = new Dictionary<double, (double AvgKmw, int Num, int Weight)>();
|
|
var current = new Dictionary<string, (double, double, int, int)[]>();
|
|
string? lastSection = null;
|
|
string? lastType = null;
|
|
string? lastQual = null;
|
|
foreach (var row in rows) {
|
|
var sec = $"{row.Variety ?? (row.Type == "R" ? "Rotweinsorten" : row.Type == "W" ? "Weißweinsorten" : "Gesamt")}" +
|
|
$"{(row.Attribute != null ? " / " : "")}{row.Attribute}" +
|
|
$"{(row.Cultivation != null ? " / " : "")}{row.Cultivation}";
|
|
if (lastQual != null && lastQual != row.QualId) {
|
|
current[lastQual] = currentQual.Select(kv => (kv.Key, kv.Value.AvgKmw, kv.Value.Num, kv.Value.Weight)).ToArray();
|
|
currentQual.Clear();
|
|
}
|
|
if (lastSection != null && lastSection != sec) {
|
|
if (!current.ContainsKey(lastQual!)) {
|
|
current[lastQual!] = currentQual.Select(kv => (kv.Key, kv.Value.AvgKmw, kv.Value.Num, kv.Value.Weight)).ToArray();
|
|
currentQual.Clear();
|
|
}
|
|
data.Add(new(lastSection, lastType, current));
|
|
current = [];
|
|
currentQual.Clear();
|
|
}
|
|
currentQual[row.Grad] = (row.AvgKmw, row.Num, row.Weight);
|
|
lastSection = sec;
|
|
lastType = row.Type;
|
|
lastQual = row.QualId;
|
|
}
|
|
if (lastQual != null) {
|
|
current[lastQual] = currentQual.Select(kv => (kv.Key, kv.Value.AvgKmw, kv.Value.Num, kv.Value.Weight)).ToArray();
|
|
currentQual.Clear();
|
|
}
|
|
if (lastSection != null) {
|
|
data.Add(new(lastSection, lastType, current));
|
|
current = [];
|
|
currentQual.Clear();
|
|
}
|
|
return [.. data];
|
|
}
|
|
|
|
public static async Task<WineQualityStatisticsData> FromQuery(IQueryable<DeliveryPart> query, int mode = 0) {
|
|
var rows = (await query
|
|
.GroupBy(p => new {
|
|
p.Variety.Type,
|
|
Variety = p.Variety.Name,
|
|
Attribute = p.Attribute!.Name,
|
|
Cultivation = p.Cultivation!.Name,
|
|
p.QualId,
|
|
Grad = mode == 0 ? Math.Round(p.Kmw * (4.54 + 0.022 * p.Kmw), 0) :
|
|
mode == 1 ? Math.Floor(p.Kmw) :
|
|
mode == 2 ? Math.Floor(p.Kmw * 2) / 2 :
|
|
mode == 3 ? Math.Floor(p.Kmw * 5) / 5 :
|
|
Math.Round(p.Kmw, 1),
|
|
}, (k, g) => new {
|
|
Key = k,
|
|
Num = g.Count(),
|
|
Weight = g.Sum(p => p.Weight),
|
|
AvgKmw = g.Sum(p => p.Weight * p.Kmw) / g.Sum(p => p.Weight),
|
|
})
|
|
.OrderBy(g => g.Key.Variety)
|
|
.ThenBy(g => g.Key.Attribute)
|
|
.ThenBy(g => g.Key.Cultivation)
|
|
.ThenBy(g => g.Key.QualId)
|
|
.ThenBy(g => g.Key.Grad)
|
|
.ToListAsync())
|
|
.Select(r => new QualityRow(r.Key.Variety, r.Key.Attribute, r.Key.Cultivation, r.Key.Type, r.Key.QualId, r.AvgKmw, r.Key.Grad, r.Num, r.Weight))
|
|
.ToList();
|
|
|
|
var data = GetSections(rows);
|
|
if (data.Length <= 1)
|
|
return new(data);
|
|
|
|
var typeRows = rows
|
|
.GroupBy(s => new { s.Type, s.QualId, s.Grad }, (k, g) => new QualityRow(
|
|
null, null, null,
|
|
k.Type, k.QualId,
|
|
g.Sum(p => p.Weight * p.AvgKmw) / g.Sum(p => p.Weight),
|
|
k.Grad,
|
|
g.Sum(p => p.Num),
|
|
g.Sum(p => p.Weight)
|
|
))
|
|
.OrderBy(g => g.Type)
|
|
.ThenBy(g => g.QualId)
|
|
.ThenBy(g => g.Grad)
|
|
.ToList();
|
|
var typeData = GetSections(typeRows);
|
|
if (typeData.Length <= 1)
|
|
return new([.. typeData, .. data]);
|
|
|
|
var totalRows = rows
|
|
.GroupBy(s => new { s.QualId, s.Grad }, (k, g) => new QualityRow(
|
|
null, null, null, null,
|
|
k.QualId,
|
|
g.Sum(p => p.Weight * p.AvgKmw) / g.Sum(p => p.Weight),
|
|
k.Grad,
|
|
g.Sum(p => p.Num),
|
|
g.Sum(p => p.Weight)
|
|
))
|
|
.OrderBy(g => g.QualId)
|
|
.ThenBy(g => g.Grad)
|
|
.ToList();
|
|
var totalData = GetSections(totalRows);
|
|
return new([.. totalData, .. typeData, .. data]) { UseOe = mode == 0 };
|
|
}
|
|
}
|
|
}
|