Implemented loading of old format.
This commit is contained in:
@@ -58,8 +58,10 @@
|
||||
LoadCompleted="OnCostsFrameLoadCompleted"
|
||||
Focusable="False" />
|
||||
</TabItem>
|
||||
<TabItem Visibility="Collapsed">
|
||||
<TabItem Visibility="Collapsed"
|
||||
Selector.Selected="OnDetailsTabSelected">
|
||||
<Frame Source="Pages/DetailsPage.xaml"
|
||||
x:Name="DetailsFrame"
|
||||
Focusable="False" />
|
||||
</TabItem>
|
||||
</TabControl>
|
||||
|
||||
@@ -190,7 +190,12 @@ namespace UCalc
|
||||
return false;
|
||||
}
|
||||
|
||||
throw new System.NotImplementedException();
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private void OnDetailsTabSelected(object sender, RoutedEventArgs e)
|
||||
{
|
||||
((DetailsPage) DetailsFrame.Content).Compute(Model);
|
||||
}
|
||||
}
|
||||
}
|
||||
+231
-3
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
@@ -70,11 +71,226 @@ namespace UCalc.Data
|
||||
|
||||
public class BillingLoader
|
||||
{
|
||||
[SuppressMessage("ReSharper", "PossibleNullReferenceException")]
|
||||
public Billing Load(string path)
|
||||
private static string AsString(JObject parent, string name, bool optional = false)
|
||||
{
|
||||
// TODO: Support older format
|
||||
if (optional && (parent[name]?.Type ?? JTokenType.Null) == JTokenType.Null)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
return parent[name]?.Value<string>() ??
|
||||
throw new JsonException($"Cannot read {parent.Path}.{name} as string");
|
||||
}
|
||||
|
||||
private static DateTime AsDate(JObject parent, string name)
|
||||
{
|
||||
return DateTime.ParseExact(AsString(parent, name), "dd.MM.yyyy", null);
|
||||
}
|
||||
|
||||
private static DateTime? AsDateOptional(JObject parent, string name)
|
||||
{
|
||||
var str = AsString(parent, name, true);
|
||||
if (string.IsNullOrEmpty(str))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return DateTime.ParseExact(str, "dd.MM.yyyy", null);
|
||||
}
|
||||
|
||||
private static int AsInt(JObject parent, string name)
|
||||
{
|
||||
return parent[name]?.Value<int>() ??
|
||||
throw new JsonException($"Cannot read {parent.Path}.{name} as integer");
|
||||
}
|
||||
|
||||
private static bool AsBool(JObject parent, string name)
|
||||
{
|
||||
return parent[name]?.Value<bool>() ??
|
||||
throw new JsonException($"Cannot read {parent.Path}.{name} as bool");
|
||||
}
|
||||
|
||||
private static decimal AsDecimal(JObject parent, string name)
|
||||
{
|
||||
return decimal.Parse(parent[name]?.Value<string>() ??
|
||||
throw new JsonException($"Cannot read {parent.Path}.{name} as decimal"));
|
||||
}
|
||||
|
||||
private static decimal? AsDecimalOptional(JObject parent, string name)
|
||||
{
|
||||
var str = AsString(parent, name, true);
|
||||
if (string.IsNullOrEmpty(str))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return decimal.Parse(str);
|
||||
}
|
||||
|
||||
private static JObject AsObject(JObject parent, string name)
|
||||
{
|
||||
if ((parent[name]?.Type ?? JTokenType.Null) != JTokenType.Object)
|
||||
{
|
||||
throw new JsonException($"Cannot read {parent.Path}.{name} as object");
|
||||
}
|
||||
|
||||
return (JObject) parent[name];
|
||||
}
|
||||
|
||||
private static JArray AsArray(JObject parent, string name, bool optional = false)
|
||||
{
|
||||
var type = parent[name]?.Type ?? JTokenType.Object;
|
||||
|
||||
if (optional && type == JTokenType.Null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (type != JTokenType.Array)
|
||||
{
|
||||
throw new JsonException($"Cannot read {parent.Path}.{name} as array");
|
||||
}
|
||||
|
||||
return (JArray) parent[name];
|
||||
}
|
||||
|
||||
private static void LoadAddress(JObject parent, string name, Address target)
|
||||
{
|
||||
var address = AsObject(parent, name);
|
||||
target.Street = AsString(address, "street");
|
||||
target.HouseNumber = AsString(address, "house_number");
|
||||
target.City = AsString(address, "city");
|
||||
target.Postcode = AsString(address, "plz");
|
||||
}
|
||||
|
||||
private static void LoadBankAccount(JObject parent, string name, BankAccount target)
|
||||
{
|
||||
var bankAccount = AsObject(parent, name);
|
||||
target.Iban = AsString(bankAccount, "iban");
|
||||
target.Bic = AsString(bankAccount, "bic");
|
||||
target.BankName = AsString(bankAccount, "bank_name");
|
||||
}
|
||||
|
||||
private Billing LoadFormat1(string path)
|
||||
{
|
||||
var content = File.ReadAllText(path);
|
||||
try
|
||||
{
|
||||
var root = JObject.Parse(content);
|
||||
var billing = new Billing
|
||||
{
|
||||
StartDate = AsDate(root, "start_date"),
|
||||
EndDate = AsDate(root, "end_date")
|
||||
};
|
||||
|
||||
var landlord = AsObject(root, "owner");
|
||||
billing.Landlord.Salutation = (Salutation) AsInt(landlord, "salutation");
|
||||
billing.Landlord.Name = AsString(landlord, "name");
|
||||
billing.Landlord.Phone = AsString(landlord, "phone");
|
||||
billing.Landlord.MailAddress = AsString(landlord, "mail");
|
||||
LoadAddress(landlord, "address", billing.Landlord.Address);
|
||||
LoadBankAccount(landlord, "account", billing.Landlord.BankAccount);
|
||||
|
||||
var house = AsObject(root, "house");
|
||||
LoadAddress(house, "address", billing.House.Address);
|
||||
|
||||
var tenants = AsArray(root, "renters");
|
||||
foreach (var item in tenants)
|
||||
{
|
||||
var tenant = (JObject) item;
|
||||
|
||||
var targetTenant = new Tenant
|
||||
{
|
||||
Salutation = (Salutation) AsInt(tenant, "salutation"),
|
||||
Name = AsString(tenant, "name"),
|
||||
PersonCount = AsInt(tenant, "person_count"),
|
||||
EntryDate = AsDateOptional(tenant, "entry_date"),
|
||||
DepartureDate = AsDateOptional(tenant, "departure_date"),
|
||||
PaidRent = AsDecimal(tenant, "paid_rent"),
|
||||
CustomMessage1 = AsString(tenant, "message1", true),
|
||||
CustomMessage2 = AsString(tenant, "message2", true)
|
||||
};
|
||||
LoadBankAccount(tenant, "account", targetTenant.BankAccount);
|
||||
|
||||
var flat = new Flat
|
||||
{
|
||||
Name = $"Wohnung von {targetTenant.Name}",
|
||||
Size = 1
|
||||
};
|
||||
|
||||
targetTenant.RentedFlats.Add(flat);
|
||||
|
||||
billing.Tenants.Add(targetTenant);
|
||||
billing.House.Flats.Add(flat);
|
||||
}
|
||||
|
||||
var costs = AsArray(root, "costs");
|
||||
foreach (var item in costs)
|
||||
{
|
||||
var cost = (JObject) item;
|
||||
|
||||
var targetCost = new Cost
|
||||
{
|
||||
Name = AsString(cost, "name"),
|
||||
Division = (CostDivision) AsInt(cost, "division"),
|
||||
AffectsAll = AsBool(cost, "affects_all_renters"),
|
||||
AffectedFlats =
|
||||
(AsArray(cost, "affected_renters", true) ?? new JArray()).Select(
|
||||
renterItem =>
|
||||
billing.House.Flats[AsInt((JObject) renterItem, "id")]).ToHashSet(),
|
||||
Entries = (AsArray(cost, "entries", true) ?? new JArray()).Select(entryItem =>
|
||||
{
|
||||
var parent = (JObject) entryItem;
|
||||
|
||||
var details = new CostEntryDetails
|
||||
{
|
||||
TotalAmount = AsDecimalOptional(parent, "cubic.sumprice") ?? 0,
|
||||
UnitCount = AsDecimalOptional(parent, "cubic.sum") ?? 0
|
||||
};
|
||||
|
||||
for (var i = 1; i <= 4; ++i)
|
||||
{
|
||||
var d = AsDecimalOptional(parent, $"cubic.discount{i}");
|
||||
|
||||
if (d != null)
|
||||
{
|
||||
details.DiscountsInUnits.Add(d.Value);
|
||||
}
|
||||
}
|
||||
|
||||
return new CostEntry
|
||||
{
|
||||
StartDate = AsDate(parent, "start_date"),
|
||||
EndDate = AsDate(parent, "end_date"),
|
||||
Amount = AsDecimal(parent, "price"),
|
||||
Details = details
|
||||
};
|
||||
}).ToList(),
|
||||
DisplayInBill = AsBool(cost, "display")
|
||||
};
|
||||
|
||||
billing.Costs.Add(targetCost);
|
||||
}
|
||||
|
||||
return billing;
|
||||
}
|
||||
catch (JsonException e)
|
||||
{
|
||||
throw new IOException($"Could not load JSON with error:\n{e.Message}", e);
|
||||
}
|
||||
catch (InvalidCastException e)
|
||||
{
|
||||
throw new IOException($"Could not load JSON with error:\n{e.Message}", e);
|
||||
}
|
||||
catch (FormatException e)
|
||||
{
|
||||
throw new IOException($"Could not load JSON with error:\n{e.Message}", e);
|
||||
}
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper", "PossibleNullReferenceException")]
|
||||
private Billing LoadFormat2(string path)
|
||||
{
|
||||
var content = File.ReadAllText(path);
|
||||
try
|
||||
{
|
||||
@@ -121,6 +337,18 @@ namespace UCalc.Data
|
||||
}
|
||||
}
|
||||
|
||||
public Billing Load(string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
return LoadFormat2(path);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return LoadFormat1(path);
|
||||
}
|
||||
}
|
||||
|
||||
public void Store(string path, Billing billing)
|
||||
{
|
||||
File.WriteAllText(path, JsonConvert.SerializeObject(billing, Formatting.Indented));
|
||||
|
||||
@@ -9,10 +9,14 @@ namespace UCalc.Models
|
||||
public CostEntriesProperty(Model model, Property parent, IEnumerable<CostEntry> data) : base(model, parent,
|
||||
"Zeiträume: Geben Sie einen oder mehr Zeiträume an.")
|
||||
{
|
||||
using var validator = Model.BeginValidation();
|
||||
|
||||
foreach (var entry in data)
|
||||
{
|
||||
Add(new CostEntryProperty(model, this, entry));
|
||||
}
|
||||
|
||||
Modified = false;
|
||||
}
|
||||
|
||||
public void Add()
|
||||
|
||||
@@ -160,10 +160,14 @@ namespace UCalc.Models
|
||||
{
|
||||
public DiscountsProperty(Model model, Property parent, IEnumerable<decimal> data) : base(model, parent)
|
||||
{
|
||||
using var validator = Model.BeginValidation();
|
||||
|
||||
foreach (var discount in data)
|
||||
{
|
||||
Add(new DiscountProperty(Model, this, "Abzug", discount));
|
||||
}
|
||||
|
||||
Modified = false;
|
||||
}
|
||||
|
||||
public void Add()
|
||||
|
||||
@@ -86,7 +86,7 @@ namespace UCalc.Models
|
||||
using var validator = Model.BeginValidation();
|
||||
validator.Notify(this, "Errors");
|
||||
|
||||
Model.Root.Costs.NotifyChanged((CostProperty) Parent);
|
||||
((CostsProperty) Parent.Parent).NotifyChanged((CostProperty) Parent);
|
||||
}
|
||||
|
||||
public IEnumerator<FlatProperty> GetEnumerator()
|
||||
|
||||
@@ -15,12 +15,14 @@ namespace UCalc.Models
|
||||
var error = "";
|
||||
using var validator = Model.BeginValidation();
|
||||
|
||||
if (Model.Root.House.Flats.Any(flat => !ReferenceEquals(this, flat.Name) && flat.Name.Value == Value))
|
||||
var flats = (FlatsProperty) Parent.Parent;
|
||||
|
||||
if (flats.Any(flat => !ReferenceEquals(this, flat.Name) && flat.Name.Value == Value))
|
||||
{
|
||||
error = $"{Name}: Der Name ist nicht eindeutig.";
|
||||
}
|
||||
|
||||
validator.ValidateRange(Model.Root.House.Flats.Select(flat => flat.Name));
|
||||
validator.ValidateRange(flats.Select(flat => flat.Name));
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,18 +21,12 @@ namespace UCalc.Models
|
||||
|
||||
public FlatProperty Add()
|
||||
{
|
||||
FlatProperty flat;
|
||||
{
|
||||
using var validator = Model.BeginValidation();
|
||||
using var validator = Model.BeginValidation(true);
|
||||
|
||||
flat = new FlatProperty(Model, this, new Flat {Name = $"Wohnung {Properties.Count + 1}"});
|
||||
base.Add(flat);
|
||||
}
|
||||
var flat = new FlatProperty(Model, this, new Flat {Name = $"Wohnung {Properties.Count + 1}"});
|
||||
base.Add(flat);
|
||||
|
||||
{
|
||||
using var validator = Model.BeginValidation();
|
||||
validator.Validate(flat);
|
||||
}
|
||||
validator.Validate(flat);
|
||||
|
||||
return flat;
|
||||
}
|
||||
|
||||
@@ -105,6 +105,8 @@ namespace UCalc.Models
|
||||
{
|
||||
_errors.Clear();
|
||||
|
||||
var tenants = (TenantsProperty) Parent.Parent;
|
||||
|
||||
try
|
||||
{
|
||||
if (_flatProperties.Count == 0)
|
||||
@@ -118,7 +120,7 @@ namespace UCalc.Models
|
||||
|
||||
foreach (var flatProperty in _flatProperties)
|
||||
{
|
||||
foreach (var tenant in Model.Root.Tenants)
|
||||
foreach (var tenant in tenants)
|
||||
{
|
||||
if (ReferenceEquals(this, tenant.RentedFlats))
|
||||
{
|
||||
@@ -158,7 +160,7 @@ namespace UCalc.Models
|
||||
using var validator = Model.BeginValidation();
|
||||
validator.Notify(this, "Errors");
|
||||
|
||||
validator.ValidateRange(Model.Root.Tenants);
|
||||
validator.ValidateRange(tenants);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using System.Windows.Controls;
|
||||
using System;
|
||||
using System.Windows.Controls;
|
||||
using UCalc.Models;
|
||||
|
||||
namespace UCalc.Pages
|
||||
{
|
||||
@@ -8,5 +10,10 @@ namespace UCalc.Pages
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public void Compute(Model model)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user