Compare commits

...

24 Commits

Author SHA1 Message Date
5b952c4eb1 Workflows: Update upload URL
All checks were successful
Test / Run tests (push) Successful in 1m37s
Deploy / Build and Deploy (push) Successful in 2m26s
2024-05-14 23:00:29 +02:00
48c441b787 Bump version to 0.8.2
Some checks failed
Test / Run tests (push) Successful in 1m43s
Deploy / Build and Deploy (push) Failing after 2m17s
2024-05-14 22:51:36 +02:00
be246d6f06 Tests: Fix old url in fetch-resources.bat 2024-05-14 22:51:00 +02:00
2b10e52ab0 Installer: Fix url for PDFtoPrinter once again
Some checks failed
Test / Run tests (push) Failing after 1m36s
Deploy / Build and Deploy (push) Has been cancelled
2024-05-14 22:45:26 +02:00
e3fd705f52 App: Show scale errors always in debug mode
All checks were successful
Test / Run tests (push) Successful in 2m12s
2024-05-13 22:34:19 +02:00
81e18ac553 Config: Add 'required' option to scales
All checks were successful
Test / Run tests (push) Successful in 4m3s
2024-05-13 11:33:27 +02:00
f95f0f0ef3 BaseDataWindow: Fix crash when CurrentLastSeason does not exist
All checks were successful
Test / Run tests (push) Successful in 2m8s
2024-05-12 22:34:53 +02:00
8eba40a8c1 Bump version to 0.8.1
All checks were successful
Test / Run tests (push) Successful in 2m15s
Deploy / Build and Deploy (push) Successful in 2m16s
2024-05-12 22:01:31 +02:00
69aa75a50a PaymentVariantSummary: Use '–' instead of '~'
All checks were successful
Test / Run tests (push) Successful in 1m56s
2024-05-09 23:42:08 +02:00
13340c0979 Tests: Remove unused code 2024-05-09 19:40:59 +02:00
4bd378e048 [#32] PaymentVariantSummary: Add summary header 2024-05-09 19:12:27 +02:00
602c237fa0 MemberDataSheet: Fix spacing 2024-05-09 12:07:16 +02:00
5e6d0ebf17 [#32] PaymentVariantsWindow: Add export options for Summary 2024-05-09 11:15:32 +02:00
b064643010 [#32] Tests: Add PaymentVariantSummaryTest 2024-05-08 23:24:05 +02:00
3526234432 [#32] Dtos/PaymentVariantSummaryData: Allow Data to be exported as Ods 2024-05-08 16:48:22 +02:00
b03f81d4f2 PaymentVariantsWindow: Add Menu and StatusBar 2024-05-08 11:53:41 +02:00
f123bb44c5 PaymentVariantWindow: Fix sum calculation and crash on export 2024-05-07 12:53:25 +02:00
30536819e7 [#32] Documents: Add PaymentVariantSummary 2024-05-07 12:32:53 +02:00
384f7c9ec0 Migrate Installer and Setup to Wix 5 2024-05-03 21:27:27 +02:00
d102a1cb7a Add german localization to Wix Setup 2024-05-03 18:56:44 +02:00
6906584ef0 App: Fix errors on startup 2024-05-03 21:22:20 +02:00
c0c0b4a26a Models: Move IAddress from Helpers to Models 2024-05-03 14:57:31 +02:00
0ce8e488f9 ChartWindow: Replace deprecated property names 2024-05-03 10:31:12 +02:00
eb4562dceb MemberAdminWindow: Save season instead of bool for cancelling or transfering area commitments 2024-05-03 10:24:01 +02:00
39 changed files with 859 additions and 358 deletions

View File

@ -48,7 +48,7 @@ jobs:
run: | run: |
$content = [System.IO.File]::ReadAllBytes("Setup/bin/x64/Release/Elwig-${{ env.APP_VERSION }}.exe") $content = [System.IO.File]::ReadAllBytes("Setup/bin/x64/Release/Elwig-${{ env.APP_VERSION }}.exe")
Invoke-WebRequest ` Invoke-WebRequest `
-Uri "https://www.necronda.net/elwig/files/Elwig-${{ env.APP_VERSION }}.exe" ` -Uri "https://elwig.at/files/Elwig-${{ env.APP_VERSION }}.exe" `
-Method PUT ` -Method PUT `
-Body $content ` -Body $content `
-Headers @{ Authorization = "${{ secrets.API_AUTHORIZATION }}" } ` -Headers @{ Authorization = "${{ secrets.API_AUTHORIZATION }}" } `

View File

@ -3,7 +3,6 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ctrl="clr-namespace:Elwig.Controls" xmlns:ctrl="clr-namespace:Elwig.Controls"
StartupUri="Windows\MainWindow.xaml"
Exit="Application_Exit"> Exit="Application_Exit">
<Application.Resources> <Application.Resources>
<ctrl:BoolToStringConverter x:Key="BoolToStarConverter" FalseValue="" TrueValue="*"/> <ctrl:BoolToStringConverter x:Key="BoolToStarConverter" FalseValue="" TrueValue="*"/>

View File

@ -17,6 +17,7 @@ using Elwig.Dialogs;
using System.Threading.Tasks; using System.Threading.Tasks;
using Elwig.Helpers.Billing; using Elwig.Helpers.Billing;
using Elwig.Models.Entities; using Elwig.Models.Entities;
using System.Text;
namespace Elwig { namespace Elwig {
public partial class App : Application { public partial class App : Application {
@ -65,7 +66,7 @@ namespace Elwig {
private readonly DispatcherTimer ContextTimer = new() { Interval = TimeSpan.FromSeconds(2) }; private readonly DispatcherTimer ContextTimer = new() { Interval = TimeSpan.FromSeconds(2) };
public App() : base() { public App() : base() {
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance); Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
Directory.CreateDirectory(TempPath); Directory.CreateDirectory(TempPath);
Directory.CreateDirectory(DataPath); Directory.CreateDirectory(DataPath);
MainDispatcher = Dispatcher; MainDispatcher = Dispatcher;
@ -158,7 +159,9 @@ namespace Elwig {
list.Add(Scale.FromConfig(s)); list.Add(Scale.FromConfig(s));
} catch (Exception e) { } catch (Exception e) {
list.Add(new InvalidScale(s.Id)); list.Add(new InvalidScale(s.Id));
MessageBox.Show($"Unable to create scale {s.Id}:\n\n{e.Message}", "Scale Error", MessageBoxButton.OK, MessageBoxImage.Error); if (Config.Debug || s.Required)
MessageBox.Show($"Unable to create scale {s.Id}:\n\n{e.Message}", "Scale Error",
MessageBoxButton.OK, MessageBoxImage.Error);
} }
} }
Scales = list; Scales = list;
@ -178,6 +181,9 @@ namespace Elwig {
} }
base.OnStartup(evt); base.OnStartup(evt);
var window = new MainWindow();
window.Show();
} }
private async void Application_Exit(object sender, ExitEventArgs evt) { private async void Application_Exit(object sender, ExitEventArgs evt) {

View File

@ -1,4 +1,5 @@
using Elwig.Helpers; using Elwig.Helpers;
using Elwig.Models;
using Elwig.Models.Entities; using Elwig.Models.Entities;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;

View File

@ -165,6 +165,7 @@ main table th.narrow {
padding-right: 0; padding-right: 0;
} }
main table .tborder {border-top: var(--border-thickness) solid black;}
main table .lborder {border-left: var(--border-thickness) solid black;} main table .lborder {border-left: var(--border-thickness) solid black;}
main table .rborder {border-right: var(--border-thickness) solid black;} main table .rborder {border-right: var(--border-thickness) solid black;}

View File

@ -88,6 +88,8 @@ namespace Elwig.Documents {
name = "MemberList"; name = "MemberList";
} else if (this is WineQualityStatistics) { } else if (this is WineQualityStatistics) {
name = "WineQualityStatistics"; name = "WineQualityStatistics";
} else if (this is PaymentVariantSummary) {
name = "PaymentVariantSummary";
} else { } else {
throw new InvalidOperationException("Invalid document object"); throw new InvalidOperationException("Invalid document object");
} }

View File

@ -2,9 +2,7 @@
@using Elwig.Helpers @using Elwig.Helpers
@inherits TemplatePage<Elwig.Documents.MemberDataSheet> @inherits TemplatePage<Elwig.Documents.MemberDataSheet>
@model Elwig.Documents.MemberDataSheet @model Elwig.Documents.MemberDataSheet
@{ @{ Layout = "BusinessDocument"; }
Layout = "BusinessDocument";
}
<link rel="stylesheet" href="file:///@Raw(Model.DataPath)\resources\MemberDataSheet.css" /> <link rel="stylesheet" href="file:///@Raw(Model.DataPath)\resources\MemberDataSheet.css" />
<main> <main>
<h1>@Model.Title</h1> <h1>@Model.Title</h1>

View File

@ -0,0 +1,30 @@
using Elwig.Helpers.Billing;
using Elwig.Models.Dtos;
using Elwig.Models.Entities;
using System.Linq;
namespace Elwig.Documents {
public class PaymentVariantSummary : Document {
public new static string Name => "Auszahlungsvariante";
public PaymentVariantSummaryData Data;
public PaymentVar Variant;
public BillingData BillingData;
public string CurrencySymbol;
public int MemberNum;
public int DeliveryNum;
public int DeliveryPartNum;
public PaymentVariantSummary(PaymentVar v, PaymentVariantSummaryData data) :
base($"{Name} {v.Year} - {v.Name}") {
Variant = v;
BillingData = BillingData.FromJson(v.Data);
Data = data;
CurrencySymbol = v.Season.Currency.Symbol ?? v.Season.Currency.Code;
MemberNum = v.Credits.Count;
DeliveryNum = v.DeliveryPartPayments.DistinctBy(p => p.DeliveryPart.Delivery).Count();
DeliveryPartNum = v.DeliveryPartPayments.Count;
}
}
}

View File

@ -0,0 +1,217 @@
@using RazorLight
@using Elwig.Helpers
@inherits TemplatePage<Elwig.Documents.PaymentVariantSummary>
@model Elwig.Documents.PaymentVariantSummary
@{ Layout = "Document"; }
<link rel="stylesheet" href="file:///@Raw(Model.DataPath)\resources\PaymentVariantSummary.css" />
<main>
<h1>Auszahlungsvariante Lese @Model.Variant.Year</h1>
<h2>@Model.Variant.Name</h2>
<table class="payment-variant border">
<colgroup>
<col style="width: 20.0mm;"/>
<col style="width: 30.0mm;"/>
<col style="width: 4.5mm;"/>
<col style="width: 28.0mm;"/>
<col style="width: 47.5mm;"/>
<col style="width: 15.0mm;"/>
<col style="width: 20.0mm;"/>
</colgroup>
@{
//var sum1 = Model.Variant.DeliveryPartPayments.Sum(p => p.NetAmount);
//var sum2 = Model.Variant.Credits.Sum(p => p.); //Model.Variant.MemberPayments.Sum(p => p.Amount);
var modifiers = Model.Variant.DeliveryPartPayments.Sum(p => p.Amount - p.NetAmount);
var sum2 = Model.Variant.Credits.Sum(p => p.NetAmount);
var sum1 = sum2 - modifiers;
var payed = -Model.Variant.Credits.Sum(p => p.PrevNetAmount ?? 0m);
var netSum = Model.Variant.Credits.Sum(p => p.NetAmount) - Model.Variant.Credits.Sum(p => p.PrevNetAmount ?? 0m);
var vat = Model.Variant.Credits.Sum(p => p.VatAmount);
var grossSum = Model.Variant.Credits.Sum(p => p.GrossAmount);
var totalMods = Model.Variant.Credits.Sum(p => p.Modifiers ?? 0m);
var considered = -Model.Variant.Credits.Sum(p => p.PrevModifiers ?? 0m);
var totalSum = Model.Variant.Credits.Sum(p => p.Amount);
}
<tbody>
<tr class="sectionheading">
<th colspan="4">Allgemein</th>
<th colspan="3" class="lborder">Berücksichtigt</th>
</tr>
<tr>
<th>Name:</th>
<td colspan="3">@Model.Variant.Name</td>
<th colspan="2" class="lborder">Zu-/Abschläge bei Lieferungen:</th>
<td class="center">@(Model.BillingData.ConsiderDelieryModifiers ? "Ja" : "Nein")</td>
</tr>
<tr>
<th>Beschr.:</th>
<td colspan="3">@Model.Variant.Comment</td>
<th colspan="2" class="lborder">Pönalen bei Unterlieferungen (FB):</th>
<td class="center">@(Model.BillingData.ConsiderContractPenalties ? "Ja" : "Nein")</td>
</tr>
<tr>
<th>Datum:</th>
<td colspan="3">@($"{Model.Variant.Date:dd.MM.yyyy}")</td>
<th colspan="2" class="lborder">Strafen bei Unterlieferungen (GA):</th>
<td class="center">@(Model.BillingData.ConsiderTotalPenalty ? "Ja" : "Nein")</td>
</tr>
<tr>
<th>Überw.:</th>
<td colspan="3">@($"{Model.Variant.TransferDate:dd.MM.yyyy}")</td>
<th colspan="2" class="lborder">Automatische Nachzeichnung der GA:</th>
<td class="center">@(Model.BillingData.ConsiderAutoBusinessShares ? "Ja" : "Nein")</td>
</tr>
<tr class="sectionheading">
<th colspan="4">Beträge</th>
<th colspan="3" class="lborder">Statistik</th>
</tr>
<tr>
<th colspan="2">Zwischensumme:</th>
<td></td>
<td class="number"><span class="fleft">@Model.CurrencySymbol</span>@($"{sum1:N2}")</td>
<th class="lborder">Lieferanten:</th>
<td colspan="2" class="number">@($"{Model.MemberNum:N0}")</td>
</tr>
<tr>
<th colspan="2">Zu-/Abschläge (Lieferungen):</th>
<td class="number">@Utils.GetSign(modifiers)</td>
<td class="number"><span class="fleft">@Model.CurrencySymbol</span>@($"{Math.Abs(modifiers):N2}")</td>
<th class="lborder">Lieferungen:</th>
<td colspan="2" class="number">@($"{Model.DeliveryNum:N0}")</td>
</tr>
<tr>
<th colspan="2">Gesamtsumme:</th>
<td class="number tborder"></td>
<td class="number tborder"><span class="fleft">@Model.CurrencySymbol</span>@($"{sum2:N2}")</td>
<th class="lborder">Teillieferungen:</th>
<td colspan="2" class="number">@($"{Model.DeliveryPartNum:N0}")</td>
</tr>
<tr>
<th colspan="2">Bisher ausgezahlt:</th>
<td class="number">@Utils.GetSign(payed)</td>
<td class="number"><span class="fleft">@Model.CurrencySymbol</span>@($"{Math.Abs(payed):N2}")</td>
<th class="lborder"></th>
<td colspan="2"></td>
</tr>
<tr>
<th colspan="2">Nettosumme:</th>
<td class="number tborder"></td>
<td class="number tborder"><span class="fleft">@Model.CurrencySymbol</span>@($"{netSum:N2}")</td>
@{
var weiRows = Model.Data.Rows.Where(r => r.QualityLevel == "Wein");
var minWei = weiRows.Min(r => r.Ungeb.Price);
var maxWei = weiRows.Max(r => r.Ungeb.Price);
}
<th class="lborder tborder">Preis (abgewertet):</th>
<td colspan="2" class="center tborder">@(minWei != maxWei ? $"{minWei:N4}{maxWei:N4}" : $"{minWei:N4}") @Model.CurrencySymbol/kg</td>
</tr>
<tr>
<th colspan="2">Mehrwertsteuer:</th>
<td class="number">@Utils.GetSign(vat)</td>
<td class="number"><span class="fleft">@Model.CurrencySymbol</span>@($"{Math.Abs(vat):N2}")</td>
@{
var quwRows = Model.Data.Rows.Where(r => r.QualityLevel != "Wein");
var minPrice = quwRows.Min(r => r.Ungeb.Price);
var maxPrice = quwRows.Max(r => r.Ungeb.Price);
}
<th class="lborder">Preis (ungeb., nicht abgew.):</th>
<td colspan="2" class="center">@(minPrice != maxPrice ? $"{minPrice:N4}{maxPrice:N4}" : $"{minPrice:N4}") @Model.CurrencySymbol/kg</td>
</tr>
<tr>
<th colspan="2">Bruttosumme:</th>
<td class="number tborder"></td>
<td class="number tborder"><span class="fleft">@Model.CurrencySymbol</span>@($"{grossSum:N2}")</td>
@{
var gebRows = Model.Data.Rows
.Where(r => r.Geb.Price != null && r.Ungeb.Price != null)
.Select(r => r.Geb.Price - r.Ungeb.Price);
var minGeb = gebRows.Min();
var maxGeb = gebRows.Max();
}
<th class="lborder">Gebunden-Zuschlag:</th>
<td colspan="2" class="center">
@(minGeb != maxGeb ? $"{minGeb:N4}{maxGeb:N4} {Model.CurrencySymbol}/kg" : minGeb == 0 ? "-" : $"{minGeb:N4} {Model.CurrencySymbol}/kg")
</td>
</tr>
<tr>
<th colspan="2">Abzüge (Strafen/Pönalen, GA, ...):</th>
<td class="number">@Utils.GetSign(totalMods)</td>
<td class="number"><span class="fleft">@Model.CurrencySymbol</span>@($"{Math.Abs(totalMods):N2}")</td>
<th class="lborder tborder">Menge (ungebunden):</th>
<td colspan="2" class="number tborder">@($"{Model.Data.Rows.Sum(r => r.Ungeb.Weight):N0}") kg</td>
</tr>
<tr>
<th colspan="2">Bereits berücksichtigte Abzüge:</th>
<td class="number">@Utils.GetSign(considered)</td>
<td class="number"><span class="fleft">@Model.CurrencySymbol</span>@($"{Math.Abs(considered):N2}")</td>
<th class="lborder">Menge (gebunden):</th>
<td colspan="2" class="number">@($"{Model.Data.Rows.Sum(r => r.Geb.Weight):N0}") kg</td>
</tr>
<tr>
<th colspan="2">Auszahlungsbetrag:</th>
<td class="number tborder"></td>
<td class="number tborder"><span class="fleft">@Model.CurrencySymbol</span>@($"{totalSum:N2}")</td>
<th class="lborder">Gesamtmenge:</th>
<td colspan="2" class="number tborder">@($"{Model.Data.Rows.Sum(r => r.Ungeb.Weight + r.Geb.Weight):N0}") kg</td>
</tr>
</tbody>
</table>
<table class="payment-variant-data">
<colgroup>
<col style="width: 30mm;"/>
<col style="width: 20mm;"/>
<col style="width: 25mm;"/>
<col style="width: 20mm;"/>
<col style="width: 25mm;"/>
<col style="width: 20mm;"/>
<col style="width: 25mm;"/>
</colgroup>
<thead>
<tr>
<th rowspan="2" style="text-align: left;">Qualitätsstufe</th>
<th>Gradation</th>
<th colspan="2">ungebunden</th>
<th colspan="2">gebunden</th>
<th>Gesamt</th>
</tr>
<tr>
<th>[@(true ? "°Oe" : "°KMW")]</th>
<th>[kg]</th>
<th>[@(Model.CurrencySymbol)/kg]</th>
<th>[kg]</th>
<th>[@(Model.CurrencySymbol)/kg]</th>
<th>[@(Model.CurrencySymbol)]</th>
</tr>
</thead>
<tbody>
@{
string? lastHdr = null;
}
@foreach (var row in Model.Data.Rows) {
var hdr = $"{row.Variety}{(row.Attribute != null ? " / " : "")}{row.Attribute}{(row.Cultivation != null ? " / " : "")}{row.Cultivation}";
if (lastHdr != hdr) {
var rows = Model.Data.Rows
.Where(r => r.Variety == row.Variety && r.Attribute == row.Attribute && r.Cultivation == row.Cultivation)
.ToList();
<tr class="subheading @(lastHdr != null ? "new" : "")">
<th colspan="2">@hdr</th>
<td class="number">@($"{rows.Sum(r => r.Ungeb.Weight):N0}")</td>
<td></td>
<td class="number">@($"{rows.Sum(r => r.Geb.Weight):N0}")</td>
<td></td>
<td class="number">@($"{rows.Sum(r => r.Amount):N2}")</td>
</tr>
}
<tr>
<td>@(row.QualityLevel)</td>
<td class="center">@($"{row.Oe:N0}")</td>
<td class="number">@(row.Ungeb.Weight != 0 ? $"{row.Ungeb.Weight:N0}" : "-")</td>
<td class="number">@(row.Ungeb.Price != null ? $"{row.Ungeb.Price:N4}" : "-")</td>
<td class="number">@(row.Geb.Weight != 0 ? $"{row.Geb.Weight:N0}" : "-")</td>
<td class="number">@(row.Geb.Price != null ? $"{row.Geb.Price:N4}" : "-")</td>
<td class="number">@($"{row.Amount:N2}")</td>
</tr>
lastHdr = hdr;
}
</tbody>
</table>
</main>

View File

@ -0,0 +1,21 @@
h1 {
text-align: center;
font-size: 24pt;
margin-top: 10mm;
margin-bottom: 2mm;
}
h2 {
text-align: center;
font-size: 14pt;
margin-top: 2mm;
}
table.payment-variant {
margin-top: 10mm;
}
table.payment-variant-data {
break-before: page;
}

View File

@ -7,7 +7,7 @@
<UseWPF>true</UseWPF> <UseWPF>true</UseWPF>
<PreserveCompilationContext>true</PreserveCompilationContext> <PreserveCompilationContext>true</PreserveCompilationContext>
<ApplicationIcon>Resources\Images\Elwig.ico</ApplicationIcon> <ApplicationIcon>Resources\Images\Elwig.ico</ApplicationIcon>
<Version>0.8.0</Version> <Version>0.8.2</Version>
<SatelliteResourceLanguages>de-AT</SatelliteResourceLanguages> <SatelliteResourceLanguages>de-AT</SatelliteResourceLanguages>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<ApplicationManifest>app.manifest</ApplicationManifest> <ApplicationManifest>app.manifest</ApplicationManifest>

View File

@ -65,6 +65,7 @@ namespace Elwig.Helpers {
public DbSet<CreditNoteDeliveryRowSingle> CreditNoteDeliveryRows { get; private set; } public DbSet<CreditNoteDeliveryRowSingle> CreditNoteDeliveryRows { get; private set; }
public DbSet<CreditNoteRowSingle> CreditNoteRows { get; private set; } public DbSet<CreditNoteRowSingle> CreditNoteRows { get; private set; }
public DbSet<WeightBreakdownRow> WeightBreakDownRows { get; private set; } public DbSet<WeightBreakdownRow> WeightBreakDownRows { get; private set; }
public DbSet<PaymentVariantSummaryRow> PaymentVariantSummaryRows { get; private set; }
private readonly StreamWriter? LogFile = null; private readonly StreamWriter? LogFile = null;
public static DateTime LastWriteTime => File.GetLastWriteTime(App.Config.DatabaseFile); public static DateTime LastWriteTime => File.GetLastWriteTime(App.Config.DatabaseFile);

View File

@ -13,10 +13,11 @@ namespace Elwig.Helpers {
public string? Empty; public string? Empty;
public string? Filling; public string? Filling;
public string? Limit; public string? Limit;
public bool Required;
public string? Log; public string? Log;
public string? _Log; public string? _Log;
public ScaleConfig(string id, string? type, string? model, string? cnx, string? empty, string? filling, string? limit, string? log) { public ScaleConfig(string id, string? type, string? model, string? cnx, string? empty, string? filling, string? limit, bool? required, string? log) {
Id = id; Id = id;
Type = type; Type = type;
Model = model; Model = model;
@ -24,6 +25,7 @@ namespace Elwig.Helpers {
Empty = empty; Empty = empty;
Filling = filling; Filling = filling;
Limit = limit; Limit = limit;
Required = required ?? true;
_Log = log; _Log = log;
Log = log != null ? Path.Combine(App.DataPath, log) : null; Log = log != null ? Path.Combine(App.DataPath, log) : null;
} }
@ -91,7 +93,9 @@ namespace Elwig.Helpers {
foreach (var s in scales) { foreach (var s in scales) {
ScaleList.Add(new( ScaleList.Add(new(
s, config[$"scale.{s}:type"], config[$"scale.{s}:model"], config[$"scale.{s}:connection"], s, config[$"scale.{s}:type"], config[$"scale.{s}:model"], config[$"scale.{s}:connection"],
config[$"scale.{s}:empty"], config[$"scale.{s}:filling"], config[$"scale.{s}:limit"], config[$"scale.{s}:log"] config[$"scale.{s}:empty"], config[$"scale.{s}:filling"], config[$"scale.{s}:limit"],
config[$"scale.{s}:required"] != null ? TrueValues.Contains(config[$"scale.{s}:required"]?.ToLower()) : null,
config[$"scale.{s}:log"]
)); ));
} }
} }

View File

@ -1,8 +1,8 @@
using Elwig.Models;
using Elwig.Models.Dtos; using Elwig.Models.Dtos;
using Elwig.Models.Entities; using Elwig.Models.Entities;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Security; using System.Security;

View File

@ -302,6 +302,7 @@ namespace Elwig.Helpers.Export {
switch (units[0]) { switch (units[0]) {
case "%": n = 1; data = $"{v:N1}"; break; case "%": n = 1; data = $"{v:N1}"; break;
case "€": n = 2; data = $"{v:N2}"; break; case "€": n = 2; data = $"{v:N2}"; break;
case "€/kg": n = 4; data = $"{v:N4}"; break;
case "°KMW": n = 1; data = $"{v:N1}"; break; case "°KMW": n = 1; data = $"{v:N1}"; break;
case "°Oe": n = 0; data = $"{v:N0}"; break; case "°Oe": n = 0; data = $"{v:N0}"; break;
case "m²": n = 0; data = $"{v:N0}"; break; case "m²": n = 0; data = $"{v:N0}"; break;

View File

@ -1,5 +1,4 @@
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using System.Threading.Tasks; using System.Threading.Tasks;

View File

@ -0,0 +1,104 @@
using Elwig.Documents;
using Elwig.Helpers;
using Elwig.Models.Entities;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.Core.Common.CommandTrees.ExpressionBuilder;
using System.Linq;
using System.Threading.Tasks;
namespace Elwig.Models.Dtos {
public class PaymentVariantSummaryData : DataTable<PaymentVariantSummaryData.PaymentRow> {
private static readonly (string, string, string?, int?)[] FieldNames = [
("Type", "Typ", null, 10),
("Variety", "Sorte", null, 40),
("Attribute", "Attribut", null, 20),
("Cultivation", "Bewirt.", null, 20),
("QualityLevel", "Qualitätsstufe", null, 30),
("Oe", "Gradation", "°Oe", 20),
("Ungeb", "ungebunden", "kg|€/kg", 40),
("Geb", "gebunden", "kg|€/kg", 40),
("Amount", "Gesamt", "€", 25),
];
public record struct PaymentRow(
string Type,
string Variety,
string? Attribute,
string? Cultivation,
string QualityLevel,
double Oe,
(int Weight, decimal? Price) Ungeb,
(int Weight, decimal? Price) Geb,
decimal Amount
);
public PaymentVariantSummaryData(PaymentVar v, IEnumerable<PaymentRow> rows) :
base($"{PaymentVariantSummary.Name} {v.Year}", $"{PaymentVariantSummary.Name} Lese {v.Year}", v.Name, rows, FieldNames) {
}
public static async Task<PaymentVariantSummaryData> ForPaymentVariant(PaymentVar v, DbSet<PaymentVariantSummaryRow> table) {
return new(v, (await FromDbSet(table, v.Year, v.AvNr))
.Select(r => new PaymentRow(r.Type, r.Variety, r.Attribute, r.Cultivation, r.QualityLevel, r.Oe,
(r.WeightUngeb, r.PriceUngeb != null ? Utils.DecFromDb(r.PriceUngeb.Value, v.Season.Precision) : null),
(r.WeightGeb, r.PriceGeb != null ? Utils.DecFromDb(r.PriceGeb.Value, v.Season.Precision) : null),
Utils.DecFromDb(r.Amount, v.Season.Precision)))
.ToArray());
}
private static async Task<IEnumerable<PaymentVariantSummaryRow>> FromDbSet(DbSet<PaymentVariantSummaryRow> table, int year, int avnr) {
return await table.FromSqlRaw($"""
SELECT v.type AS type,
v.name AS variety,
a.name AS attribute,
c.name AS cultivation,
q.name AS quality_level,
ROUND(kmw * (4.54 + 0.022 * kmw)) AS oe,
SUM(IIF(w.discr = '_', w.value, 0)) AS weight_ungeb,
MAX(IIF(w.discr = '_', b.price, NULL)) AS price_ungeb,
SUM(IIF(w.discr != '_', w.value, 0)) AS weight_geb,
MAX(IIF(w.discr != '_', b.price, NULL)) AS price_geb,
SUM(b.amount) AS amount
FROM payment_delivery_part_bucket b
LEFT JOIN delivery_part_bucket w ON (w.year, w.did, w.dpnr, w.bktnr) = (b.year, b.did, b.dpnr, b.bktnr)
LEFT JOIN delivery_part p ON (p.year, p.did, p.dpnr) = (b.year, b.did, b.dpnr)
LEFT JOIN delivery d ON (d.year, d.did) = (p.year, p.did)
LEFT JOIN wine_variety v ON v.sortid = p.sortid
LEFT JOIN wine_attribute a ON a.attrid = p.attrid
LEFT JOIN wine_cultivation c ON c.cultid = p.cultid
LEFT JOIN wine_quality_level q ON q.qualid = p.qualid
WHERE d.year = {year} AND b.avnr = {avnr}
GROUP BY variety, attribute, cultivation, q.min_kmw, oe
ORDER BY variety, attribute, cultivation, q.min_kmw, oe
""").ToListAsync();
}
}
[Keyless]
public class PaymentVariantSummaryRow {
[Column("type")]
public required string Type { get; set; }
[Column("variety")]
public required string Variety { get; set; }
[Column("attribute")]
public string? Attribute { get; set; }
[Column("cultivation")]
public string? Cultivation { get; set; }
[Column("quality_level")]
public required string QualityLevel { get; set; }
[Column("oe")]
public double Oe { get; set; }
[Column("weight_ungeb")]
public int WeightUngeb { get; set; }
[Column("price_ungeb")]
public long? PriceUngeb { get; set; }
[Column("weight_geb")]
public int WeightGeb { get; set; }
[Column("price_geb")]
public long? PriceGeb { get; set; }
[Column("amount")]
public long Amount { get; set; }
}
}

View File

@ -19,7 +19,7 @@ namespace Elwig.Models.Dtos {
Sections = sections; Sections = sections;
} }
private static QualitySection[] GetQualitySections(IEnumerable<QualityRow> rows) { private static QualitySection[] GetSections(IEnumerable<QualityRow> rows) {
var data = new List<QualitySection>(); var data = new List<QualitySection>();
var currentQual = new Dictionary<double, (double AvgKmw, int Num, int Weight)>(); var currentQual = new Dictionary<double, (double AvgKmw, int Num, int Weight)>();
var current = new Dictionary<string, (double, double, int, int)[]>(); var current = new Dictionary<string, (double, double, int, int)[]>();
@ -88,7 +88,7 @@ namespace Elwig.Models.Dtos {
.Select(r => new QualityRow(r.Key.Variety, r.Key.Attribute, r.Key.Cultivation, r.Key.Type, r.Key.QualId, r.AvgKmw, r.Key.Grad, r.Num, r.Weight)) .Select(r => new QualityRow(r.Key.Variety, r.Key.Attribute, r.Key.Cultivation, r.Key.Type, r.Key.QualId, r.AvgKmw, r.Key.Grad, r.Num, r.Weight))
.ToList(); .ToList();
var data = GetQualitySections(rows); var data = GetSections(rows);
if (data.Length <= 1) if (data.Length <= 1)
return new(data); return new(data);
@ -105,7 +105,7 @@ namespace Elwig.Models.Dtos {
.ThenBy(g => g.QualId) .ThenBy(g => g.QualId)
.ThenBy(g => g.Grad) .ThenBy(g => g.Grad)
.ToList(); .ToList();
var typeData = GetQualitySections(typeRows); var typeData = GetSections(typeRows);
if (typeData.Length <= 1) if (typeData.Length <= 1)
return new([.. typeData, .. data]); return new([.. typeData, .. data]);
@ -121,7 +121,7 @@ namespace Elwig.Models.Dtos {
.OrderBy(g => g.QualId) .OrderBy(g => g.QualId)
.ThenBy(g => g.Grad) .ThenBy(g => g.Grad)
.ToList(); .ToList();
var totalData = GetQualitySections(totalRows); var totalData = GetSections(totalRows);
return new([.. totalData, .. typeData, .. data]) { UseOe = mode == 0 }; return new([.. totalData, .. typeData, .. data]) { UseOe = mode == 0 };
} }
} }

View File

@ -1,4 +1,3 @@
using Elwig.Helpers;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;

View File

@ -1,6 +1,6 @@
using Elwig.Models.Entities; using Elwig.Models.Entities;
namespace Elwig.Helpers { namespace Elwig.Models {
public interface IAddress { public interface IAddress {
string Name { get; } string Name { get; }
string Address { get; } string Address { get; }

View File

@ -148,7 +148,7 @@ namespace Elwig.Windows {
protected override async Task OnRenewContext(AppDbContext ctx) { protected override async Task OnRenewContext(AppDbContext ctx) {
await base.OnRenewContext(ctx); await base.OnRenewContext(ctx);
FillInputs(App.Client, (await ctx.Seasons.FindAsync(Utils.CurrentLastSeason))!); FillInputs(App.Client, await ctx.Seasons.FindAsync(Utils.CurrentLastSeason));
ControlUtils.RenewItemsSource(SeasonList, await ctx.Seasons ControlUtils.RenewItemsSource(SeasonList, await ctx.Seasons
.OrderByDescending(s => s.Year) .OrderByDescending(s => s.Year)
.Include(s => s.Modifiers) .Include(s => s.Modifiers)
@ -274,7 +274,7 @@ namespace Elwig.Windows {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
ClearInputStates(); ClearInputStates();
FillInputs(App.Client, (await ctx.Seasons.FindAsync(Utils.CurrentLastSeason))!); FillInputs(App.Client, await ctx.Seasons.FindAsync(Utils.CurrentLastSeason));
LockInputs(); LockInputs();
} }
@ -294,7 +294,7 @@ namespace Elwig.Windows {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
ClearInputStates(); ClearInputStates();
FillInputs(App.Client, (await ctx.Seasons.FindAsync(Utils.CurrentLastSeason))!); FillInputs(App.Client, await ctx.Seasons.FindAsync(Utils.CurrentLastSeason));
UpdateButtons(); UpdateButtons();
} }
@ -325,14 +325,14 @@ namespace Elwig.Windows {
using (var ctx = new AppDbContext()) { using (var ctx = new AppDbContext()) {
ClearInputStates(); ClearInputStates();
FillInputs(App.Client, (await ctx.Seasons.FindAsync(Utils.CurrentLastSeason))!); FillInputs(App.Client, await ctx.Seasons.FindAsync(Utils.CurrentLastSeason));
LockInputs(); LockInputs();
} }
await HintContextChange(); await HintContextChange();
} }
private void FillInputs(ClientParameters p, Season s) { private void FillInputs(ClientParameters p, Season? s) {
ClearOriginalValues(); ClearOriginalValues();
ClearDefaultValues(); ClearDefaultValues();
@ -363,9 +363,9 @@ namespace Elwig.Windows {
TextElementDeliveryConfirmation.Text = p.TextDeliveryConfirmation; TextElementDeliveryConfirmation.Text = p.TextDeliveryConfirmation;
TextElementCreditNote.Text = p.TextCreditNote; TextElementCreditNote.Text = p.TextCreditNote;
ParameterAllowAttrIntoLowerInput.IsChecked = s.Billing_AllowAttrsIntoLower; ParameterAllowAttrIntoLowerInput.IsChecked = s?.Billing_AllowAttrsIntoLower ?? false;
ParameterAvoidUnderDeliveriesInput.IsChecked = s.Billing_AvoidUnderDeliveries; ParameterAvoidUnderDeliveriesInput.IsChecked = s?.Billing_AvoidUnderDeliveries ?? false;
ParameterHonorGebundenInput.IsChecked = s.Billing_HonorGebunden; ParameterHonorGebundenInput.IsChecked = s?.Billing_HonorGebunden ?? false;
FinishInputFilling(); FinishInputFilling();
} }

View File

@ -38,21 +38,21 @@ namespace Elwig.Windows {
private static readonly LegendItem private static readonly LegendItem
UngebundenLegend = new() { UngebundenLegend = new() {
Label = "Ungebunden", LineWidth = 1, LineColor = ColorUngebunden, LabelText = "Ungebunden", LineWidth = 1, LineColor = ColorUngebunden,
Marker = new(MarkerShape.FilledCircle, 5, ColorUngebunden) MarkerStyle = new(MarkerShape.FilledCircle, 5, ColorUngebunden)
}, },
GebundenLegend = new() { GebundenLegend = new() {
Label = "Gebunden", LineWidth = 1, LineColor = ColorGebunden, LabelText = "Gebunden", LineWidth = 1, LineColor = ColorGebunden,
Marker = new(MarkerShape.FilledCircle, 5, ColorGebunden) MarkerStyle = new(MarkerShape.FilledCircle, 5, ColorGebunden)
}, },
LdwLegend = new() { LdwLegend = new() {
Label = "68 °Oe (LDW)", LineWidth = 2, LineColor = Colors.Red, Marker = MarkerStyle.None LabelText = "68 °Oe (LDW)", LineWidth = 2, LineColor = Colors.Red, MarkerStyle = MarkerStyle.None
}, },
QuwLegend = new() { QuwLegend = new() {
Label = "73 °Oe (QUW)", LineWidth = 2, LineColor = Colors.Orange, Marker = MarkerStyle.None LabelText = "73 °Oe (QUW)", LineWidth = 2, LineColor = Colors.Orange, MarkerStyle = MarkerStyle.None
}, },
KabLegend = new() { KabLegend = new() {
Label = "84 °Oe (KAB)", LineWidth = 2, LineColor = Colors.Green, Marker = MarkerStyle.None LabelText = "84 °Oe (KAB)", LineWidth = 2, LineColor = Colors.Green, MarkerStyle = MarkerStyle.None
}; };
private (Graph? Graph, int Index) LastHighlighted = (null, -1); private (Graph? Graph, int Index) LastHighlighted = (null, -1);
@ -379,7 +379,7 @@ namespace Elwig.Windows {
} }
private void ShowLegend() { private void ShowLegend() {
OechslePricePlot.Plot.Legend.Location = Alignment.UpperLeft; OechslePricePlot.Plot.Legend.Alignment = Alignment.UpperLeft;
OechslePricePlot.Plot.Legend.IsVisible = true; OechslePricePlot.Plot.Legend.IsVisible = true;
OechslePricePlot.Plot.Legend.ManualItems.Add(LdwLegend); OechslePricePlot.Plot.Legend.ManualItems.Add(LdwLegend);

View File

@ -19,8 +19,8 @@ using Elwig.Helpers.Billing;
namespace Elwig.Windows { namespace Elwig.Windows {
public partial class MemberAdminWindow : AdministrationWindow { public partial class MemberAdminWindow : AdministrationWindow {
protected bool TransferPredecessorAreaComs = false; protected int? TransferPredecessorAreaComs = null;
protected bool CancelAreaComs = false; protected int? CancelAreaComs = null;
protected List<string> TextFilter = []; protected List<string> TextFilter = [];
private readonly (ComboBox Type, TextBox Number, TextBox Comment)[] PhoneNrInputs; private readonly (ComboBox Type, TextBox Number, TextBox Comment)[] PhoneNrInputs;
@ -412,8 +412,8 @@ namespace Elwig.Windows {
IsCreating = true; IsCreating = true;
MemberList.IsEnabled = false; MemberList.IsEnabled = false;
MemberList.SelectedItem = null; MemberList.SelectedItem = null;
TransferPredecessorAreaComs = false; TransferPredecessorAreaComs = null;
CancelAreaComs = false; CancelAreaComs = null;
HideNewEditDeleteButtons(); HideNewEditDeleteButtons();
ShowSaveResetCancelButtons(); ShowSaveResetCancelButtons();
UnlockInputs(); UnlockInputs();
@ -434,8 +434,8 @@ namespace Elwig.Windows {
IsEditing = true; IsEditing = true;
MemberList.IsEnabled = false; MemberList.IsEnabled = false;
TransferPredecessorAreaComs = false; TransferPredecessorAreaComs = null;
CancelAreaComs = false; CancelAreaComs = null;
HideNewEditDeleteButtons(); HideNewEditDeleteButtons();
ShowSaveResetCancelButtons(); ShowSaveResetCancelButtons();
@ -509,8 +509,8 @@ namespace Elwig.Windows {
} }
private void ResetButton_Click(object? sender, RoutedEventArgs? evt) { private void ResetButton_Click(object? sender, RoutedEventArgs? evt) {
TransferPredecessorAreaComs = false; TransferPredecessorAreaComs = null;
CancelAreaComs = false; CancelAreaComs = null;
if (IsEditing) { if (IsEditing) {
RefreshInputs(); RefreshInputs();
} else if (IsCreating) { } else if (IsCreating) {
@ -524,8 +524,8 @@ namespace Elwig.Windows {
IsEditing = false; IsEditing = false;
IsCreating = false; IsCreating = false;
MemberList.IsEnabled = true; MemberList.IsEnabled = true;
TransferPredecessorAreaComs = false; TransferPredecessorAreaComs = null;
CancelAreaComs = false; CancelAreaComs = null;
HideSaveResetCancelButtons(); HideSaveResetCancelButtons();
ShowNewEditDeleteButtons(); ShowNewEditDeleteButtons();
RefreshInputs(); RefreshInputs();
@ -909,8 +909,7 @@ namespace Elwig.Windows {
await ctx.SaveChangesAsync(); await ctx.SaveChangesAsync();
if (TransferPredecessorAreaComs && m.PredecessorMgNr is int predecessor) { if (TransferPredecessorAreaComs is int year && m.PredecessorMgNr is int predecessor) {
var year = Utils.FollowingSeason;
var areaComs = await ctx.AreaCommitments var areaComs = await ctx.AreaCommitments
.Where(c => c.MgNr == predecessor && (c.YearTo == null || c.YearTo >= year)) .Where(c => c.MgNr == predecessor && (c.YearTo == null || c.YearTo >= year))
.ToListAsync(); .ToListAsync();
@ -934,20 +933,19 @@ namespace Elwig.Windows {
ctx.UpdateRange(areaComs); ctx.UpdateRange(areaComs);
await ctx.SaveChangesAsync(); await ctx.SaveChangesAsync();
} }
TransferPredecessorAreaComs = false; TransferPredecessorAreaComs = null;
if (CancelAreaComs) { if (CancelAreaComs is int yearTo) {
var year = Utils.FollowingSeason;
var areaComs = await ctx.AreaCommitments var areaComs = await ctx.AreaCommitments
.Where(c => c.MgNr == m.MgNr && (c.YearTo == null || c.YearTo >= year)) .Where(c => c.MgNr == m.MgNr && (c.YearTo == null || c.YearTo > yearTo))
.ToListAsync(); .ToListAsync();
foreach (var ac in areaComs) foreach (var ac in areaComs)
ac.YearTo = year - 1; ac.YearTo = yearTo;
ctx.UpdateRange(areaComs); ctx.UpdateRange(areaComs);
await ctx.SaveChangesAsync(); await ctx.SaveChangesAsync();
} }
CancelAreaComs = false; CancelAreaComs = null;
if (newMgNr != m.MgNr) { if (newMgNr != m.MgNr) {
await ctx.Database.ExecuteSqlAsync($"UPDATE member SET mgnr = {newMgNr} WHERE mgnr = {oldMgNr}"); await ctx.Database.ExecuteSqlAsync($"UPDATE member SET mgnr = {newMgNr} WHERE mgnr = {oldMgNr}");
@ -1131,7 +1129,7 @@ namespace Elwig.Windows {
"Aktive Flächenbindungen übernehmen", MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No); "Aktive Flächenbindungen übernehmen", MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No);
if (res != MessageBoxResult.Yes) if (res != MessageBoxResult.Yes)
return; return;
TransferPredecessorAreaComs = true; TransferPredecessorAreaComs = Utils.FollowingSeason;
SetOriginalValue(PredecessorMgNrInput, -1); // hack to allow user to save SetOriginalValue(PredecessorMgNrInput, -1); // hack to allow user to save
UpdateButtons(); UpdateButtons();
} }
@ -1184,7 +1182,7 @@ namespace Elwig.Windows {
"übertragen werden sollen bitte \"Nein\" auswählen!\n\n" + "übertragen werden sollen bitte \"Nein\" auswählen!\n\n" +
"Die Änderungen werden erst beim Speichern übernommen!", "Die Änderungen werden erst beim Speichern übernommen!",
"Flächenbindungen kündigen", MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No); "Flächenbindungen kündigen", MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No);
CancelAreaComs = res == MessageBoxResult.Yes; CancelAreaComs = res == MessageBoxResult.Yes ? Utils.FollowingSeason - 1 : null;
} }
} }
CheckBox_Changed(sender, evt); CheckBox_Changed(sender, evt);

View File

@ -7,7 +7,7 @@
xmlns:local="clr-namespace:Elwig.Windows" xmlns:local="clr-namespace:Elwig.Windows"
xmlns:ctrl="clr-namespace:Elwig.Controls" xmlns:ctrl="clr-namespace:Elwig.Controls"
mc:Ignorable="d" mc:Ignorable="d"
Title="Auszahlungsvarianten - Elwig" Height="510" Width="820" MinHeight="500" MinWidth="820"> Title="Auszahlungsvarianten - Elwig" Height="450" Width="820" MinHeight="380" MinWidth="820">
<Window.Resources> <Window.Resources>
<Style TargetType="Label"> <Style TargetType="Label">
<Setter Property="HorizontalAlignment" Value="Left"/> <Setter Property="HorizontalAlignment" Value="Left"/>
@ -44,179 +44,215 @@
</Style> </Style>
</Window.Resources> </Window.Resources>
<Grid> <Grid>
<Grid.RowDefinitions>
<RowDefinition Height="19"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="24"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="320"/> <ColumnDefinition Width="320"/>
<ColumnDefinition Width="100"/> <ColumnDefinition Width="2.5*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="220"/>
</Grid.RowDefinitions>
<ListBox x:Name="PaymentVariantList" Margin="10,10,35,10" Grid.RowSpan="2" SelectionChanged="PaymentVariantList_SelectionChanged"> <Menu Grid.ColumnSpan="2" BorderThickness="0,0,0,1" BorderBrush="LightGray" Background="White">
<ListBox.ItemTemplate> <MenuItem Header="Variantendaten">
<DataTemplate> <MenuItem x:Name="Menu_SummaryShow" Header="...anzeigen (PDF)" IsEnabled="False"
<StackPanel Orientation="Horizontal"> Click="Menu_SummaryShow_Click" InputGestureText="Strg+P"/>
<TextBlock Text="{Binding Name}" Width="200"/> <MenuItem x:Name="Menu_SummarySave" Header="...speichern... (PDF)" IsEnabled="False"
<TextBlock Text="{Binding Date}" Width="60"/> Click="Menu_SummarySave_Click"/>
</StackPanel> <MenuItem x:Name="Menu_SummaryExport" Header="...speichern... (Excel)" IsEnabled="False"
</DataTemplate> Click="Menu_SummaryExport_Click"/>
</ListBox.ItemTemplate> <MenuItem x:Name="Menu_SummaryPrint" Header="...drucken" IsEnabled="False"
</ListBox> Click="Menu_SummaryPrint_Click" InputGestureText="Strg+Shift+P"/>
<Button x:Name="AddButton" Content="&#xF8AA;" FontFamily="Segoe MDL2 Assets" FontSize="11" Padding="0,1.5,0,0" ToolTip="Neue Auszahlungsvariante hinzufügen" </MenuItem>
VerticalAlignment="Center" HorizontalAlignment="Right" Width="25" Height="25" Margin="5,0,5,60" Grid.RowSpan="2" <MenuItem Header="Buchungsliste">
Click="AddButton_Click"/> <MenuItem x:Name="Menu_ExportSave" Header="...speichern... (Excel)" IsEnabled="False"
<Button x:Name="CopyButton" Content="&#xE8C8;" FontFamily="Segoe MDL2 Assets" FontSize="12" Padding="0,0,0,0" IsEnabled="False" ToolTip="Ausgewählte Auszahlungsvariante duplizieren" Click="Menu_ExportSave_Click" InputGestureText="Strg+L"/>
VerticalAlignment="Center" HorizontalAlignment="Right" Width="25" Height="25" Margin="5,0,5,0" Grid.RowSpan="2" </MenuItem>
Click="CopyButton_Click"/> <MenuItem Header="Überweisungsdaten">
<Button x:Name="DeleteButton" Content="&#xF8AB;" FontFamily="Segoe MDL2 Assets" FontSize="11" Padding="0,1.5,0,0" IsEnabled="False" ToolTip="Ausgewählte Auszahlungsvariante löschen" <MenuItem x:Name="Menu_EbicsSave" Header="...exportieren... (EBICS)" IsEnabled="False"
VerticalAlignment="Center" HorizontalAlignment="Right" Width="25" Height="25" Margin="5,60,5,0" Grid.RowSpan="2" Click="Menu_EbicsSave_Click" InputGestureText="Strg+Ü"/>
Click="DeleteButton_Click"/> </MenuItem>
</Menu>
<TextBox x:Name="DataInput" Margin="10,200,35,10" Grid.Column="0" Grid.RowSpan="2" <Grid Grid.Row="1">
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Height="auto" <ListBox x:Name="PaymentVariantList" Margin="10,10,35,10" Grid.RowSpan="2" SelectionChanged="PaymentVariantList_SelectionChanged">
AcceptsReturn="True" VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Auto" <ListBox.ItemTemplate>
FontFamily="Cascadia Code Light" FontSize="13" <DataTemplate>
TextChanged="DataInput_TextChanged"/> <StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" Width="200"/>
<TextBlock Text="{Binding Date}" Width="60"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button x:Name="AddButton" Content="&#xF8AA;" FontFamily="Segoe MDL2 Assets" FontSize="11" Padding="0,1.5,0,0" ToolTip="Neue Auszahlungsvariante hinzufügen"
VerticalAlignment="Center" HorizontalAlignment="Right" Width="25" Height="25" Margin="5,0,5,60" Grid.RowSpan="2"
Click="AddButton_Click"/>
<Button x:Name="CopyButton" Content="&#xE8C8;" FontFamily="Segoe MDL2 Assets" FontSize="12" Padding="0,0,0,0" IsEnabled="False" ToolTip="Ausgewählte Auszahlungsvariante duplizieren"
VerticalAlignment="Center" HorizontalAlignment="Right" Width="25" Height="25" Margin="5,0,5,0" Grid.RowSpan="2"
Click="CopyButton_Click"/>
<Button x:Name="DeleteButton" Content="&#xF8AB;" FontFamily="Segoe MDL2 Assets" FontSize="11" Padding="0,1.5,0,0" IsEnabled="False" ToolTip="Ausgewählte Auszahlungsvariante löschen"
VerticalAlignment="Center" HorizontalAlignment="Right" Width="25" Height="25" Margin="5,60,5,0" Grid.RowSpan="2"
Click="DeleteButton_Click"/>
<Label Content="Name:" Margin="10,10,0,0" Grid.Column="1"/> <TextBox x:Name="DataInput" Margin="10,200,35,10"
<TextBox x:Name="NameInput" Width="200" Grid.Column="2" HorizontalAlignment="Left" Margin="0,10,0,0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Height="auto"
TextChanged="NameInput_TextChanged"/> AcceptsReturn="True" VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Auto"
FontFamily="Cascadia Code Light" FontSize="13"
<Label Content="Beschreibung:" Margin="10,40,0,0" Grid.Column="1"/> TextChanged="DataInput_TextChanged"/>
<TextBox x:Name="CommentInput" Grid.Column="2" HorizontalAlignment="Stretch" Margin="0,40,10,0"
TextChanged="CommentInput_TextChanged"/>
<Label Content="Erstellt am:" Margin="10,70,0,0" Grid.Column="1"/>
<TextBox x:Name="DateInput" Grid.Column="2" Width="77" HorizontalAlignment="Left" Margin="0,70,10,0" IsReadOnly="True"/>
<Label Content="Überwiesen am:" Margin="10,100,0,0" Grid.Column="1"/>
<TextBox x:Name="TransferDateInput" Grid.Column="2" Width="77" HorizontalAlignment="Left" Margin="0,100,10,0"
TextChanged="TransferDateInput_TextChanged"/>
<Label Content="Rebelzuschlag:" Margin="10,130,0,0" Grid.Column="1"/>
<ctrl:UnitTextBox x:Name="WeightModifierInput" Grid.Column="2" Width="60" Margin="0,130,10,0" Unit="%"
HorizontalAlignment="Left" VerticalAlignment="Top"
TextChanged="WeightModifierInput_TextChanged" LostFocus="WeightModifierInput_LostFocus"/>
<Label Content="Berücksichtigen:" Margin="90,70,10,10" Grid.Column="2"/>
<CheckBox x:Name="ConsiderModifiersInput" Content="Zu-/Abschläge bei Lieferungen"
Margin="110,95,10,10" Grid.Column="2" HorizontalAlignment="Left" VerticalAlignment="Top"
Checked="ConsiderModifiersInput_Changed" Unchecked="ConsiderModifiersInput_Changed"/>
<CheckBox x:Name="ConsiderPenaltiesInput" Content="Pönalen bei Unterlieferungen (FB)"
Margin="110,115,10,10" Grid.Column="2" HorizontalAlignment="Left" VerticalAlignment="Top"
Checked="ConsiderPenaltiesInput_Changed" Unchecked="ConsiderPenaltiesInput_Changed"/>
<CheckBox x:Name="ConsiderPenaltyInput" Content="Strafen bei Unterlieferungen (GA)"
Margin="110,135,10,10" Grid.Column="2" HorizontalAlignment="Left" VerticalAlignment="Top"
Checked="ConsiderPenaltyInput_Changed" Unchecked="ConsiderPenaltyInput_Changed"/>
<CheckBox x:Name="ConsiderAutoInput" Content="Automatische Nachzeichnungen der GA"
Margin="110,155,10,10" Grid.Column="2" HorizontalAlignment="Left" VerticalAlignment="Top"
Checked="ConsiderAutoInput_Changed" Unchecked="ConsiderAutoInput_Changed"/>
<Label Content="&#xF0AE;" FontFamily="Segoe MDL2 Assets" FontSize="16" Grid.Row="0" Grid.Column="2" Margin="108,175,10,10"/>
<Grid Grid.Column="1" Grid.ColumnSpan="2" VerticalAlignment="Bottom" HorizontalAlignment="Center" Margin="10,10,10,10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="110"/>
<ColumnDefinition Width="27"/>
<ColumnDefinition Width="110"/>
<ColumnDefinition Width="27"/>
<ColumnDefinition Width="110"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="27"/>
<RowDefinition Height="5"/>
<RowDefinition Height="27"/>
</Grid.RowDefinitions>
<Grid.Resources>
<Style TargetType="Label">
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="Height" Value="auto"/>
</Style>
<Style TargetType="Button">
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="FontSize" Value="14"/>
</Style>
</Grid.Resources>
<Button x:Name="ModifierButton" Content="Zu-/Abschläge" Grid.Column="0" Grid.Row="0"
Click="ModifierButton_Click"/>
<Label Content="&#xF0AF;" FontFamily="Segoe MDL2 Assets" FontSize="16" Grid.Row="0" Grid.Column="1" RenderTransformOrigin="0.5,0.5" >
<Label.RenderTransform>
<TransformGroup>
<RotateTransform Angle="45"/>
<TranslateTransform Y="5"/>
</TransformGroup>
</Label.RenderTransform>
</Label>
<Button x:Name="EditButton" Content="Bearbeiten" Grid.Column="0" Grid.Row="2"
Click="EditButton_Click"/>
<Label Content="&#xF0AF;" FontFamily="Segoe MDL2 Assets" FontSize="16" Grid.Row="2" Grid.Column="1"/>
<Button x:Name="CalculateButton" Content="Berechnen" Grid.Column="2" Grid.Row="2"
Click="CalculateButton_Click"/>
<Label Content="&#xF0AF;" FontFamily="Segoe MDL2 Assets" FontSize="16" Grid.Row="2" Grid.Column="3" x:Name="Arrow3"/>
<Button x:Name="CommitButton" Content="Festsetzen" Grid.Column="4" Grid.Row="2"
Click="CommitButton_Click"/>
<Button x:Name="RevertButton" Content="Freigeben" Grid.Column="4" Grid.Row="2"
Click="RevertButton_Click"/>
<Button x:Name="SaveButton" Content="Speichern" Grid.Column="4" Grid.Row="0"
Click="SaveButton_Click"/>
</Grid> </Grid>
<Grid Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2"> <Grid Grid.Column="1" Grid.Row="1">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/>
<ColumnDefinition Width="250"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<GroupBox Header="Abschluss" Margin="10,0,5,10"> <Label Content="Name:" Margin="10,10,0,0" Grid.Column="0"/>
<Grid> <TextBox x:Name="NameInput" Width="200" Grid.Column="1" HorizontalAlignment="Left" Margin="0,10,0,0"
<Button x:Name="ExportButton" Content="Exportieren" FontSize="14" Width="180" Margin="10,10,10,10" Height="27" IsEnabled="False" TextChanged="NameInput_TextChanged"/>
Click="ExportButton_Click"
VerticalAlignment="Top" HorizontalAlignment="Left"/>
<Button x:Name="TransactionButton" Content="Buchungsliste" FontSize="14" Width="180" Margin="10,42,10,10" Height="27" IsEnabled="False"
Click="TransactionButton_Click"
VerticalAlignment="Top" HorizontalAlignment="Left"/>
<Button x:Name="MailButton" Content="Traubengutschriften" FontSize="14" Width="180" Margin="10,74,10,10" Height="27" IsEnabled="False"
Click="MailButton_Click"
VerticalAlignment="Top" HorizontalAlignment="Left"/>
</Grid>
</GroupBox>
<GroupBox Header="Ergebnis" Margin="5,0,10,10" Grid.Column="1"> <Label Content="Beschreibung:" Margin="10,40,0,0" Grid.Column="0"/>
<Grid> <TextBox x:Name="CommentInput" Grid.Column="1" HorizontalAlignment="Stretch" Margin="0,40,10,0"
<Grid.ColumnDefinitions> TextChanged="CommentInput_TextChanged"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.Resources>
<Style TargetType="TextBlock">
<Setter Property="Grid.Column" Value="1"/>
<Setter Property="VerticalAlignment" Value="Top"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="TextAlignment" Value="Right"/>
</Style>
</Grid.Resources>
<Label Content="Zu-/Abschläge:" Margin="10,10,0,0"/> <Label Content="Erstellt am:" Margin="10,70,0,0" Grid.Column="0"/>
<TextBlock x:Name="ModifierSum" Margin="0,12,10,0"/> <TextBox x:Name="DateInput" Grid.Column="1" Width="77" HorizontalAlignment="Left" Margin="0,70,10,0" IsReadOnly="True"/>
<Label Content="Gesamtbeträge:" Margin="10,40,0,0"/> <Label Content="Überwiesen am:" Margin="10,100,0,0" Grid.Column="0"/>
<TextBlock x:Name="TotalSum" Margin="0,42,10,0"/> <TextBox x:Name="TransferDateInput" Grid.Column="1" Width="77" HorizontalAlignment="Left" Margin="0,100,10,0"
TextChanged="TransferDateInput_TextChanged"/>
<Label Content="Mehrwertsteuer:" Margin="10,70,0,0"/> <Label Content="Rebelzuschlag:" Margin="10,130,0,0" Grid.Column="0"/>
<TextBlock x:Name="VatSum" Margin="0,72,10,0"/> <ctrl:UnitTextBox x:Name="WeightModifierInput" Grid.Column="1" Width="60" Margin="0,130,10,0" Unit="%"
HorizontalAlignment="Left" VerticalAlignment="Top"
TextChanged="WeightModifierInput_TextChanged" LostFocus="WeightModifierInput_LostFocus"/>
<Label Content="Abzüge:" Margin="10,100,0,0"/> <Label Content="Berücksichtigen:" Margin="90,70,10,10" Grid.Column="1"/>
<TextBlock x:Name="DeductionSum" Margin="0,102,10,0"/> <CheckBox x:Name="ConsiderModifiersInput" Content="Zu-/Abschläge bei Lieferungen"
Margin="110,95,10,10" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Top"
Checked="ConsiderModifiersInput_Changed" Unchecked="ConsiderModifiersInput_Changed"/>
<CheckBox x:Name="ConsiderPenaltiesInput" Content="Pönalen bei Unterlieferungen (FB)"
Margin="110,115,10,10" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Top"
Checked="ConsiderPenaltiesInput_Changed" Unchecked="ConsiderPenaltiesInput_Changed"/>
<CheckBox x:Name="ConsiderPenaltyInput" Content="Strafen bei Unterlieferungen (GA)"
Margin="110,135,10,10" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Top"
Checked="ConsiderPenaltyInput_Changed" Unchecked="ConsiderPenaltyInput_Changed"/>
<CheckBox x:Name="ConsiderAutoInput" Content="Automatische Nachzeichnungen der GA"
Margin="110,155,10,10" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Top"
Checked="ConsiderAutoInput_Changed" Unchecked="ConsiderAutoInput_Changed"/>
<Label Content="&#xF0AE;" FontFamily="Segoe MDL2 Assets" FontSize="16" Grid.Row="0" Grid.Column="1" Margin="108,175,10,10"/>
<Label Content="Auszuzahlen:" Margin="10,130,0,0"/> <Grid Grid.Column="0" Grid.ColumnSpan="2" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="50,180,10,10">
<TextBlock x:Name="PaymentSum" Margin="0,132,10,0"/> <Grid.ColumnDefinitions>
</Grid> <ColumnDefinition Width="110"/>
</GroupBox> <ColumnDefinition Width="27"/>
<ColumnDefinition Width="110"/>
<ColumnDefinition Width="27"/>
<ColumnDefinition Width="110"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="27"/>
<RowDefinition Height="5"/>
<RowDefinition Height="27"/>
</Grid.RowDefinitions>
<Grid.Resources>
<Style TargetType="Label">
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="Height" Value="auto"/>
</Style>
<Style TargetType="Button">
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="FontSize" Value="14"/>
</Style>
</Grid.Resources>
<Button x:Name="ModifierButton" Content="Zu-/Abschläge" Grid.Column="0" Grid.Row="0"
Click="ModifierButton_Click"/>
<Label Content="&#xF0AF;" FontFamily="Segoe MDL2 Assets" FontSize="16" Grid.Row="0" Grid.Column="1" RenderTransformOrigin="0.5,0.5" >
<Label.RenderTransform>
<TransformGroup>
<RotateTransform Angle="45"/>
<TranslateTransform Y="5"/>
</TransformGroup>
</Label.RenderTransform>
</Label>
<Button x:Name="EditButton" Content="Bearbeiten" Grid.Column="0" Grid.Row="2"
Click="EditButton_Click"/>
<Label Content="&#xF0AF;" FontFamily="Segoe MDL2 Assets" FontSize="16" Grid.Row="2" Grid.Column="1"/>
<Button x:Name="CalculateButton" Content="Berechnen" Grid.Column="2" Grid.Row="2"
Click="CalculateButton_Click"/>
<Label Content="&#xF0AF;" FontFamily="Segoe MDL2 Assets" FontSize="16" Grid.Row="2" Grid.Column="3" x:Name="Arrow3"/>
<Button x:Name="CommitButton" Content="Festsetzen" Grid.Column="4" Grid.Row="2"
Click="CommitButton_Click"/>
<Button x:Name="RevertButton" Content="Freigeben" Grid.Column="4" Grid.Row="2"
Click="RevertButton_Click"/>
<Button x:Name="SaveButton" Content="Speichern" Grid.Column="4" Grid.Row="0"
Click="SaveButton_Click"/>
</Grid>
<Button x:Name="MailButton" Content="Traubengutschriften"
FontSize="14" Width="160" Margin="10,10,10,10" Height="27" IsEnabled="False"
Click="MailButton_Click"
VerticalAlignment="Bottom" HorizontalAlignment="Right" Grid.Column="1"/>
</Grid> </Grid>
<StatusBar Grid.Row="2" Grid.ColumnSpan="2" BorderThickness="0,1,0,0" BorderBrush="Gray">
<StatusBar.ItemsPanel>
<ItemsPanelTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
</StatusBar.ItemsPanel>
<StatusBarItem Grid.Column="0" HorizontalContentAlignment="Stretch">
<DockPanel>
<TextBlock Text="Zu-/Abschl.:"/>
<TextBlock x:Name="ModifierSum" Text="-" TextAlignment="Right"/>
</DockPanel>
</StatusBarItem>
<Separator Grid.Column="1"/>
<StatusBarItem Grid.Column="2" HorizontalContentAlignment="Stretch">
<DockPanel>
<TextBlock Text="Gesamt:"/>
<TextBlock x:Name="TotalSum" Text="-" TextAlignment="Right"/>
</DockPanel>
</StatusBarItem>
<Separator Grid.Column="3"/>
<StatusBarItem Grid.Column="4" HorizontalContentAlignment="Stretch">
<DockPanel>
<TextBlock Text="MwSt.:"/>
<TextBlock x:Name="VatSum" Text="-" TextAlignment="Right"/>
</DockPanel>
</StatusBarItem>
<Separator Grid.Column="5"/>
<StatusBarItem Grid.Column="6" HorizontalContentAlignment="Stretch">
<DockPanel>
<TextBlock Text="Abzüge:"/>
<TextBlock x:Name="DeductionSum" Text="-" TextAlignment="Right"/>
</DockPanel>
</StatusBarItem>
<Separator Grid.Column="7"/>
<StatusBarItem Grid.Column="8" HorizontalContentAlignment="Stretch">
<DockPanel>
<TextBlock Text="Auszahl.:"/>
<TextBlock x:Name="PaymentSum" Text="-" TextAlignment="Right"/>
</DockPanel>
</StatusBarItem>
</StatusBar>
</Grid> </Grid>
</local:ContextWindow> </local:ContextWindow>

View File

@ -12,6 +12,7 @@ using Elwig.Helpers.Billing;
using Elwig.Helpers.Export; using Elwig.Helpers.Export;
using Microsoft.Win32; using Microsoft.Win32;
using System.Text.Json; using System.Text.Json;
using Elwig.Documents;
namespace Elwig.Windows { namespace Elwig.Windows {
public partial class PaymentVariantsWindow : ContextWindow { public partial class PaymentVariantsWindow : ContextWindow {
@ -24,8 +25,17 @@ namespace Elwig.Windows {
private static readonly JsonSerializerOptions JsonOpt = new() { WriteIndented = true }; private static readonly JsonSerializerOptions JsonOpt = new() { WriteIndented = true };
private readonly RoutedCommand CtrlL = new("CtrlL", typeof(MemberAdminWindow), [new KeyGesture(Key.L, ModifierKeys.Control)]);
private readonly RoutedCommand CtrlP = new("CtrlP", typeof(MemberAdminWindow), [new KeyGesture(Key.P, ModifierKeys.Control)]);
private readonly RoutedCommand CtrlÜ = new("CtrlÜ", typeof(MemberAdminWindow), [new KeyGesture(Key.Oem1, ModifierKeys.Control)]);
private readonly RoutedCommand CtrlShiftP = new("CtrlShiftP", typeof(MemberAdminWindow), [new KeyGesture(Key.P, ModifierKeys.Control | ModifierKeys.Shift)]);
public PaymentVariantsWindow(int year) { public PaymentVariantsWindow(int year) {
InitializeComponent(); InitializeComponent();
CommandBindings.Add(new CommandBinding(CtrlL, Menu_ExportSave_Click));
CommandBindings.Add(new CommandBinding(CtrlP, Menu_SummaryShow_Click));
CommandBindings.Add(new CommandBinding(CtrlÜ, Menu_EbicsSave_Click));
CommandBindings.Add(new CommandBinding(CtrlShiftP, Menu_SummaryPrint_Click));
Year = year; Year = year;
using (var ctx = new AppDbContext()) { using (var ctx = new AppDbContext()) {
SeasonLocked = ctx.Seasons.Find(Year + 1) != null; SeasonLocked = ctx.Seasons.Find(Year + 1) != null;
@ -60,8 +70,12 @@ namespace Elwig.Windows {
EditButton.IsEnabled = true; EditButton.IsEnabled = true;
SaveButton.IsEnabled = !locked; SaveButton.IsEnabled = !locked;
MailButton.IsEnabled = true; MailButton.IsEnabled = true;
ExportButton.IsEnabled = locked; Menu_ExportSave.IsEnabled = locked;
TransactionButton.IsEnabled = locked; Menu_EbicsSave.IsEnabled = locked;
Menu_SummaryExport.IsEnabled = true;
Menu_SummaryShow.IsEnabled = true;
Menu_SummarySave.IsEnabled = true;
Menu_SummaryPrint.IsEnabled = true;
NameInput.Text = v.Name; NameInput.Text = v.Name;
NameInput.IsReadOnly = false; NameInput.IsReadOnly = false;
@ -113,8 +127,12 @@ namespace Elwig.Windows {
Arrow3.Content = "\xF0AF"; Arrow3.Content = "\xF0AF";
DeleteButton.IsEnabled = false; DeleteButton.IsEnabled = false;
MailButton.IsEnabled = false; MailButton.IsEnabled = false;
ExportButton.IsEnabled = false; Menu_ExportSave.IsEnabled = false;
TransactionButton.IsEnabled = false; Menu_EbicsSave.IsEnabled = false;
Menu_SummaryExport.IsEnabled = false;
Menu_SummaryShow.IsEnabled = false;
Menu_SummarySave.IsEnabled = false;
Menu_SummaryPrint.IsEnabled = false;
BillingData = null; BillingData = null;
NameInput.Text = ""; NameInput.Text = "";
@ -158,7 +176,7 @@ namespace Elwig.Windows {
private async Task UpdateSums() { private async Task UpdateSums() {
if (PaymentVariantList.SelectedItem is PaymentVar v) { if (PaymentVariantList.SelectedItem is PaymentVar v) {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
var sym = v.Season.Currency.Symbol; var sym = v.Season.Currency.Symbol ?? v.Season.Currency.Code;
var modSum = await ctx.PaymentDeliveryParts var modSum = await ctx.PaymentDeliveryParts
.Where(p => p.Year == v.Year && p.AvNr == v.AvNr) .Where(p => p.Year == v.Year && p.AvNr == v.AvNr)
.SumAsync(p => p.AmountValue - p.NetAmountValue); .SumAsync(p => p.AmountValue - p.NetAmountValue);
@ -173,9 +191,11 @@ namespace Elwig.Windows {
DeductionSum.Text = $"- {sym}"; DeductionSum.Text = $"- {sym}";
PaymentSum.Text = $"- {sym}"; PaymentSum.Text = $"- {sym}";
} else { } else {
VatSum.Text = $"{v.Season.DecFromDb(await credits.SumAsync(c => c.VatAmountValue)):N2} {sym}"; // all values in the credit table are stored with precision 2!
DeductionSum.Text = $"{-v.Season.DecFromDb(await credits.SumAsync(c => c.ModifiersValue ?? 0)):N2} {sym}"; TotalSum.Text = $"{Utils.DecFromDb(await credits.SumAsync(c => c.NetAmountValue), 2):N2} {sym}";
PaymentSum.Text = $"{v.Season.DecFromDb(await credits.SumAsync(c => c.AmountValue)):N2} {sym}"; VatSum.Text = $"{Utils.DecFromDb(await credits.SumAsync(c => c.VatAmountValue), 2):N2} {sym}";
DeductionSum.Text = $"{-Utils.DecFromDb(await credits.SumAsync(c => c.ModifiersValue ?? 0), 2):N2} {sym}";
PaymentSum.Text = $"{Utils.DecFromDb(await credits.SumAsync(c => c.AmountValue), 2):N2} {sym}";
} }
} else { } else {
ModifierSum.Text = "-"; ModifierSum.Text = "-";
@ -254,7 +274,7 @@ namespace Elwig.Windows {
} }
private async void CalculateButton_Click(object sender, RoutedEventArgs evt) { private async void CalculateButton_Click(object sender, RoutedEventArgs evt) {
if (PaymentVariantList.SelectedValue is not PaymentVar v) if (PaymentVariantList.SelectedItem is not PaymentVar v)
return; return;
CalculateButton.IsEnabled = false; CalculateButton.IsEnabled = false;
Mouse.OverrideCursor = Cursors.AppStarting; Mouse.OverrideCursor = Cursors.AppStarting;
@ -288,8 +308,62 @@ namespace Elwig.Windows {
w.AddCreditNote(Array.IndexOf(vars, pv.AvNr)); w.AddCreditNote(Array.IndexOf(vars, pv.AvNr));
} }
private async void Menu_SummaryExport_Click(object sender, RoutedEventArgs evt) {
if (PaymentVariantList.SelectedItem is not PaymentVar v)
return;
var d = new SaveFileDialog() {
FileName = $"Variantendaten-{v.Name.Trim().Replace(' ', '-')}.ods",
DefaultExt = "ods",
Filter = "OpenDocument Format Spreadsheet (*.ods)|*.ods",
Title = $"Variantendaten {v.Name} speichern unter - Elwig"
};
if (d.ShowDialog() == false)
return;
Mouse.OverrideCursor = Cursors.AppStarting;
try {
using var ctx = new AppDbContext();
var data = await PaymentVariantSummaryData.ForPaymentVariant(v, ctx.PaymentVariantSummaryRows);
using var ods = new OdsFile(d.FileName);
await ods.AddTable(data);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = null;
}
private async void Menu_SummaryShow_Click(object sender, RoutedEventArgs evt) {
if (PaymentVariantList.SelectedItem is not PaymentVar v)
return;
await GenerateSummary(v, ExportMode.Show);
}
private async void Menu_SummarySave_Click(object sender, RoutedEventArgs evt) {
if (PaymentVariantList.SelectedItem is not PaymentVar v)
return;
await GenerateSummary(v, ExportMode.SavePdf);
}
private async void Menu_SummaryPrint_Click(object sender, RoutedEventArgs evt) {
if (PaymentVariantList.SelectedItem is not PaymentVar v)
return;
await GenerateSummary(v, ExportMode.Print);
}
private static async Task GenerateSummary(PaymentVar v, ExportMode mode) {
Mouse.OverrideCursor = Cursors.AppStarting;
try {
using var ctx = new AppDbContext();
var data = await PaymentVariantSummaryData.ForPaymentVariant(v, ctx.PaymentVariantSummaryRows);
using var doc = new PaymentVariantSummary((await ctx.PaymentVariants.FindAsync(v.Year, v.AvNr))!, data);
await Utils.ExportDocument(doc, mode);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
Mouse.OverrideCursor = null;
}
private async void CommitButton_Click(object sender, RoutedEventArgs evt) { private async void CommitButton_Click(object sender, RoutedEventArgs evt) {
if (PaymentVariantList.SelectedValue is not PaymentVar v) if (PaymentVariantList.SelectedItem is not PaymentVar v)
return; return;
CommitButton.IsEnabled = false; CommitButton.IsEnabled = false;
Mouse.OverrideCursor = Cursors.AppStarting; Mouse.OverrideCursor = Cursors.AppStarting;
@ -305,7 +379,7 @@ namespace Elwig.Windows {
} }
private async void RevertButton_Click(object sender, RoutedEventArgs evt) { private async void RevertButton_Click(object sender, RoutedEventArgs evt) {
if (PaymentVariantList.SelectedValue is not PaymentVar v) if (PaymentVariantList.SelectedItem is not PaymentVar v)
return; return;
var res = MessageBox.Show( var res = MessageBox.Show(
"Sollen wirklich alle festgesetzten Traubengutschriften der ausgewählten Auszahlungsvariante unwiderruflich gelöscht werden?\n\n" + "Sollen wirklich alle festgesetzten Traubengutschriften der ausgewählten Auszahlungsvariante unwiderruflich gelöscht werden?\n\n" +
@ -322,14 +396,17 @@ namespace Elwig.Windows {
CommitButton.IsEnabled = true; CommitButton.IsEnabled = true;
} }
private async void ExportButton_Click(object sender, RoutedEventArgs evt) { private async void Menu_EbicsSave_Click(object sender, RoutedEventArgs evt) {
if (PaymentVariantList.SelectedValue is not PaymentVar v) { if (PaymentVariantList.SelectedItem is not PaymentVar v) {
return; return;
} else if (v.TransferDate == null) { } else if (v.TransferDate == null) {
MessageBox.Show("Überweisungsdatum muss gesetzt sein!", "Exportieren nicht möglich", MessageBoxButton.OK, MessageBoxImage.Error); MessageBox.Show("Überweisungsdatum muss gesetzt sein!", "Exportieren nicht möglich", MessageBoxButton.OK, MessageBoxImage.Error);
return; return;
} }
using var ctx = new AppDbContext();
v = (await ctx.PaymentVariants.FindAsync(v.Year, v.AvNr))!;
var withoutIban = v.Credits.Count(c => c.Member.Iban == null); var withoutIban = v.Credits.Count(c => c.Member.Iban == null);
if (withoutIban > 0) { if (withoutIban > 0) {
var r = MessageBox.Show($"Achtung: Für {withoutIban} Mitglieder ist kein IBAN hinterlegt.\nDiese werden NICHT exportiert.", var r = MessageBox.Show($"Achtung: Für {withoutIban} Mitglieder ist kein IBAN hinterlegt.\nDiese werden NICHT exportiert.",
@ -344,7 +421,7 @@ namespace Elwig.Windows {
Title = $"Überweisungsdaten speichern unter - Elwig", Title = $"Überweisungsdaten speichern unter - Elwig",
}; };
if (d.ShowDialog() == true) { if (d.ShowDialog() == true) {
ExportButton.IsEnabled = false; Menu_EbicsSave.IsEnabled = false;
Mouse.OverrideCursor = Cursors.AppStarting; Mouse.OverrideCursor = Cursors.AppStarting;
try { try {
using var e = new Ebics(v, d.FileName, 9); using var e = new Ebics(v, d.FileName, 9);
@ -353,12 +430,12 @@ namespace Elwig.Windows {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
} }
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
ExportButton.IsEnabled = true; Menu_EbicsSave.IsEnabled = true;
} }
} }
private async void TransactionButton_Click(object sender, RoutedEventArgs evt) { private async void Menu_ExportSave_Click(object sender, RoutedEventArgs evt) {
if (PaymentVariantList.SelectedValue is not PaymentVar v) { if (PaymentVariantList.SelectedItem is not PaymentVar v) {
return; return;
} }
var d = new SaveFileDialog() { var d = new SaveFileDialog() {
@ -368,7 +445,7 @@ namespace Elwig.Windows {
Title = $"Buchungsliste speichern unter - Elwig" Title = $"Buchungsliste speichern unter - Elwig"
}; };
if (d.ShowDialog() == true) { if (d.ShowDialog() == true) {
TransactionButton.IsEnabled = false; Menu_ExportSave.IsEnabled = false;
Mouse.OverrideCursor = Cursors.AppStarting; Mouse.OverrideCursor = Cursors.AppStarting;
try { try {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
@ -379,7 +456,7 @@ namespace Elwig.Windows {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error); MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
} }
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
TransactionButton.IsEnabled = true; Menu_ExportSave.IsEnabled = true;
} }
} }

View File

@ -1,5 +1,5 @@
::mkdir "C:\Program Files\Elwig" ::mkdir "C:\Program Files\Elwig"
::curl -s -L "http://www.columbia.edu/~em36/PDFtoPrinter.exe" -z "C:\Program Files\Elwig\PDFtoPrinter.exe" -o "C:\Program Files\Elwig\PDFtoPrinter.exe" ::curl -s -L "https://github.com/emendelson/pdftoprinter/raw/main/PDFtoPrinter.exe" -z "C:\Program Files\Elwig\PDFtoPrinter.exe" -o "C:\Program Files\Elwig\PDFtoPrinter.exe"
mkdir "C:\ProgramData\Elwig\resources" mkdir "C:\ProgramData\Elwig\resources"
copy /b /y Documents\*.css "C:\ProgramData\Elwig\resources" copy /b /y Documents\*.css "C:\ProgramData\Elwig\resources"
copy /b /y Documents\*.cshtml "C:\ProgramData\Elwig\resources" copy /b /y Documents\*.cshtml "C:\ProgramData\Elwig\resources"

View File

@ -1,50 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:wix="http://wixtoolset.org/schemas/v4/wxs"
xmlns="http://wixtoolset.org/schemas/v4/wxs"
version="1.0"
exclude-result-prefixes="xsl wix">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />
<xsl:strip-space elements="*" />
<!--
Find all <Component> elements with <File> elements with Source="" attributes ending in ".exe" and tag it with the "ExeToRemove" key.
<Component Id="cmpSYYKP6B1M7WSD5KLEQ7PZW4YLOPYG61L" Directory="INSTALLDIR" Guid="*">
<File Id="filKUS7ZRMJ0AOKDU6ATYY6IRUSR2ECPDFO" KeyPath="yes" Source="!(wix.StagingAreaPath)\ProofOfPEqualsNP.exe" />
</Component>
Because WiX's Heat.exe only supports XSLT 1.0 and not XSLT 2.0 we cannot use `ends-with( haystack, needle )` (e.g. `ends-with( wix:File/@Source, '.exe' )`...
...but we can use this longer `substring` expression instead (see https://github.com/wixtoolset/issues/issues/5609 )
-->
<xsl:key
name="ExeToRemove"
match="wix:Component[ substring( wix:File/@Source, string-length( wix:File/@Source ) - 3 ) = '.exe' ]"
use="@Id"
/>
<!-- Get the last 4 characters of a string using `substring( s, len(s) - 3 )`, it uses -3 and not -4 because XSLT uses 1-based indexes, not 0-based indexes. -->
<!-- We can also remove .pdb files too, for example: -->
<xsl:key
name="PdbToRemove"
match="wix:Component[ substring( wix:File/@Source, string-length( wix:File/@Source ) - 3 ) = '.pdb' ]"
use="@Id"
/>
<!-- By default, copy all elements and nodes into the output... -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<!-- ...but if the element has the "ExeToRemove" key then don't render anything (i.e. removing it from the output) -->
<xsl:template match="*[ self::wix:Component or self::wix:ComponentRef ][ key( 'ExeToRemove', @Id ) ]" />
<xsl:template match="*[ self::wix:Component or self::wix:ComponentRef ][ key( 'PdbToRemove', @Id ) ]" />
</xsl:stylesheet>

View File

@ -1,41 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:wix="http://wixtoolset.org/schemas/v4/wxs"
xmlns="http://wixtoolset.org/schemas/v4/wxs"
version="1.0"
exclude-result-prefixes="xsl wix">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />
<xsl:strip-space elements="*" />
<!--
Find all <Component> elements with <File> elements with Source="" attributes ending in ".exe" and tag it with the "ExeToRemove" key.
<Component Id="cmpSYYKP6B1M7WSD5KLEQ7PZW4YLOPYG61L" Directory="INSTALLDIR" Guid="*">
<File Id="filKUS7ZRMJ0AOKDU6ATYY6IRUSR2ECPDFO" KeyPath="yes" Source="!(wix.StagingAreaPath)\ProofOfPEqualsNP.exe" />
</Component>
Because WiX's Heat.exe only supports XSLT 1.0 and not XSLT 2.0 we cannot use `ends-with( haystack, needle )` (e.g. `ends-with( wix:File/@Source, '.exe' )`...
...but we can use this longer `substring` expression instead (see https://github.com/wixtoolset/issues/issues/5609 )
-->
<xsl:key
name="FileToRemove"
match="wix:Component[ substring( wix:File/@Source, string-length( wix:File/@Source ) - 2 ) = '.cs' ]"
use="@Id"
/>
<!-- Get the last 3 characters of a string using `substring( s, len(s) - 2 )`, it uses -2 and not -3 because XSLT uses 1-based indexes, not 0-based indexes. -->
<!-- By default, copy all elements and nodes into the output... -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<!-- ...but if the element has the "ExeToRemove" key then don't render anything (i.e. removing it from the output) -->
<xsl:template match="*[ self::wix:Component or self::wix:ComponentRef ][ key( 'FileToRemove', @Id ) ]" />
</xsl:stylesheet>

View File

@ -2,7 +2,7 @@
<Fragment> <Fragment>
<!-- C:\Program Files (x86)\Elwig oder C:\Program Files\Elwig --> <!-- C:\Program Files (x86)\Elwig oder C:\Program Files\Elwig -->
<StandardDirectory Id="ProgramFiles64Folder"> <StandardDirectory Id="ProgramFiles64Folder">
<Directory Id="InstallFolder" Name="!(bind.Property.ProductName)" /> <Directory Id="InstallFolder" Name="!(bind.Property.ProductName)" />
</StandardDirectory> </StandardDirectory>
<!-- C:\ProgramData\Elwig --> <!-- C:\ProgramData\Elwig -->

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
<Fragment>
<ComponentGroup Id="HeatComponents">
<Files Directory="InstallFolder" Include="..\Elwig\bin\Publish\**">
<Exclude Files="..\Elwig\bin\Publish\**.exe" />
<Exclude Files="..\Elwig\bin\Publish\**.pdb" />
</Files>
<Files Directory="ConfigFolderResources" Include="..\Elwig\Documents\**">
<Exclude Files="..\Elwig\Documents\**.cs" />
</Files>
</ComponentGroup>
</Fragment>
</Wix>

View File

@ -1,4 +1,4 @@
<Project Sdk="WixToolset.Sdk/4.0.1"> <Project Sdk="WixToolset.Sdk/5.0.0">
<PropertyGroup> <PropertyGroup>
<HarvestFileSuppressUniqueIds>false</HarvestFileSuppressUniqueIds> <HarvestFileSuppressUniqueIds>false</HarvestFileSuppressUniqueIds>
<HarvestFileGenerateGuidsNow>true</HarvestFileGenerateGuidsNow> <HarvestFileGenerateGuidsNow>true</HarvestFileGenerateGuidsNow>
@ -25,7 +25,7 @@
</Task> </Task>
</UsingTask> </UsingTask>
<Target Name="CustomBeforeBuild" BeforeTargets="BeforeBuild"> <Target Name="CustomBeforeBuild" BeforeTargets="BeforeBuild">
<Exec Command="curl -s -L &quot;http://www.columbia.edu/~em36/PDFtoPrinter.exe&quot; -z &quot;$(ProjectDir)\Files\PDFtoPrinter.exe&quot; -o &quot;$(ProjectDir)\Files\PDFtoPrinter.exe&quot;" /> <Exec Command="curl -s -L &quot;https://github.com/emendelson/pdftoprinter/raw/main/PDFtoPrinter.exe&quot; -z &quot;$(ProjectDir)\Files\PDFtoPrinter.exe&quot; -o &quot;$(ProjectDir)\Files\PDFtoPrinter.exe&quot;" />
<Exec Command="dotnet publish &quot;$(ProjectDir)\..\Elwig\Elwig.csproj&quot; &quot;/p:PublishProfile=$(ProjectDir)\..\Elwig\Properties\PublishProfiles\FolderProfile.pubxml&quot;" /> <Exec Command="dotnet publish &quot;$(ProjectDir)\..\Elwig\Elwig.csproj&quot; &quot;/p:PublishProfile=$(ProjectDir)\..\Elwig\Properties\PublishProfiles\FolderProfile.pubxml&quot;" />
<GetFileVersion AssemblyPath="..\Elwig\bin\Publish\Elwig.exe"> <GetFileVersion AssemblyPath="..\Elwig\bin\Publish\Elwig.exe">
<Output TaskParameter="Version" PropertyName="ElwigFileVersion" /> <Output TaskParameter="Version" PropertyName="ElwigFileVersion" />
@ -35,31 +35,8 @@
</PropertyGroup> </PropertyGroup>
</Target> </Target>
<ItemGroup> <ItemGroup>
<HarvestDirectory Include="../Elwig/bin/Publish">
<ComponentGroupName>BuildFiles</ComponentGroupName>
<DirectoryRefId>InstallFolder</DirectoryRefId>
<SuppressRootDirectory>true</SuppressRootDirectory>
<PreprocessorVariable>BuildPath</PreprocessorVariable>
<Transforms>BuildFilesTransform.xslt</Transforms>
</HarvestDirectory>
<BindPath BindName="BuildBindPath" Include="../Elwig/bin/Publish" />
</ItemGroup>
<ItemGroup>
<HarvestDirectory Include="../Elwig/Documents">
<ComponentGroupName>DocumentTemplates</ComponentGroupName>
<DirectoryRefId>ConfigFolderResources</DirectoryRefId>
<SuppressRootDirectory>true</SuppressRootDirectory>
<PreprocessorVariable>DocumentPath</PreprocessorVariable>
<Transforms>DocumentTransform.xslt</Transforms>
</HarvestDirectory>
<BindPath BindName="DocumentTemplateBindPath" Include="../Elwig/Documents" />
</ItemGroup>
<ItemGroup>
<None Include="DocumentTransform.xslt" />
<None Include="BuildFilesTransform.xslt" />
<None Include="Files\config.ini" /> <None Include="Files\config.ini" />
</ItemGroup> <None Include="Files\PDFtoPrinter.exe" />
<ItemGroup> <None Include="Files\WinziPrint.exe" />
<PackageReference Include="WixToolset.Heat" Version="5.0.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -9,8 +9,7 @@
<Feature Id="Main"> <Feature Id="Main">
<ComponentGroupRef Id="ShortcutComponents"/> <ComponentGroupRef Id="ShortcutComponents"/>
<ComponentGroupRef Id="MainComponents"/> <ComponentGroupRef Id="MainComponents"/>
<ComponentGroupRef Id="BuildFiles"/> <ComponentGroupRef Id="HeatComponents"/>
<ComponentGroupRef Id="DocumentTemplates"/>
</Feature> </Feature>
</Package> </Package>
</Wix> </Wix>

View File

@ -2,7 +2,7 @@
<Bundle Name="Elwig" Manufacturer="Elwig" Version="!(bind.packageVersion.ElwigMsi)" UpgradeCode="f3c8fcab-c37c-43aa-9ab8-e42f4bb518b7" <Bundle Name="Elwig" Manufacturer="Elwig" Version="!(bind.packageVersion.ElwigMsi)" UpgradeCode="f3c8fcab-c37c-43aa-9ab8-e42f4bb518b7"
IconSourceFile="$(var.ElwigProjectDir)\Resources\Images\Elwig.ico"> IconSourceFile="$(var.ElwigProjectDir)\Resources\Images\Elwig.ico">
<BootstrapperApplication> <BootstrapperApplication>
<bal:WixStandardBootstrapperApplication LicenseUrl="" Theme="hyperlinkLicense" LogoFile="$(var.ElwigProjectDir)\Resources\Images\Elwig.png" <bal:WixStandardBootstrapperApplication LocalizationFile="HyperlinkTheme.wxl" LicenseUrl="" Theme="hyperlinkLicense" LogoFile="$(var.ElwigProjectDir)\Resources\Images\Elwig.png"
SuppressOptionsUI="yes" ShowVersion="yes"/> SuppressOptionsUI="yes" ShowVersion="yes"/>
</BootstrapperApplication> </BootstrapperApplication>

76
Setup/HyperlinkTheme.wxl Normal file
View File

@ -0,0 +1,76 @@
<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
<!--
https://github.com/wixtoolset/wix/blob/f9569df0316d0ee4b0564eb900154cdca50a75f0/src/ext/Bal/stdbas/Resources/1031/wixpreq.wxl
https://github.com/wixtoolset/wix/blob/f9569df0316d0ee4b0564eb900154cdca50a75f0/src/ext/Bal/stdbas/Resources/wixpreq.wxl
https://github.com/wixtoolset/wix/blob/f9569df0316d0ee4b0564eb900154cdca50a75f0/src/ext/Bal/stdbas/Resources/HyperlinkTheme.xml
https://github.com/wixtoolset/wix/blob/f9569df0316d0ee4b0564eb900154cdca50a75f0/src/ext/Bal/stdbas/Resources/HyperlinkTheme.wxl
-->
<WixLocalization Culture="de-at" Language="3079" xmlns="http://wixtoolset.org/schemas/v4/wxl">
<String Id="Caption" Value="[WixBundleName]-Setup" />
<String Id="Title" Value="[WixBundleName]" />
<String Id="CheckingForUpdatesLabel" Value="Auf Updates überprüfen" />
<String Id="UpdateButton" Value="&amp;Update auf Version [WixStdBAUpdateAvailable]" />
<String Id="InstallHeader" Value="Willkommen" />
<String Id="InstallMessage" Value="Das Setup wird [WixBundleName] auf dem Computer installieren. Klicken Sie Installieren um fortzufahren oder Abbrechen um den Vorgang zu vorzeitig beenden." />
<String Id="InstallMessageOptions" Value="Das Setup wird [WixBundleName] auf dem Computer installieren. Klicken Sie Installieren um fortzufahren, Optionen um die Installationsoptionen zu bearbeiten oder Abbrechen um den Vorgang zu vorzeitig beenden." />
<String Id="InstallVersion" Value="Version [WixBundleVersion]" />
<String Id="ConfirmCancelMessage" Value="Wollen Sie wirklich abbrechen?" />
<String Id="ExecuteUpgradeRelatedBundleMessage" Value="Vorherige Version" />
<String Id="HelpHeader" Value="Setup Hilfe" />
<String Id="HelpText" Value="/install | /repair | /uninstall | /layout [directory] - installs, repairs, uninstalls or&#xA; creates a complete local copy of the bundle in directory. Install is the default.&#xA;&#xA;/passive | /quiet - displays minimal UI with no prompts or displays no UI and&#xA; no prompts. By default UI and all prompts are displayed.&#xA;&#xA;/norestart - suppress any attempts to restart. By default UI will prompt before restart.&#xA;/log log.txt - logs to a specific file. By default a log file is created in %TEMP%." />
<String Id="HelpCloseButton" Value="&amp;Schließen" />
<String Id="InstallLicenseLinkText" Value="[WixBundleName] &lt;a href=&quot;#&quot;&gt;license terms&lt;/a&gt;." />
<String Id="InstallAcceptCheckbox" Value="I &amp;agree to the license terms and conditions" />
<String Id="InstallOptionsButton" Value="&amp;Optionen" />
<String Id="InstallInstallButton" Value="&amp;Installieren" />
<String Id="InstallCancelButton" Value="&amp;Abbrechen" />
<String Id="OptionsHeader" Value="Setup Optionen" />
<String Id="OptionsLocationLabel" Value="Installationsort:" />
<String Id="OptionsBrowseButton" Value="&amp;Suche" />
<String Id="OptionsOkButton" Value="&amp;OK" />
<String Id="OptionsCancelButton" Value="&amp;Ablehnen" />
<String Id="ProgressHeader" Value="Setup Fortschritt" />
<String Id="ProgressLabel" Value="Verarbeitung:" />
<String Id="OverallProgressPackageText" Value="Initialisieren..." />
<String Id="ProgressCancelButton" Value="&amp;Abbrechen" />
<String Id="ModifyHeader" Value="Setup Bearbeiten" />
<String Id="ModifyRepairButton" Value="&amp;Reparieren" />
<String Id="ModifyUninstallButton" Value="&amp;Deinstallieren" />
<String Id="ModifyCancelButton" Value="&amp;Abbrechen" />
<String Id="SuccessHeader" Value="Setup erfolgreich" />
<String Id="SuccessCacheHeader" Value="Cache erfolgreich abgeschlossen" />
<String Id="SuccessInstallHeader" Value="Installation erfolgreich abgeschlossen" />
<String Id="SuccessLayoutHeader" Value="Layout erfolgreich abgeschlossen" />
<String Id="SuccessModifyHeader" Value="Modify erfolgreich abgeschlossen" />
<String Id="SuccessRepairHeader" Value="Repair erfolgreich abgeschlossen" />
<String Id="SuccessUninstallHeader" Value="Deinstallation erfolgreich abgeschlossen" />
<String Id="SuccessUnsafeUninstallHeader" Value="Deinstallation erfolgreich abgeschlossen" />
<String Id="SuccessLaunchButton" Value="&amp;Starten" />
<String Id="SuccessRestartText" Value="Starten Sie den Rechner neu bevor Sie das Programm verwenden." />
<String Id="SuccessUninstallRestartText" Value="You must restart your computer to complete the removal of the software." />
<String Id="SuccessRestartButton" Value="&amp;Neustarten" />
<String Id="SuccessCloseButton" Value="&amp;Schließen" />
<String Id="FailureHeader" Value="Setup fehlgeschlagen" />
<String Id="FailureCacheHeader" Value="Cache fehlgeschlagen" />
<String Id="FailureInstallHeader" Value="Setup fehlgeschlagen" />
<String Id="FailureLayoutHeader" Value="Layout fehlgeschlagen" />
<String Id="FailureModifyHeader" Value="Bearbeiten fehlgeschlagen" />
<String Id="FailureRepairHeader" Value="Reparieren fehlgeschlagen" />
<String Id="FailureUninstallHeader" Value="Deinstallation fehlgeschlagen" />
<String Id="FailureUnsafeUninstallHeader" Value="Deinstallation fehlgeschlagen" />
<String Id="FailureHyperlinkLogText" Value="Beim Setup ist aufgrund mindestens eines Problems ein Fehler aufgetreten. Beheben Sie die Probleme, und wiederholen Sie das Setup. Weitere Informationen finden Sie in der &lt;a href=&quot;#&quot;&gt;Protokolldatei&lt;/a&gt;." />
<String Id="FailureRestartText" Value="Sie müssen den Computer neu starten, um das Zurücksetzen der Software abzuschließen." />
<String Id="FailureRestartButton" Value="&amp;Neustarten" />
<String Id="FailureCloseButton" Value="&amp;Schließen" />
<String Id="FilesInUseTitle" Value="Dateien in Verwendung" />
<String Id="FilesInUseLabel" Value="The following applications are using files that need to be updated:" />
<String Id="FilesInUseNetfxCloseRadioButton" Value="Close the &amp;applications." />
<String Id="FilesInUseCloseRadioButton" Value="Close the &amp;applications and attempt to restart them." />
<String Id="FilesInUseDontCloseRadioButton" Value="&amp;Do not close applications. A reboot will be required." />
<String Id="FilesInUseRetryButton" Value="&amp;Wiederholen" />
<String Id="FilesInUseIgnoreButton" Value="&amp;Ignorieren" />
<String Id="FilesInUseExitButton" Value="E&amp;xit" />
</WixLocalization>

View File

@ -1,4 +1,4 @@
<Project Sdk="WixToolset.Sdk/4.0.1"> <Project Sdk="WixToolset.Sdk/5.0.0">
<PropertyGroup> <PropertyGroup>
<OutputType>Bundle</OutputType> <OutputType>Bundle</OutputType>
<OutputName>Elwig</OutputName> <OutputName>Elwig</OutputName>
@ -13,7 +13,7 @@
</Target> </Target>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Installer\Installer.wixproj" /> <ProjectReference Include="..\Installer\Installer.wixproj" />
<PackageReference Include="WixToolset.Bal.wixext" Version="4.0.5" /> <PackageReference Include="WixToolset.Bal.wixext" Version="5.0.0" />
<PackageReference Include="WixToolset.Util.wixext" Version="4.0.5" /> <PackageReference Include="WixToolset.Util.wixext" Version="5.0.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -28,7 +28,7 @@ namespace Tests.DocumentTests {
Assert.That(text, Contains.Substring("Traubengutschrift Max Mustermann Probevariante")); Assert.That(text, Contains.Substring("Traubengutschrift Max Mustermann Probevariante"));
Assert.That(text, Contains.Substring("AT12 3456 7890 1234 5678")); Assert.That(text, Contains.Substring("AT12 3456 7890 1234 5678"));
Assert.That(text, Contains.Substring(""" Assert.That(text, Contains.Substring("""
20201001X001 1 Grüner Veltliner 73 15,0 ungeb.: 3 219 - - 20201001X001 1 Grüner Veltliner 73 15,0 ungeb.: 3 219 0,5000 - - 1 609,50
20201001X003 1 Grüner Veltliner 75 15,4 ungeb.: 2 561 - - 20201001X003 1 Grüner Veltliner 75 15,4 ungeb.: 2 561 - -
20201001X003 2 Grüner Veltliner Kabinett 87 17,6 ungeb.: 3 129 - - 20201001X003 2 Grüner Veltliner Kabinett 87 17,6 ungeb.: 3 129 - -
20201001X003 3 Grüner Veltliner 79 16,1 ungeb.: 1 280 - - 20201001X003 3 Grüner Veltliner 79 16,1 ungeb.: 1 280 - -

View File

@ -0,0 +1,28 @@
using Elwig.Documents;
using Elwig.Helpers;
using Elwig.Models.Dtos;
namespace Tests.DocumentTests {
[TestFixture]
public class PaymentVariantSummaryTest {
[Test]
public async Task Test_01_PaymentVariant2020() {
using var ctx = new AppDbContext();
var v = (await ctx.PaymentVariants.FindAsync(2020, 1))!;
var data = await PaymentVariantSummaryData.ForPaymentVariant(v, ctx.PaymentVariantSummaryRows);
using var doc = new PaymentVariantSummary(v, data);
var text = await Utils.GeneratePdfText(doc);
Assert.Multiple(() => {
Assert.That(text, Contains.Substring("Auszahlungsvariante"));
Assert.That(text, Contains.Substring(v.Name));
Assert.That(text, Contains.Substring("""
Gradation ungebunden gebunden Gesamt
[°Oe] [kg] [/kg] [kg] [/kg] []
Grüner Veltliner 3 219 0 1 609,50
Qualitätswein 73 3 219 0,5000 - - 1 609,50
"""));
});
}
}
}

View File

@ -61,7 +61,11 @@ INSERT INTO delivery_part_bucket (year, did, dpnr, bktnr, discr, value) VALUES
(2020, 5, 2, 0, '_', 2190); (2020, 5, 2, 0, '_', 2190);
INSERT INTO payment_variant (year, avnr, name, date, transfer_date, test_variant, calc_time, comment, data) VALUES INSERT INTO payment_variant (year, avnr, name, date, transfer_date, test_variant, calc_time, comment, data) VALUES
(2020, 1, 'Probevariante', '2021-01-15', '2021-01-15', TRUE, NULL, NULL, '{}'); (2020, 1, 'Probevariante', '2021-01-15', '2021-01-15', TRUE, NULL, NULL, '{"mode":"elwig","version":1,"payment":0.5,"curves":[]}');
INSERT INTO payment_delivery_part_bucket (year, did, dpnr, bktnr, avnr, price, amount) VALUES
(2020, 1, 1, 0, 1, 5000, 16095000);
DELETE FROM payment_member;
INSERT INTO payment_member (year, avnr, mgnr, net_amount) VALUES INSERT INTO payment_member (year, avnr, mgnr, net_amount) VALUES
(2020, 1, 101, 10000000); (2020, 1, 101, 10000000);

View File

@ -1 +1 @@
curl -s -L "https://www.necronda.net/elwig/files/create.sql?v=19" -u "elwig:ganzGeheim123!" -o "Resources\Sql\Create.sql" curl -s -L "https://elwig.at/files/create.sql?v=19" -u "elwig:ganzGeheim123!" -o "Resources\Sql\Create.sql"