Implemented cost entries excluding cost entry details.
This commit is contained in:
@@ -16,5 +16,8 @@ namespace UCalc
|
||||
|
||||
public static readonly ImmutableList<string> SalutationStrs =
|
||||
((Salutation[]) Enum.GetValues(typeof(Salutation))).Select(value => value.AsString()).ToImmutableList();
|
||||
|
||||
public static readonly ImmutableList<string> CostDivisionStrs =
|
||||
((CostDivision[]) Enum.GetValues(typeof(CostDivision))).Select(value => value.AsString()).ToImmutableList();
|
||||
}
|
||||
}
|
||||
@@ -79,6 +79,21 @@ namespace UCalc.Controls
|
||||
}
|
||||
}
|
||||
|
||||
public class FlatToAffectedConverter : IValueConverter
|
||||
{
|
||||
public CostProperty Cost { get; set; }
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return Cost.AffectedFlats.Contains((FlatProperty) value);
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
public class EmptyMultiPropertyToVisibilityConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
@@ -133,4 +148,17 @@ namespace UCalc.Controls
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
public class NegateConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return !(bool?) value;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return !(bool?) value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,13 @@
|
||||
ShowInTaskbar="False"
|
||||
Icon="logo.ico">
|
||||
|
||||
<Window.Resources>
|
||||
<controls:NegateConverter x:Key="NegateConverter" />
|
||||
<controls:FlatToAffectedConverter x:Key="FlatToAffectedConverter" />
|
||||
<controls:DatePickerTextToDateTimeConverter x:Key="DatePickerTextToDateTimeConverter" />
|
||||
<controls:EmptyMultiPropertyToVisibilityConverter x:Key="EmptyMultiPropertyToVisibilityConverter" />
|
||||
</Window.Resources>
|
||||
|
||||
<DockPanel>
|
||||
<StackPanel DockPanel.Dock="Bottom">
|
||||
<Separator Margin="0, 12, 0, 0"
|
||||
@@ -52,6 +59,203 @@
|
||||
Text="{Binding Path=Cost.Name.Value, RelativeSource={RelativeSource AncestorType=local:CostWindow}, UpdateSourceTrigger=PropertyChanged}" />
|
||||
</DockPanel>
|
||||
|
||||
<DockPanel Margin="12, 8, 12, 0">
|
||||
<TextBlock DockPanel.Dock="Left"
|
||||
Margin="4, 0, 4, 0"
|
||||
Text="Detailiert in Ausdruck berechnen:"
|
||||
Width="172"
|
||||
TextWrapping="Wrap"
|
||||
Foreground="{x:Static local:Constants.SubMainColor}" />
|
||||
|
||||
<CheckBox
|
||||
IsChecked="{Binding Path=Cost.DisplayInBill.Value, RelativeSource={RelativeSource AncestorType=local:CostWindow}, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" />
|
||||
|
||||
</DockPanel>
|
||||
|
||||
<controls:SectionHeader Header="Verteilung" />
|
||||
|
||||
<DockPanel Margin="12, 0, 12, 0">
|
||||
<Label DockPanel.Dock="Left"
|
||||
Content="Betrifft alle Wohnungen:"
|
||||
Width="180"
|
||||
Foreground="{x:Static local:Constants.SubMainColor}" />
|
||||
|
||||
<CheckBox
|
||||
VerticalAlignment="Center"
|
||||
IsChecked="{Binding Path=Cost.AffectsAll.Value, RelativeSource={RelativeSource AncestorType=local:CostWindow}, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" />
|
||||
|
||||
</DockPanel>
|
||||
|
||||
<DockPanel Margin="12, 8, 12, 0">
|
||||
<Label DockPanel.Dock="Left"
|
||||
Content="Betroffene Wohnungen:"
|
||||
Width="180"
|
||||
Foreground="{x:Static local:Constants.SubMainColor}" />
|
||||
|
||||
<controls:ErrorIcon Margin="12, 0, 0, 0"
|
||||
DockPanel.Dock="Right"
|
||||
VerticalAlignment="Center"
|
||||
Property="{Binding Path=Cost.AffectedFlats, RelativeSource={RelativeSource AncestorType=local:CostWindow}}" />
|
||||
|
||||
<ListBox Height="120"
|
||||
ItemsSource="{Binding Path=House.Flats, RelativeSource={RelativeSource AncestorType=local:CostWindow}}"
|
||||
IsEnabled="{Binding Path=Cost.AffectsAll.Value, RelativeSource={RelativeSource AncestorType=local:CostWindow}, Converter={StaticResource NegateConverter}}">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<CheckBox Content="{Binding Name.Value}"
|
||||
IsChecked="{Binding Path=., Converter={StaticResource FlatToAffectedConverter}, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
Checked="OnFlatChecked"
|
||||
Unchecked="OnFlatUnchecked" />
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
</DockPanel>
|
||||
|
||||
<DockPanel Margin="12, 12, 12, 0">
|
||||
<TextBlock DockPanel.Dock="Left"
|
||||
Margin="4, 0, 4, 0"
|
||||
Text="Lege Kosten für unvermietete Wohnungen auf vermietete Wohnungen um:"
|
||||
Width="172"
|
||||
TextWrapping="Wrap"
|
||||
Foreground="{x:Static local:Constants.SubMainColor}" />
|
||||
|
||||
<CheckBox
|
||||
IsChecked="{Binding Path=Cost.IncludeUnrented.Value, RelativeSource={RelativeSource AncestorType=local:CostWindow}, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" />
|
||||
|
||||
</DockPanel>
|
||||
|
||||
<DockPanel Margin="12, 8, 12, 8">
|
||||
<Label DockPanel.Dock="Left"
|
||||
Content="Art der Aufteilung:"
|
||||
Width="180"
|
||||
Foreground="{x:Static local:Constants.SubMainColor}" />
|
||||
|
||||
<ComboBox Margin="0, 0, 28, 0"
|
||||
ItemsSource="{x:Static local:Constants.CostDivisionStrs}"
|
||||
SelectedIndex="{Binding Path=Cost.Division.Value, RelativeSource={RelativeSource AncestorType=local:CostWindow}}" />
|
||||
</DockPanel>
|
||||
|
||||
<controls:SectionHeader Header="Zeiträume" />
|
||||
|
||||
<DockPanel>
|
||||
<controls:ErrorIcon Margin="0, 0, 12, 0"
|
||||
DockPanel.Dock="Right"
|
||||
VerticalAlignment="Center"
|
||||
Property="{Binding Path=Cost.Entries, RelativeSource={RelativeSource AncestorType=local:CostWindow}}"
|
||||
Visibility="{Binding Path=Cost.Entries.Count, RelativeSource={RelativeSource AncestorType=local:CostWindow}, Converter={StaticResource EmptyMultiPropertyToVisibilityConverter}}" />
|
||||
|
||||
<controls:HighlightButton Margin="12, 0, 12, 0"
|
||||
HighlightForeground="{x:Static local:Constants.SubMainColor}"
|
||||
HighlightBackground="{x:Static local:Constants.MainColor}"
|
||||
Click="OnAddCostEntryClick">
|
||||
<Viewbox Width="24"
|
||||
Height="24"
|
||||
Margin="12, 12, 6, 12"
|
||||
Stretch="Uniform">
|
||||
<Canvas Width="512" Height="512">
|
||||
<Canvas.RenderTransform>
|
||||
<TranslateTransform X="0" Y="0" />
|
||||
</Canvas.RenderTransform>
|
||||
<Path>
|
||||
<Path.Data>
|
||||
<PathGeometry
|
||||
Figures="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm144 276c0 6.6-5.4 12-12 12h-92v92c0 6.6-5.4 12-12 12h-56c-6.6 0-12-5.4-12-12v-92h-92c-6.6 0-12-5.4-12-12v-56c0-6.6 5.4-12 12-12h92v-92c0-6.6 5.4-12 12-12h56c6.6 0 12 5.4 12 12v92h92c6.6 0 12 5.4 12 12v56z"
|
||||
FillRule="NonZero" />
|
||||
</Path.Data>
|
||||
</Path>
|
||||
</Canvas>
|
||||
</Viewbox>
|
||||
|
||||
<Label Content="Zeitraum hinzufügen"
|
||||
Margin="0, 12, 12, 12" />
|
||||
</controls:HighlightButton>
|
||||
</DockPanel>
|
||||
|
||||
<ItemsControl
|
||||
ItemsSource="{Binding Path=Cost.Entries, RelativeSource={RelativeSource AncestorType=local:CostWindow}}"
|
||||
Margin="12, 0, 12, 12">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<DockPanel>
|
||||
<controls:HighlightButton DockPanel.Dock="Right"
|
||||
HighlightForeground="Red"
|
||||
HighlightBackground="White"
|
||||
Click="OnCostEntryDeleteClick">
|
||||
<Viewbox Width="24"
|
||||
Height="24"
|
||||
Margin="8, 12, 8, 12"
|
||||
Stretch="Uniform">
|
||||
<Canvas Width="448" Height="512">
|
||||
<Canvas.RenderTransform>
|
||||
<TranslateTransform X="0" Y="0" />
|
||||
</Canvas.RenderTransform>
|
||||
<Path>
|
||||
<Path.Data>
|
||||
<PathGeometry
|
||||
Figures="M32 464a48 48 0 0 0 48 48h288a48 48 0 0 0 48-48V128H32zm272-256a16 16 0 0 1 32 0v224a16 16 0 0 1-32 0zm-96 0a16 16 0 0 1 32 0v224a16 16 0 0 1-32 0zm-96 0a16 16 0 0 1 32 0v224a16 16 0 0 1-32 0zM432 32H312l-9.4-18.7A24 24 0 0 0 281.1 0H166.8a23.72 23.72 0 0 0-21.4 13.3L136 32H16A16 16 0 0 0 0 48v32a16 16 0 0 0 16 16h416a16 16 0 0 0 16-16V48a16 16 0 0 0-16-16z"
|
||||
FillRule="NonZero" />
|
||||
</Path.Data>
|
||||
</Path>
|
||||
</Canvas>
|
||||
</Viewbox>
|
||||
</controls:HighlightButton>
|
||||
|
||||
<StackPanel Margin="0, 8, 8, 8">
|
||||
<DockPanel Margin="0, 0, 0, 2">
|
||||
<Label DockPanel.Dock="Left" Content="Startdatum:"
|
||||
Width="180"
|
||||
Foreground="{x:Static local:Constants.SubMainColor}" />
|
||||
|
||||
<controls:ErrorIcon Margin="12, 0, 0, 0"
|
||||
DockPanel.Dock="Right"
|
||||
VerticalAlignment="Center"
|
||||
Property="{Binding StartDate}" />
|
||||
|
||||
<DatePicker VerticalAlignment="Center"
|
||||
MinHeight="22"
|
||||
DisplayDateStart="{Binding Path=Model.StartDate, RelativeSource={RelativeSource AncestorType=local:CostWindow}, Mode=OneWay}"
|
||||
DisplayDateEnd="{Binding Path=Model.EndDate, RelativeSource={RelativeSource AncestorType=local:CostWindow}, Mode=OneWay}"
|
||||
Text="{Binding Path=StartDate.Value, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay, Converter={StaticResource DatePickerTextToDateTimeConverter}}" />
|
||||
|
||||
</DockPanel>
|
||||
|
||||
<DockPanel Margin="0, 2, 0, 2">
|
||||
<Label DockPanel.Dock="Left" Content="Enddatum:"
|
||||
Width="180"
|
||||
Foreground="{x:Static local:Constants.SubMainColor}" />
|
||||
|
||||
<controls:ErrorIcon Margin="12, 0, 0, 0"
|
||||
DockPanel.Dock="Right"
|
||||
VerticalAlignment="Center"
|
||||
Property="{Binding EndDate}" />
|
||||
|
||||
<DatePicker VerticalAlignment="Center"
|
||||
MinHeight="22"
|
||||
DisplayDateStart="{Binding Path=Model.StartDate, RelativeSource={RelativeSource AncestorType=local:CostWindow}, Mode=OneWay}"
|
||||
DisplayDateEnd="{Binding Path=Model.EndDate, RelativeSource={RelativeSource AncestorType=local:CostWindow}, Mode=OneWay}"
|
||||
Text="{Binding Path=EndDate.Value, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay, Converter={StaticResource DatePickerTextToDateTimeConverter}}" />
|
||||
|
||||
</DockPanel>
|
||||
|
||||
<DockPanel Margin="0, 2, 0, 0">
|
||||
<Label DockPanel.Dock="Left" Content="Betrag:"
|
||||
Width="180"
|
||||
Foreground="{x:Static local:Constants.SubMainColor}" />
|
||||
|
||||
<controls:ErrorIcon Margin="12, 0, 0, 0"
|
||||
DockPanel.Dock="Right"
|
||||
VerticalAlignment="Center"
|
||||
Property="{Binding Amount}" />
|
||||
|
||||
<TextBox VerticalAlignment="Center"
|
||||
MinHeight="22"
|
||||
Text="{Binding Path=Amount.Value, UpdateSourceTrigger=PropertyChanged}" />
|
||||
</DockPanel>
|
||||
</StackPanel>
|
||||
</DockPanel>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using UCalc.Controls;
|
||||
using UCalc.Models;
|
||||
|
||||
namespace UCalc
|
||||
@@ -14,13 +16,40 @@ namespace UCalc
|
||||
Model = model;
|
||||
Cost = cost;
|
||||
House = house;
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
((FlatToAffectedConverter) FindResource("FlatToAffectedConverter")).Cost = Cost;
|
||||
}
|
||||
|
||||
private void OnOkClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
private void OnFlatChecked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var flat = (FlatProperty) ((CheckBox) sender).DataContext;
|
||||
|
||||
Cost.AffectedFlats.Add(flat);
|
||||
}
|
||||
|
||||
private void OnFlatUnchecked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var flat = (FlatProperty) ((CheckBox) sender).DataContext;
|
||||
|
||||
Cost.AffectedFlats.Remove(flat);
|
||||
}
|
||||
|
||||
private void OnCostEntryDeleteClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var entry = (CostEntryProperty) ((HighlightButton) sender).DataContext;
|
||||
|
||||
Cost.Entries.Remove(entry);
|
||||
}
|
||||
|
||||
private void OnAddCostEntryClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Cost.Entries.Add();
|
||||
}
|
||||
}
|
||||
}
|
||||
+24
-6
@@ -296,7 +296,7 @@ namespace UCalc.Data
|
||||
|
||||
public class CostEntryDetails
|
||||
{
|
||||
public decimal TotalPrice { get; set; }
|
||||
public decimal TotalAmount { get; set; }
|
||||
public decimal UnitCount { get; set; }
|
||||
public List<decimal> DiscountsInUnits { get; private set; }
|
||||
|
||||
@@ -307,7 +307,7 @@ namespace UCalc.Data
|
||||
|
||||
private bool Equals(CostEntryDetails other)
|
||||
{
|
||||
return TotalPrice == other.TotalPrice && UnitCount == other.UnitCount &&
|
||||
return TotalAmount == other.TotalAmount && UnitCount == other.UnitCount &&
|
||||
DiscountsInUnits.SequenceEqual(other.DiscountsInUnits);
|
||||
}
|
||||
|
||||
@@ -322,7 +322,7 @@ namespace UCalc.Data
|
||||
{
|
||||
return new CostEntryDetails
|
||||
{
|
||||
TotalPrice = TotalPrice,
|
||||
TotalAmount = TotalAmount,
|
||||
UnitCount = UnitCount,
|
||||
DiscountsInUnits = new List<decimal>(DiscountsInUnits)
|
||||
};
|
||||
@@ -333,7 +333,7 @@ namespace UCalc.Data
|
||||
{
|
||||
public DateTime StartDate { get; set; }
|
||||
public DateTime EndDate { get; set; }
|
||||
public decimal Price { get; set; }
|
||||
public decimal Amount { get; set; }
|
||||
public CostEntryDetails Details { get; set; }
|
||||
|
||||
public CostEntry()
|
||||
@@ -343,7 +343,7 @@ namespace UCalc.Data
|
||||
|
||||
private bool Equals(CostEntry other)
|
||||
{
|
||||
return StartDate.Equals(other.StartDate) && EndDate.Equals(other.EndDate) && Price == other.Price &&
|
||||
return StartDate.Equals(other.StartDate) && EndDate.Equals(other.EndDate) && Amount == other.Amount &&
|
||||
Details.Equals(other.Details);
|
||||
}
|
||||
|
||||
@@ -360,7 +360,7 @@ namespace UCalc.Data
|
||||
{
|
||||
StartDate = StartDate,
|
||||
EndDate = EndDate,
|
||||
Price = Price,
|
||||
Amount = Amount,
|
||||
Details = Details?.Clone()
|
||||
};
|
||||
}
|
||||
@@ -373,6 +373,24 @@ namespace UCalc.Data
|
||||
Size
|
||||
}
|
||||
|
||||
public static class CostDivisions
|
||||
{
|
||||
public static string AsString(this CostDivision division)
|
||||
{
|
||||
switch (division)
|
||||
{
|
||||
case CostDivision.Person:
|
||||
return "Pro Person";
|
||||
case CostDivision.Flat:
|
||||
return "Pro Wohnung";
|
||||
case CostDivision.Size:
|
||||
return "Pro m²";
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Cost
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UCalc.Data;
|
||||
|
||||
namespace UCalc.Models
|
||||
{
|
||||
public class CostEntriesProperty : MultiProperty<CostEntryProperty>
|
||||
{
|
||||
public CostEntriesProperty(Model model, Property parent, IEnumerable<CostEntry> data) : base(model, parent,
|
||||
"Zeiträume: Geben Sie einen oder mehr Zeiträume an.")
|
||||
{
|
||||
foreach (var entry in data)
|
||||
{
|
||||
Add(new CostEntryProperty(model, this, entry));
|
||||
}
|
||||
}
|
||||
|
||||
public void Add()
|
||||
{
|
||||
var entry = new CostEntryProperty(Model, this, new CostEntry());
|
||||
entry.StartDate.Value = null;
|
||||
entry.EndDate.Value = null;
|
||||
base.Add(entry);
|
||||
}
|
||||
|
||||
public new void Remove(CostEntryProperty entry)
|
||||
{
|
||||
using var validator = Model.BeginValidation();
|
||||
|
||||
base.Remove(entry);
|
||||
|
||||
validator.ValidateRange(Properties.Select(otherEntry => otherEntry.EndDate));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using UCalc.Controls;
|
||||
using UCalc.Data;
|
||||
|
||||
namespace UCalc.Models
|
||||
{
|
||||
public class DateProperty : ValueProperty<DateTime?>
|
||||
{
|
||||
public DateProperty(Model model, Property parent, string name, DateTime value) : base(model, parent, name,
|
||||
value)
|
||||
{
|
||||
}
|
||||
|
||||
protected override string ValidateValue()
|
||||
{
|
||||
var error = Value == null ? $"{Name}: Geben Sie einen Wert ein." : "";
|
||||
|
||||
using var validator = Model.BeginValidation();
|
||||
validator.Validate(((CostEntryProperty) Parent).EndDate);
|
||||
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
public class EndDateProperty : ValueProperty<DateTime?>
|
||||
{
|
||||
public EndDateProperty(Model model, Property parent, string name, DateTime value) : base(model, parent, name,
|
||||
value)
|
||||
{
|
||||
}
|
||||
|
||||
protected override string ValidateValue()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Value == null)
|
||||
{
|
||||
return $"{Name}: Geben Sie einen Wert ein.";
|
||||
}
|
||||
|
||||
var startDate = ((CostEntryProperty) Parent).StartDate.Value;
|
||||
if (startDate != null)
|
||||
{
|
||||
if (startDate > Value)
|
||||
{
|
||||
return $"{Name}: Das Enddatum liegt vor dem Startdatum.";
|
||||
}
|
||||
|
||||
foreach (var entry in ((CostProperty) Parent.Parent.Parent).Entries)
|
||||
{
|
||||
if (!ReferenceEquals(entry.EndDate, this) && entry.StartDate.Value != null &&
|
||||
entry.EndDate.Value != null &&
|
||||
startDate.Value.Intersects(Value.Value, entry.StartDate.Value.Value,
|
||||
entry.EndDate.Value.Value))
|
||||
{
|
||||
return $"{Name}: Dieser Zeitraum überschneidet sich mit einem anderen.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
finally
|
||||
{
|
||||
using var validator = Model.BeginValidation();
|
||||
validator.ValidateRange(((CostProperty) Parent.Parent.Parent).Entries.Select(entry => entry.EndDate));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class CostEntryProperty : NestedProperty
|
||||
{
|
||||
public DateProperty StartDate { get; }
|
||||
public EndDateProperty EndDate { get; }
|
||||
public PositiveDecimalProperty Amount { get; }
|
||||
|
||||
// TODO: Details
|
||||
|
||||
public CostEntryProperty(Model model, Property parent, CostEntry data) : base(model, parent)
|
||||
{
|
||||
StartDate = Add(new DateProperty(model, this, "Startdatum", data.StartDate));
|
||||
EndDate = Add(new EndDateProperty(model, this, "Enddatum", data.EndDate));
|
||||
Amount = Add(new PositiveDecimalProperty(model, this, "Betrag", data.Amount));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,97 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UCalc.Data;
|
||||
|
||||
namespace UCalc.Models
|
||||
{
|
||||
public class AffectsAllProperty : AlwaysValidProperty<bool>
|
||||
{
|
||||
public AffectsAllProperty(Model model, Property parent, string name, bool value) : base(model, parent, name,
|
||||
value)
|
||||
{
|
||||
}
|
||||
|
||||
protected override string ValidateValue()
|
||||
{
|
||||
using var validator = Model.BeginValidation();
|
||||
validator.Validate(((CostProperty) Parent).AffectedFlats);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public class AffectedFlatsProperty : Property
|
||||
{
|
||||
private const string NoFlatsError = "Betroffene Wohnungen: Es wurde keine Wohnung zugewiesen.";
|
||||
private readonly HashSet<FlatProperty> _flats;
|
||||
private readonly List<string> _errors;
|
||||
|
||||
public AffectedFlatsProperty(Model model, Property parent, IEnumerable<Flat> data,
|
||||
IReadOnlyDictionary<Flat, FlatProperty> flatToProperty = null) : base(model, parent)
|
||||
{
|
||||
_flats = new HashSet<FlatProperty>();
|
||||
_errors = new List<string>();
|
||||
|
||||
foreach (var flat in data)
|
||||
{
|
||||
_flats.Add(flatToProperty?[flat] ?? throw new InvalidOperationException());
|
||||
}
|
||||
|
||||
Validate();
|
||||
}
|
||||
|
||||
public override IReadOnlyList<string> Errors => _errors;
|
||||
|
||||
public void Add(FlatProperty flat)
|
||||
{
|
||||
if (!_flats.Add(flat))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using var validator = Model.BeginValidation();
|
||||
validator.Validate(this);
|
||||
Modified = true;
|
||||
}
|
||||
|
||||
public void Remove(FlatProperty flat)
|
||||
{
|
||||
if (!_flats.Remove(flat))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using var validator = Model.BeginValidation();
|
||||
validator.Validate(this);
|
||||
Modified = true;
|
||||
}
|
||||
|
||||
public bool Contains(FlatProperty flat)
|
||||
{
|
||||
return _flats.Contains(flat);
|
||||
}
|
||||
|
||||
public sealed override void Validate()
|
||||
{
|
||||
_errors.Clear();
|
||||
|
||||
if (_flats.Count == 0 && !((CostProperty) Parent).AffectsAll.Value)
|
||||
{
|
||||
_errors.Add(NoFlatsError);
|
||||
}
|
||||
|
||||
using var validator = Model.BeginValidation();
|
||||
validator.Notify(this, "Errors");
|
||||
}
|
||||
}
|
||||
|
||||
public class CostProperty : NestedProperty
|
||||
{
|
||||
public NotEmptyStringProperty Name { get; }
|
||||
public AlwaysValidProperty<int> Division { get; }
|
||||
public AlwaysValidProperty<bool> AffectsAll { get; }
|
||||
|
||||
public AffectsAllProperty AffectsAll { get; }
|
||||
public AlwaysValidProperty<bool> IncludeUnrented { get; }
|
||||
|
||||
// TODO: public HashSet<Flat> AffectedFlats { get; }
|
||||
// TODO: public List<CostEntry> Entries { get; }
|
||||
public AffectedFlatsProperty AffectedFlats { get; }
|
||||
public CostEntriesProperty Entries { get; }
|
||||
public AlwaysValidProperty<bool> DisplayInBill { get; }
|
||||
|
||||
public CostProperty(Model model, Property parent, Cost cost,
|
||||
@@ -20,9 +99,11 @@ namespace UCalc.Models
|
||||
{
|
||||
Name = Add(new NotEmptyStringProperty(model, this, "Name", cost.Name));
|
||||
Division = Add(new AlwaysValidProperty<int>(model, this, "Aufteilung", (int) cost.Division));
|
||||
AffectsAll = Add(new AlwaysValidProperty<bool>(model, this, "Betrifft alle", cost.AffectsAll));
|
||||
AffectsAll = Add(new AffectsAllProperty(model, this, "Betrifft alle", cost.AffectsAll));
|
||||
AffectedFlats = Add(new AffectedFlatsProperty(model, this, cost.AffectedFlats, flatToProperty));
|
||||
IncludeUnrented =
|
||||
Add(new AlwaysValidProperty<bool>(model, this, "Unvermietete einbeziehen", cost.IncludeUnrented));
|
||||
Entries = Add(new CostEntriesProperty(model, this, cost.Entries));
|
||||
DisplayInBill = Add(new AlwaysValidProperty<bool>(model, this, "In Rechnung anzeigen", cost.DisplayInBill));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,6 +103,8 @@ namespace UCalc.Models
|
||||
{
|
||||
_errors.Clear();
|
||||
|
||||
try
|
||||
{
|
||||
if (_flatProperties.Count == 0)
|
||||
{
|
||||
_errors.Add(NoFlatsError);
|
||||
@@ -148,12 +150,15 @@ namespace UCalc.Models
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
using var validator = Model.BeginValidation();
|
||||
validator.Notify(this, "Errors");
|
||||
|
||||
validator.ValidateRange(Model.Root.Tenants);
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsRented(FlatProperty flat, DateTime? start, DateTime? end)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user