Implemented cost entries excluding cost entry details.

This commit is contained in:
Tobias Erbshäußer
2020-06-16 13:59:12 +02:00
parent 1e21078d3f
commit 69cb2c924a
9 changed files with 546 additions and 56 deletions
+3
View File
@@ -16,5 +16,8 @@ namespace UCalc
public static readonly ImmutableList<string> SalutationStrs = public static readonly ImmutableList<string> SalutationStrs =
((Salutation[]) Enum.GetValues(typeof(Salutation))).Select(value => value.AsString()).ToImmutableList(); ((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();
} }
} }
+28
View File
@@ -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 class EmptyMultiPropertyToVisibilityConverter : IValueConverter
{ {
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
@@ -133,4 +148,17 @@ namespace UCalc.Controls
throw new InvalidOperationException(); 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;
}
}
} }
+204
View File
@@ -15,6 +15,13 @@
ShowInTaskbar="False" ShowInTaskbar="False"
Icon="logo.ico"> 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> <DockPanel>
<StackPanel DockPanel.Dock="Bottom"> <StackPanel DockPanel.Dock="Bottom">
<Separator Margin="0, 12, 0, 0" <Separator Margin="0, 12, 0, 0"
@@ -52,6 +59,203 @@
Text="{Binding Path=Cost.Name.Value, RelativeSource={RelativeSource AncestorType=local:CostWindow}, UpdateSourceTrigger=PropertyChanged}" /> Text="{Binding Path=Cost.Name.Value, RelativeSource={RelativeSource AncestorType=local:CostWindow}, UpdateSourceTrigger=PropertyChanged}" />
</DockPanel> </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> </StackPanel>
</ScrollViewer> </ScrollViewer>
+30 -1
View File
@@ -1,4 +1,6 @@
using System.Windows; using System.Windows;
using System.Windows.Controls;
using UCalc.Controls;
using UCalc.Models; using UCalc.Models;
namespace UCalc namespace UCalc
@@ -14,13 +16,40 @@ namespace UCalc
Model = model; Model = model;
Cost = cost; Cost = cost;
House = house; House = house;
InitializeComponent(); InitializeComponent();
((FlatToAffectedConverter) FindResource("FlatToAffectedConverter")).Cost = Cost;
} }
private void OnOkClick(object sender, RoutedEventArgs e) private void OnOkClick(object sender, RoutedEventArgs e)
{ {
Close(); 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
View File
@@ -296,7 +296,7 @@ namespace UCalc.Data
public class CostEntryDetails public class CostEntryDetails
{ {
public decimal TotalPrice { get; set; } public decimal TotalAmount { get; set; }
public decimal UnitCount { get; set; } public decimal UnitCount { get; set; }
public List<decimal> DiscountsInUnits { get; private set; } public List<decimal> DiscountsInUnits { get; private set; }
@@ -307,7 +307,7 @@ namespace UCalc.Data
private bool Equals(CostEntryDetails other) private bool Equals(CostEntryDetails other)
{ {
return TotalPrice == other.TotalPrice && UnitCount == other.UnitCount && return TotalAmount == other.TotalAmount && UnitCount == other.UnitCount &&
DiscountsInUnits.SequenceEqual(other.DiscountsInUnits); DiscountsInUnits.SequenceEqual(other.DiscountsInUnits);
} }
@@ -322,7 +322,7 @@ namespace UCalc.Data
{ {
return new CostEntryDetails return new CostEntryDetails
{ {
TotalPrice = TotalPrice, TotalAmount = TotalAmount,
UnitCount = UnitCount, UnitCount = UnitCount,
DiscountsInUnits = new List<decimal>(DiscountsInUnits) DiscountsInUnits = new List<decimal>(DiscountsInUnits)
}; };
@@ -333,7 +333,7 @@ namespace UCalc.Data
{ {
public DateTime StartDate { get; set; } public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; } public DateTime EndDate { get; set; }
public decimal Price { get; set; } public decimal Amount { get; set; }
public CostEntryDetails Details { get; set; } public CostEntryDetails Details { get; set; }
public CostEntry() public CostEntry()
@@ -343,7 +343,7 @@ namespace UCalc.Data
private bool Equals(CostEntry other) 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); Details.Equals(other.Details);
} }
@@ -360,7 +360,7 @@ namespace UCalc.Data
{ {
StartDate = StartDate, StartDate = StartDate,
EndDate = EndDate, EndDate = EndDate,
Price = Price, Amount = Amount,
Details = Details?.Clone() Details = Details?.Clone()
}; };
} }
@@ -373,6 +373,24 @@ namespace UCalc.Data
Size 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 class Cost
{ {
public string Name { get; set; } public string Name { get; set; }
+35
View File
@@ -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));
}
}
}
+87
View File
@@ -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));
}
}
}
+88 -7
View File
@@ -1,18 +1,97 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
using UCalc.Data; using UCalc.Data;
namespace UCalc.Models 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 class CostProperty : NestedProperty
{ {
public NotEmptyStringProperty Name { get; } public NotEmptyStringProperty Name { get; }
public AlwaysValidProperty<int> Division { get; } public AlwaysValidProperty<int> Division { get; }
public AlwaysValidProperty<bool> AffectsAll { get; } public AffectsAllProperty AffectsAll { get; }
public AlwaysValidProperty<bool> IncludeUnrented { get; } public AlwaysValidProperty<bool> IncludeUnrented { get; }
public AffectedFlatsProperty AffectedFlats { get; }
// TODO: public HashSet<Flat> AffectedFlats { get; } public CostEntriesProperty Entries { get; }
// TODO: public List<CostEntry> Entries { get; }
public AlwaysValidProperty<bool> DisplayInBill { get; } public AlwaysValidProperty<bool> DisplayInBill { get; }
public CostProperty(Model model, Property parent, Cost cost, public CostProperty(Model model, Property parent, Cost cost,
@@ -20,9 +99,11 @@ namespace UCalc.Models
{ {
Name = Add(new NotEmptyStringProperty(model, this, "Name", cost.Name)); Name = Add(new NotEmptyStringProperty(model, this, "Name", cost.Name));
Division = Add(new AlwaysValidProperty<int>(model, this, "Aufteilung", (int) cost.Division)); 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 = IncludeUnrented =
Add(new AlwaysValidProperty<bool>(model, this, "Unvermietete einbeziehen", cost.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)); DisplayInBill = Add(new AlwaysValidProperty<bool>(model, this, "In Rechnung anzeigen", cost.DisplayInBill));
} }
} }
+44 -39
View File
@@ -103,56 +103,61 @@ namespace UCalc.Models
{ {
_errors.Clear(); _errors.Clear();
if (_flatProperties.Count == 0) try
{ {
_errors.Add(NoFlatsError); if (_flatProperties.Count == 0)
return;
}
var entryDate = ((TenantProperty) Parent).EntryDate.Value;
var departureDate = ((TenantProperty) Parent).DepartureDate.Value;
foreach (var flatProperty in _flatProperties)
{
foreach (var tenant in Model.Root.Tenants)
{ {
if (ReferenceEquals(this, tenant.RentedFlats)) _errors.Add(NoFlatsError);
{ return;
continue; }
}
if (tenant.RentedFlats.IsRented(flatProperty, entryDate, departureDate)) var entryDate = ((TenantProperty) Parent).EntryDate.Value;
{ var departureDate = ((TenantProperty) Parent).DepartureDate.Value;
var error = $"Gemietete Wohnungen: Die Wohnung \"{flatProperty.Name.Value}\" ist bereits ";
if (entryDate != null) foreach (var flatProperty in _flatProperties)
{
foreach (var tenant in Model.Root.Tenants)
{
if (ReferenceEquals(this, tenant.RentedFlats))
{ {
if (departureDate != null) continue;
{
_errors.Add(
$"von {entryDate.Value.ToString(Constants.DateFormat)} - {departureDate.Value.ToString(Constants.DateFormat)} ");
}
else
{
_errors.Add($"seit dem {entryDate.Value.ToString(Constants.DateFormat)} ");
}
}
else if (departureDate != null)
{
_errors.Add($"bis zum {departureDate.Value.ToString(Constants.DateFormat)} ");
} }
error += "an einen anderen Mieter vermietet."; if (tenant.RentedFlats.IsRented(flatProperty, entryDate, departureDate))
_errors.Add(error); {
break; var error = $"Gemietete Wohnungen: Die Wohnung \"{flatProperty.Name.Value}\" ist bereits ";
if (entryDate != null)
{
if (departureDate != null)
{
_errors.Add(
$"von {entryDate.Value.ToString(Constants.DateFormat)} - {departureDate.Value.ToString(Constants.DateFormat)} ");
}
else
{
_errors.Add($"seit dem {entryDate.Value.ToString(Constants.DateFormat)} ");
}
}
else if (departureDate != null)
{
_errors.Add($"bis zum {departureDate.Value.ToString(Constants.DateFormat)} ");
}
error += "an einen anderen Mieter vermietet.";
_errors.Add(error);
break;
}
} }
} }
} }
finally
{
using var validator = Model.BeginValidation();
validator.Notify(this, "Errors");
using var validator = Model.BeginValidation(); validator.ValidateRange(Model.Root.Tenants);
validator.Notify(this, "Errors"); }
validator.ValidateRange(Model.Root.Tenants);
} }
private bool IsRented(FlatProperty flat, DateTime? start, DateTime? end) private bool IsRented(FlatProperty flat, DateTime? start, DateTime? end)