Files
elwig/Elwig/Services/DeliveryService.cs
Lorenz Stechauner f09753ccc2
All checks were successful
Test / Run tests (push) Successful in 2m4s
Remove byte order marks
2024-07-26 19:44:41 +02:00

802 lines
44 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Elwig.Documents;
using Elwig.Helpers.Export;
using Elwig.Helpers;
using Elwig.Models.Dtos;
using Elwig.Models.Entities;
using Microsoft.Win32;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Input;
using System.Windows;
using System;
using Elwig.ViewModels;
using LinqKit;
using System.Globalization;
using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore;
using System.IO;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using System.Windows.Controls;
namespace Elwig.Services {
public static class DeliveryService {
public static async Task<Member?> GetMemberAsync(int mgnr) {
using var ctx = new AppDbContext();
return await ctx.Members
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.DefaultWbKg!.AtKg)
.FirstOrDefaultAsync(m => m.MgNr == mgnr);
}
public static Member? GetMember(int mgnr) {
return GetMemberAsync(mgnr).GetAwaiter().GetResult();
}
public static void ClearInputs(this DeliveryAdminViewModel vm) {
}
public static void FillInputs(this DeliveryAdminViewModel vm, Delivery d) {
vm.MgNrString = $"{d.MgNr}";
vm.Branch = (Branch?)ControlUtils.GetItemFromSourceWithPk(vm.BranchSource, d.ZwstId);
vm.LsNr = d.LsNr;
vm.Date = $"{d.Date:dd.MM.yyyy}";
vm.Time = $"{d.Time:HH:mm}";
vm.Comment = d.Comment ?? "";
vm.SortId = "";
vm.GradationKmwString = "";
vm.WeightString = "";
vm.IsManualWeighing = false;
vm.PartComment = "";
vm.TemperatureString = "";
vm.AcidString = "";
}
public static void FillInputs(this DeliveryAdminViewModel vm, DeliveryPart p) {
vm.SortId = p.SortId;
vm.WineAttr = ControlUtils.GetItemFromSourceWithPk(vm.WineAttrSource, p.AttrId) as WineAttr;
vm.WineCult = ControlUtils.GetItemFromSourceWithPk(vm.WineCultSource, p.CultId) as WineCult;
vm.GradationKmwString = $"{p.Kmw:N1}";
vm.WineQualityLevel = (WineQualLevel?)ControlUtils.GetItemFromSourceWithPk(vm.WineQualityLevelSource, p.QualId);
vm.WineKg = ControlUtils.GetItemFromSourceWithPk(vm.WineKgSource, p.KgNr) as AT_Kg;
vm.WineRd = ControlUtils.GetItemFromSourceWithPk(vm.WineRdSource, p.KgNr, p.RdNr) as WbRd;
vm.WineOrigin = ControlUtils.GetItemFromSourceWithPk(vm.WineOriginSource, p.HkId) as WineOrigin;
vm.WeightString = $"{p.Weight:N0}";
vm.IsManualWeighing = p.IsManualWeighing;
vm.IsNetWeight = p.IsNetWeight;
vm.Modifiers.Clear();
foreach (var m in p.Modifiers) {
vm.Modifiers.Add((Modifier)ControlUtils.GetItemFromSourceWithPk(vm.ModifiersSource, m.Year, m.ModId)!);
}
vm.PartComment = p.Comment ?? "";
vm.TemperatureString = (p.Temperature != null) ? $"{p.Temperature:N1}" : "";
vm.AcidString = (p.Acid != null) ? $"{p.Acid:N1}" : "";
vm.IsLesewagen = p.IsLesewagen ?? false;
vm.IsHandPicked = p.IsHandPicked;
vm.IsGebunden = p.IsGebunden;
vm.ScaleId = p.ScaleId;
vm.WeighingData = p.WeighingData;
vm.ManualWeighingReason = p.WeighingReason;
}
public static async Task<(List<string>, IQueryable<Delivery>, IQueryable<DeliveryPart>, Predicate<DeliveryPart>, List<string>)> GetFilters(this DeliveryAdminViewModel vm, AppDbContext ctx) {
List<string> filterNames = [];
IQueryable<Delivery> deliveryQuery = ctx.Deliveries;
if (vm.IsReceipt && App.BranchNum > 1) {
deliveryQuery = deliveryQuery.Where(d => d.ZwstId == App.ZwstId);
filterNames.Add($"Zweigstelle {App.BranchName}");
}
if (vm.FilterMember != null) {
deliveryQuery = deliveryQuery.Where(d => d.MgNr == vm.FilterMember.MgNr);
filterNames.Add(vm.FilterMember.AdministrativeName);
}
if (vm.FilterTodayOnly) {
deliveryQuery = deliveryQuery
.Where(d => (d.DateString == Utils.Today.ToString("yyyy-MM-dd") && (d.TimeString == null || d.TimeString.CompareTo("03:00:00") > 0)) ||
(d.DateString == Utils.Today.AddDays(1).ToString("yyyy-MM-dd") && (d.TimeString == null || d.TimeString.CompareTo("03:00:00") <= 0)));
filterNames.Add(Utils.Today.ToString("dd.MM.yyyy"));
} else if (!vm.FilterAllSeasons) {
deliveryQuery = deliveryQuery.Where(d => d.Year == vm.FilterSeason);
filterNames.Add($"{vm.FilterSeason}");
}
Expression<Func<DeliveryPart, bool>> prd = p => true;
var filterVar = new List<string>();
var filterNotVar = new List<string>();
var filterQual = new List<string>();
var filterNotQual = new List<string>();
var filterMgNr = new List<int>();
var filterZwst = new List<string>();
var filterAttr = new List<string>();
var filterNotAttr = new List<string>();
var filterCult = new List<string>();
var filterNotCult = new List<string>();
var filterDate = new List<(string?, string?)>();
var filterTime = new List<(string?, string?)>();
int filterYearGt = 0, filterYearLt = 0;
double filterKmwGt = 0, filterKmwLt = 0;
double filterOeGt = 0, filterOeLt = 0;
var filter = vm.TextFilter;
if (filter.Count > 0) {
var var = await ctx.WineVarieties.ToDictionaryAsync(v => v.SortId, v => v);
var qual = await ctx.WineQualityLevels.Where(q => !q.IsPredicate).ToDictionaryAsync(q => q.QualId, q => q);
var mgnr = await ctx.Members.ToDictionaryAsync(m => m.MgNr.ToString(), m => m);
var zwst = await ctx.Branches.ToDictionaryAsync(b => b.Name.ToLower().Split(" ")[0], b => b);
var attr = await ctx.WineAttributes.ToDictionaryAsync(a => a.Name.ToLower().Split(' ')[0], a => a);
var cult = await ctx.WineCultivations.ToDictionaryAsync(c => c.Name.ToLower().Split(' ')[0], c => c);
for (int i = 0; i < filter.Count; i++) {
var e = filter[i];
if (e.ToLower() is "r" or "rot") {
filterVar.AddRange(var.Values.Where(v => v.IsRed).Select(v => v.SortId));
filter.RemoveAt(i--);
filterNames.Add("Rotweinsorten");
} else if (e.ToLower() is "w" or "weiß" or "weiss") {
filterVar.AddRange(var.Values.Where(v => v.IsWhite).Select(v => v.SortId));
filter.RemoveAt(i--);
filterNames.Add("Weißweinsorten");
} else if (e.Length >= 3 && e.Length <= 8 && "gebunden".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
prd = prd.And(p => p.IsGebunden == true);
filter.RemoveAt(i--);
filterNames.Add("gebunden");
} else if (e.Length >= 4 && e.Length <= 9 && "!gebunden".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
prd = prd.And(p => p.IsGebunden != true);
filter.RemoveAt(i--);
filterNames.Add("nicht gebunden");
} else if (e.Length >= 5 && e.Length <= 10 && "ungebunden".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
prd = prd.And(p => p.IsGebunden == false);
filter.RemoveAt(i--);
filterNames.Add("ungebunden");
} else if (e.Length >= 6 && e.Length <= 11 && "!ungebunden".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
prd = prd.And(p => p.IsGebunden != false);
filter.RemoveAt(i--);
filterNames.Add("nicht ungebunden");
} else if (e.Length >= 5 && e.Length <= 8 && "handlese".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
prd = prd.And(p => p.IsHandPicked == true);
filter.RemoveAt(i--);
filterNames.Add("Handlese");
} else if (e.Length >= 6 && e.Length <= 9 && "!handlese".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
prd = prd.And(p => p.IsHandPicked == false);
filter.RemoveAt(i--);
filterNames.Add("keine Handlese");
} else if (e.Length >= 5 && e.Length <= 11 && "handwiegung".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
prd = prd.And(p => p.IsManualWeighing == true);
filter.RemoveAt(i--);
filterNames.Add("Handwiegung");
} else if (e.Length >= 6 && e.Length <= 12 && "!handwiegung".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
prd = prd.And(p => p.IsManualWeighing == false);
filter.RemoveAt(i--);
filterNames.Add("keine Handwiegung");
} else if (e.ToLower() == "!gerebelt") {
prd = prd.And(p => p.IsNetWeight == false);
filter.RemoveAt(i--);
filterNames.Add("brutto Wiegung");
} else if (e.ToLower() == "gerebelt") {
prd = prd.And(p => p.IsNetWeight == true);
filter.RemoveAt(i--);
filterNames.Add("netto Wiegung");
} else if (e.Length >= 5 && e.Length <= 9 && "lesewagen".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
prd = prd.And(p => p.IsLesewagen == true);
filter.RemoveAt(i--);
filterNames.Add("Lesewagen");
} else if (e.Length >= 6 && e.Length <= 10 && "!lesewagen".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
prd = prd.And(p => p.IsLesewagen == false);
filter.RemoveAt(i--);
filterNames.Add("kein Lesewagen");
} else if (e.Length == 2 && var.ContainsKey(e.ToUpper())) {
filterVar.Add(e.ToUpper());
filter.RemoveAt(i--);
filterNames.Add(var[e.ToUpper()].Name);
} else if (e.Length == 3 && e[0] == '!' && var.ContainsKey(e[1..].ToUpper())) {
filterNotVar.Add(e[1..].ToUpper());
filter.RemoveAt(i--);
filterNames.Add("außer " + var[e[1..].ToUpper()].Name);
} else if (e.Length == 3 && qual.ContainsKey(e.ToUpper())) {
var qualId = e.ToUpper();
filterQual.Add(qualId);
filter.RemoveAt(i--);
filterNames.Add(qualId == "WEI" ? "abgewertet" : qual[e.ToUpper()].Name);
} else if (e[0] == '!' && qual.ContainsKey(e[1..].ToUpper())) {
var qualId = e[1..].ToUpper();
filterNotQual.Add(qualId);
filter.RemoveAt(i--);
filterNames.Add(qualId == "WEI" ? "nicht abgewertet" : "außer " + qual[e[1..].ToUpper()].Name);
} else if (e.Length >= 5 && e.Length <= 10 && "abgewertet".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
filterQual.Add("WEI");
filter.RemoveAt(i--);
filterNames.Add("abgewertet");
} else if (e.Length >= 6 && e.Length <= 11 && "!abgewertet".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
filterNotQual.Add("WEI");
filter.RemoveAt(i--);
filterNames.Add("nicht abgewertet");
} else if (e.All(char.IsAsciiDigit) && mgnr.TryGetValue(e, out var member)) {
filterMgNr.Add(int.Parse(e));
filter.RemoveAt(i--);
filterNames.Add(member.AdministrativeName);
} else if (attr.ContainsKey(e.ToLower())) {
var a = attr[e.ToLower()];
filterAttr.Add(a.AttrId);
filter.RemoveAt(i--);
filterNames.Add($"Attribut {a.Name}");
} else if (e[0] == '!' && attr.ContainsKey(e[1..].ToLower())) {
var a = attr[e[1..].ToLower()];
filterNotAttr.Add(a.AttrId);
filter.RemoveAt(i--);
filterNames.Add($"ohne Attribut {a.Name}");
} else if (cult.ContainsKey(e.ToLower())) {
var c = cult[e.ToLower()];
filterCult.Add(c.CultId);
filter.RemoveAt(i--);
filterNames.Add($"Bewirtschaftung {c.Name}");
} else if (e[0] == '!' && cult.ContainsKey(e[1..].ToLower())) {
var c = cult[e[1..].ToLower()];
filterNotCult.Add(c.CultId);
filter.RemoveAt(i--);
filterNames.Add($"ohne Bewirtschaftung {c.Name}");
} else if (zwst.ContainsKey(e.ToLower())) {
var b = zwst[e.ToLower()];
filterZwst.Add(b.ZwstId);
filter.RemoveAt(i--);
filterNames.Add($"Zweigstelle {b.Name}");
} else if (e.StartsWith('>') || e.StartsWith('<')) {
if (double.TryParse(e[1..], out var num)) {
switch ((e[0], num)) {
case ('>', <= 30): filterKmwGt = num; break;
case ('<', <= 30): filterKmwLt = num; break;
case ('>', >= 1900): filterYearGt = (int)num; break;
case ('<', >= 1900): filterYearLt = (int)num; break;
case ('>', _): filterOeGt = num; break;
case ('<', _): filterOeLt = num; break;
}
filter.RemoveAt(i--);
}
if (e.Length == 1) filter.RemoveAt(i--);
} else if (e.Length > 1 && Utils.FromToRegex.IsMatch(e)) {
var parts = e.Split("-");
double? from = (parts[0].Length > 0) ? double.Parse(parts[0], CultureInfo.InvariantCulture) : null;
double? to = (parts[1].Length > 0) ? double.Parse(parts[1], CultureInfo.InvariantCulture) : null;
switch ((from, to)) {
case ( <= 30, <= 30):
case ( <= 30, null):
case (null, <= 30):
filterKmwGt = from ?? 0;
filterKmwLt = to ?? 0;
break;
case ( >= 1900, >= 1900):
case ( >= 1900, null):
case (null, >= 1900):
filterYearGt = (int)(from ?? 0);
filterYearLt = (int)(to ?? -1) + 1;
break;
case (_, _):
filterOeGt = from ?? 0;
filterOeLt = to ?? 0;
break;
}
filter.RemoveAt(i--);
} else if (e.Length > 1 && Utils.FromToTimeRegex.IsMatch(e)) {
var parts = e.Split("-");
filterTime.Add((TimeOnly.TryParse(parts[0], out var from) ? $"{from:HH:mm}" : null, TimeOnly.TryParse(parts[1], out var to) ? $"{to:HH:mm}" : null));
filter.RemoveAt(i--);
var t = filterTime.Last();
if (t.Item1 != null && t.Item2 != null) {
filterNames.Add($"{t.Item1}{t.Item2}");
} else if (t.Item1 != null) {
filterNames.Add($"ab {t.Item1}");
} else if (t.Item2 != null) {
filterNames.Add($"bis {t.Item2}");
}
} else if (DateOnly.TryParse(e, out var date)) {
var s = date.ToString("yyyy-MM-dd");
filterDate.Add((s, s));
filter.RemoveAt(i--);
if (filterNames.Contains($"{vm.FilterSeason}") && vm.FilterSeason == date.Year)
filterNames.Remove($"{vm.FilterSeason}");
filterNames.Add(date.ToString("dd.MM.yyyy"));
} else if (Utils.DateFromToRegex.IsMatch(e)) {
var parts = e.Split("-");
if (parts.Length == 1) {
// single date
var dParts = parts[0].Split('.');
var s = $"{dParts[2]}-{dParts[1].PadLeft(2, '0')}-{dParts[0].PadLeft(2, '0')}";
filterDate.Add((s, s));
filter.RemoveAt(i--);
var n = string.Join('.', s.Split('-').Reverse());
if (dParts[2] == "") {
filterNames.Remove($"{vm.FilterSeason}");
filterNames.Add(n + $"{vm.FilterSeason}");
} else {
if ($"{vm.FilterSeason}" == dParts[2])
filterNames.Remove($"{vm.FilterSeason}");
filterNames.Add(n);
}
} else if (parts.Length == 2) {
// from/to date
var d1Parts = parts[0].Split('.');
var d2Parts = parts[1].Split('.');
var s1 = d1Parts.Length < 2 ? null : $"{d1Parts.ElementAtOrDefault(2)}-{d1Parts[1].PadLeft(2, '0')}-{d1Parts[0].PadLeft(2, '0')}";
var s2 = d2Parts.Length < 2 ? null : $"{d2Parts.ElementAtOrDefault(2)}-{d2Parts[1].PadLeft(2, '0')}-{d2Parts[0].PadLeft(2, '0')}";
filterDate.Add((s1, s2));
filter.RemoveAt(i--);
var n1 = s1 == null ? null : string.Join('.', s1.Split('-').Reverse());
var n2 = s2 == null ? null : string.Join('.', s2.Split('-').Reverse());
if (n1 != null && n2 != null) {
filterNames.Add($"{n1}{n2}");
} else if (n1 != null) {
filterNames.Add($"ab dem {n1}");
} else if (n2 != null) {
filterNames.Add($"bis zum {n2}");
}
}
} else if (e.Length > 2 && e.StartsWith('"') && e.EndsWith('"')) {
filter[i] = e[1..^1];
} else if (e.Length <= 2) {
filter.RemoveAt(i--);
}
}
if (filterYearGt > 0) prd = prd.And(p => p.Year >= filterYearGt);
if (filterYearLt > 0) prd = prd.And(p => p.Year < filterYearLt);
if (filterMgNr.Count > 0) prd = prd.And(p => filterMgNr.Contains(p.Delivery.MgNr));
if (filterDate.Count > 0) {
var pr = PredicateBuilder.New<DeliveryPart>(false);
foreach (var (d1, d2) in filterDate)
pr.Or(p => (d1 == null || d1.CompareTo(p.Delivery.DateString.Substring(10 - d1.Length)) <= 0) && (d2 == null || d2.CompareTo(p.Delivery.DateString.Substring(10 - d2.Length)) >= 0));
prd = prd.And(pr);
}
if (filterTime.Count > 0) {
var pr = PredicateBuilder.New<DeliveryPart>(false);
foreach (var (t1, t2) in filterTime)
pr.Or(p => (t1 == null || t1.CompareTo(p.Delivery.TimeString) <= 0) && (t2 == null || t2.CompareTo(p.Delivery.TimeString) > 0));
prd = prd.And(p => p.Delivery.TimeString != null).And(pr);
}
if (filterVar.Count > 0) prd = prd.And(p => filterVar.Contains(p.SortId));
if (filterNotVar.Count > 0) prd = prd.And(p => !filterNotVar.Contains(p.SortId));
if (filterQual.Count > 0) prd = prd.And(p => filterQual.Contains(p.QualId));
if (filterNotQual.Count > 0) prd = prd.And(p => !filterNotQual.Contains(p.QualId));
if (filterZwst.Count > 0) prd = prd.And(p => filterZwst.Contains(p.Delivery.ZwstId));
if (filterAttr.Count > 0) prd = prd.And(p => p.AttrId != null && filterAttr.Contains(p.AttrId));
if (filterNotAttr.Count > 0) prd = prd.And(p => p.AttrId == null || !filterNotAttr.Contains(p.AttrId));
if (filterCult.Count > 0) prd = prd.And(p => p.CultId != null && filterCult.Contains(p.CultId));
if (filterNotCult.Count > 0) prd = prd.And(p => p.CultId == null || !filterNotCult.Contains(p.CultId));
if (filterKmwGt > 0) prd = prd.And(p => p.Kmw >= filterKmwGt);
if (filterKmwLt > 0) prd = prd.And(p => p.Kmw < filterKmwLt);
if (filterOeGt > 0) prd = prd.And(p => p.Kmw * (4.54 + 0.022 * p.Kmw) >= filterOeGt);
if (filterOeLt > 0) prd = prd.And(p => p.Kmw * (4.54 + 0.022 * p.Kmw) < filterOeLt);
if (filterYearGt > 0 && filterYearLt > 0) {
filterNames.Insert(0, $"{filterYearGt}{filterYearLt - 1}");
} else if (filterYearGt > 0) {
filterNames.Insert(0, $"ab {filterYearGt}");
} else if (filterYearLt > 0) {
filterNames.Insert(0, $"bis {filterYearLt - 1}");
}
if (filterKmwGt > 0 && filterKmwLt > 0) {
filterNames.Add($"{filterKmwGt:N1}{filterKmwLt:N1} °KMW");
} else if (filterKmwGt > 0) {
filterNames.Add($"ab {filterKmwGt:N1} °KMW");
} else if (filterKmwLt > 0) {
filterNames.Add($"unter {filterKmwLt:N1} °KMW");
}
if (filterOeGt > 0 && filterOeLt > 0) {
filterNames.Add($"{filterOeGt:N1}{filterOeLt:N1} °Oe");
} else if (filterOeGt > 0) {
filterNames.Add($"ab {filterOeGt:N1} °Oe");
} else if (filterOeLt > 0) {
filterNames.Add($"unter {filterOeLt:N1} °Oe");
}
}
IQueryable<DeliveryPart> dpq = deliveryQuery
.SelectMany(d => d.Parts)
.Where(prd)
.OrderBy(p => p.Delivery.DateString)
.ThenBy(p => p.Delivery.TimeString)
.ThenBy(p => p.Delivery.LsNr)
.ThenBy(p => p.DPNr);
return (filterNames, dpq.Select(p => p.Delivery).Distinct().OrderBy(d => d.DateString).ThenBy(d => d.TimeString), dpq, prd.Invoke, filter);
}
public static async Task<DeliveryPart> UpdateDeliveryPart(this DeliveryAdminViewModel vm, int? oldYear, int? oldDid, int? oldDpnr, bool dateHasChanged, bool timeHasChanged, bool timeIsDefault) {
using var ctx = new AppDbContext();
int year = oldYear ?? Utils.CurrentYear;
int did = oldDid ?? await ctx.NextDId(year);
int dpnr = oldDpnr ?? await ctx.NextDPNr(year, did);
var oldDelivery = await ctx.Deliveries.FindAsync(year, did);
bool deliveryNew = (oldDid == null);
bool partNew = (oldDpnr == null);
var originalMgNr = oldDelivery?.MgNr;
var originalMemberKgNr = oldDelivery?.Member.DefaultKgNr;
var date = DateOnly.ParseExact(vm.Date!, "dd.MM.yyyy");
int? newLnr = (deliveryNew || dateHasChanged) ? await ctx.NextLNr(date) : null;
string? newTimeString = null;
if (partNew && timeIsDefault) {
newTimeString = DateTime.Now.ToString("HH:mm:ss");
} else if (partNew || timeHasChanged) {
newTimeString = string.IsNullOrEmpty(vm.Time) ? null : vm.Time + ":00";
}
var d = new Delivery {
Year = year,
DId = did,
DateString = $"{date:yyyy-MM-dd}",
TimeString = newTimeString ?? oldDelivery?.TimeString,
LNr = newLnr ?? oldDelivery!.LNr,
ZwstId = vm.Branch!.ZwstId,
LsNr = vm.LsNr!,
MgNr = (int)vm.MgNr!,
Comment = string.IsNullOrEmpty(vm.Comment) ? null : vm.Comment,
};
var p = new DeliveryPart {
Year = year,
DId = did,
DPNr = dpnr,
SortId = vm.WineVar!.SortId,
AttrId = vm.WineAttr?.AttrId,
CultId = vm.WineCult?.CultId,
Kmw = (double)vm.GradationKmw!,
QualId = vm.WineQualityLevel!.QualId,
HkId = vm.WineOrigin!.HkId,
KgNr = vm.WineKg?.KgNr,
RdNr = vm.WineRd?.RdNr,
IsNetWeight = vm.IsNetWeight,
IsHandPicked = vm.IsHandPicked,
IsLesewagen = vm.IsLesewagen,
IsGebunden = vm.IsGebunden,
Temperature = vm.Temperature,
Acid = vm.Acid,
Comment = string.IsNullOrEmpty(vm.PartComment) ? null : vm.PartComment,
Weight = (int)vm.Weight!,
IsManualWeighing = vm.IsManualWeighing,
ScaleId = vm.ScaleId,
WeighingData = vm.WeighingData,
WeighingReason = vm.ManualWeighingReason,
};
try {
if (oldDelivery != null && ctx.Entry(oldDelivery) is EntityEntry<Delivery> entry) {
entry.State = EntityState.Detached;
}
if (!deliveryNew) {
ctx.Update(d);
} else {
ctx.Add(d);
}
if (!partNew) {
ctx.Update(p);
} else {
ctx.Add(p);
}
ctx.UpdateDeliveryPartModifiers(p, await ctx.DeliveryPartModifiers
.Where(m => m.Year == p.Year && m.DId == p.DId && m.DPNr == p.DPNr)
.Select(m => m.Modifier)
.ToListAsync(), vm.Modifiers);
if (originalMgNr != null && originalMgNr.Value != d.MgNr) {
// update origin (KgNr), if default is selected
var newKgNr = (await ctx.Members.FindAsync(d.MgNr))?.DefaultKgNr;
foreach (var part in d.Parts.Where(part => part.DPNr != dpnr && part.KgNr == originalMemberKgNr)) {
part.KgNr = newKgNr;
ctx.Update(part);
}
}
await ctx.SaveChangesAsync();
} catch (Exception exc) {
var str = "Der Eintrag konnte nicht in der Datenbank aktualisiert werden!\n\n" + exc.Message;
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
MessageBox.Show(str, "Lieferung aktualisieren", MessageBoxButton.OK, MessageBoxImage.Error);
}
return p;
}
public static async Task GenerateDeliveryNote(int year, int did, ExportMode mode) {
Mouse.OverrideCursor = Cursors.AppStarting;
try {
using var ctx = new AppDbContext();
var d = (await ctx.Deliveries.FindAsync(year, did))!;
using var doc = new DeliveryNote(d, ctx);
await Utils.ExportDocument(doc, mode, d.LsNr, (d.Member, $"{DeliveryNote.Name} Nr. {d.LsNr}", $"Im Anhang finden Sie den {DeliveryNote.Name} Nr. {d.LsNr}"));
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = null;
}
public static async Task GenerateDeliveryJournal(this DeliveryAdminViewModel vm, int modeWho, ExportMode exportMode) {
using var ctx = new AppDbContext();
IQueryable<DeliveryPart> query;
List<string> filterNames = [];
if (modeWho == 0) {
var (f, _, q, _, _) = await vm.GetFilters(ctx);
query = q;
filterNames.AddRange(f);
} else if (modeWho == 2) {
query = ctx.DeliveryParts
.Where(p => p.Year == Utils.CurrentLastSeason && p.Delivery.ZwstId == App.ZwstId);
filterNames.AddRange([$"{Utils.CurrentLastSeason}", $"Zweigstelle {App.BranchName}"]);
} else {
var date = $"{Utils.Today:yyyy-MM-dd}";
query = ctx.DeliveryParts
.Where(p => p.Delivery.DateString == date);
filterNames.Add($"{Utils.Today:dd.MM.yyyy}");
}
query = query
.OrderBy(p => p.Delivery.DateString)
.ThenBy(p => p.Delivery.TimeString)
.ThenBy(p => p.Delivery.LsNr)
.ThenBy(p => p.DPNr);
if (exportMode == ExportMode.SaveList) {
var d = new SaveFileDialog() {
FileName = $"{DeliveryJournal.Name}.ods",
DefaultExt = "ods",
Filter = "OpenDocument Format Spreadsheet (*.ods)|*.ods",
Title = $"{DeliveryJournal.Name} speichern unter - Elwig"
};
if (d.ShowDialog() == true) {
Mouse.OverrideCursor = Cursors.AppStarting;
try {
var data = await DeliveryJournalData.FromQuery(query, filterNames);
using var ods = new OdsFile(d.FileName);
await ods.AddTable(data);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = null;
}
} else if (exportMode == ExportMode.Export) {
var d = new SaveFileDialog() {
FileName = $"Lieferungen_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{App.ZwstId}.zip",
DefaultExt = "zip",
Filter = "ZIP-Datei (*.zip)|*.zip",
Title = $"{DeliveryJournal.Name} speichern unter - Elwig"
};
if (d.ShowDialog() == true) {
Mouse.OverrideCursor = Cursors.AppStarting;
try {
await ElwigData.Export(d.FileName, await query
.Select(p => p.Delivery)
.Distinct()
.Include(d => d.Parts)
.ThenInclude(p => p.PartModifiers)
.AsSplitQuery()
.ToListAsync(), filterNames);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = null;
}
} else if (exportMode == ExportMode.Upload && App.Config.SyncUrl != null) {
Mouse.OverrideCursor = Cursors.AppStarting;
try {
var filename = $"{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{App.ZwstId}.zip";
var path = Path.Combine(App.TempPath, filename);
var list = await query
.Select(p => p.Delivery)
.Distinct()
.Include(d => d.Parts)
.ThenInclude(p => p.PartModifiers)
.AsSplitQuery()
.ToListAsync();
if (list.Count == 0) {
MessageBox.Show("Es wurden keine Lieferungen zum Hochladen ausgewählt!", "Lieferungen hochladen",
MessageBoxButton.OK, MessageBoxImage.Error);
} else {
await ElwigData.Export(path, list, filterNames);
await Utils.UploadExportData(path, App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
MessageBox.Show($"Lieferungen erfolgreich hochgeladen!", "Lieferungen hochgeladen",
MessageBoxButton.OK, MessageBoxImage.Information);
}
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = null;
} else {
Mouse.OverrideCursor = Cursors.AppStarting;
try {
var data = await DeliveryJournalData.FromQuery(query, filterNames);
using var doc = new DeliveryJournal(string.Join(" / ", filterNames), data);
await Utils.ExportDocument(doc, exportMode);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = null;
}
}
public static async Task GenerateWineQualityStatistics(this DeliveryAdminViewModel vm, int modeWho, ExportMode exportMode) {
using var ctx = new AppDbContext();
IQueryable<DeliveryPart> query;
List<string> filterNames = [];
if (modeWho == 0) {
var (f, _, q, _, _) = await vm.GetFilters(ctx);
query = q;
filterNames.AddRange(f);
} else {
var date = $"{Utils.Today:yyyy-MM-dd}";
query = ctx.DeliveryParts
.Where(p => p.Delivery.DateString == date);
filterNames.Add($"{Utils.Today:dd.MM.yyyy}");
}
Mouse.OverrideCursor = Cursors.AppStarting;
try {
var data = await WineQualityStatisticsData.FromQuery(query, App.Client.OrderingMemberList);
using var doc = new WineQualityStatistics(string.Join(" / ", filterNames), data);
await Utils.ExportDocument(doc, exportMode);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = null;
}
private static void AddToolTipCell(Grid grid, string text, int row, int col, int colSpan = 1, bool bold = false, bool alignRight = false, bool alignCenter = false) {
var tb = new TextBlock() {
Text = text,
TextAlignment = alignRight ? TextAlignment.Right : alignCenter ? TextAlignment.Center : TextAlignment.Left,
Margin = new(0, 12 * row, 0, 0),
FontWeight = bold ? FontWeights.Bold : FontWeights.Normal,
};
tb.SetValue(Grid.ColumnProperty, col);
tb.SetValue(Grid.ColumnSpanProperty, colSpan);
grid.Children.Add(tb);
}
private static void AddWeightToolTipRow(Grid grid, int row, string? h1, string? h2, int weight, int? total1, int total2) {
var bold = h2 == null;
if (h1 != null) AddToolTipCell(grid, h1 + ":", row, 0, (h2 == null) ? 2 : 1, bold);
if (h2 != null) AddToolTipCell(grid, h2 + ":", row, 1, 1, bold);
AddToolTipCell(grid, $"{weight:N0} kg", row, 2, 1, bold, true);
if (total1 != null && total1 != 0)
AddToolTipCell(grid, $"{weight * 100.0 / total1:N1} %", row, 3, 1, bold, true);
if (total2 != 0)
AddToolTipCell(grid, $"{weight * 100.0 / total2:N1} %", row, 4, 1, bold, true);
}
private static void AddGradationToolTipRow(Grid grid, int row, string? h1, string? h2, double min, double avg, double max) {
var bold = h2 == null;
if (h1 != null) AddToolTipCell(grid, h1 + ":", row, 0, (h2 == null) ? 2 : 1, bold);
if (h2 != null) AddToolTipCell(grid, h2 + ":", row, 1, 1, bold);
AddToolTipCell(grid, $"{min:N1}°", row, 2, 1, bold, true);
AddToolTipCell(grid, $"{avg:N1}°", row, 3, 1, bold, true);
AddToolTipCell(grid, $"{max:N1}°", row, 4, 1, bold, true);
}
public static async Task<(string WeightText, Grid WeightGrid, string GradationText, Grid GradationGrid)> GenerateToolTip(IQueryable<DeliveryPart> deliveryParts) {
var wGrid = new Grid();
wGrid.ColumnDefinitions.Add(new() { Width = new(10) });
wGrid.ColumnDefinitions.Add(new() { Width = new(60) });
wGrid.ColumnDefinitions.Add(new() { Width = new(80) });
wGrid.ColumnDefinitions.Add(new() { Width = new(50) });
wGrid.ColumnDefinitions.Add(new() { Width = new(50) });
var wText = "-";
var gGrid = new Grid();
gGrid.ColumnDefinitions.Add(new() { Width = new(10) });
gGrid.ColumnDefinitions.Add(new() { Width = new(60) });
gGrid.ColumnDefinitions.Add(new() { Width = new(35) });
gGrid.ColumnDefinitions.Add(new() { Width = new(35) });
gGrid.ColumnDefinitions.Add(new() { Width = new(35) });
AddToolTipCell(gGrid, "Min.", 0, 2, 1, false, false, true);
AddToolTipCell(gGrid, "⌀", 0, 3, 1, false, false, true);
AddToolTipCell(gGrid, "Max.", 0, 4, 1, false, false, true);
var gText = "-";
var weight = await deliveryParts.SumAsync(p => p.Weight);
wText = $"{weight:N0} kg";
AddWeightToolTipRow(wGrid, 0, "Gewicht", null, weight, null, weight);
if (await deliveryParts.AnyAsync()) {
var kmwMin = await deliveryParts.MinAsync(p => p.Kmw);
var kmwAvg = Utils.AggregateDeliveryPartsKmw(deliveryParts);
var kmwMax = await deliveryParts.MaxAsync(p => p.Kmw);
gText = $"{kmwMin:N1}° / {kmwAvg:N1}° / {kmwMax:N1}°";
AddGradationToolTipRow(gGrid, 1, "Gradation", null, kmwMin, kmwAvg, kmwMax);
var attrGroups = await deliveryParts
.GroupBy(p => new { Attr = p.Attribute!.Name, Cult = p.Cultivation!.Name })
.Select(g => new {
g.Key.Attr,
g.Key.Cult,
Weight = g.Sum(p => p.Weight),
Min = g.Min(p => p.Kmw),
Avg = g.Sum(p => p.Kmw * p.Weight) / g.Sum(p => p.Weight),
Max = g.Max(p => p.Kmw),
})
.OrderByDescending(g => g.Weight)
.ThenBy(g => g.Attr)
.ToListAsync();
var sortGroups = await deliveryParts
.GroupBy(p => p.SortId)
.Select(g => new {
SortId = g.Key,
Weight = g.Sum(p => p.Weight),
Min = g.Min(p => p.Kmw),
Avg = g.Sum(p => p.Kmw * p.Weight) / g.Sum(p => p.Weight),
Max = g.Max(p => p.Kmw),
})
.OrderByDescending(g => g.Weight)
.ThenBy(g => g.SortId)
.ToListAsync();
var groups = await deliveryParts
.GroupBy(p => new {
Attr = p.Attribute!.Name,
Cult = p.Cultivation!.Name,
p.SortId,
})
.Select(g => new {
g.Key.Attr,
g.Key.Cult,
g.Key.SortId,
Weight = g.Sum(p => p.Weight),
Min = g.Min(p => p.Kmw),
Avg = g.Sum(p => p.Kmw * p.Weight) / g.Sum(p => p.Weight),
Max = g.Max(p => p.Kmw)
})
.OrderByDescending(g => g.SortId)
.ThenBy(g => g.Attr)
.ThenBy(g => g.SortId)
.ToListAsync();
int rowNum = 1;
foreach (var attrG in attrGroups) {
rowNum++;
var name = attrG.Attr == null && attrG.Cult == null ? null : attrG.Attr + (attrG.Attr != null && attrG.Cult != null ? " / " : "") + attrG.Cult;
AddWeightToolTipRow(wGrid, rowNum++, name, null, attrG.Weight, attrG.Weight, weight);
foreach (var g in groups.Where(g => g.Attr == attrG.Attr && g.Cult == attrG.Cult).OrderByDescending(g => g.Weight).ThenBy(g => g.SortId)) {
AddWeightToolTipRow(wGrid, rowNum++, null, g.SortId, g.Weight, attrG.Weight, weight);
}
}
rowNum = 2;
foreach (var attrG in attrGroups) {
rowNum++;
var name = attrG.Attr == null && attrG.Cult == null ? null : attrG.Attr + (attrG.Attr != null && attrG.Cult != null ? " / " : "") + attrG.Cult;
AddGradationToolTipRow(gGrid, rowNum++, name, null, attrG.Min, attrG.Avg, attrG.Max);
foreach (var g in groups.Where(g => g.Attr == attrG.Attr && g.Cult == attrG.Cult).OrderByDescending(g => g.Avg).ThenBy(g => g.SortId)) {
AddGradationToolTipRow(gGrid, rowNum++, null, g.SortId, g.Min, g.Avg, g.Max);
}
}
if (attrGroups.Count == 1) {
var g = attrGroups.First();
var name = g.Attr == null && g.Cult == null ? null : g.Attr + (g.Attr != null && g.Cult != null ? " / " : "") + g.Cult;
if (name != null) {
wText += $" [{name}]";
gText += $" [{name}]";
}
if (sortGroups.Count > 1 && sortGroups.Count <= 4) {
wText += $" = {string.Join(" + ", sortGroups.Select(g => $"{g.Weight:N0} kg ({(double)g.Weight / weight:0%})" + (g.SortId == null ? "" : $" [{g.SortId}]")))}";
gText += $" = {string.Join(" + ", sortGroups.Select(g => $"{g.Min:N1}/{g.Avg:N1}/{g.Max:N1}" + (g.SortId == null ? "" : $" [{g.SortId}]")))}";
}
} else if (attrGroups.Count <= 4) {
wText += $" = {string.Join(" + ", attrGroups.Select(g => $"{g.Weight:N0} kg ({(double)g.Weight / weight:0%})" + (g.Attr == null && g.Cult == null ? "" : $" [{g.Attr}{(g.Attr != null && g.Cult != null ? " / " : "")}{g.Cult}]")))}";
gText += $" = {string.Join(" + ", attrGroups.Select(g => $"{g.Min:N1}/{g.Avg:N1}/{g.Max:N1}" + (g.Attr == null && g.Cult == null ? "" : $" [{g.Attr}{(g.Attr != null && g.Cult != null ? " / " : "")}{g.Cult}]")))}";
}
}
return (wText, wGrid, gText, gGrid);
}
}
}