diff --git a/Elwig/Helpers/AppDbUpdater.cs b/Elwig/Helpers/AppDbUpdater.cs index de4b797..2747f91 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 = 14; + public static readonly int RequiredSchemaVersion = 15; private static int VersionOffset = 0; diff --git a/Elwig/Helpers/Billing/Billing.cs b/Elwig/Helpers/Billing/Billing.cs index 1deb8e1..3b8dfdd 100644 --- a/Elwig/Helpers/Billing/Billing.cs +++ b/Elwig/Helpers/Billing/Billing.cs @@ -1,3 +1,5 @@ +using Elwig.Models.Entities; +using Microsoft.Data.Sqlite; using System; using System.Collections.Generic; using System.Linq; @@ -8,6 +10,7 @@ namespace Elwig.Helpers.Billing { protected readonly int Year; protected readonly AppDbContext Context; + protected readonly Season Season; protected readonly Dictionary Attributes; protected readonly Dictionary Modifiers; protected readonly Dictionary AreaComTypes; @@ -15,6 +18,7 @@ namespace Elwig.Helpers.Billing { public Billing(int year) { Year = year; Context = new AppDbContext(); + Season = Context.Seasons.Find(Year)!; 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.AttrId, v.Discriminator, v.MinKgPerHa, v.PenaltyAmount)); @@ -26,8 +30,6 @@ namespace Elwig.Helpers.Billing { UPDATE season SET (start_date, end_date) = (SELECT MIN(date), MAX(date) FROM delivery WHERE year = {Year}) WHERE year = {Year}; - - DELETE FROM delivery_part_bucket WHERE year = {Year}; """); } @@ -43,10 +45,11 @@ namespace Elwig.Helpers.Billing { """); } - public async Task CalculateBuckets(bool allowAttrsIntoLower, bool avoidUnderDeliveries, bool honorGebunden) { + public async Task CalculateBuckets(bool allowAttrsIntoLower, bool avoidUnderDeliveries, bool honorGebunden, SqliteConnection? cnx = null) { var attrVals = Context.WineAttributes.ToDictionary(a => a.AttrId, a => (a.IsStrict, a.FillLower)); var attrForced = attrVals.Where(a => a.Value.IsStrict && a.Value.FillLower == 0).Select(a => a.Key).ToArray(); - using var cnx = await AppDbContext.ConnectAsync(); + var ownCnx = cnx == null; + cnx ??= await AppDbContext.ConnectAsync(); await Context.GetMemberAreaCommitmentBuckets(Year, 0, cnx); var inserts = new List<(int, int, int, string, int)>(); @@ -65,7 +68,7 @@ namespace Elwig.Helpers.Billing { reader.GetInt32(0), reader.GetInt32(1), reader.GetInt32(2), reader.GetString(3), reader.GetInt32(4), reader.GetDouble(5), reader.GetString(6), reader.IsDBNull(7) ? null : reader.GetString(7), - reader.IsDBNull(8) ? Array.Empty() : reader.GetString(8).Split(",").Order().ToArray(), + reader.IsDBNull(8) ? [] : reader.GetString(8).Split(",").Order().ToArray(), reader.IsDBNull(9) ? null : reader.GetBoolean(9) )); } @@ -73,11 +76,11 @@ namespace Elwig.Helpers.Billing { int lastMgNr = 0; Dictionary? rightsAndObligations = null; - Dictionary used = new(); + Dictionary used = []; foreach (var (mgnr, did, dpnr, sortid, weight, kmw, qualid, attrid, modifiers, gebunden) in deliveries) { if (lastMgNr != mgnr) { rightsAndObligations = await Context.GetMemberAreaCommitmentBuckets(Year, mgnr); - used = new(); + used = []; } if ((honorGebunden && gebunden == false) || rightsAndObligations == null || rightsAndObligations.Count == 0 || @@ -92,16 +95,16 @@ namespace Elwig.Helpers.Billing { } int w = weight; - var attributes = attrid == null ? Array.Empty() : new string[] { attrid }; + var attributes = attrid == null ? [] : new string[] { attrid }; var isStrict = attrid != null && attrVals[attrid].IsStrict; foreach (var p in Utils.Permutate(attributes, attributes.Intersect(attrForced))) { var c = p.Count(); var key = sortid + string.Join("", p); - if (rightsAndObligations.ContainsKey(key)) { + if (rightsAndObligations.TryGetValue(key, out AreaComBucket value)) { int i = (c == 0) ? 1 : 2; var u = used.GetValueOrDefault(key, 0); - var vr = Math.Max(0, Math.Min(rightsAndObligations[key].Right - u, w)); - var vo = Math.Max(0, Math.Min(rightsAndObligations[key].Obligation - u, w)); + var vr = Math.Max(0, Math.Min(value.Right - u, w)); + var vo = Math.Max(0, Math.Min(value.Obligation - u, w)); var v = (attributes.Length == c || attributes.Select(a => !attrVals[a].IsStrict ? 2 : attrVals[a].FillLower).Min() == 2) ? vr : vo; used[key] = u + v; if (key.Length > 2 && !isStrict) used[key[..2]] = used.GetValueOrDefault(key[..2], 0) + v; @@ -115,14 +118,17 @@ namespace Elwig.Helpers.Billing { } await AppDbContext.ExecuteBatch(cnx, $""" + UPDATE delivery_part_bucket SET value = 0 WHERE year = {Year}; INSERT INTO delivery_part_bucket (year, did, dpnr, bktnr, discr, value) VALUES {string.Join(",\n ", inserts.Select(i => $"({Year}, {i.Item1}, {i.Item2}, {i.Item3}, '{i.Item4}', {i.Item5})"))} ON CONFLICT DO UPDATE SET discr = excluded.discr, value = value + excluded.value; """); - if (!avoidUnderDeliveries) + if (!avoidUnderDeliveries) { + if (ownCnx) await cnx.DisposeAsync(); return; + } // FIXME avoidUnderDelivery-calculations not always right! @@ -200,6 +206,8 @@ namespace Elwig.Helpers.Billing { ON CONFLICT DO UPDATE SET value = excluded.value; """); + + if (ownCnx) await cnx.DisposeAsync(); } } } diff --git a/Elwig/Helpers/Billing/BillingVariant.cs b/Elwig/Helpers/Billing/BillingVariant.cs index 0d4842b..70a8b93 100644 --- a/Elwig/Helpers/Billing/BillingVariant.cs +++ b/Elwig/Helpers/Billing/BillingVariant.cs @@ -21,6 +21,11 @@ namespace Elwig.Helpers.Billing { public async Task Calculate() { using var cnx = await AppDbContext.ConnectAsync(); using var tx = await cnx.BeginTransactionAsync(); + await CalculateBuckets( + Season.Billing_AllowAttrsIntoLower, + Season.Billing_AvoidUnderDeliveries, + Season.Billing_HonorGebunden, + cnx); await DeleteInDb(cnx); await SetCalcTime(cnx); await CalculatePrices(cnx); diff --git a/Elwig/Models/Entities/Season.cs b/Elwig/Models/Entities/Season.cs index dccf686..d96e6fe 100644 --- a/Elwig/Models/Entities/Season.cs +++ b/Elwig/Models/Entities/Season.cs @@ -65,7 +65,6 @@ namespace Elwig.Models.Entities { [Column("start_date")] public string? StartDateString { get; set; } - [NotMapped] public DateOnly? StartDate { get => StartDateString != null ? DateOnly.ParseExact(StartDateString, "yyyy-MM-dd") : null; @@ -74,13 +73,30 @@ namespace Elwig.Models.Entities { [Column("end_date")] public string? EndDateString { get; set; } - [NotMapped] public DateOnly? EndDate { get => EndDateString != null ? DateOnly.ParseExact(EndDateString, "yyyy-MM-dd") : null; set => EndDateString = value?.ToString("yyyy-MM-dd"); } + [Column("calc_mode")] + public int CalcMode { get; set; } + [NotMapped] + public bool Billing_HonorGebunden { + get => (CalcMode & 0x1) != 0; + set => CalcMode = value ? CalcMode | 0x1 : CalcMode & ~0x1; + } + [NotMapped] + public bool Billing_AllowAttrsIntoLower { + get => (CalcMode & 0x4) != 0; + set => CalcMode = value ? CalcMode | 0x4 : CalcMode & ~0x4; + } + [NotMapped] + public bool Billing_AvoidUnderDeliveries { + get => (CalcMode & 0x2) != 0; + set => CalcMode = value ? CalcMode | 0x2 : CalcMode & ~0x2; + } + [ForeignKey("CurrencyCode")] public virtual Currency Currency { get; private set; } diff --git a/Elwig/Resources/Sql/14-15.sql b/Elwig/Resources/Sql/14-15.sql new file mode 100644 index 0000000..8e58a7f --- /dev/null +++ b/Elwig/Resources/Sql/14-15.sql @@ -0,0 +1,18 @@ +-- schema version 14 to 15 + +ALTER TABLE season ADD COLUMN calc_mode INTEGER NOT NULL DEFAULT 0; + +DROP TRIGGER t_payment_delivery_part_u; + +CREATE TRIGGER t_payment_delivery_part_u + AFTER UPDATE ON payment_delivery_part FOR EACH ROW +BEGIN + UPDATE payment_member + SET net_amount = net_amount - OLD.amount + WHERE (year, avnr, mgnr) IN (SELECT year, OLD.avnr, mgnr FROM delivery WHERE (year, did) = (OLD.year, OLD.did)); + INSERT INTO payment_member (year, avnr, mgnr, net_amount) + SELECT d.year, v.avnr, d.mgnr, NEW.amount + FROM delivery d, payment_variant v + WHERE (d.year, d.did) = (NEW.year, NEW.did) AND (v.year, v.avnr) = (NEW.year, NEW.avnr) + ON CONFLICT DO UPDATE SET net_amount = net_amount + excluded.net_amount; +END; diff --git a/Elwig/Windows/SeasonFinishWindow.xaml.cs b/Elwig/Windows/SeasonFinishWindow.xaml.cs index 77b7893..ad3c9ad 100644 --- a/Elwig/Windows/SeasonFinishWindow.xaml.cs +++ b/Elwig/Windows/SeasonFinishWindow.xaml.cs @@ -1,8 +1,8 @@ -using Elwig.Dialogs; using Elwig.Helpers; using Elwig.Helpers.Billing; using Elwig.Helpers.Export; using Elwig.Models.Dtos; +using Elwig.Models.Entities; using Microsoft.Win32; using System; using System.Threading.Tasks; @@ -33,19 +33,34 @@ namespace Elwig.Windows { OverUnderDeliveryButton.IsEnabled = valid; AutoBusinessSharesButton.IsEnabled = valid; PaymentButton.IsEnabled = valid; + AllowAttrIntoLowerInput.IsEnabled = valid && last; + AvoidUnderDeliveriesInput.IsEnabled = valid && last; + HonorGebundenInput.IsEnabled = valid && last; + AllowAttrIntoLowerInput.IsChecked = s0?.Billing_AllowAttrsIntoLower; + AvoidUnderDeliveriesInput.IsChecked = s0?.Billing_AvoidUnderDeliveries; + HonorGebundenInput.IsChecked = s0?.Billing_HonorGebunden; } private async void CalculateBucketsButton_Click(object sender, RoutedEventArgs evt) { - if (SeasonInput.Value is not int year) + if (SeasonInput.Value is not int year || await Context.Seasons.FindAsync(year) is not Season s) return; CalculateBucketsButton.IsEnabled = false; Mouse.OverrideCursor = Cursors.AppStarting; + + try { + s.Billing_AllowAttrsIntoLower = AllowAttrIntoLowerInput.IsChecked ?? false; + s.Billing_AvoidUnderDeliveries = AvoidUnderDeliveriesInput.IsChecked ?? false; + s.Billing_HonorGebunden = HonorGebundenInput.IsChecked ?? false; + Context.Update(s); + await Context.SaveChangesAsync(); + } catch { } + var b = new Billing(year); await b.FinishSeason(); await b.CalculateBuckets( - AllowAttrIntoLowerInput.IsChecked ?? false, - AvoidUnderDeliveriesInput.IsChecked ?? false, - HonorGebundenInput.IsChecked ?? false); + s.Billing_AllowAttrsIntoLower, + s.Billing_AvoidUnderDeliveries, + s.Billing_HonorGebunden); Mouse.OverrideCursor = null; CalculateBucketsButton.IsEnabled = true; } diff --git a/Tests/fetch-resources.bat b/Tests/fetch-resources.bat index 9ee5029..e964600 100644 --- a/Tests/fetch-resources.bat +++ b/Tests/fetch-resources.bat @@ -1 +1 @@ -curl -s -L "https://www.necronda.net/elwig/files/create.sql?v=14" -u "elwig:ganzGeheim123!" -o "Resources\Create.sql" +curl -s -L "https://www.necronda.net/elwig/files/create.sql?v=15" -u "elwig:ganzGeheim123!" -o "Resources\Create.sql"