diff --git a/Elwig/Documents/CreditNote.cs b/Elwig/Documents/CreditNote.cs index 082f3d6..58fff68 100644 --- a/Elwig/Documents/CreditNote.cs +++ b/Elwig/Documents/CreditNote.cs @@ -18,6 +18,7 @@ namespace Elwig.Documents { public string MemberModifier; public IEnumerable<(string Name, int Kg, decimal Amount)>? MemberUnderDeliveries; public decimal MemberTotalUnderDelivery; + public decimal MemberAutoBusinessShares; public CreditNote(AppDbContext ctx, PaymentMember p, CreditNoteData data, Dictionary? underDeliveries = null) : base($"{Name} {(p.Credit != null ? $"Nr. {p.Credit.Year}/{p.Credit.TgNr:000}" : p.Member.Name)} – {p.Variant.Name}", p.Member) { @@ -36,6 +37,12 @@ namespace Elwig.Documents { var total = data.Rows.SelectMany(r => r.Buckets).Sum(b => b.Value); var totalUnderDelivery = total - p.Member.BusinessShares * season.MinKgPerBusinessShare; MemberTotalUnderDelivery = totalUnderDelivery < 0 ? totalUnderDelivery * (season.PenaltyPerKg ?? 0) - (season.PenaltyAmount ?? 0) : 0; + var fromDate = $"{season.Year}-06-01"; + var toDate = $"{season.Year + 1}-06-01"; + MemberAutoBusinessShares = ctx.MemberHistory + .Where(h => h.MgNr == p.Member.MgNr && h.Type == "auto") + .Where(h => h.DateString.CompareTo(fromDate) >= 0 && h.DateString.CompareTo(toDate) < 0) + .Sum(h => h.BusinessShares) * (-season.BusinessShareValue ?? 0); if (total == 0) MemberTotalUnderDelivery -= (season.PenaltyNone ?? 0); Aside = Aside.Replace("", "") + $"Gutschrift" + diff --git a/Elwig/Documents/CreditNote.cshtml b/Elwig/Documents/CreditNote.cshtml index 97061e5..49016da 100644 --- a/Elwig/Documents/CreditNote.cshtml +++ b/Elwig/Documents/CreditNote.cshtml @@ -138,7 +138,11 @@ } @if (Model.MemberTotalUnderDelivery != 0) { @Raw(FormatRow("Unterlieferung (GA)", Model.MemberTotalUnderDelivery, add: true)); - penalty += Math.Round(Model.MemberTotalUnderDelivery, 2, MidpointRounding.AwayFromZero); + penalty += Model.MemberTotalUnderDelivery; + } + @if (Model.MemberAutoBusinessShares != 0) { + @Raw(FormatRow("Autom. Nachz. von GA", Model.MemberAutoBusinessShares, add: true)); + penalty += Model.MemberAutoBusinessShares; } @if (Model.Credit == null) { diff --git a/Elwig/Helpers/AppDbContext.cs b/Elwig/Helpers/AppDbContext.cs index d3f9fdc..926a7f5 100644 --- a/Elwig/Helpers/AppDbContext.cs +++ b/Elwig/Helpers/AppDbContext.cs @@ -44,6 +44,7 @@ namespace Elwig.Helpers { public DbSet Members { get; private set; } public DbSet BillingAddresses { get; private set; } public DbSet MemberTelephoneNrs { get; private set; } + public DbSet MemberHistory { get; private set; } public DbSet AreaCommitments { get; private set; } public DbSet Seasons { get; private set; } public DbSet Modifiers { get; private set; } diff --git a/Elwig/Helpers/Billing/Billing.cs b/Elwig/Helpers/Billing/Billing.cs index d018536..1deb8e1 100644 --- a/Elwig/Helpers/Billing/Billing.cs +++ b/Elwig/Helpers/Billing/Billing.cs @@ -31,6 +31,18 @@ namespace Elwig.Helpers.Billing { """); } + public async Task AutoAdjustBusinessShare() { + using var cnx = await AppDbContext.ConnectAsync(); + await AppDbContext.ExecuteBatch(cnx, $""" + INSERT INTO member_history (mgnr, date, business_shares, type) + SELECT u.mgnr, '{Utils.Today:yyyy-MM-dd}', u.diff / s.max_kg_per_bs AS bs, 'auto' + FROM v_total_under_delivery u + JOIN season s ON s.year = u.year + WHERE s.year = {Year} AND bs > 0 + ON CONFLICT DO NOTHING + """); + } + public async Task CalculateBuckets(bool allowAttrsIntoLower, bool avoidUnderDeliveries, bool honorGebunden) { 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(); diff --git a/Elwig/Helpers/Billing/BillingVariant.cs b/Elwig/Helpers/Billing/BillingVariant.cs index 8d8f108..028cb38 100644 --- a/Elwig/Helpers/Billing/BillingVariant.cs +++ b/Elwig/Helpers/Billing/BillingVariant.cs @@ -52,7 +52,7 @@ namespace Elwig.Helpers.Billing { ROUND( IIF({Data.ConsiderContractPenalties}, COALESCE(u.total_penalty, 0) / POW(10, 4 - 2), 0) + IIF({Data.ConsiderTotalPenalty}, COALESCE(b.total_penalty, 0), 0) + - IIF({Data.ConsiderAutoBusinessShares}, 0, 0) + IIF({Data.ConsiderAutoBusinessShares}, -COALESCE(a.business_shares * s.bs_value, 0), 0) / POW(10, s.precision - 2) ) AS modifiers, lc.modifiers AS prev_modifiers FROM season s @@ -84,6 +84,11 @@ namespace Elwig.Helpers.Billing { FROM v_total_under_delivery u JOIN season s ON s.year = u.year WHERE u.diff < 0) b ON (b.year, b.mgnr) = (s.year, m.mgnr) + LEFT JOIN (SELECT h.mgnr, h.business_shares + FROM member_history h + WHERE type = 'auto' AND + date >= '{Year}-06-01' AND + date < '{Year + 1}-06-01') a ON a.mgnr = m.mgnr WHERE s.year = {Year} AND v.avnr = {AvNr}; UPDATE payment_variant SET test_variant = FALSE WHERE (year, avnr) = ({Year}, {AvNr}); diff --git a/Elwig/Models/Entities/Member.cs b/Elwig/Models/Entities/Member.cs index 52428a2..6c728f6 100644 --- a/Elwig/Models/Entities/Member.cs +++ b/Elwig/Models/Entities/Member.cs @@ -62,12 +62,8 @@ namespace Elwig.Models.Entities { [NotMapped] public DateOnly? EntryDate { - get { - return EntryDateString != null ? DateOnly.ParseExact(EntryDateString, "yyyy-MM-dd") : null; - } - set { - EntryDateString = value?.ToString("yyyy-MM-dd"); - } + get => EntryDateString != null ? DateOnly.ParseExact(EntryDateString, "yyyy-MM-dd") : null; + set => EntryDateString = value?.ToString("yyyy-MM-dd"); } [Column("exit_date")] @@ -75,12 +71,8 @@ namespace Elwig.Models.Entities { [NotMapped] public DateOnly? ExitDate { - get { - return ExitDateString != null ? DateOnly.ParseExact(ExitDateString, "yyyy-MM-dd") : null; - } - set { - ExitDateString = value?.ToString("yyyy-MM-dd"); - } + get => ExitDateString != null ? DateOnly.ParseExact(ExitDateString, "yyyy-MM-dd") : null; + set => ExitDateString = value?.ToString("yyyy-MM-dd"); } [Column("business_shares")] diff --git a/Elwig/Models/Entities/MemberHistory.cs b/Elwig/Models/Entities/MemberHistory.cs new file mode 100644 index 0000000..3835581 --- /dev/null +++ b/Elwig/Models/Entities/MemberHistory.cs @@ -0,0 +1,31 @@ +using Microsoft.EntityFrameworkCore; +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Elwig.Models.Entities { + [Table("member_history"), PrimaryKey("MgNr", "DateString")] + public class MemberHistory { + [Column("mgnr")] + public int MgNr { get; set; } + + [Column("date")] + public string DateString { get; set; } + [NotMapped] + public DateOnly Date { + get => DateOnly.ParseExact(DateString, "yyyy-MM-dd"); + set => value.ToString("yyyy-MM-dd"); + } + + [Column("business_shares")] + public int BusinessShares { get; set; } + + [Column("type")] + public string Type { get; set; } + + [Column("comment")] + public string? Comment { get; set; } + + [ForeignKey("MgNr")] + public virtual Member Member { get; private set; } + } +} diff --git a/Elwig/Models/Entities/Season.cs b/Elwig/Models/Entities/Season.cs index 35a995f..dccf686 100644 --- a/Elwig/Models/Entities/Season.cs +++ b/Elwig/Models/Entities/Season.cs @@ -55,6 +55,14 @@ namespace Elwig.Models.Entities { set => PenaltyNoneValue = value != null ? DecToDb(value.Value) : null; } + [Column("bs_value")] + public long? BusinessShareValueValue { get; set; } + [NotMapped] + public decimal? BusinessShareValue { + get => BusinessShareValueValue != null ? DecFromDb(BusinessShareValueValue.Value) : null; + set => BusinessShareValueValue = value != null ? DecToDb(value.Value) : null; + } + [Column("start_date")] public string? StartDateString { get; set; } diff --git a/Elwig/Windows/BaseDataWindow.xaml b/Elwig/Windows/BaseDataWindow.xaml index f8070b4..5640694 100644 --- a/Elwig/Windows/BaseDataWindow.xaml +++ b/Elwig/Windows/BaseDataWindow.xaml @@ -382,7 +382,7 @@ - + @@ -446,6 +446,10 @@