diff --git a/Elwig/Helpers/AppDbContext.cs b/Elwig/Helpers/AppDbContext.cs index 3d904da..f587c21 100644 --- a/Elwig/Helpers/AppDbContext.cs +++ b/Elwig/Helpers/AppDbContext.cs @@ -7,8 +7,9 @@ namespace Elwig.Helpers { public class AppDbContext : DbContext { public DbSet Countries { get; set; } + public DbSet Currencies { get; set; } public DbSet Members { get; set; } - public DbSet BillingAddresses { get; set; } + public DbSet BillingAddresses { get; set; } public DbSet Gemeinden { get; set; } public DbSet Katastralgemeinden { get; set; } public DbSet Orte { get; set; } @@ -17,12 +18,15 @@ namespace Elwig.Helpers { public DbSet Branches { get; set; } public DbSet WbKgs { get; set; } public DbSet WbRde { get; set; } - public DbSet AreaCommitments { get; set; } + public DbSet AreaCommitments { get; set; } + public DbSet AreaCommitmentParcels { get; set; } + public DbSet AreaCommitmentAttributes { get; set; } public DbSet Contracts { get; set; } public DbSet WineAttributes { get; set; } public DbSet WineCultivations { get; set; } public DbSet WineQualities { get; set; } public DbSet WineVarieties { get; set; } + public DbSet Seasons { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlite($"Data Source=\"{App.Config.DatabaseFile}\"; Foreign Keys=True; Mode=ReadWrite; Cache=Default"); diff --git a/Elwig/Helpers/Utils.cs b/Elwig/Helpers/Utils.cs index 321d5d0..d91ac73 100644 --- a/Elwig/Helpers/Utils.cs +++ b/Elwig/Helpers/Utils.cs @@ -86,5 +86,13 @@ namespace Elwig.Helpers { UseShellExecute = true, }); } + + public static double KmwToOe(double kmw) { + return Math.Round(kmw * (4.54 + 0.022 * kmw), 0); + } + + public static double OeToKmw(double oe) { + return Math.Round((-4.54 + Math.Sqrt(4.54 * 4.54 - 4 * 0.022 * -oe)) / 2 * 0.022, 1); + } } } diff --git a/Elwig/Models/AreaCommitment.cs b/Elwig/Models/AreaCom.cs similarity index 51% rename from Elwig/Models/AreaCommitment.cs rename to Elwig/Models/AreaCom.cs index bd4a8be..14a7ce6 100644 --- a/Elwig/Models/AreaCommitment.cs +++ b/Elwig/Models/AreaCom.cs @@ -1,49 +1,39 @@ using Microsoft.EntityFrameworkCore; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; namespace Elwig.Models { - [Table("area_commitment"), PrimaryKey("VNr", "KgNr", "GstNr")] - public class AreaCommitment { + [Table("area_commitment"), PrimaryKey("VNr")] + public class AreaCom { [Column("vnr")] public int VNr { get; set; } - [Column("kgnr")] - public int KgNr { get; set; } - - [Column("gstnr")] - public string? GstNr { get; set; } - - [Column("rdnr")] - public int? RdNr { get; set; } - [Column("area")] public int Area { get; set; } [Column("sortid")] public string SortId { get; set; } - [Column("attrid")] - public string? AttrId { get; set; } - [Column("cultid")] public string CultId { get; set; } - [ForeignKey("KgNr")] - public virtual WbKg Kg { get; private set; } - - [ForeignKey("KgNr, RdNr")] - public virtual WbRd? Rd { get; private set; } - [ForeignKey("VNr")] public virtual Contract Contract { get; private set; } [ForeignKey("SortId")] public virtual WineVar WineVar { get; private set; } - [ForeignKey("AttrId")] - public virtual WineAttr WineAttr { get; private set; } - [ForeignKey("CultId")] public virtual WineCult WineCult { get; private set; } + + [InverseProperty("AreaCom")] + public virtual ISet Parcels { get; private set; } + + [InverseProperty("AreaCom")] + public virtual ISet AttributeEntries { get; private set; } + + [NotMapped] + public IEnumerable Attributes => AttributeEntries.Select(e => e.WineAttr); } } diff --git a/Elwig/Models/AreaComAttr.cs b/Elwig/Models/AreaComAttr.cs new file mode 100644 index 0000000..c8e58e9 --- /dev/null +++ b/Elwig/Models/AreaComAttr.cs @@ -0,0 +1,19 @@ +using Microsoft.EntityFrameworkCore; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Elwig.Models { + [Table("area_commitment_attribute"), PrimaryKey("VNr", "AttrId")] + public class AreaComAttr { + [Column("vnr")] + public int VNr { get; set; } + + [Column("attrid")] + public string AttrId { get; set; } + + [ForeignKey("VNr")] + public virtual AreaCom AreaCom { get; private set; } + + [ForeignKey("AttrId")] + public virtual WineAttr WineAttr { get; private set; } + } +} diff --git a/Elwig/Models/AreaComParcel.cs b/Elwig/Models/AreaComParcel.cs new file mode 100644 index 0000000..e367ff5 --- /dev/null +++ b/Elwig/Models/AreaComParcel.cs @@ -0,0 +1,31 @@ +using Microsoft.EntityFrameworkCore; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Elwig.Models { + [Table("area_commitment_parcel"), PrimaryKey("VNr", "KgNr", "GstNr")] + public class AreaComParcel { + [Column("vnr")] + public int VNr { get; set; } + + [Column("kgnr")] + public int KgNr { get; set; } + + [Column("gstnr")] + public string? GstNr { get; set; } + + [Column("rdnr")] + public int? RdNr { get; set; } + + [Column("area")] + public int? Area { get; set; } + + [ForeignKey("KgNr")] + public virtual WbKg Kg { get; private set; } + + [ForeignKey("KgNr, RdNr")] + public virtual WbRd? Rd { get; private set; } + + [ForeignKey("VNr")] + public virtual AreaCom AreaCom { get; private set; } + } +} diff --git a/Elwig/Models/BillingAddress.cs b/Elwig/Models/BillingAddr.cs similarity index 96% rename from Elwig/Models/BillingAddress.cs rename to Elwig/Models/BillingAddr.cs index ef7205c..e025884 100644 --- a/Elwig/Models/BillingAddress.cs +++ b/Elwig/Models/BillingAddr.cs @@ -3,7 +3,7 @@ using System.ComponentModel.DataAnnotations.Schema; namespace Elwig.Models { [Table("member_billing_address"), PrimaryKey("MgNr")] - public class BillingAddress { + public class BillingAddr { [Column("mgnr")] public int MgNr { get; set; } diff --git a/Elwig/Models/Contract.cs b/Elwig/Models/Contract.cs index 498f506..3b4dfc3 100644 --- a/Elwig/Models/Contract.cs +++ b/Elwig/Models/Contract.cs @@ -1,7 +1,6 @@ using Microsoft.EntityFrameworkCore; -using System.Collections.Generic; +using System; using System.ComponentModel.DataAnnotations.Schema; -using System.Linq; namespace Elwig.Models { [Table("contract"), PrimaryKey("VNr")] @@ -12,19 +11,35 @@ namespace Elwig.Models { [Column("mgnr")] public int MgNr { get; set; } + [Column("date")] + public string? DateString { get; set; } + + [NotMapped] + public DateOnly? Date { + get { + return DateString != null ? DateOnly.ParseExact(DateString, "yyyy-MM-dd") : null; + } + set { + DateString = value?.ToString("yyyy-MM-dd"); + } + } + [Column("year_from")] public int YearFrom { get; set; } [Column("year_to")] public int? YearTo { get; set; } + [Column("comment")] + public string? Comment { get; set; } + [ForeignKey("MgNr")] public virtual Member Member { get; private set; } [InverseProperty("Contract")] - public virtual ISet AreaCommitments { get; private set; } + public virtual AreaCom? AreaCom { get; private set; } [NotMapped] - public int Area => AreaCommitments.Select(a => a.Area).Sum(); + public int? Area => AreaCom?.Area; } } diff --git a/Elwig/Models/Currency.cs b/Elwig/Models/Currency.cs new file mode 100644 index 0000000..7d5e937 --- /dev/null +++ b/Elwig/Models/Currency.cs @@ -0,0 +1,22 @@ +using Microsoft.EntityFrameworkCore; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Elwig.Models { + [Table("currency"), PrimaryKey("Code")] + public class Currency { + [Column("code")] + public string Code { get; private set; } + + [Column("name")] + public string Name { get; private set; } + + [Column("symbol")] + public string? Symbol { get; private set; } + + [Column("one_euro")] + public int? OneEuroValue { get; private set; } + + [NotMapped] + public decimal? OneEuro => OneEuroValue / 1_000_000; + } +} diff --git a/Elwig/Models/Member.cs b/Elwig/Models/Member.cs index 4f22268..2fa6654 100644 --- a/Elwig/Models/Member.cs +++ b/Elwig/Models/Member.cs @@ -38,10 +38,30 @@ namespace Elwig.Models { public string? Birthday { get; set; } [Column("entry_date")] - public string? EntryDate { get; set; } + public string? EntryDateString { get; set; } + + [NotMapped] + public DateOnly? EntryDate { + get { + return EntryDateString != null ? DateOnly.ParseExact(EntryDateString, "yyyy-MM-dd") : null; + } + set { + EntryDateString = value?.ToString("yyyy-MM-dd"); + } + } [Column("exit_date")] - public string? ExitDate { get; set; } + public string? ExitDateString { get; set; } + + [NotMapped] + public DateOnly? ExitDate { + get { + return ExitDateString != null ? DateOnly.ParseExact(ExitDateString, "yyyy-MM-dd") : null; + } + set { + ExitDateString = value?.ToString("yyyy-MM-dd"); + } + } [Column("business_shares")] public int BusinessShares { get; set; } @@ -125,7 +145,7 @@ namespace Elwig.Models { public virtual ISet Contracts { get; private set; } [InverseProperty("Member")] - public virtual BillingAddress BillingAddress { get; private set; } + public virtual BillingAddr BillingAddress { get; private set; } public int SearchScore(IEnumerable keywords) { keywords = keywords.Where(s => s.Length >= 2 || (s.Length > 0 && s.All(c => char.IsDigit(c)))); diff --git a/Elwig/Models/Season.cs b/Elwig/Models/Season.cs new file mode 100644 index 0000000..a59f7f6 --- /dev/null +++ b/Elwig/Models/Season.cs @@ -0,0 +1,46 @@ +using Microsoft.EntityFrameworkCore; +using System; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Elwig.Models { + [Table("season"), PrimaryKey("Year")] + public class Season { + [Column("year")] + public int Year { get; set; } + + [Column("currency")] + public string CurrencyCode { get; set; } + + [Column("precision")] + public int Precision { get; set; } + + [Column("start_date")] + public string? StartDateString { get; set; } + + [NotMapped] + public DateOnly? StartDate { + get { + return StartDateString != null ? DateOnly.ParseExact(StartDateString, "yyyy-MM-dd") : null; + } + set { + StartDateString = value?.ToString("yyyy-MM-dd"); + } + } + + [Column("end_date")] + public string? EndDateString { get; set; } + + [NotMapped] + public DateOnly? EndDate { + get { + return EndDateString != null ? DateOnly.ParseExact(EndDateString, "yyyy-MM-dd") : null; + } + set { + EndDateString = value?.ToString("yyyy-MM-dd"); + } + } + + [ForeignKey("CurrencyCode")] + public virtual Currency Currency { get; private set; } + } +} diff --git a/Elwig/Models/WineQual.cs b/Elwig/Models/WineQual.cs index f9d413f..2b6680e 100644 --- a/Elwig/Models/WineQual.cs +++ b/Elwig/Models/WineQual.cs @@ -1,4 +1,5 @@ -using Microsoft.EntityFrameworkCore; +using Elwig.Helpers; +using Microsoft.EntityFrameworkCore; using System.ComponentModel.DataAnnotations.Schema; namespace Elwig.Models { @@ -10,13 +11,16 @@ namespace Elwig.Models { [Column("origin_level")] public int? OriginLevel { get; private set; } + [Column("predicate")] + public bool IsPredicate { get; private set; } + + [Column("min_kmw")] + public double? MinKmw { get; private set; } + + [NotMapped] + public double? MinOe => MinKmw != null ? Utils.KmwToOe((double)MinKmw) : null; + [Column("name")] public string Name { get; private set; } - - [Column("from_kmw")] - public double? FromKmw { get; private set; } - - [Column("to_kmw")] - public double? ToKmw { get; private set; } } } diff --git a/Elwig/Windows/AreaCommAdminWindow.xaml b/Elwig/Windows/AreaComAdminWindow.xaml similarity index 99% rename from Elwig/Windows/AreaCommAdminWindow.xaml rename to Elwig/Windows/AreaComAdminWindow.xaml index cc21a7d..166598b 100644 --- a/Elwig/Windows/AreaCommAdminWindow.xaml +++ b/Elwig/Windows/AreaComAdminWindow.xaml @@ -1,4 +1,4 @@ - commitments = await Context.AreaCommitments.Where(a => a.VNr == contract.VNr).ToListAsync(); + List parcels = (await Context.AreaCommitments.FindAsync(contract.VNr)).Parcels.ToList(); - AreaCommitmentList.ItemsSource = commitments; - if (commitments.Count == 1) + AreaCommitmentList.ItemsSource = parcels; + if (parcels.Count == 1) AreaCommitmentList.SelectedIndex = 0; RefreshInputs(); } @@ -81,7 +80,7 @@ namespace Elwig.Windows { private void RefreshInputs(bool validate = false) { ClearInputStates(); Contract? c = (Contract)ContractList.SelectedItem; - AreaCommitment? a = (AreaCommitment)AreaCommitmentList.SelectedItem; + AreaComParcel? a = (AreaComParcel)AreaCommitmentList.SelectedItem; if (c != null) { DeleteContractButton.IsEnabled = true; @@ -105,22 +104,23 @@ namespace Elwig.Windows { GC.Collect(); } - private void FillInputs(AreaCommitment a) { + private void FillInputs(AreaComParcel a) { ClearOriginalValues(); VNrInput.Text = a.VNr.ToString(); - MgNrInput.Text = a.Contract.MgNr.ToString(); - YearFromInput.Text = a.Contract.YearFrom.ToString(); - YearToInput.Text = a.Contract.YearTo.ToString(); + MgNrInput.Text = a.AreaCom.Contract.MgNr.ToString(); + YearFromInput.Text = a.AreaCom.Contract.YearFrom.ToString(); + YearToInput.Text = a.AreaCom.Contract.YearTo.ToString(); KgInput.SelectedItem = a.Kg.Kg; RdInput.SelectedItem = a.Rd; GstNrInput.Text = a.GstNr; AreaInput.Text = a.Area.ToString(); - SortInput.SelectedItem = a.WineVar; - AttrInput.SelectedItem = a.WineAttr; - CultInput.SelectedItem = a.WineCult; + SortInput.SelectedItem = a.AreaCom.WineVar; + // FIXME + //AttrInput.SelectedItem = a.WineAttr; + CultInput.SelectedItem = a.AreaCom.WineCult; FillOriginalValues(); } @@ -155,12 +155,12 @@ namespace Elwig.Windows { } private async void DeleteAreaCommitmentButton_Click(object sender, RoutedEventArgs evt) { - AreaCommitment a = (AreaCommitment)AreaCommitmentList.SelectedItem; + AreaComParcel a = (AreaComParcel)AreaCommitmentList.SelectedItem; if (a == null) return; var r = MessageBox.Show( - $"Soll die Flächenbindung {a.Kg.Kg.Name}{(a.Rd.Name == null ? "" : $", {a.Rd.Name}")}, {a.GstNr} wirklich unwiderruflich gelöscht werden?", - "Flächenbindung löschen", MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No); + $"Soll die Parzelle {a.GstNr} ({a.Area} m²) wirklich unwiderruflich gelöscht werden?", + "Parzelle löschen", MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No); if (r == MessageBoxResult.Yes) { Context.Remove(a); Context.SaveChanges(); @@ -186,7 +186,7 @@ namespace Elwig.Windows { if (c == null) return; var r = MessageBox.Show( - $"Soll der Vertrag \"{c.VNr} und alle enthaltenen Flächenbindungen wirklich unwiderruflich gelöscht werden?", + $"Soll der Vertrag {c.VNr} und alle enthaltenen Parzellen wirklich unwiderruflich gelöscht werden?", "Vertrag löschen", MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No); if (r == MessageBoxResult.Yes) { Context.Remove(c); @@ -226,17 +226,18 @@ namespace Elwig.Windows { return c; } - private async Task UpdateaAreaCommitment(AreaCommitment a) { + private async Task UpdateaAreaComParcel(AreaComParcel a) { a.VNr = int.Parse(VNrInput.Text); a.KgNr = ((AT_Kg)KgInput.SelectedItem).KgNr; a.RdNr = ((WbRd)RdInput.SelectedItem).RdNr; a.GstNr = GstNrInput.Text; a.Area = int.Parse(AreaInput.Text); - a.SortId = ((WineVar)SortInput.SelectedItem).SortId; - a.AttrId = ((WineAttr)AttrInput.SelectedItem).AttrId; - a.CultId = ((WineCult)CultInput.SelectedItem).CultId; + a.AreaCom.SortId = ((WineVar)SortInput.SelectedItem).SortId; + // FIXME + //a.AttrId = ((WineAttr)AttrInput.SelectedItem).AttrId; + a.AreaCom.CultId = ((WineCult)CultInput.SelectedItem).CultId; - EntityEntry? tr = null; + EntityEntry? tr = null; try { if (IsEditing) { tr = Context.Update(a); @@ -257,7 +258,7 @@ namespace Elwig.Windows { private async void AreaCommitmentSaveButton_Click(object sender, RoutedEventArgs evt) { Contract c = await UpdateContract((Contract)ContractList.SelectedItem); - AreaCommitment a = await UpdateaAreaCommitment(IsEditing ? (AreaCommitment)AreaCommitmentList.SelectedItem : Context.CreateProxy()); + AreaComParcel a = await UpdateaAreaComParcel(IsEditing ? (AreaComParcel)AreaCommitmentList.SelectedItem : Context.CreateProxy()); IsEditing = false; IsCreating = false; @@ -297,7 +298,7 @@ namespace Elwig.Windows { private async void ContractSaveButton_Click(object sender, RoutedEventArgs evt) { Contract c = await UpdateContract(Context.CreateProxy()); - AreaCommitment a = await UpdateaAreaCommitment(Context.CreateProxy()); + AreaComParcel a = await UpdateaAreaComParcel(Context.CreateProxy()); IsEditing = false; IsCreating = false; diff --git a/Elwig/Windows/MemberAdminWindow.xaml.cs b/Elwig/Windows/MemberAdminWindow.xaml.cs index 450c784..5e0639b 100644 --- a/Elwig/Windows/MemberAdminWindow.xaml.cs +++ b/Elwig/Windows/MemberAdminWindow.xaml.cs @@ -189,7 +189,7 @@ namespace Elwig.Windows { } private void AreaCommitmentButton_Click(object sender, RoutedEventArgs evt) { - var w = new AreaCommAdminWindow((Member)MemberList.SelectedItem); + var w = new AreaComAdminWindow((Member)MemberList.SelectedItem); w.Show(); } @@ -281,8 +281,8 @@ namespace Elwig.Windows { // TODO Rechnungsadresse - m.EntryDate = (EntryDateInput.Text == "") ? null : string.Join("-", EntryDateInput.Text.Split(".").Reverse()); - m.ExitDate = (ExitDateInput.Text == "") ? null : string.Join("-", ExitDateInput.Text.Split(".").Reverse()); + m.EntryDateString = (EntryDateInput.Text == "") ? null : string.Join("-", EntryDateInput.Text.Split(".").Reverse()); + m.ExitDateString = (ExitDateInput.Text == "") ? null : string.Join("-", ExitDateInput.Text.Split(".").Reverse()); m.BusinessShares = (BusinessSharesInput.Text == "") ? 0 : int.Parse(BusinessSharesInput.Text); m.AccountingNr = (AccountingNrInput.Text == "") ? null : AccountingNrInput.Text; m.IsActive = ActiveInput.IsChecked ?? false; @@ -372,8 +372,8 @@ namespace Elwig.Windows { BillingOrtInput.SelectedItem = null; } - EntryDateInput.Text = (m.EntryDate != null) ? string.Join(".", m.EntryDate.Split("-").Reverse()) : null; - ExitDateInput.Text = (m.ExitDate != null) ? string.Join(".", m.ExitDate.Split("-").Reverse()) : null; + EntryDateInput.Text = (m.EntryDateString != null) ? string.Join(".", m.EntryDateString.Split("-").Reverse()) : null; + ExitDateInput.Text = (m.ExitDateString != null) ? string.Join(".", m.ExitDateString.Split("-").Reverse()) : null; BusinessSharesInput.Text = m.BusinessShares.ToString(); AccountingNrInput.Text = m.AccountingNr; BranchInput.SelectedItem = m.Branch;