diff --git a/Installer/MietRechner.iss b/Installer/MietRechner.iss index cdc8ddd..1f5ce51 100644 --- a/Installer/MietRechner.iss +++ b/Installer/MietRechner.iss @@ -1,6 +1,6 @@ [Setup] AppName=MietRechner -AppVersion=2.1 +AppVersion=2.2 WizardStyle=modern DefaultDirName={autopf}\MietRechner DefaultGroupName=MietRechner diff --git a/ucalc/Controls/PrintableBilling.cs b/ucalc/Controls/PrintableBilling.cs new file mode 100644 index 0000000..4c3de6c --- /dev/null +++ b/ucalc/Controls/PrintableBilling.cs @@ -0,0 +1,217 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Windows; +using System.Windows.Documents; +using System.Windows.Media; +using UCalc.Data; + +namespace UCalc.Controls +{ + public class PrintableBilling : PrintableDocument>> + { + public PrintableBilling(Billing billing, IEnumerable tenants) : base( + new Tuple>(billing, tenants)) + { + } + + protected override void FillFlowDocument(FlowDocument document, Tuple> args) + { + var (billing, tenants) = args; + + foreach (var tenant in tenants) + { + var result = BillingCalculator.CalculateForTenant(billing, tenant); + AddPagesForTenant(document, billing, tenant, result); + } + } + + private static void AddPagesForTenant(FlowDocument document, Billing billing, Tenant tenant, + TenantCalculationResult result) + { + var section = new Section {BreakPageBefore = true, FontSize = Constants.PrintDefaultFontSize}; + document.Blocks.Add(section); + + var table = new Table {CellSpacing = 0}; + section.Blocks.Add(table); + table.Columns.Add(new TableColumn {Width = new GridLength(1, GridUnitType.Star)}); + table.Columns.Add(new TableColumn {Width = new GridLength(1, GridUnitType.Star)}); + + var rowGroup = new TableRowGroup(); + table.RowGroups.Add(rowGroup); + + void AddCost(string name, decimal amount, bool isLast = false) + { + var row2 = new TableRow(); + rowGroup.Rows.Add(row2); + + if (isLast) + { + row2.Background = Brushes.LightGray; + } + + var cell2 = new TableCell + {BorderBrush = Brushes.Gray, BorderThickness = new Thickness(1, 1, 0, isLast ? 1 : 0)}; + row2.Cells.Add(cell2); + + cell2.Blocks.Add(new Paragraph(new Run(name)) {Padding = new Thickness(6)}); + + cell2 = new TableCell + { + BorderBrush = Brushes.Gray, BorderThickness = new Thickness(1, 1, 1, isLast ? 1 : 0), + TextAlignment = TextAlignment.Right + }; + row2.Cells.Add(cell2); + + cell2.Blocks.Add(new Paragraph(new Run($"{amount.CeilToString()} €")) {Padding = new Thickness(6)}); + } + + void AddTextLeftRight(string leftText, string rightText) + { + var row2 = new TableRow(); + rowGroup.Rows.Add(row2); + + var cell2 = new TableCell(); + row2.Cells.Add(cell2); + + cell2.Blocks.Add(new Paragraph(new Run(leftText))); + + cell2 = new TableCell + { + TextAlignment = TextAlignment.Right + }; + row2.Cells.Add(cell2); + + cell2.Blocks.Add(new Paragraph(new Run(rightText))); + } + + AddTextLeftRight( + $"{billing.Landlord.Name}\n" + + $"{billing.Landlord.Address.Street} {billing.Landlord.Address.HouseNumber}\n" + + $"{billing.Landlord.Address.Postcode} {billing.Landlord.Address.City}\n" + + $"Telefon: {billing.Landlord.Phone}" + + (string.IsNullOrEmpty(billing.Landlord.MailAddress) ? "" : $"\nEmail: {billing.Landlord.MailAddress}"), + DateTime.Now.ToString(Constants.DateFormat) + ); + + AddLineBreaks(rowGroup, 2); + + AddText( + rowGroup, + $"{tenant.Salutation.AsString()} {tenant.Name}\n" + + $"{billing.House.Address.Street} {billing.House.Address.HouseNumber}\n" + + $"{billing.House.Address.Postcode} {billing.House.Address.City}" + ); + + AddLineBreaks(rowGroup, 4); + + AddText(rowGroup, $"{tenant.Salutation.AsString()} {tenant.Name}"); + + AddLineBreaks(rowGroup, 1); + + var startDate = billing.StartDate; + if (tenant.EntryDate.HasValue && tenant.EntryDate.Value > startDate) + { + startDate = tenant.EntryDate.Value; + } + + var endDate = billing.EndDate; + if (tenant.DepartureDate.HasValue && tenant.DepartureDate.Value < endDate) + { + endDate = tenant.DepartureDate.Value; + } + + AddText( + rowGroup, + $"Nebenkostenabrechnung vom {startDate.ToString(Constants.DateFormat)} zum {endDate.ToString(Constants.DateFormat)}", + Constants.PrintSubjectFontSize + ); + + AddLineBreaks(rowGroup, 1); + + if (!string.IsNullOrEmpty(tenant.CustomMessage1)) + { + AddText(rowGroup, tenant.CustomMessage1); + + AddLineBreaks(rowGroup, 1); + } + + foreach (var (cost, costResult) in result.Costs) + { + AddCost(cost.Name, costResult.TotalAmount); + } + + AddCost("Zwischensumme", result.SubTotalAmount); + AddCost("Bereits gezahlt", tenant.PaidRent); + AddCost(result.TotalAmount > 0 ? "Einmalige Nachzahlung" : "Einmalige Rückzahlung", result.TotalAmount, + true); + + AddLineBreaks(rowGroup, 1); + + if (result.TotalAmount > 0) + { + AddText( + rowGroup, + $"Bitte überweisen Sie den einmaligen Betrag von {result.TotalAmount.CeilToString()} € auf das untenstehende Konto." + ); + } + else + { + AddText( + rowGroup, + $"Der einmalige Betrag von {(result.TotalAmount * -1).CeilToString()} € wird in den nächsten Tagen auf Ihr Konto überwiesen." + ); + } + + AddLineBreaks(rowGroup, 1); + + if (!string.IsNullOrEmpty(tenant.CustomMessage2)) + { + AddText(rowGroup, tenant.CustomMessage2); + AddLineBreaks(rowGroup, 1); + } + + AddText(rowGroup, "Kontoverbindung:"); + AddText(rowGroup, $"IBAN: {billing.Landlord.BankAccount.Iban}"); + AddText(rowGroup, $"BIC: {billing.Landlord.BankAccount.Bic}"); + AddText(rowGroup, $"Name der Bank: {billing.Landlord.BankAccount.BankName}"); + + AddLineBreaks(rowGroup, 2); + + AddText(rowGroup, "Mit freundlichen Grüßen"); + + if (result.Costs.Any(t => t.Key.DisplayInBill)) + { + AddPagesForTenantDetails(document, result); + } + } + + private static void AddPagesForTenantDetails(FlowDocument document, TenantCalculationResult result) + { + var section = new Section {BreakPageBefore = true, FontSize = Constants.PrintDefaultFontSize}; + document.Blocks.Add(section); + + var table = new Table {CellSpacing = 0}; + section.Blocks.Add(table); + table.Columns.Add(new TableColumn {Width = new GridLength(1, GridUnitType.Star)}); + table.Columns.Add(new TableColumn {Width = new GridLength(1, GridUnitType.Star)}); + + var rowGroup = new TableRowGroup(); + table.RowGroups.Add(rowGroup); + + AddText(rowGroup, "Details zur Berechnung:"); + + AddLineBreaks(rowGroup, 1); + + foreach (var (cost, costResult) in result.Costs) + { + if (!cost.DisplayInBill) + { + continue; + } + + AddText(rowGroup, costResult.Details); + } + } + } +} \ No newline at end of file diff --git a/ucalc/Controls/PrintableDocument.cs b/ucalc/Controls/PrintableDocument.cs index 946f1d4..15c50b9 100644 --- a/ucalc/Controls/PrintableDocument.cs +++ b/ucalc/Controls/PrintableDocument.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.IO.Packaging; @@ -8,11 +7,9 @@ using System.Printing; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; -using System.Windows.Media; using System.Windows.Xps.Packaging; using System.Windows.Xps.Serialization; using Microsoft.Win32; -using UCalc.Data; namespace UCalc.Controls { @@ -23,7 +20,7 @@ namespace UCalc.Controls } } - public class PrintableDocument : IDisposable + public abstract class PrintableDocument : IDisposable { private static readonly Uri DocUri = new Uri($"pack://mietrechner{new Guid()}.xps"); private readonly Package _package; @@ -31,12 +28,12 @@ namespace UCalc.Controls private readonly FixedDocumentSequence _previewDocument; private XpsDocument _fixedDocument; - public PrintableDocument(Billing billing, IEnumerable tenants) + protected PrintableDocument(T args) { _package = Package.Open(new MemoryStream(), FileMode.Create, FileAccess.ReadWrite); PackageStore.AddPackage(DocUri, _package); - _flowDocument = CreateFlowDocument(billing, tenants); + _flowDocument = CreateFlowDocument(args); _previewDocument = CreatePreview(_flowDocument); } @@ -127,11 +124,7 @@ namespace UCalc.Controls xpsDocument.Close(); - var process = new Process(); - process.StartInfo = new ProcessStartInfo(path) - { - UseShellExecute = true - }; + var process = new Process {StartInfo = new ProcessStartInfo(path) {UseShellExecute = true}}; process.Start(); } } @@ -193,7 +186,7 @@ namespace UCalc.Controls public override IDocumentPaginatorSource Source => _paginator.Source; } - private static FlowDocument CreateFlowDocument(Billing billing, IEnumerable tenants) + private FlowDocument CreateFlowDocument(T args) { var size = GetPrinterMediaSize(); if (!size.HasValue) @@ -209,16 +202,13 @@ namespace UCalc.Controls ColumnWidth = double.PositiveInfinity }; - foreach (var tenant in tenants) - { - var result = BillingCalculator.CalculateForTenant(billing, tenant); - AddPagesForTenant(document, billing, tenant, result); - } - + FillFlowDocument(document, args); return document; } - private static void AddLineBreaks(TableRowGroup rowGroup, int count) + protected abstract void FillFlowDocument(FlowDocument flowDocument, T args); + + protected static void AddLineBreaks(TableRowGroup rowGroup, int count) { var row = new TableRow(); rowGroup.Rows.Add(row); @@ -229,7 +219,7 @@ namespace UCalc.Controls {FontSize = Constants.PrintNewlineFontSize})); } - private static void AddText(TableRowGroup rowGroup, string text, double? fontSize = null, + protected static void AddText(TableRowGroup rowGroup, string text, double? fontSize = null, bool alignRight = false) { var row = new TableRow(); @@ -251,193 +241,5 @@ namespace UCalc.Controls paragraph.FontSize = fontSize.Value; } } - - private static void AddPagesForTenant(FlowDocument document, Billing billing, Tenant tenant, - TenantCalculationResult result) - { - var section = new Section {BreakPageBefore = true, FontSize = Constants.PrintDefaultFontSize}; - document.Blocks.Add(section); - - var table = new Table {CellSpacing = 0}; - section.Blocks.Add(table); - table.Columns.Add(new TableColumn {Width = new GridLength(1, GridUnitType.Star)}); - table.Columns.Add(new TableColumn {Width = new GridLength(1, GridUnitType.Star)}); - - var rowGroup = new TableRowGroup(); - table.RowGroups.Add(rowGroup); - - void AddCost(string name, decimal amount, bool isLast = false) - { - var row2 = new TableRow(); - rowGroup.Rows.Add(row2); - - if (isLast) - { - row2.Background = Brushes.LightGray; - } - - var cell2 = new TableCell - {BorderBrush = Brushes.Gray, BorderThickness = new Thickness(1, 1, 0, isLast ? 1 : 0)}; - row2.Cells.Add(cell2); - - cell2.Blocks.Add(new Paragraph(new Run(name)) {Padding = new Thickness(6)}); - - cell2 = new TableCell - { - BorderBrush = Brushes.Gray, BorderThickness = new Thickness(1, 1, 1, isLast ? 1 : 0), - TextAlignment = TextAlignment.Right - }; - row2.Cells.Add(cell2); - - cell2.Blocks.Add(new Paragraph(new Run($"{amount.CeilToString()} €")) {Padding = new Thickness(6)}); - } - - void AddTextLeftRight(string leftText, string rightText) - { - var row2 = new TableRow(); - rowGroup.Rows.Add(row2); - - var cell2 = new TableCell(); - row2.Cells.Add(cell2); - - cell2.Blocks.Add(new Paragraph(new Run(leftText))); - - cell2 = new TableCell - { - TextAlignment = TextAlignment.Right - }; - row2.Cells.Add(cell2); - - cell2.Blocks.Add(new Paragraph(new Run(rightText))); - } - - AddTextLeftRight( - $"{billing.Landlord.Name}\n" + - $"{billing.Landlord.Address.Street} {billing.Landlord.Address.HouseNumber}\n" + - $"{billing.Landlord.Address.Postcode} {billing.Landlord.Address.City}\n" + - $"Telefon: {billing.Landlord.Phone}" + - (string.IsNullOrEmpty(billing.Landlord.MailAddress) ? "" : $"\nEmail: {billing.Landlord.MailAddress}"), - DateTime.Now.ToString(Constants.DateFormat) - ); - - AddLineBreaks(rowGroup, 2); - - AddText( - rowGroup, - $"{tenant.Salutation.AsString()} {tenant.Name}\n" + - $"{billing.House.Address.Street} {billing.House.Address.HouseNumber}\n" + - $"{billing.House.Address.Postcode} {billing.House.Address.City}" - ); - - AddLineBreaks(rowGroup, 4); - - AddText(rowGroup, $"{tenant.Salutation.AsString()} {tenant.Name}"); - - AddLineBreaks(rowGroup, 1); - - var startDate = billing.StartDate; - if (tenant.EntryDate.HasValue && tenant.EntryDate.Value > startDate) - { - startDate = tenant.EntryDate.Value; - } - - var endDate = billing.EndDate; - if (tenant.DepartureDate.HasValue && tenant.DepartureDate.Value < endDate) - { - endDate = tenant.DepartureDate.Value; - } - - AddText( - rowGroup, - $"Nebenkostenabrechnung vom {startDate.ToString(Constants.DateFormat)} zum {endDate.ToString(Constants.DateFormat)}", - Constants.PrintSubjectFontSize - ); - - AddLineBreaks(rowGroup, 1); - - if (!string.IsNullOrEmpty(tenant.CustomMessage1)) - { - AddText(rowGroup, tenant.CustomMessage1); - - AddLineBreaks(rowGroup, 1); - } - - foreach (var (cost, costResult) in result.Costs) - { - AddCost(cost.Name, costResult.TotalAmount); - } - - AddCost("Zwischensumme", result.SubTotalAmount); - AddCost("Bereits gezahlt", tenant.PaidRent); - AddCost(result.TotalAmount > 0 ? "Einmalige Nachzahlung" : "Einmalige Rückzahlung", result.TotalAmount, - true); - - AddLineBreaks(rowGroup, 1); - - if (result.TotalAmount > 0) - { - AddText( - rowGroup, - $"Bitte überweisen Sie den einmaligen Betrag von {result.TotalAmount.CeilToString()} € auf das untenstehende Konto." - ); - } - else - { - AddText( - rowGroup, - $"Der einmalige Betrag von {(result.TotalAmount * -1).CeilToString()} € wird in den nächsten Tagen auf Ihr Konto überwiesen." - ); - } - - AddLineBreaks(rowGroup, 1); - - if (!string.IsNullOrEmpty(tenant.CustomMessage2)) - { - AddText(rowGroup, tenant.CustomMessage2); - AddLineBreaks(rowGroup, 1); - } - - AddText(rowGroup, "Kontoverbindung:"); - AddText(rowGroup, $"IBAN: {billing.Landlord.BankAccount.Iban}"); - AddText(rowGroup, $"BIC: {billing.Landlord.BankAccount.Bic}"); - AddText(rowGroup, $"Name der Bank: {billing.Landlord.BankAccount.BankName}"); - - AddLineBreaks(rowGroup, 2); - - AddText(rowGroup, "Mit freundlichen Grüßen"); - - if (result.Costs.Any(t => t.Key.DisplayInBill)) - { - AddPagesForTenantDetails(document, result); - } - } - - private static void AddPagesForTenantDetails(FlowDocument document, TenantCalculationResult result) - { - var section = new Section {BreakPageBefore = true, FontSize = Constants.PrintDefaultFontSize}; - document.Blocks.Add(section); - - var table = new Table {CellSpacing = 0}; - section.Blocks.Add(table); - table.Columns.Add(new TableColumn {Width = new GridLength(1, GridUnitType.Star)}); - table.Columns.Add(new TableColumn {Width = new GridLength(1, GridUnitType.Star)}); - - var rowGroup = new TableRowGroup(); - table.RowGroups.Add(rowGroup); - - AddText(rowGroup, "Details zur Berechnung:"); - - AddLineBreaks(rowGroup, 1); - - foreach (var (cost, costResult) in result.Costs) - { - if (!cost.DisplayInBill) - { - continue; - } - - AddText(rowGroup, costResult.Details); - } - } } } \ No newline at end of file diff --git a/ucalc/Controls/PrintableTextBox.cs b/ucalc/Controls/PrintableTextBox.cs new file mode 100644 index 0000000..a1b700b --- /dev/null +++ b/ucalc/Controls/PrintableTextBox.cs @@ -0,0 +1,28 @@ +using System.Windows; +using System.Windows.Controls; +using System.Windows.Documents; + +namespace UCalc.Controls +{ + public class PrintableTextBox : PrintableDocument + { + public PrintableTextBox(TextBox textBox) : base(textBox) + { + } + + protected override void FillFlowDocument(FlowDocument document, TextBox textBox) + { + var section = new Section {BreakPageBefore = true, FontSize = Constants.PrintDefaultFontSize}; + document.Blocks.Add(section); + + var table = new Table {CellSpacing = 0}; + section.Blocks.Add(table); + table.Columns.Add(new TableColumn {Width = new GridLength(1, GridUnitType.Star)}); + + var rowGroup = new TableRowGroup(); + table.RowGroups.Add(rowGroup); + + AddText(rowGroup, textBox.Text); + } + } +} \ No newline at end of file diff --git a/ucalc/Data/BillingCalculator.cs b/ucalc/Data/BillingCalculator.cs index 7ae4494..fc979f9 100644 --- a/ucalc/Data/BillingCalculator.cs +++ b/ucalc/Data/BillingCalculator.cs @@ -603,6 +603,23 @@ namespace UCalc.Data var details = new StringBuilder(); var detailsLandlord = new StringBuilder(); + var startDate = billing.StartDate; + if (tenant.EntryDate.HasValue && startDate < tenant.EntryDate.Value) + { + startDate = tenant.EntryDate.Value; + } + + var endDate = billing.EndDate; + if (tenant.DepartureDate.HasValue && endDate < tenant.DepartureDate.Value) + { + endDate = tenant.DepartureDate.Value; + } + + detailsLandlord.Append( + $"Berechnungsdetails für {tenant.Name} vom {startDate.ToString(Constants.DateFormat)} zum {endDate.ToString(Constants.DateFormat)}\n" + ); + detailsLandlord.Append($"Stand {DateTime.Now.ToString(Constants.DateFormat)}\n\n"); + decimal totalAmount = 0; foreach (var cost in billing.Costs) @@ -647,6 +664,10 @@ namespace UCalc.Data var tenantResults = billing.Tenants.Select(tenant => CalculateForTenant(billing, tenant)).ToList(); decimal landlordAmount = 0; + str.Append( + $"Kostenübersicht vom {billing.StartDate.ToString(Constants.DateFormat)} zum {billing.EndDate.ToString(Constants.DateFormat)}\n" + ); + str.Append($"Stand {DateTime.Now.ToString(Constants.DateFormat)}\n\n"); foreach (var cost in billing.Costs) { diff --git a/ucalc/Pages/DetailsPage.xaml b/ucalc/Pages/DetailsPage.xaml index e57dce2..65c70d6 100644 --- a/ucalc/Pages/DetailsPage.xaml +++ b/ucalc/Pages/DetailsPage.xaml @@ -19,6 +19,33 @@ Width="180" Foreground="{x:Static local:Constants.SubMainColor}" /> + + + + + + + + + + + + + + + + + Foreground="{x:Static local:Constants.SubMainColor}" /> \ No newline at end of file diff --git a/ucalc/Pages/DetailsPage.xaml.cs b/ucalc/Pages/DetailsPage.xaml.cs index 350eabf..1ab4e59 100644 --- a/ucalc/Pages/DetailsPage.xaml.cs +++ b/ucalc/Pages/DetailsPage.xaml.cs @@ -1,5 +1,7 @@ using System.Collections.ObjectModel; +using System.Windows; using System.Windows.Controls; +using UCalc.Controls; using UCalc.Data; using UCalc.Models; @@ -71,5 +73,11 @@ namespace UCalc.Pages CalculationTextBox.Text = result.DetailsForLandlord; } + + private void OnPrintTextClick(object sender, RoutedEventArgs e) + { + using var printable = new PrintableTextBox(CalculationTextBox); + printable.Print(TenantComboBox.Text); + } } } \ No newline at end of file diff --git a/ucalc/Pages/SideBar.xaml.cs b/ucalc/Pages/SideBar.xaml.cs index 42802ac..04c0a52 100644 --- a/ucalc/Pages/SideBar.xaml.cs +++ b/ucalc/Pages/SideBar.xaml.cs @@ -50,7 +50,7 @@ namespace UCalc.Pages private void OnAboutClick(object sender, RoutedEventArgs e) { - MessageBox.Show("MietRechner Version 2.1\n\nCopyright © 2020-2021 by Tobias Erbshäußer", "Über MietRechner", + MessageBox.Show("MietRechner Version 2.2\n\nCopyright © 2020-2021 by Tobias Erbshäußer", "Über MietRechner", MessageBoxButton.OK, MessageBoxImage.Information); } } diff --git a/ucalc/PrintWindow.xaml.cs b/ucalc/PrintWindow.xaml.cs index 523b3e7..7f645c7 100644 --- a/ucalc/PrintWindow.xaml.cs +++ b/ucalc/PrintWindow.xaml.cs @@ -54,16 +54,16 @@ namespace UCalc public partial class PrintWindow { - public Billing Billing { get; } + private readonly Billing _billing; public IReadOnlyList TenantMenuItems { get; } - private PrintableDocument _document; + private PrintableBilling _document; public PrintWindow(Model model) { - Billing = model.Dump(); + _billing = model.Dump(); TenantMenuItems = new[] {new TenantMenuItem(null, false), new TenantMenuItem(null, true)}.Concat( - Billing.Tenants.Select(tenant => new TenantMenuItem(tenant, false))).ToList(); + _billing.Tenants.Select(tenant => new TenantMenuItem(tenant, false))).ToList(); foreach (var item in TenantMenuItems) { @@ -86,8 +86,8 @@ namespace UCalc { _document?.Dispose(); - _document = new PrintableDocument( - Billing, + _document = new PrintableBilling( + _billing, TenantMenuItems.Where(item => item.Selected).Select(item => item.Tenant) ); _document.PreviewIn(Viewer); @@ -96,14 +96,8 @@ namespace UCalc private void OnPrintClick(object sender, RoutedEventArgs e) { _document.Print( - $"MietRechner Abrechnung {Billing.StartDate.ToString(Constants.DateFormat)} - {Billing.EndDate.ToString(Constants.DateFormat)}" + $"MietRechner Abrechnung {_billing.StartDate.ToString(Constants.DateFormat)} - {_billing.EndDate.ToString(Constants.DateFormat)}" ); - - /*PrintDialog printDialog = new PrintDialog(); - if (printDialog.ShowDialog() == true) - { - printDialog.PrintQueue.AddJob("test", "C:\\test.xps", false); - }*/ } private void OnSelectedTenantChanged(object sender, PropertyChangedEventArgs e)