[#34] First step of not using Bio as Attribute
This commit is contained in:
		| @@ -40,19 +40,19 @@ namespace Elwig.Documents { | ||||
|             return "<colgroup>\n" + string.Join("\n", cols.Select(g => $"<col style=\"width: {g.ToString(CultureInfo.InvariantCulture)}mm;\"/>")) + "\n</colgroup>\n"; | ||||
|         } | ||||
|  | ||||
|         public static string PrintSortenaufteilung(Dictionary<string, MemberBucket> buckets) { | ||||
|             List<string> attributes = ["_", ""]; | ||||
|             List<string> names = ["kein Qual.Wein", "ohne Attribut"]; | ||||
|             List<(string, string)> bucketAttrs = [ | ||||
|                 .. buckets | ||||
|                 .Where(b => b.Key.Length > 2 && b.Key[2] != '_' && b.Value.DeliveryStrict > 0) | ||||
|                 .Select(b => (b.Key[2..], b.Value.Name.Split("(")[1][..^1])) | ||||
|         public static string PrintSortenaufteilung(List<MemberStat> stats) { | ||||
|             List<string> discrs = [""]; | ||||
|             List<string> names = ["ohne Attr./Bewirt."]; | ||||
|             List<string> bucketAttrs = [ | ||||
|                 .. stats | ||||
|                 .Select(s => s.Discr) | ||||
|                 .Distinct() | ||||
|                 .OrderBy(v => v.Item1) | ||||
|                 .Where(s => s.Length > 0) | ||||
|                 .Order() | ||||
|             ]; | ||||
|             names.AddRange(bucketAttrs.Select(b => b.Item2)); | ||||
|             names.AddRange(bucketAttrs); | ||||
|             names.Add("Gesamt"); | ||||
|             attributes.AddRange(bucketAttrs.Select(b => b.Item1)); | ||||
|             discrs.AddRange(bucketAttrs); | ||||
|  | ||||
|             List<double> cols = [40]; | ||||
|             cols.AddRange(names.Select(_ => 125.0 / names.Count)); | ||||
| @@ -62,19 +62,18 @@ namespace Elwig.Documents { | ||||
|                 string.Join("", names.Select(c => $"<th>{c}</th>")) + | ||||
|                 "</tr></thead>"; | ||||
|  | ||||
|             tbl += string.Join("\n", buckets | ||||
|                 .GroupBy(b => (b.Key[..2], b.Value.Name.Split("(")[0].Trim())) | ||||
|                 .Where(g => g.Sum(a => a.Value.DeliveryStrict) > 0) | ||||
|                 .OrderBy(g => g.Key.Item1) | ||||
|             tbl += string.Join("\n", stats | ||||
|                 .GroupBy(b => b.Variety) | ||||
|                 .OrderBy(b => b.Key) | ||||
|                 .Select(g => { | ||||
|                     var dict = g.ToDictionary(a => a.Key[2..], a => a.Value); | ||||
|                     var vals = attributes.Select(a => dict.TryGetValue(a, out MemberBucket value) ? value.DeliveryStrict : 0).ToList(); | ||||
|                     return $"<tr><th>{g.Key.Item2}</th>" + string.Join("", vals.Select(v => "<td class=\"number\">" + (v == 0 ? "-" : $"{v:N0}") + "</td>")) + | ||||
|                         $"<td class=\"number\">{dict.Values.Select(v => v.DeliveryStrict).Sum():N0}</td></tr>"; | ||||
|                     var dict = g.ToDictionary(a => a.Discr, a => a.Weight); | ||||
|                     var vals = discrs.Select(a => dict.GetValueOrDefault(a, 0)).ToList(); | ||||
|                     return $"<tr><th>{g.Key}</th>" + string.Join("", vals.Select(v => "<td class=\"number\">" + (v == 0 ? "-" : $"{v:N0}") + "</td>")) + | ||||
|                         $"<td class=\"number\">{dict.Values.Sum():N0}</td></tr>"; | ||||
|                 }) | ||||
|             ); | ||||
|             var totalDict = buckets.GroupBy(b => b.Key[2..]).ToDictionary(g => g.Key, g => g.Sum(a => a.Value.DeliveryStrict)); | ||||
|             var totals = attributes.Select(a => totalDict.TryGetValue(a, out int value) ? value : 0); | ||||
|             var totalDict = stats.GroupBy(s => s.Discr).ToDictionary(g => g.Key, g => g.Sum(a => a.Weight)); | ||||
|             var totals = discrs.Select(a => totalDict.TryGetValue(a, out int value) ? value : 0); | ||||
|             tbl += "<tr class=\"sum bold\"><td></td>" + string.Join("", totals.Select(v => $"<td class=\"number\">{v:N0}</td>")) + | ||||
|                 $"<td class=\"number\">{totalDict.Values.Sum():N0}</td></tr>"; | ||||
|  | ||||
|   | ||||
| @@ -10,8 +10,8 @@ | ||||
|         <colgroup> | ||||
|             <col style="width: 25mm;"/> | ||||
|             <col style="width:  5mm;"/> | ||||
|             <col style="width: 20mm;"/> | ||||
|             <col style="width: 20mm;"/> | ||||
|             <col style="width: 24mm;"/> | ||||
|             <col style="width: 16mm;"/> | ||||
|             <col style="width: 10mm;"/> | ||||
|             <col style="width: 10mm;"/> | ||||
|             <col style="width: 15mm;"/> | ||||
| @@ -25,7 +25,7 @@ | ||||
|                 <th rowspan="2" style="text-align: left;">Lieferschein-Nr.</th> | ||||
|                 <th rowspan="2" class="narrow">Pos.</th> | ||||
|                 <th rowspan="2" style="text-align: left;">Sorte</th> | ||||
|                 <th rowspan="2" style="text-align: left;">Attribut</th> | ||||
|                 <th rowspan="2" style="text-align: left;">Attr./Bewirt.</th> | ||||
|                 <th colspan="2">Gradation</th> | ||||
|                 <th colspan="2">Flächenbindung</th> | ||||
|                 <th>Preis</th> | ||||
| @@ -50,7 +50,7 @@ | ||||
|                             <td rowspan="@rows">@p.LsNr</td> | ||||
|                             <td rowspan="@rows">@p.DPNr</td> | ||||
|                             <td class="small">@p.Variety</td> | ||||
|                             <td class="small">@p.Attribute</td> | ||||
|                             <td class="small">@p.Attribute@(p.Attribute != null && p.Cultivation != null ? " / " : "")@p.Cultivation</td> | ||||
|                             <td rowspan="@rows" class="center">@($"{p.Gradation.Oe:N0}")</td> | ||||
|                             <td rowspan="@rows" class="center">@($"{p.Gradation.Kmw:N1}")</td> | ||||
|                         } | ||||
|   | ||||
| @@ -13,6 +13,7 @@ namespace Elwig.Documents { | ||||
|         public DeliveryConfirmationDeliveryData Data; | ||||
|         public string? Text = App.Client.TextDeliveryConfirmation; | ||||
|         public Dictionary<string, MemberBucket> MemberBuckets; | ||||
|         public List<MemberStat> MemberStats; | ||||
|  | ||||
|         public DeliveryConfirmation(AppDbContext ctx, int year, Member m, DeliveryConfirmationDeliveryData data) : | ||||
|             base($"{Name} {year}", m) { | ||||
| @@ -23,6 +24,7 @@ namespace Elwig.Documents { | ||||
|             DocumentId = $"Anl.-Best. {Season.Year}/{m.MgNr}"; | ||||
|             Data = data; | ||||
|             MemberBuckets = ctx.GetMemberBuckets(Season.Year, m.MgNr).GetAwaiter().GetResult(); | ||||
|             MemberStats = AppDbContext.GetMemberStats(Season.Year, m.MgNr).GetAwaiter().GetResult(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -10,8 +10,8 @@ | ||||
|         <colgroup> | ||||
|             <col style="width: 25mm;"/> | ||||
|             <col style="width:  5mm;"/> | ||||
|             <col style="width: 20mm;"/> | ||||
|             <col style="width: 21mm;"/> | ||||
|             <col style="width: 24mm;"/> | ||||
|             <col style="width: 17mm;"/> | ||||
|             <col style="width: 19mm;"/> | ||||
|             <col style="width: 10mm;"/> | ||||
|             <col style="width: 10mm;"/> | ||||
| @@ -25,7 +25,7 @@ | ||||
|                 <th rowspan="2" style="text-align: left;">Lieferschein-Nr.</th> | ||||
|                 <th rowspan="2" class="narrow">Pos.</th> | ||||
|                 <th rowspan="2" style="text-align: left;">Sorte</th> | ||||
|                 <th rowspan="2" style="text-align: left;">Attribut</th> | ||||
|                 <th rowspan="2" style="text-align: left;">Attr./Bewirt.</th> | ||||
|                 <th rowspan="2" style="text-align: left;">Qualitätsstufe</th> | ||||
|                 <th colspan="2">Gradation</th> | ||||
|                 <th colspan="2">Flächenbindung</th> | ||||
| @@ -53,7 +53,7 @@ | ||||
|                             <td rowspan="@rows">@p.LsNr</td> | ||||
|                             <td rowspan="@rows">@p.DPNr</td> | ||||
|                             <td class="small">@p.Variety</td> | ||||
|                             <td class="small">@p.Attribute</td> | ||||
|                             <td class="small">@p.Attribute@(p.Attribute != null && p.Cultivation != null ? " / " : "")@p.Cultivation</td> | ||||
|                             <td class="small">@p.QualityLevel</td> | ||||
|                             <td rowspan="@rows" class="center">@($"{p.Gradation.Oe:N0}")</td> | ||||
|                             <td rowspan="@rows" class="center">@($"{p.Gradation.Kmw:N1}")</td> | ||||
| @@ -90,7 +90,7 @@ | ||||
|             </tr> | ||||
|         </tbody> | ||||
|     </table> | ||||
|     @Raw(BusinessDocument.PrintSortenaufteilung(Model.MemberBuckets)) | ||||
|     @Raw(BusinessDocument.PrintSortenaufteilung(Model.MemberStats)) | ||||
|     @Raw(Model.PrintBucketTable(Model.Season, Model.MemberBuckets, includePayment: true)) | ||||
|     <div style="margin-top: 2em;"> | ||||
|         @if (Model.Text != null) { | ||||
|   | ||||
| @@ -43,6 +43,14 @@ | ||||
|                 <td class="center">@($"{part.Kmw:N1}")</td> | ||||
|                 <td class="number">@($"{part.Weight:N0}")</td> | ||||
|             </tr> | ||||
|             @if (part.Cultivation != null) { | ||||
|                 <tr><td></td><td><i>Bewirtschaftung:</i></td><td colspan="4"><b> | ||||
|                     @part.Cultivation.Name | ||||
|                     @if(part.Cultivation.Description != null) { | ||||
|                         @("(")@part.Cultivation.Description@(")") | ||||
|                     } | ||||
|                     </b></td></tr> | ||||
|             } | ||||
|             <tr><td></td><td colspan="5" style="white-space: pre;"><i>Herkunft:</i> @part.OriginString</td></tr> | ||||
|             @if (part.Modifiers.Count() > 0) { | ||||
|                 var first = true; | ||||
| @@ -52,8 +60,8 @@ | ||||
|                 } | ||||
|             } | ||||
|             <tr><td></td><td colspan="5"> | ||||
|                 @Raw(part.ManualWeighing ? "<i>Handwiegung</i>" : $"<i>Waage:</i> {part.ScaleId ?? "?"}, <i>ID:</i> {part.WeighingId ?? "?"}") | ||||
|                 (@(part.IsGerebelt ? "gerebelt gewogen" : "nicht gerebelt gewogen"))@Raw(part.WeighingReason != null ? $", <i>Begründung:</i>" : "") @part.WeighingReason | ||||
|                 @Raw(part.IsManualWeighing ? "<i>Handwiegung</i>" : $"<i>Waage:</i> {part.ScaleId ?? "?"}, <i>ID:</i> {part.WeighingId ?? "?"}") | ||||
|                 (@(part.IsNetWeight ? "gerebelt gewogen" : "nicht gerebelt gewogen"))@Raw(part.WeighingReason != null ? $", <i>Begründung:</i>" : "") @part.WeighingReason | ||||
|             </td></tr> | ||||
|             @if (part.Comment != null) { | ||||
|                 <tr><td></td><td colspan="5"><i>Anmerkung:</i> @part.Comment</td></tr> | ||||
|   | ||||
| @@ -17,6 +17,7 @@ namespace Elwig.Helpers { | ||||
|     public record struct AreaComBucket(int Area, int Obligation, int Right); | ||||
|     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 class AppDbContext : DbContext { | ||||
|  | ||||
| @@ -159,6 +160,10 @@ namespace Elwig.Helpers { | ||||
|             return await WineAttributes.FindAsync(attrId) != null; | ||||
|         } | ||||
|  | ||||
|         public async Task<bool> CultIdExists(string cultId) { | ||||
|             return await WineCultivations.FindAsync(cultId) != null; | ||||
|         } | ||||
|  | ||||
|         public async Task<int> NextMgNr() { | ||||
|             int c = 0; | ||||
|             (await Members.OrderBy(m => m.MgNr).Select(m => m.MgNr).ToListAsync()) | ||||
| @@ -384,5 +389,31 @@ namespace Elwig.Helpers { | ||||
|             } | ||||
|             return buckets; | ||||
|         } | ||||
|  | ||||
|         public static async Task<List<MemberStat>> GetMemberStats(int year, int mgnr, SqliteConnection? cnx = null) { | ||||
|             var ownCnx = cnx == null; | ||||
|             cnx ??= await ConnectAsync(); | ||||
|             var list = new List<MemberStat>(); | ||||
|             using (var cmd = cnx.CreateCommand()) { | ||||
|                 cmd.CommandText = $""" | ||||
|                     SELECT v.name AS variety, | ||||
|                            COALESCE(a.name, '') || IIF(a.name IS NOT NULL AND c.name IS NOT NULL, ' / ', '') || COALESCE(c.name, '') AS disc, | ||||
|                            SUM(weight) AS weight | ||||
|                     FROM v_delivery d | ||||
|                         LEFT JOIN wine_variety v ON v.sortid = d.sortid | ||||
|                         LEFT JOIN wine_attribute a ON a.attrid = d.attrid | ||||
|                         LEFT JOIN wine_cultivation c ON c.cultid = d.cultid | ||||
|                     WHERE d.year = {year} AND d.mgnr = {mgnr} | ||||
|                     GROUP BY d.sortid, d.attrid, d.cultid | ||||
|                     ORDER BY variety, disc; | ||||
|                     """; | ||||
|                 using var reader = await cmd.ExecuteReaderAsync(); | ||||
|                 while (await reader.ReadAsync()) { | ||||
|                     list.Add(new(reader.GetString(0), reader.GetString(1), reader.GetInt32(2))); | ||||
|                 } | ||||
|             } | ||||
|             if (ownCnx) await cnx.DisposeAsync(); | ||||
|             return list; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -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 = 17; | ||||
|         public static readonly int RequiredSchemaVersion = 18; | ||||
|  | ||||
|         private static int VersionOffset = 0; | ||||
|  | ||||
|   | ||||
| @@ -454,9 +454,9 @@ namespace Elwig.Helpers { | ||||
|             if (input.Text.Length < 2 || !ctx.SortIdExists(input.Text[0..2]).GetAwaiter().GetResult()) { | ||||
|                 return new(false, "Ungültige Sorte"); | ||||
|             } else if (input.Text.Length >= 3) { | ||||
|                 var attr = input.Text[2..]; | ||||
|                 if (!ctx.AttrIdExists(attr).GetAwaiter().GetResult()) { | ||||
|                     return new(false, "Ungültiges Attribut"); | ||||
|                 var disc = input.Text[2..]; | ||||
|                 if (!ctx.AttrIdExists(disc).GetAwaiter().GetResult() && !ctx.CultIdExists(disc).GetAwaiter().GetResult()) { | ||||
|                     return new(false, "Ungültiges Attribut/Bewirt."); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|   | ||||
| @@ -43,10 +43,11 @@ namespace Elwig.Models.Dtos { | ||||
|             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, q.name AS quality_level, d.oe, d.kmw | ||||
|                        s.name AS variety, a.name AS attribute, c.name AS cultivation, q.name AS quality_level, d.oe, d.kmw | ||||
|                 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 | ||||
| @@ -70,6 +71,7 @@ namespace Elwig.Models.Dtos { | ||||
|         public int DPNr; | ||||
|         public string Variety; | ||||
|         public string? Attribute; | ||||
|         public string? Cultivation; | ||||
|         public string[] Modifiers; | ||||
|         public string QualityLevel; | ||||
|         public (double Oe, double Kmw) Gradation; | ||||
| @@ -88,6 +90,7 @@ namespace Elwig.Models.Dtos { | ||||
|             DPNr = f.DPNr; | ||||
|             Variety = f.Variety; | ||||
|             Attribute = f.Attribute; | ||||
|             Cultivation = f.Cultivation; | ||||
|             var modifiers = (IEnumerable<Modifier>)(f.Modifiers ?? "").Split(',') | ||||
|                 .Select(m => season?.Modifiers.FirstOrDefault(s => s.ModId == m)) | ||||
|                 .Where(m => m != null) | ||||
| @@ -149,6 +152,8 @@ namespace Elwig.Models.Dtos { | ||||
|         public string Variety { get; set; } | ||||
|         [Column("attribute")] | ||||
|         public string? Attribute { get; set; } | ||||
|         [Column("cultivation")] | ||||
|         public string? Cultivation { get; set; } | ||||
|         [Column("quality_level")] | ||||
|         public string QualityLevel { get; set; } | ||||
|         [Column("oe")] | ||||
|   | ||||
| @@ -73,6 +73,7 @@ namespace Elwig.Models.Dtos { | ||||
|         public int DPNr; | ||||
|         public string Variety; | ||||
|         public string? Attribute; | ||||
|         public string? Cultivation; | ||||
|         public string QualityLevel; | ||||
|         public (double Oe, double Kmw) Gradation; | ||||
|         public string[] Modifiers; | ||||
| @@ -85,6 +86,7 @@ namespace Elwig.Models.Dtos { | ||||
|             DPNr = p.DPNr; | ||||
|             Variety = p.Variety.Name; | ||||
|             Attribute = p.Attribute?.Name; | ||||
|             Cultivation = p.Cultivation?.Name; | ||||
|             QualityLevel = p.Quality.Name; | ||||
|             Gradation = (p.Oe, p.Kmw); | ||||
|             Modifiers = p.Modifiers | ||||
|   | ||||
| @@ -17,7 +17,7 @@ namespace Elwig.Models.Entities { | ||||
|         public string VtrgId { get; set; } | ||||
|  | ||||
|         [Column("cultid")] | ||||
|         public string CultId { get; set; } | ||||
|         public string? CultId { get; set; } | ||||
|  | ||||
|         [Column("area")] | ||||
|         public int Area { get; set; } | ||||
| @@ -47,7 +47,7 @@ namespace Elwig.Models.Entities { | ||||
|         public virtual AreaComType AreaComType { get; private set; } | ||||
|  | ||||
|         [ForeignKey("CultId")] | ||||
|         public virtual WineCult WineCult { get; private set; } | ||||
|         public virtual WineCult? WineCult { get; private set; } | ||||
|  | ||||
|         [ForeignKey("KgNr")] | ||||
|         public virtual WbKg Kg { get; private set; } | ||||
| @@ -57,7 +57,7 @@ namespace Elwig.Models.Entities { | ||||
|  | ||||
|         public int SearchScore(IEnumerable<string> keywords) { | ||||
|             var list = new string?[] { | ||||
|                 WineCult.Name, Kg.AtKg.Name, Rd.Name, GstNr, Comment, | ||||
|                 WineCult?.Name, Kg.AtKg.Name, Rd.Name, GstNr, Comment, | ||||
|             }.ToList(); | ||||
|             return Utils.GetSearchScore(list, keywords); | ||||
|         } | ||||
|   | ||||
| @@ -31,6 +31,12 @@ namespace Elwig.Models.Entities { | ||||
|         [ForeignKey("AttrId")] | ||||
|         public virtual WineAttr? Attribute { get; private set; } | ||||
|  | ||||
|         [Column("cultid")] | ||||
|         public string? CultId { get; set; } | ||||
|  | ||||
|         [ForeignKey("CultId")] | ||||
|         public virtual WineCult? Cultivation { get; private set; } | ||||
|  | ||||
|         [Column("weight")] | ||||
|         public int Weight { get; set; } | ||||
|  | ||||
| @@ -66,14 +72,14 @@ namespace Elwig.Models.Entities { | ||||
|         [ForeignKey("KgNr, RdNr")] | ||||
|         public virtual WbRd? Rd { get; private set; } | ||||
|  | ||||
|         [Column("gerebelt")] | ||||
|         public bool IsGerebelt { get; set; } | ||||
|         [Column("net_weight")] | ||||
|         public bool IsNetWeight { get; set; } | ||||
|  | ||||
|         [Column("manual_weighing")] | ||||
|         public bool ManualWeighing { get; set; } | ||||
|         public bool IsManualWeighing { get; set; } | ||||
|  | ||||
|         [Column("spl_check")] | ||||
|         public bool SplCheck { get; set; } | ||||
|         public bool IsSplCheck { get; set; } | ||||
|  | ||||
|         [Column("hand_picked")] | ||||
|         public bool? IsHandPicked { get; set; } | ||||
|   | ||||
| @@ -43,7 +43,7 @@ | ||||
|         } | ||||
|       }, | ||||
|       "patternProperties": { | ||||
|         "^([A-Z]{2})?(\/[A-Z]*)?$": { | ||||
|         "^([A-Z]{2})?(\/[A-Z]*)?(-[A-Z][A-Z0-9]*)?$": { | ||||
|           "type": ["number", "string"], | ||||
|           "pattern": "^curve:[0-9]+$" | ||||
|         } | ||||
| @@ -64,7 +64,7 @@ | ||||
|               } | ||||
|             }, | ||||
|             "patternProperties": { | ||||
|               "^([A-Z]{2})?(\/[A-Z]*)?$": { | ||||
|               "^([A-Z]{2})?(\/[A-Z]*)?(-[A-Z][A-Z0-9]*)?$": { | ||||
|                 "type": ["number", "string"], | ||||
|                 "pattern": "^curve:[0-9]+$" | ||||
|               } | ||||
|   | ||||
							
								
								
									
										92
									
								
								Elwig/Resources/Sql/17-18.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								Elwig/Resources/Sql/17-18.sql
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,92 @@ | ||||
| -- schema version 17 to 18 | ||||
|  | ||||
| ALTER TABLE delivery_part ADD COLUMN cultid TEXT DEFAULT NULL; | ||||
|  | ||||
| PRAGMA writable_schema = ON; | ||||
| UPDATE sqlite_schema SET sql = REPLACE(sql, CHAR(10) || | ||||
|     ') STRICT', | ||||
|     ',' || CHAR(10) || | ||||
|     '    CONSTRAINT fk_delivery_part_wine_cultivation FOREIGN KEY (cultid) REFERENCES wine_cultivation (cultid)' || CHAR(10) || | ||||
|     '        ON UPDATE CASCADE' || CHAR(10) || | ||||
|     '        ON DELETE RESTRICT' || CHAR(10) || | ||||
|     ') STRICT') | ||||
| WHERE type = 'table' AND name = 'delivery_part'; | ||||
| UPDATE sqlite_schema SET sql = REPLACE(sql, 'gerebelt  ', 'net_weight') | ||||
| WHERE type = 'table' AND name = 'delivery_part'; | ||||
|  | ||||
| UPDATE sqlite_schema SET sql = REPLACE(sql, 'CHECK (cultid REGEXP ''^[A-Z]+$'')', 'CHECK (cultid REGEXP ''^[A-Z][A-Z0-9]*$'')') | ||||
| WHERE type = 'table' AND name = 'wine_cultivation'; | ||||
|  | ||||
| UPDATE sqlite_schema SET sql = REPLACE(sql, 'cultid    TEXT    NOT NULL', 'cultid    TEXT             DEFAULT NULL') | ||||
| WHERE type = 'table' AND name = 'area_commitment'; | ||||
|  | ||||
| DROP VIEW v_delivery; | ||||
| 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.cultid, | ||||
|        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.net_weight, 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, | ||||
|        IIF(a.strict, COALESCE(a.fill_lower, 0), 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; | ||||
|  | ||||
| CREATE VIEW v_wine_attribute AS | ||||
| SELECT a.attrid, name, active, max_kg_per_ha, strict, fill_lower, | ||||
|        COUNT(t.attrid) > 0 AS area_com | ||||
| FROM wine_attribute a | ||||
|     LEFT JOIN area_commitment_type t ON t.attrid = a.attrid | ||||
| GROUP BY a.attrid; | ||||
|  | ||||
| DROP VIEW v_delivery_bucket_strict; | ||||
| CREATE VIEW v_delivery_bucket_strict AS | ||||
| SELECT year, mgnr, | ||||
|        sortid || IIF(min_quw OR NOT COALESCE(area_com, TRUE), COALESCE(a.attrid, ''), '_') AS bucket, | ||||
|        sortid, IIF(min_quw OR NOT COALESCE(area_com, TRUE), a.attrid, NULL) AS attrid, | ||||
|        SUM(weight) AS weight, | ||||
|        min_quw OR NOT COALESCE(area_com, TRUE) AS valid | ||||
| FROM v_delivery d | ||||
|     LEFT JOIN v_wine_attribute a ON a.attrid = d.attrid | ||||
| GROUP BY year, mgnr, bucket | ||||
| ORDER BY year, mgnr, bucket; | ||||
|  | ||||
| DROP VIEW v_delivery_bucket; | ||||
| CREATE VIEW v_delivery_bucket AS | ||||
| SELECT year, mgnr, bucket, weight | ||||
| FROM v_delivery_bucket_strict | ||||
| WHERE attrid IS NOT NULL OR NOT valid | ||||
| UNION ALL | ||||
| SELECT b.year, b.mgnr, b.sortid, | ||||
|        SUM(b.weight) AS weight | ||||
| FROM v_delivery_bucket_strict b | ||||
|     LEFT JOIN wine_attribute a ON a.attrid = b.attrid | ||||
| WHERE valid AND (a.strict IS NULL OR a.strict = FALSE) | ||||
| GROUP BY b.year, b.mgnr, b.sortid | ||||
| ORDER BY year, mgnr, bucket; | ||||
|  | ||||
| PRAGMA schema_version = 1701; | ||||
| PRAGMA writable_schame = OFF; | ||||
|  | ||||
| ---------------------------------------------------------------- | ||||
|  | ||||
| UPDATE area_commitment SET cultid = NULL WHERE cultid = 'N'; | ||||
| DELETE FROM wine_cultivation WHERE cultid = 'N'; | ||||
| UPDATE wine_cultivation SET cultid = 'B', name = 'Bio', description = 'AT-BIO-302' WHERE cultid = 'BIO'; | ||||
|  | ||||
| UPDATE area_commitment SET cultid = 'B', vtrgid = SUBSTR(vtrgid, 0, 2) WHERE vtrgid LIKE '__B'; | ||||
| DELETE FROM area_commitment_type WHERE attrid = 'B'; | ||||
| UPDATE delivery_part SET cultid = 'B', attrid = NULL WHERE attrid = 'B'; | ||||
| DELETE FROM wine_attribute WHERE attrid = 'B'; | ||||
|  | ||||
| UPDATE payment_variant SET data = REPLACE(REPLACE(data, '/B', '/-B'), '"/-B"', '"-B"'); | ||||
| @@ -280,21 +280,25 @@ | ||||
|             <GroupBox Header="Sorte" Grid.Column="1" Grid.Row="0"  Margin="5,5,5,5"> | ||||
|                 <Grid> | ||||
|                     <Grid.ColumnDefinitions> | ||||
|                         <ColumnDefinition Width="70"/> | ||||
|                         <ColumnDefinition Width="80"/> | ||||
|                         <ColumnDefinition/> | ||||
|                         <ColumnDefinition/> | ||||
|                     </Grid.ColumnDefinitions> | ||||
|  | ||||
|                     <Label Content="Sorte:" Margin="10,10,0,0" Grid.Column="0"/> | ||||
|                     <TextBox x:Name="SortIdInput" Width="36" Grid.Row="1" Grid.Column="1" Margin="0,10,0,0" HorizontalAlignment="Left" | ||||
|                              TextChanged="SortIdInput_TextChanged" LostFocus="SortIdInput_LostFocus" KeyUp="Input_KeyUp"/> | ||||
|                     <ComboBox x:Name="WineVarietyInput" Grid.Row="1" Grid.Column="1" Margin="41,10,10,10" | ||||
|                     <ComboBox x:Name="WineVarietyInput" Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2" Margin="41,10,10,10" | ||||
|                               ItemTemplate="{StaticResource WineVarietyTemplate}" TextSearch.TextPath="Name" | ||||
|                               SelectionChanged="WineVarietyInput_SelectionChanged" KeyUp="Input_KeyUp"/> | ||||
|  | ||||
|                     <Label Content="Attribut:" Margin="10,40,0,0" Grid.Column="0"/> | ||||
|                     <ComboBox x:Name="AttributeInput" Grid.Row="1" Grid.Column="1" Margin="0,40,10,10" | ||||
|                     <Label Content="Attr./Bewirt.:" Margin="10,40,0,0" Grid.Column="0"/> | ||||
|                     <ComboBox x:Name="AttributeInput" Grid.Row="1" Grid.Column="1" Margin="0,40,5,10" | ||||
|                               DisplayMemberPath="Name" | ||||
|                               SelectionChanged="AttributeInput_SelectionChanged" KeyUp="Input_KeyUp"/> | ||||
|                     <ComboBox x:Name="CultivationInput" Grid.Row="1" Grid.Column="2" Margin="0,40,10,10" | ||||
|                               DisplayMemberPath="Name" | ||||
|                               SelectionChanged="CultivationInput_SelectionChanged" KeyUp="Input_KeyUp"/> | ||||
|                 </Grid> | ||||
|             </GroupBox> | ||||
|  | ||||
|   | ||||
| @@ -292,7 +292,7 @@ namespace Elwig.Windows { | ||||
|             if (ctrl == MgNrInput || ctrl == MemberInput) { | ||||
|                 SortIdInput.Focus(); | ||||
|                 SortIdInput.SelectAll(); | ||||
|             } else if (ctrl == SortIdInput || ctrl == WineVarietyInput || ctrl == AttributeInput) { | ||||
|             } else if (ctrl == SortIdInput || ctrl == WineVarietyInput || ctrl == AttributeInput || ctrl == CultivationInput) { | ||||
|                 GradationOeInput.Focus(); | ||||
|                 GradationOeInput.TextBox.SelectAll(); | ||||
|             } else if (ctrl == GradationKmwInput || ctrl == GradationOeInput || ctrl == WineQualityLevelInput) { | ||||
| @@ -762,6 +762,9 @@ namespace Elwig.Windows { | ||||
|             var attrList = await Context.WineAttributes.Where(a => !IsCreating || a.IsActive).OrderBy(a => a.Name).Cast<object>().ToListAsync(); | ||||
|             attrList.Insert(0, new NullItem("")); | ||||
|             ControlUtils.RenewItemsSource(AttributeInput, attrList, i => (i as WineAttr)?.AttrId, null, ControlUtils.RenewSourceDefault.First); | ||||
|             var cultList = await Context.WineCultivations.OrderBy(a => a.Name).Cast<object>().ToListAsync(); | ||||
|             cultList.Insert(0, new NullItem("")); | ||||
|             ControlUtils.RenewItemsSource(CultivationInput, cultList, i => (i as WineCult)?.CultId, null, ControlUtils.RenewSourceDefault.First); | ||||
|             ControlUtils.RenewItemsSource(WineQualityLevelInput, await Context.WineQualityLevels.ToListAsync(), i => (i as WineQualLevel)?.QualId); | ||||
|             ControlUtils.RenewItemsSource(ModifiersInput, await Context.Modifiers.Where(m => m.Year == y).OrderBy(m => m.Ordering).ToListAsync(), i => (i as Modifier)?.ModId); | ||||
|             ControlUtils.RenewItemsSource(WineOriginInput, (await Context.WineOrigins.ToListAsync()).OrderByDescending(o => o.SortKey).ThenBy(o => o.HkId), i => (i as WineOrigin)?.HkId); | ||||
| @@ -836,14 +839,15 @@ namespace Elwig.Windows { | ||||
|  | ||||
|             SortIdInput.Text = p?.SortId ?? ""; | ||||
|             ControlUtils.SelectComboBoxItem(AttributeInput, p?.Attribute, i => (i as WineAttr)?.AttrId); | ||||
|             ControlUtils.SelectComboBoxItem(CultivationInput, p?.Cultivation, i => (i as WineCult)?.CultId); | ||||
|             GradationKmwInput.Text = (p != null) ? $"{p.Kmw:N1}" : ""; | ||||
|             ControlUtils.SelectComboBoxItem(WineQualityLevelInput, q => (q as WineQualLevel)?.QualId, p?.QualId); | ||||
|             ControlUtils.SelectComboBoxItem(WineKgInput, k => (k as AT_Kg)?.KgNr, p?.KgNr); | ||||
|             ControlUtils.SelectComboBoxItem(WineRdInput, r => (r as WbRd)?.RdNr, p?.RdNr); | ||||
|             ControlUtils.SelectComboBoxItem(WineOriginInput, r => (r as WineOrigin)?.HkId, p?.HkId); | ||||
|             WeightInput.Text = (p != null) ? $"{p.Weight:N0}" : ""; | ||||
|             ManualWeighingInput.IsChecked = p?.ManualWeighing ?? false; | ||||
|             GerebeltGewogenInput.IsChecked = p?.IsGerebelt ?? false; | ||||
|             ManualWeighingInput.IsChecked = p?.IsManualWeighing ?? false; | ||||
|             GerebeltGewogenInput.IsChecked = p?.IsNetWeight ?? false; | ||||
|             ControlUtils.SelectCheckComboBoxItems(ModifiersInput, p?.Modifiers, i => (i as Modifier)?.ModId); | ||||
|             PartCommentInput.Text = p?.Comment ?? ""; | ||||
|             TemperatureInput.Text = (p != null && p.Temperature != null) ? $"{p.Temperature:N1}" : ""; | ||||
| @@ -900,13 +904,14 @@ namespace Elwig.Windows { | ||||
|  | ||||
|             p.SortId = (WineVarietyInput.SelectedItem as WineVar)?.SortId; | ||||
|             p.AttrId = (AttributeInput.SelectedItem as WineAttr)?.AttrId; | ||||
|             p.CultId = (CultivationInput.SelectedItem as WineCult)?.CultId; | ||||
|             p.Kmw = double.Parse(GradationKmwInput.Text); | ||||
|             p.QualId = (WineQualityLevelInput.SelectedItem as WineQualLevel)?.QualId; | ||||
|             p.HkId = (WineOriginInput.SelectedItem as WineOrigin)?.HkId; | ||||
|             p.KgNr = (WineKgInput.SelectedItem as AT_Kg)?.KgNr; | ||||
|             p.RdNr = (WineRdInput.SelectedItem as WbRd)?.RdNr; | ||||
|  | ||||
|             p.IsGerebelt = GerebeltGewogenInput.IsChecked ?? false; | ||||
|             p.IsNetWeight = GerebeltGewogenInput.IsChecked ?? false; | ||||
|             p.IsHandPicked = HandPickedInput.IsChecked; | ||||
|             p.IsLesewagen = LesewagenInput.IsChecked; | ||||
|             p.IsGebunden = GebundenInput.IsChecked; | ||||
| @@ -915,7 +920,7 @@ namespace Elwig.Windows { | ||||
|             p.Comment = (PartCommentInput.Text == "") ? null : PartCommentInput.Text; | ||||
|  | ||||
|             p.Weight = int.Parse(WeightInput.Text.Replace(Utils.GroupSeparator, "")); | ||||
|             p.ManualWeighing = ManualWeighingInput.IsChecked ?? false; | ||||
|             p.IsManualWeighing = ManualWeighingInput.IsChecked ?? false; | ||||
|             p.ScaleId = ScaleId; | ||||
|             p.WeighingId = WeighingId; | ||||
|             p.WeighingReason = ManualWeighingReason; | ||||
| @@ -1563,11 +1568,13 @@ namespace Elwig.Windows { | ||||
|                 WineVarietyInput.SelectedItem = Context.WineVarieties.Find(text[0..2]); | ||||
|                 if (text.Length >= 3) { | ||||
|                     ControlUtils.SelectComboBoxItem(AttributeInput, Context.WineAttributes.Find(text[2..]), a => (a as WineAttr)?.AttrId); | ||||
|                     ControlUtils.SelectComboBoxItem(CultivationInput, Context.WineCultivations.Find(text[2..]), i => (i as WineCult)?.CultId); | ||||
|                     SortIdInput.Text = text[0..2]; | ||||
|                 } | ||||
|             } else { | ||||
|                 WineVarietyInput.SelectedItem = null; | ||||
|                 AttributeInput.SelectedIndex = 0; | ||||
|                 CultivationInput.SelectedIndex = 0; | ||||
|             } | ||||
|         } | ||||
|  | ||||
| @@ -1648,6 +1655,10 @@ namespace Elwig.Windows { | ||||
|  | ||||
|         } | ||||
|  | ||||
|         private void CultivationInput_SelectionChanged(object sender, SelectionChangedEventArgs evt) { | ||||
|  | ||||
|         } | ||||
|  | ||||
|         private void ModifiersInput_SelectionChanged(object sender, ItemSelectionChangedEventArgs evt) { | ||||
|             if (!IsEditing && !IsCreating) return; | ||||
|             var mod = ModifiersInput.SelectedItems.Cast<Modifier>(); | ||||
|   | ||||
| @@ -42,7 +42,7 @@ INSERT INTO delivery (mgnr, year, did, date, time, zwstid, lnr) VALUES | ||||
| (101, 2020, 1, '2020-10-01', NULL, 'X', 1), | ||||
| (101, 2020, 2, '2020-10-01', NULL, 'X', 2), | ||||
| (101, 2020, 3, '2020-10-01', NULL, 'X', 3); | ||||
| INSERT INTO delivery_part (year, did, dpnr, sortid, attrid, weight, kmw, qualid, hkid, kgnr, gerebelt, manual_weighing, spl_check, scale_id, weighing_id, weighing_reason) VALUES | ||||
| INSERT INTO delivery_part (year, did, dpnr, sortid, attrid, weight, kmw, qualid, hkid, kgnr, net_weight, manual_weighing, spl_check, scale_id, weighing_id, weighing_reason) VALUES | ||||
| (2020, 1, 1, 'GV', 'K',  4000, 17, 'KAB', 'WLNO', 06109, TRUE, FALSE, FALSE, NULL, NULL, NULL), | ||||
| (2020, 1, 2, 'GV', NULL, 4000, 16, 'QUW', 'WLNO', 06109, TRUE, FALSE, FALSE, NULL, NULL, NULL), | ||||
| (2020, 2, 1, 'GV', 'B',  4000, 15, 'QUW', 'WLNO', 06109, TRUE, FALSE, FALSE, NULL, NULL, NULL), | ||||
| @@ -57,7 +57,7 @@ INSERT INTO delivery (mgnr, year, did, date, time, zwstid, lnr) VALUES | ||||
| (101, 2021, 1, '2021-10-01', NULL, 'X', 1), | ||||
| (101, 2021, 2, '2021-10-01', NULL, 'X', 2), | ||||
| (101, 2021, 3, '2021-10-01', NULL, 'X', 3); | ||||
| INSERT INTO delivery_part (year, did, dpnr, sortid, attrid, weight, kmw, qualid, hkid, kgnr, gebunden, gerebelt, manual_weighing, spl_check, scale_id, weighing_id, weighing_reason) VALUES | ||||
| INSERT INTO delivery_part (year, did, dpnr, sortid, attrid, weight, kmw, qualid, hkid, kgnr, gebunden, net_weight, manual_weighing, spl_check, scale_id, weighing_id, weighing_reason) VALUES | ||||
| (2021, 1, 1, 'GV', 'K',  4000, 17, 'KAB', 'WLNO', 06109, TRUE,  TRUE, FALSE, FALSE, NULL, NULL, NULL), | ||||
| (2021, 1, 2, 'GV', NULL, 4000, 16, 'QUW', 'WLNO', 06109, FALSE, TRUE, FALSE, FALSE, NULL, NULL, NULL), | ||||
| (2021, 2, 1, 'GV', 'B',  4000, 15, 'QUW', 'WLNO', 06109, TRUE,  TRUE, FALSE, FALSE, NULL, NULL, NULL), | ||||
|   | ||||
| @@ -16,5 +16,5 @@ INSERT INTO delivery (mgnr, year, did, date, time, zwstid, lnr) VALUES | ||||
| (101, 2020, 2, '2020-10-01', NULL, 'X', 2), | ||||
| (101, 2020, 3, '2020-10-01', NULL, 'X', 3); | ||||
|  | ||||
| INSERT INTO delivery_part (year, did, dpnr, sortid, attrid, weight, kmw, qualid, hkid, kgnr, gerebelt, manual_weighing, spl_check, scale_id, weighing_id, weighing_reason) VALUES | ||||
| INSERT INTO delivery_part (year, did, dpnr, sortid, attrid, weight, kmw, qualid, hkid, kgnr, net_weight, manual_weighing, spl_check, scale_id, weighing_id, weighing_reason) VALUES | ||||
| (2020, 1, 1, 'GV', NULL,  4000, 17, 'KAB', 'WLNO', 06109, TRUE, FALSE, FALSE, NULL, NULL, NULL); | ||||
|   | ||||
| @@ -1 +1 @@ | ||||
| curl -s -L "https://www.necronda.net/elwig/files/create.sql?v=17" -u "elwig:ganzGeheim123!" -o "Resources\Sql\Create.sql" | ||||
| curl -s -L "https://www.necronda.net/elwig/files/create.sql?v=18" -u "elwig:ganzGeheim123!" -o "Resources\Sql\Create.sql" | ||||
|   | ||||
		Reference in New Issue
	
	Block a user