Compare commits

..
8 Commits
Author SHA1 Message Date
lorenz.stechauner 09642e643c ClientParameters: Add option to hide business share history on MemberDataSheet
Test / Run tests (push) Successful in 2m16s
2026-10-03 00:07:04 +02:00
lorenz.stechauner b262e17293 Elwig: Update dependencies 2026-10-02 23:48:11 +02:00
lorenz.stechauner 4f4d026b7b AppDbUpdater: Fix update to v42 2026-10-02 23:48:11 +02:00
lorenz.stechauner abb9e5a577 MemberAdminWindow: Add pending member movement export 2026-10-02 23:47:56 +02:00
lorenz.stechauner 0e586cc438 DeliveryAdminWindow: Invalidate non-positive weight
Test / Run tests (push) Successful in 2m12s
2026-10-02 10:31:47 +02:00
lorenz.stechauner 829ad106cf DeliverySplittingDialog: Use color for wine variety
Test / Run tests (push) Successful in 3m3s
2026-10-02 09:26:46 +02:00
lorenz.stechauner ba7c37fd70 Helpers/Export: Code cleanup
Test / Run tests (push) Successful in 3m6s
2026-10-01 12:29:47 +02:00
lorenz.stechauner 66a1185dc3 MemberAdminWindow: Swap postal dest and Ort.Name
Test / Run tests (push) Successful in 2m38s
2026-09-30 15:41:47 +02:00
27 changed files with 386 additions and 160 deletions

No files matched your search

-6
View File
@@ -7,12 +7,6 @@
<ctrl:BoolToStringConverter x:Key="BoolToStarConverter" FalseValue="" TrueValue="*"/>
<ctrl:WidthToMarginConverter x:Key="WidthToMarginConverter"/>
<DataTemplate x:Key="PostalDestTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Dest}"/>
<TextBlock Text="{Binding Ort.Name, StringFormat='{} ({0})'}"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="KgNrTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}"/>
+1 -1
View File
@@ -74,7 +74,7 @@
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Part.DPNr}" Width="20" TextAlignment="Right"
VerticalAlignment="Center" Margin="0,0,5,0" FontSize="14"/>
<TextBlock Text="{Binding Part.SortId}" Width="40" TextAlignment="Center"
<TextBlock Text="{Binding Part.SortId}" Foreground="{Binding Part.Variety.Color}" Width="40" TextAlignment="Center"
VerticalAlignment="Center" Margin="0,0,0,0" FontSize="14"/>
<TextBlock Text="{Binding Part.Kmw, StringFormat='{}{0:N1}°'}" Width="40" TextAlignment="Right" Padding="0,0,10,0"
VerticalAlignment="Center"/>
@@ -2,7 +2,6 @@ using Elwig.Helpers;
using Elwig.Models.Entities;
using Elwig.Windows;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
+7 -7
View File
@@ -70,7 +70,7 @@ namespace Elwig.Documents {
doc.Add(new KernedParagraph(12).Add(Bold($"Flächenbindungen per {Date:dd.MM.yyyy}")).SetMargins(firstOnPage ? 0 : 24, 0, 6, 0));
doc.Add(NewAreaCmtTable(ActiveAreaCommitments));
}
if (App.Client.EnableMemberHistory) {
if (App.Client.EnableMemberHistory && App.Client.ModeMemberDataSheetShares > 0) {
bool firstOnPage = false;
if (pdf.GetNumberOfPages() == 1) {
doc.Add(new AreaBreak(AreaBreakType.NEXT_PAGE));
@@ -274,11 +274,11 @@ namespace Elwig.Documents {
.AddCells(NewBusinessSharesCells(new()));
}
var recorded = history.Aggregate(new MemberHistoryPoint(), (s, h) => new(
s.Shares + (h.ToMgNr == Member.MgNr && h.ToType == BusinessShareType.Normal ? h.Shares : 0) - (h.FromMgNr == Member.MgNr && h.FromType == BusinessShareType.Normal ? h.Shares : 0),
s.SharesRed + (h.ToMgNr == Member.MgNr && h.ToType == BusinessShareType.Red ? h.Shares : 0) - (h.FromMgNr == Member.MgNr && h.FromType == BusinessShareType.Red ? h.Shares : 0),
s.SharesWhite + (h.ToMgNr == Member.MgNr && h.ToType == BusinessShareType.White ? h.Shares : 0) - (h.FromMgNr == Member.MgNr && h.FromType == BusinessShareType.White ? h.Shares : 0),
s.SharesDormant + (h.ToMgNr == Member.MgNr && h.ToType == BusinessShareType.Dormant ? h.Shares : 0) - (h.FromMgNr == Member.MgNr && h.FromType == BusinessShareType.Dormant ? h.Shares : 0)));
var recorded = history.Aggregate(new MemberHistoryPoint(), (s, h) => new(
s.Shares + (h.ToMgNr == Member.MgNr && h.ToType == BusinessShareType.Normal ? h.Shares : 0) - (h.ToMgNr == h.FromMgNr && h.ToType == BusinessShareType.Normal && h.FromType == BusinessShareType.Normal ? 0 : h.FromMgNr == Member.MgNr && h.FromType == BusinessShareType.Normal ? h.Shares : 0),
s.SharesRed + (h.ToMgNr == Member.MgNr && h.ToType == BusinessShareType.Red ? h.Shares : 0) - (h.ToMgNr == h.FromMgNr && h.ToType == BusinessShareType.Red && h.FromType == BusinessShareType.Red ? 0 : h.FromMgNr == Member.MgNr && h.FromType == BusinessShareType.Red ? h.Shares : 0),
s.SharesWhite + (h.ToMgNr == Member.MgNr && h.ToType == BusinessShareType.White ? h.Shares : 0) - (h.ToMgNr == h.FromMgNr && h.ToType == BusinessShareType.White && h.FromType == BusinessShareType.White ? 0 : h.FromMgNr == Member.MgNr && h.FromType == BusinessShareType.White ? h.Shares : 0),
s.SharesDormant + (h.ToMgNr == Member.MgNr && h.ToType == BusinessShareType.Dormant ? h.Shares : 0) - (h.ToMgNr == h.FromMgNr && h.ToType == BusinessShareType.Dormant && h.FromType == BusinessShareType.Dormant ? 0 : h.FromMgNr == Member.MgNr && h.FromType == BusinessShareType.Dormant ? h.Shares : 0)));
var cur = new MemberHistoryPoint(Member.Shares - recorded.Shares, Member.SharesRed - recorded.SharesRed, Member.SharesWhite - recorded.SharesWhite, Member.SharesDormant - recorded.SharesDormant);
if (cur.Shares != 0 || cur.SharesRed != 0 || cur.SharesWhite != 0 || cur.SharesDormant != 0) {
@@ -297,7 +297,7 @@ namespace Elwig.Documents {
DateOnly? lastDate = null;
foreach (var row in history) {
int s = 0, r = 0, w = 0, d = 0;
if (row.FromMgNr == Member.MgNr) {
if (row.FromMgNr == Member.MgNr && !(row.FromMgNr == row.ToMgNr && row.FromType == row.ToType)) {
switch (row.FromType) {
case BusinessShareType.Normal: s -= row.Shares; break;
case BusinessShareType.Red: r -= row.Shares; break;
+2 -2
View File
@@ -25,8 +25,8 @@
<ItemGroup>
<PackageReference Include="bblanchon.PDFium.Win32" Version="156.0.8076" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.2" />
<PackageReference Include="itext" Version="9.7.0" />
<PackageReference Include="itext.bouncy-castle-adapter" Version="9.7.0" />
<PackageReference Include="itext" Version="9.8.0" />
<PackageReference Include="itext.bouncy-castle-adapter" Version="9.8.0" />
<PackageReference Include="LinqKit" Version="1.3.11" />
<PackageReference Include="MailKit" Version="4.18.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.12" />
+39
View File
@@ -1,3 +1,4 @@
using Elwig.Models;
using Elwig.Models.Dtos;
using Elwig.Models.Entities;
using Elwig.Services;
@@ -531,6 +532,44 @@ namespace Elwig.Helpers {
return _memberHistory[year].GetValueOrDefault(mgnr, new());
}
public async Task<Dictionary<int, SortedDictionary<DateOnly, MemberHistoryPoint>>> GetMemberHistory() {
var today = DateOnly.FromDateTime(DateTime.Today).AddDays(1);
var history = new Dictionary<int, SortedDictionary<DateOnly, MemberHistoryPoint>>();
var members = await Members.ToListAsync();
foreach (var m in members) {
history[m.MgNr] = new() {
[today] = new(m.Shares, m.SharesRed, m.SharesWhite, m.SharesDormant),
};
}
var hist = await MemberHistory.OrderByDescending(h => h.DateNoticeString).ToListAsync();
foreach (var h in hist) {
if (h.FromMgNr is int from) {
var latest = history[from].Last().Value;
switch (h.FromType) {
case BusinessShareType.Normal: latest.Shares += h.Shares; break;
case BusinessShareType.Red: latest.SharesRed += h.Shares; break;
case BusinessShareType.White: latest.SharesWhite += h.Shares; break;
case BusinessShareType.Dormant: latest.SharesDormant += h.Shares; break;
}
history[from][h.DateNotice] = latest;
}
if (h.ToMgNr is int to) {
var latest = history[to].Last().Value;
switch (h.ToType) {
case BusinessShareType.Normal: latest.Shares -= h.Shares; break;
case BusinessShareType.Red: latest.SharesRed -= h.Shares; break;
case BusinessShareType.White: latest.SharesWhite -= h.Shares; break;
case BusinessShareType.Dormant: latest.SharesDormant -= h.Shares; break;
}
history[to][h.DateNotice] = latest;
}
}
return history;
}
public async Task<Dictionary<string, AreaCmtBucket>> GetMemberAreaCommitmentBuckets(int year, int mgnr, SqliteConnection? cnx = null) {
if (!_memberAreaCommitmentBuckets.ContainsKey(year))
await FetchMemberAreaCommitmentBuckets(year, cnx);
+11
View File
@@ -61,6 +61,7 @@ namespace Elwig.Helpers {
public int ModeBusinessShares;
public bool HasRedWhite => ModeBusinessShares == 1;
public int ModeMemberDataSheetShares;
public int ModeDeliveryNoteStats;
public int ModeWineQualityStatistics;
public int OrderingMemberList;
@@ -127,6 +128,10 @@ namespace Elwig.Helpers {
case "SIMPLE": ModeBusinessShares = 0; break;
case "RED_WHITE": ModeBusinessShares = 1; break;
}
switch (parameters.GetValueOrDefault("MODE_MEMBERDATASHEET_SHARES", "FULL")?.ToUpper()) {
case "NONE": ModeMemberDataSheetShares = 0; break;
case "FULL": ModeMemberDataSheetShares = 1; break;
}
switch (parameters.GetValueOrDefault("MODE_DELIVERYNOTE_STATS", "SHORT")?.ToUpper()) {
case "NONE": ModeDeliveryNoteStats = 0; break;
case "GA_ONLY": ModeDeliveryNoteStats = 1; break;
@@ -209,6 +214,11 @@ namespace Elwig.Helpers {
case 0: businessShares = "SIMPLE"; break;
case 1: businessShares = "RED_WHITE"; break;
}
string memberDataSheetShares = "FULL";
switch (ModeMemberDataSheetShares) {
case 0: memberDataSheetShares = "NONE"; break;
case 1: memberDataSheetShares = "FULL"; break;
}
string deliveryNoteStats = "SHORT";
switch (ModeDeliveryNoteStats) {
case 0: deliveryNoteStats = "NONE"; break;
@@ -279,6 +289,7 @@ namespace Elwig.Helpers {
("CLIENT_ORGANIC_AUTHORITYCODE", OrganicAuthorityCode),
("ENABLE_MEMBERHISTORY", EnableMemberHistory ? "YES" : "NO"),
("MODE_BUSINESSSHARES", businessShares),
("MODE_MEMBERDATASHEET_SHARES", memberDataSheetShares),
("MODE_DELIVERYNOTE_STATS", deliveryNoteStats),
("MODE_WINEQUALITYSTATISTICS", modeWineQualityStatistics),
("ORDERING_MEMBERLIST", orderingMemberList),
+1 -5
View File
@@ -8,7 +8,7 @@ namespace Elwig.Helpers.Export {
using Row = Tuple<(string?, string?, string?, string?, string, int, string, bool, int), (string, int, string, string, string, int, string, double, double)>;
public class Bki : Csv<Row> {
public class Bki : CsvFile<Row> {
private readonly string _clientData;
@@ -46,10 +46,6 @@ namespace Elwig.Helpers.Export {
await ExportAsync(rows);
}
public void Export(int year) {
ExportAsync(year).GetAwaiter().GetResult();
}
public override string FormatRow(Row row) {
var (member, delivery) = row;
var (lfBisNr, familyName, name, billingName, address, plz, ort, vollablieferer, area) = member;
@@ -7,7 +7,7 @@ using System.Text;
using System.Threading.Tasks;
namespace Elwig.Helpers.Export {
public abstract class Csv<T> : IExporter<T> {
public abstract class CsvFile<T> : IExporter<T> {
public static string FileExtension => "csv";
@@ -15,11 +15,11 @@ namespace Elwig.Helpers.Export {
protected readonly char Separator;
protected string? Header;
public Csv(string filename, char separator = ';') :
public CsvFile(string filename, char separator = ';') :
this(filename, separator, Utils.UTF8) {
}
public Csv(string filename, char separator, Encoding encoding) {
public CsvFile(string filename, char separator, Encoding encoding) {
_writer = new StreamWriter(filename, false, encoding);
Separator = separator;
}
@@ -29,11 +29,6 @@ namespace Elwig.Helpers.Export {
_writer.Dispose();
}
public ValueTask DisposeAsync() {
GC.SuppressFinalize(this);
return _writer.DisposeAsync();
}
public async Task ExportAsync(IEnumerable<T> data, IProgress<double>? progress = null) {
progress?.Report(0.0);
int count = data.Count() + 2, i = 0;
@@ -50,10 +45,6 @@ namespace Elwig.Helpers.Export {
progress?.Report(100.0);
}
public void Export(IEnumerable<T> data, IProgress<double>? progress = null) {
ExportAsync(data, progress).GetAwaiter().GetResult();
}
public string FormatRow(IEnumerable row) {
return string.Join(Separator, row);
}
@@ -61,7 +52,7 @@ namespace Elwig.Helpers.Export {
public abstract string FormatRow(T row);
}
public class CsvSimple : Csv<IEnumerable<object?>> {
public class CsvSimple : CsvFile<IEnumerable<object?>> {
public CsvSimple(string filename, char separator, Encoding encoding) :
base(filename, separator, encoding) {
+1 -10
View File
@@ -9,7 +9,7 @@ using System.Security;
using System.Threading.Tasks;
namespace Elwig.Helpers.Export {
public class Ebics(PaymentVar variant, string filename, int version, Ebics.AddressMode mode = Ebics.AddressMode.Full) : IBankingExporter {
public class Ebics(PaymentVar variant, string filename, int version, Ebics.AddressMode mode = Ebics.AddressMode.Full) : IExporter<Transaction> {
public enum AddressMode { Omit = 0, Lines = 1, Full = 2 }
@@ -28,15 +28,6 @@ namespace Elwig.Helpers.Export {
Writer.Dispose();
}
public ValueTask DisposeAsync() {
GC.SuppressFinalize(this);
return Writer.DisposeAsync();
}
public void Export(IEnumerable<Transaction> transactions, IProgress<double>? progress = null) {
ExportAsync(transactions, progress).GetAwaiter().GetResult();
}
public async Task ExportAsync(IEnumerable<Transaction> transactions, IProgress<double>? progress = null) {
if (transactions.Any(tx => tx.Amount < 0)) {
throw new ArgumentException("Tranaction amount may not be negative");
-15
View File
@@ -1,15 +0,0 @@
using Elwig.Models.Dtos;
using System;
namespace Elwig.Helpers.Export {
public class Elba : Csv<Transaction>, IBankingExporter {
public static new string FileExtension => "elba";
public Elba(string filename) : base(filename) { }
public override string FormatRow(Transaction row) {
throw new NotImplementedException();
}
}
}
-8
View File
@@ -1,8 +0,0 @@
using Elwig.Models.Dtos;
namespace Elwig.Helpers.Export {
/// <summary>
/// Interface for exporting banking data
/// </summary>
public interface IBankingExporter : IExporter<Transaction> { }
}
+4 -2
View File
@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Threading.Tasks;
namespace Elwig.Helpers.Export {
public interface IExporter<T> : IDisposable, IAsyncDisposable {
public interface IExporter<T> : IDisposable {
/// <summary>
/// The default file extension of the exported files to be used (whithout a preceding ".")
/// </summary>
@@ -14,7 +14,9 @@ namespace Elwig.Helpers.Export {
/// </summary>
/// <param name="data">The data to be exported</param>
/// <param name="progress">The progress object to report to</param>
void Export(IEnumerable<T> data, IProgress<double>? progress = null);
void Export(IEnumerable<T> data, IProgress<double>? progress = null) {
ExportAsync(data, progress).GetAwaiter().GetResult();
}
/// <summary>
/// Asynchronosly export the given data to the given file.
@@ -109,8 +109,13 @@ namespace Elwig.Helpers.Export {
<style:paragraph-properties fo:text-align="center"/>
<style:text-properties fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold"/>
</style:style>
<style:style style:name="sectionheader" style:family="table-cell" style:parent-style-name="default">
<style:table-cell-properties style:text-align-source="fix" style:repeat-content="false"/>
<style:paragraph-properties fo:text-align="left"/>
<style:text-properties fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold" fo:font-size="14pt"/>
</style:style>
<style:style style:name="th" style:family="table-cell" style:parent-style-name="default">
<style:table-cell-properties style:text-align-source="fix" style:repeat-content="false" style:vertical-align="middle"/>
<style:table-cell-properties style:text-align-source="fix" style:repeat-content="false" style:vertical-align="middle" fo:wrap-option="wrap"/>
<style:paragraph-properties fo:text-align="center"/>
<style:text-properties fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold"/>
</style:style>
@@ -211,35 +216,59 @@ namespace Elwig.Helpers.Export {
}
}
await Content.WriteAsync(
$" <table:table-row>\r\n" +
FormatCell(table.FullName, colSpan: totalSpan, style: "header") +
$" </table:table-row>\r\n" +
$" <table:table-row>\r\n" +
FormatCell(table.Subtitle, colSpan: totalSpan, style: "subheader") +
$" </table:table-row>\r\n" +
$" <table:table-row>\r\n" +
$" <table:table-cell table:number-columns-repeated=\"{totalSpan}\"/>\r\n" +
$" </table:table-row>\r\n" +
$" <table:table-row>\r\n");
foreach (var (name, span, units) in table.ColumnNames.Zip(table.ColumnSpans, table.ColumnUnits)) {
var hasUnits = units.Length > 0;
await Content.WriteAsync(FormatCell(name, colSpan: span, rowSpan: hasUnits ? 1 : 2, style: "th"));
}
await Content.WriteAsync(" </table:table-row>\r\n <table:table-row>\r\n");
foreach (var (span, units) in table.ColumnSpans.Zip(table.ColumnUnits)) {
if (units.Length == 0) {
await Content.WriteAsync($" <table:covered-table-cell table:number-columns-repeated=\"{span}\"/>\r\n");
continue;
}
foreach (var u in units) {
await Content.WriteAsync(FormatCell(u == null ? null : $"[{u}]", style: "th"));
}
}
await Content.WriteAsync(" </table:table-row>\r\n");
await Content.WriteAsync($"""
<table:table-row>
{FormatCell(table.FullName, colSpan: totalSpan, style: "header")}
</table:table-row>
<table:table-row>
{FormatCell(table.Subtitle, colSpan: totalSpan, style: "subheader")}
</table:table-row>
<table:table-row>
<table:table-cell table:number-columns-repeated="{totalSpan}"/>
</table:table-row>
""");
foreach (var row in table.GetData()) {
await FormatRow(row, table.ColumnUnits, mergeSubRowCells);
var firstSection = true;
foreach (var sec in table.GetData()) {
if (!firstSection) {
await Content.WriteAsync($"""
<table:table-row>
<table:table-cell table:number-columns-repeated="{totalSpan}"/>
</table:table-row>
<table:table-row>
<table:table-cell table:number-columns-repeated="{totalSpan}"/>
</table:table-row>
""");
}
if (sec.Name != null) {
await Content.WriteAsync($"""
<table:table-row>
{FormatCell(sec.Name, colSpan: totalSpan, style: "sectionheader")}
</table:table-row>
""");
}
await Content.WriteAsync(" <table:table-row>\r\n");
foreach (var (name, span, units) in table.ColumnNames.Zip(table.ColumnSpans, table.ColumnUnits)) {
var hasUnits = units.Length > 0;
await Content.WriteAsync(FormatCell(name, colSpan: span, rowSpan: hasUnits ? 1 : 2, style: "th"));
}
await Content.WriteAsync(" </table:table-row>\r\n <table:table-row>\r\n");
foreach (var (span, units) in table.ColumnSpans.Zip(table.ColumnUnits)) {
if (units.Length == 0) {
await Content.WriteAsync($" <table:covered-table-cell table:number-columns-repeated=\"{span}\"/>\r\n");
continue;
}
foreach (var u in units) {
await Content.WriteAsync(FormatCell(u == null ? null : $"[{u}]", style: "th"));
}
}
await Content.WriteAsync(" </table:table-row>\r\n");
foreach (var row in sec.Rows) {
await FormatRow(row, table.ColumnUnits, mergeSubRowCells);
}
firstSection = false;
}
await Content.WriteAsync(" </table:table>\r\n");
@@ -314,7 +343,8 @@ namespace Elwig.Helpers.Export {
}
c = $"<{ct} office:value-type=\"float\" calcext:value-type=\"float\" office:value=\"{v.ToString(CultureInfo.InvariantCulture)}\"{add}><text:p>{data}</text:p></{ct}>";
} else {
c = $"<{ct} office:value-type=\"string\" calcext:value-type=\"string\"{add}><text:p>{SecurityElement.Escape(data.ToString())}</text:p></{ct}>";
var lines = string.Join("", data.ToString()?.Split('\n').Select(l => $"<text:p>{SecurityElement.Escape(l)}</text:p>") ?? []);
c = $"<{ct} office:value-type=\"string\" calcext:value-type=\"string\"{add}>{lines}</{ct}>";
}
return $" {c}\r\n" + (colSpan > 1 ? $" <table:covered-table-cell table:number-columns-repeated=\"{colSpan - 1}\"/>\r\n" : "");
+3 -10
View File
@@ -13,7 +13,9 @@ namespace Elwig.Helpers.Export {
private readonly StreamWriter _writer;
public VCard(string filename) : this(filename, Utils.UTF8) { }
public VCard(string filename) :
this(filename, Utils.UTF8) {
}
public VCard(string filename, Encoding encoding) {
_writer = new StreamWriter(filename, false, encoding);
@@ -24,11 +26,6 @@ namespace Elwig.Helpers.Export {
_writer.Dispose();
}
public ValueTask DisposeAsync() {
GC.SuppressFinalize(this);
return _writer.DisposeAsync();
}
public async Task ExportAsync(IEnumerable<Member> data, IProgress<double>? progress = null) {
progress?.Report(0.0);
int count = data.Count() + 1, i = 0;
@@ -58,10 +55,6 @@ namespace Elwig.Helpers.Export {
progress?.Report(100.0);
}
public void Export(IEnumerable<Member> data, IProgress<double>? progress = null) {
ExportAsync(data, progress).GetAwaiter().GetResult();
}
private static string? Escape(string? text) {
return text?.Replace("\\", "\\\\").Replace(",", "\\,").Replace(";", "\\;").Replace("\n", "\\n").Replace("\r", "");
}
+54 -35
View File
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
@@ -9,13 +10,14 @@ namespace Elwig.Models.Dtos {
public string Name { get; set; }
public string FullName { get; set; }
public string? Subtitle { get; set; }
public IEnumerable<T> Rows { get; private set; }
public IEnumerable<(string? Name, IEnumerable<T> Rows)> Sections { get; private set; }
public IEnumerable<T> Rows => Sections.SelectMany(s => s.Rows);
public int RowNum => Rows.Count();
public int ColNum => ColumnNames.Count();
public IEnumerable<(string, Type?)> ColumnDefs => _map.Select(m => (m.Item1, m.Item2?.PropertyType ?? m.Item3?.FieldType));
public IEnumerable<string> ColumnNames => ColumnDefs.Select(m => m.Item1);
public IEnumerable<Type?> ColumnTypes => ColumnDefs.Select(m => m.Item2);
public IEnumerable<(string Name, Type? Type)> ColumnDefs => _map.Select(m => (m.Name, m.PInfo?.PropertyType ?? m.FInfo?.FieldType));
public IEnumerable<string> ColumnNames => ColumnDefs.Select(m => m.Name);
public IEnumerable<Type?> ColumnTypes => ColumnDefs.Select(m => m.Type);
public IEnumerable<Type?> ColumnFlatTypes { get; private set; }
public IEnumerable<int> ColumnSpans { get; private set; }
public IEnumerable<int?> ColumnWidths { get; private set; }
@@ -23,70 +25,87 @@ namespace Elwig.Models.Dtos {
private readonly PropertyInfo[] _properties;
private readonly FieldInfo[] _fields;
private readonly (string, PropertyInfo?, FieldInfo?)[] _map;
private readonly (string Name, PropertyInfo? PInfo, FieldInfo? FInfo)[] _map;
public DataTable(string name, string fullName, string subtitle, IEnumerable<T> rows, IEnumerable<(string, string, string?, int?)>? colNames = null) :
this(name, fullName, rows, colNames) {
public DataTable(string name, string fullName, string subtitle, IEnumerable<(string? Name, IEnumerable<T> Rows)> sections, IEnumerable<(string Property, string Name, string? Unit, int? Width)>? colNames = null) :
this(name, fullName, sections, colNames) {
Subtitle = subtitle;
}
public DataTable(string name, string fullName, IEnumerable<T> rows, IEnumerable<(string, string, string?, int?)>? colNames = null) {
public DataTable(string name, string fullName, string subtitle, IEnumerable<T> rows, IEnumerable<(string Property, string Name, string? Unit, int? Width)>? colNames = null) :
this(name, fullName, subtitle, [(null, rows)], colNames) {
}
public DataTable(string name, string fullName, IEnumerable<(string? Name, IEnumerable<T> Rows)> sections, IEnumerable<(string Property, string Name, string? Unit, int? Width)>? colNames = null) {
_fields = typeof(T).GetFields();
_properties = typeof(T).GetProperties();
colNames ??= _properties.Select(p => p.Name).Union(_fields.Select(f => f.Name)).Select(i => (i, i, (string?)null, (int?)null)).ToList();
_map = colNames.Select(n => (n.Item2, _properties.FirstOrDefault(p => p?.Name == n.Item1, null), _fields.FirstOrDefault(f => f?.Name == n.Item1, null))).ToArray();
colNames ??= [.. _properties.Select(p => p.Name).Union(_fields.Select(f => f.Name)).Select(i => (i, i, (string?)null, (int?)null))];
_map = [.. colNames.Select(n => (n.Name, _properties.FirstOrDefault(p => p?.Name == n.Property, null), _fields.FirstOrDefault(f => f?.Name == n.Property, null)))];
Name = name;
FullName = fullName;
Rows = rows;
ColumnFlatTypes = ColumnTypes.SelectMany(type => {
Sections = sections;
ColumnFlatTypes = [.. ColumnTypes.SelectMany(type => {
var elType = type?.GetElementType();
return type != null && type.IsValueType && type.Name.StartsWith("ValueTuple") ? type.GetFields().Select(f => f.FieldType) :
type != null && elType != null && type.IsArray && elType.IsValueType && elType.Name.StartsWith("ValueTuple") ? elType.GetFields().Select(f => f.FieldType) :
return type != null && type.IsValueType && type.Name.StartsWith("ValueTuple") ? type.GetFields().Select(f => (Type?)f.FieldType) :
type != null && elType != null && type.IsArray && elType.IsValueType && elType.Name.StartsWith("ValueTuple") ? elType.GetFields().Select(f => (Type?)f.FieldType) :
[type];
}).ToList();
ColumnSpans = ColumnTypes.Select(type => {
})];
ColumnSpans = [.. ColumnTypes.Select(type => {
var elType = type?.GetElementType();
return type != null && type.IsValueType && type.Name.StartsWith("ValueTuple") ? type.GetFields().Length :
type != null && elType != null && type.IsArray && elType.IsValueType && elType.Name.StartsWith("ValueTuple") ? elType.GetFields().Length : 1;
}).ToList();
ColumnWidths = colNames.Select(c => c.Item4).ToList();
ColumnUnits = colNames.Select(c => c.Item3?.Split("|").Select(p => p.Length == 0 ? null : p).ToArray() ?? []).ToList();
type != null && elType != null && type.IsArray && elType.IsValueType && elType.Name.StartsWith("ValueTuple") ? elType.GetFields().Length :
1;
})];
ColumnWidths = [.. colNames.Select(c => c.Width)];
ColumnUnits = [.. colNames.Select(c => c.Unit?.Split("|").Select(p => p.Length == 0 ? null : p).ToArray() ?? [])];
}
public DataTable(string name, string fullName, IEnumerable<T> rows, IEnumerable<(string, string, string?)>? colNames = null) :
this(name, fullName, rows, colNames?.Select(c => (c.Item1, c.Item2, c.Item3, (int?)null))) {
public DataTable(string name, string fullName, IEnumerable<T> rows, IEnumerable<(string Property, string Name, string? Unit, int? Width)>? colNames = null) :
this(name, fullName, [(null, rows)], colNames) {
}
public DataTable(string name, IEnumerable<T> rows, IEnumerable<(string, string, string?)>? colNames = null) :
public DataTable(string name, string fullName, IEnumerable<T> rows, IEnumerable<(string Property, string Name, string? Unit)>? colNames = null) :
this(name, fullName, rows, colNames?.Select(c => (c.Property, c.Name, c.Unit, (int?)null))) {
}
public DataTable(string name, string fullName, IEnumerable<T> rows, IEnumerable<(string Property, string Name, string? Unit, int Width)>? colNames = null) :
this(name, fullName, rows, colNames?.Select(c => (c.Property, c.Name, c.Unit, (int?)c.Width))) {
}
public DataTable(string name, IEnumerable<T> rows, IEnumerable<(string Property, string Name, string? Unit, int? Width)>? colNames = null) :
this(name, name, rows, colNames) {
}
public DataTable(string name, IEnumerable<T> rows, IEnumerable<(string, string, string?, int?)>? colNames = null) :
public DataTable(string name, IEnumerable<T> rows, IEnumerable<(string Property, string Name, string? Unit)>? colNames = null) :
this(name, name, rows, colNames) {
}
public DataTable(string name, IEnumerable<T> rows, IEnumerable<(string, string, string?, int)>? colNames = null) :
public DataTable(string name, IEnumerable<T> rows, IEnumerable<(string Property, string Name, string? Unit, int Width)>? colNames = null) :
this(name, name, rows, colNames) {
}
public DataTable(string name, string fullName, IEnumerable<T> rows, IEnumerable<(string, string, string?, int)>? colNames = null) :
this(name, fullName, rows, colNames?.Select(c => (c.Item1, c.Item2, c.Item3, (int?)c.Item4))) {
public DataTable(string name, string fullName, IEnumerable<(string? Name, IEnumerable<T> Rows)> sections, IEnumerable<(string Property, string Name, string? Unit)>? colNames = null) :
this(name, fullName, sections, colNames?.Select(c => (c.Property, c.Name, c.Unit, (int?)null))) {
}
protected IEnumerable<(string, object?)> GetNamedRowData(T row) {
return _map.Select(i => (i.Item1, i.Item2?.GetValue(row) ?? i.Item3?.GetValue(row)));
public DataTable(string name, string fullName, IEnumerable<(string? Name, IEnumerable<T> Rows)> sections, IEnumerable<(string Property, string Name, string? Unit, int Width)>? colNames = null) :
this(name, fullName, sections, colNames?.Select(c => (c.Property, c.Name, c.Unit, (int?)c.Width))) {
}
protected IEnumerable<object?> GetRowData(T row) {
return GetNamedRowData(row).Select(i => i.Item2);
protected IEnumerable<(string Name, object? Value)> GetNamedRowValues(T row) {
return _map.Select(i => (i.Name, i.PInfo?.GetValue(row) ?? i.FInfo?.GetValue(row)));
}
public IEnumerable<IEnumerable<object?>> GetData() {
return Rows.Select(GetRowData);
protected IEnumerable<object?> GetRowValues(T row) {
return GetNamedRowValues(row).Select(i => i.Value);
}
public IEnumerable<IEnumerable<(string, object?)>> GetNamedData() {
return Rows.Select(GetNamedRowData);
public IEnumerable<(string? Name, IEnumerable<IEnumerable<object?>> Rows)> GetData() {
return Sections.Select(s => (s.Name, s.Rows.Select(GetRowValues)));
}
public IEnumerable<(string? Name, IEnumerable<IEnumerable<(string Name, object? Value)>> Rows)> GetNamedData() {
return Sections.Select(s => (s.Name, s.Rows.Select(GetNamedRowValues)));
}
}
}
+142
View File
@@ -0,0 +1,142 @@
using Elwig.Helpers;
using Elwig.Models.Entities;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Elwig.Models.Dtos {
public class MemberMovementData : DataTable<MemberMovementDataRow> {
private static readonly (string, string, string?, int)[] FieldNames = [
("Type", "\u2026 durch", null, 30),
("MgNr", "MgNr.", null, 12),
("Name1", "Name", null, 40),
("Name2", "Vorname", null, 25),
("Address", "Adresse", null, 50),
("Plz", "PLZ", null, 10),
("Locality", "Ort", null, 50),
("Date", "Datum", null, 20),
("SharesOld", "GA\nalt", null, 10),
("SharesDiff", "GA\nDiff.", null, 10),
("SharesNew", "GA\nneu", null, 10),
("Costs", "Kosten", "€", 15),
];
private MemberMovementData(string name, IEnumerable<(string? Name, IEnumerable<MemberMovementDataRow> Rows)> sections) :
base("Mitgl.-Bewegungen", name, sections, FieldNames) {
}
public static MemberMovementData FromMemberHistory(string name, IEnumerable<MemberHistory> rows, Dictionary<int, SortedDictionary<DateOnly, MemberHistoryPoint>> history) {
(string? Name, List<MemberMovementDataRow> Rows)[] sections = [
("Beitritt", []),
("Nachzeichnung (GA)", []),
("Überschreibung", []),
("Kündigung (GA)", []),
("Austritt", []),
];
foreach (var h in rows.OrderBy(r => r.DateNotice).ThenBy(r => r.ToMgNr).ThenBy(r => r.FromMgNr)) {
int cat;
if (h.ToMgNr == h.FromMgNr) {
// Umwandlung
if (h.ToType == BusinessShareType.Dormant) {
// Kündigung (GA)
cat = 3;
} else if (h.FromType == h.ToType) {
// Überschreibung
cat = 2;
} else {
throw new NotImplementedException();
}
} else if (h.DateNotice <= h.ToMember?.EntryDate && h.DateNotice >= h.FromMember?.ExitDate) {
// Überschreibung
cat = 2;
} else if (h.DateNotice <= h.ToMember?.EntryDate) {
// Beitritt
cat = 0;
} else if (h.DateNotice >= h.FromMember?.ExitDate) {
// Austritt
cat = 4;
} else if (h.ToMember == null) {
// Auszahlung
continue;
} else {
// Nachzeichnung (GA)
cat = 1;
}
Member a;
Member? b = null;
if (h.FromMember != null && h.ToMember != null) {
if (cat <= 1) {
a = h.ToMember;
b = h.FromMember;
} else {
a = h.FromMember;
b = h.ToMember;
}
} else if (h.FromMember != null) {
a = h.FromMember;
} else if (h.ToMember != null) {
a = h.ToMember;
} else {
throw new ArgumentException();
}
var oldA = history[a.MgNr].GetValueOrDefault(h.DateNotice);
var d = new MemberMovementDataRow {
Type = [h.ReasonPretty],
MgNr = [a.MgNr],
Name1 = [a.Name],
Name2 = [a.AdministrativeName2],
Address = [a.Address],
Plz = [a.PostalDest.AtPlz!.Plz],
Locality = [a.PostalDest.AtPlz.Ort.Name],
Date = h.DateNotice,
SharesOld = [oldA.Shares + oldA.SharesRed + oldA.SharesWhite],
SharesDiff = [cat != 3 && a == h.ToMember ? h.Shares : -h.Shares],
Costs = [h.FromMember == null ? h.TotalValue : null],
};
d.SharesNew = [d.SharesOld[^1] + (h.FromMgNr == h.ToMgNr ? 0 : d.SharesDiff[^1])];
if (b != null) {
var oldB = history[b.MgNr].GetValueOrDefault(h.DateNotice);
d.Type = [..d.Type, "\u2026 " + (cat <= 1 ? "von" : "an")];
d.MgNr = [.. d.MgNr, b.MgNr];
d.Name1 = [.. d.Name1, b.Name];
d.Name2 = [.. d.Name2, b.AdministrativeName2];
d.Address = [.. d.Address, b.Address];
d.Plz = [.. d.Plz, b.PostalDest.AtPlz!.Plz];
d.Locality = [.. d.Locality, b.PostalDest.AtPlz.Ort.Name];
d.SharesOld = [.. d.SharesOld, oldB.Shares + oldB.SharesRed + oldB.SharesWhite];
d.SharesDiff = [.. d.SharesDiff, b == h.ToMember ? h.Shares : -h.Shares];
d.SharesNew = [.. d.SharesNew, d.SharesOld[^1] + d.SharesDiff[^1]];
}
sections[cat].Rows.Add(d);
}
return new MemberMovementData($"Mitglieder-Bewegungen {name}", sections.Select(s => (s.Name, (IEnumerable<MemberMovementDataRow>)s.Rows)));
}
}
public class MemberMovementDataRow {
public string[] Type = [];
public int[] MgNr = [];
public string[] Name1 = [];
public string?[] Name2 = [];
public string[] Address = [];
public int[] Plz = [];
public string[] Locality = [];
public DateOnly Date;
public int?[] SharesOld = [];
public int[] SharesDiff = [];
public int?[] SharesNew = [];
public decimal?[] Costs = [];
}
}
+3
View File
@@ -20,6 +20,9 @@ namespace Elwig.Models.Entities {
[Column("dest")]
public string Dest { get; private set; } = null!;
[NotMapped]
public string FullDest => $"{Ort.Name} ({Dest})";
[ForeignKey("Plz")]
public virtual AT_Plz AtPlz { get; private set; } = null!;
+3 -3
View File
@@ -104,10 +104,10 @@ namespace Elwig.Models.Entities {
public string FormatReasonPhrase(int mgnr) {
if (Reason == REASON_TRANSFER) {
if (FromMgNr == mgnr) {
return $"{ReasonPretty} an {ToMember?.FullAdministrativeName ?? "Nachfolger"}" + (Comment != null ? $", {Comment}" : "");
} else if (ToMgNr == mgnr) {
if (ToMgNr == mgnr) {
return $"{ReasonPretty} von {FromMember?.FullAdministrativeName ?? "Vorgänger"}" + (Comment != null ? $", {Comment}" : "");
} else if (FromMgNr == mgnr) {
return $"{ReasonPretty} an {ToMember?.FullAdministrativeName ?? "Nachfolger"}" + (Comment != null ? $", {Comment}" : "");
}
}
return ReasonPretty + (Comment != null ? $", {Comment}" : "");
+2 -2
View File
@@ -52,8 +52,8 @@ UPDATE client_parameter SET param = 'CLIENT_ORGANIC_AUTHORITYCODE' WHERE param =
UPDATE member_telephone_number SET comment = NULL WHERE comment = '';
UPDATE member_email_address SET comment = NULL WHERE comment = '';
UPDATE member SET address = 'Untere Weißgerberstraße' WHERE address = 'U. Weißgasse Straße';
UPDATE member SET address = 'Edgar-Penzig-Franz-Straße' WHERE address = 'Edgar-Penzing-Franz-Straße';
UPDATE member SET address = CONCAT('Untere Weißgerberstraße ', SUBSTR(address, 21)) WHERE address LIKE 'U. Weißgasse Straße %';
UPDATE member SET address = CONCAT('Edgar-Penzig-Franz-Straße ', SUBSTR(address, 28)) WHERE address LIKE 'Edgar-Penzing-Franz-Straße %';
UPDATE member
SET address = NORMALIZE_ADDRESS(address, (SELECT o.name FROM AT_plz_dest p JOIN AT_ort o ON o.okz = p.okz WHERE p.id = member.postal_dest))
@@ -1,5 +1,7 @@
using Elwig.Helpers;
using Elwig.Helpers.Export;
using Elwig.Models;
using Elwig.Models.Dtos;
using Elwig.Models.Entities;
using Elwig.ViewModels;
using Microsoft.EntityFrameworkCore;
@@ -10,6 +12,10 @@ using System.Threading.Tasks;
namespace Elwig.Services {
public static class MemberBusinessSharesService {
public enum ExportSubject {
Pending,
};
public static async Task InitInputs(this MemberBusinessSharesViewModel vm) {
using var ctx = new AppDbContext();
vm.DateNoticeString = $"{DateTime.Today:dd.MM.yyyy}";
@@ -97,5 +103,19 @@ namespace Elwig.Services {
await tx.CommitAsync();
});
}
public static async Task GenerateMemberMovements(ExportSubject subject, ExportMode mode) {
var today = DateTime.Today;
var filename = InteractionService.SaveFile($"Ausstehende Mitgl.-Bewegungen {today:dd.MM.yyyy}", $"MitglBewegungen_{today:yyyy-MM-dd}", "ods");
if (filename == null)
return;
await Utils.RunForeground(async () => {
using var ctx = new AppDbContext();
var hist = await ctx.MemberHistory.Where(h => !h.CompanyHasSigned).ToListAsync();
var data = MemberMovementData.FromMemberHistory($"Ausstehend ({today:dd.MM.yyyy})", hist, await ctx.GetMemberHistory());
using var ods = new OdsFile(filename);
await ods.AddTable(data);
});
}
}
}
+1 -1
View File
@@ -117,7 +117,7 @@ namespace Elwig.ViewModels {
public partial string? WeightString { get; set; }
public int? Weight {
get => int.TryParse(WeightString?.Replace(Utils.GroupSeparator, ""), out var w) ? w : null;
set => WeightString = $"{value:N0}";
set => WeightString = value > 0 ? $"{value:N0}" : null;
}
[ObservableProperty]
public partial string? TareString { get; set; } = "-";
+9 -2
View File
@@ -195,7 +195,7 @@
<Label Content="PLZ/Ort:" Margin="10,70,0,10"/>
<TextBox x:Name="BranchPlzInput" Margin="0,70,0,0" Width="42" Grid.Column="1" HorizontalAlignment="Left"
TextChanged="BranchPlzInput_TextChanged" LostFocus="PlzInput_LostFocus" Tag="PLZ"/>
<ComboBox x:Name="BranchOrtInput" ItemTemplate="{StaticResource PostalDestTemplate}" TextSearch.TextPath="Ort.Name"
<ComboBox x:Name="BranchOrtInput" DisplayMemberPath="FullDest" TextSearch.TextPath="Ort.Name"
Margin="47,70,10,0" Grid.Column="1" Grid.ColumnSpan="3" Width="253" HorizontalAlignment="Left"
SelectionChanged="Branch_Changed"/>
@@ -561,7 +561,7 @@
</ComboBox>
<Label Content="Mitgliederbewegungen:" Margin="10,40,10,10"/>
<CheckBox x:Name="ParameterBusinessShareHistoryInput" Content="Mit Elwig erfassen" Margin="160,45,10,15"
<CheckBox x:Name="ParameterBusinessShareHistoryInput" Content="Mit Elwig erfassen" Margin="160,45,10,15"
HorizontalAlignment="Left"
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"/>
</Grid>
@@ -611,6 +611,13 @@
<TabItem Header="Textelemente">
<ScrollViewer VerticalScrollBarVisibility="Visible">
<StackPanel>
<GroupBox Header="Stammdatenblatt" Margin="10,10,10,10" Height="70">
<Grid>
<CheckBox x:Name="ModeMemberDataSheetShares" Content="Verlauf der Geschäftsanteile anzeigen" Margin="15,15,10,15"
HorizontalAlignment="Left" VerticalAlignment="Top"
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"/>
</Grid>
</GroupBox>
<GroupBox Header="Lieferschein" Margin="10,10,10,10" Height="180">
<Grid>
<Grid.ColumnDefinitions>
+2
View File
@@ -338,6 +338,7 @@ namespace Elwig.Windows {
ClientEmailAddressInput.Text = p.EmailAddress;
ClientWebsiteInput.Text = p.Website;
ModeMemberDataSheetShares.IsChecked = p.ModeMemberDataSheetShares > 0;
TextElementDeliveryNote.Text = p.TextDeliveryNote;
switch (p.ModeDeliveryNoteStats) {
case 0: ModeDeliveryNoteNone.IsChecked = true; break;
@@ -381,6 +382,7 @@ namespace Elwig.Windows {
p.ModeBusinessShares = ParameterBusinessShareModeInput.SelectedIndex;
p.EnableMemberHistory = ParameterBusinessShareHistoryInput.IsChecked ?? false;
p.ModeMemberDataSheetShares = ModeMemberDataSheetShares.IsChecked == true ? 1 : 0;
p.TextDeliveryNote = string.IsNullOrWhiteSpace(TextElementDeliveryNote.Text) ? null : TextElementDeliveryNote.Text;
p.ModeDeliveryNoteStats = (ModeDeliveryNoteNone.IsChecked == true) ? 0 : (ModeDeliveryNoteGaOnly.IsChecked == true) ? 1 : (ModeDeliveryNoteShort.IsChecked == true) ? 2 : (ModeDeliveryNoteFull.IsChecked == true) ? 3 : 2;
p.TextDeliveryConfirmation = string.IsNullOrWhiteSpace(TextElementDeliveryConfirmation.Text) ? null : TextElementDeliveryConfirmation.Text;
+2 -2
View File
@@ -629,7 +629,7 @@ namespace Elwig.Windows {
var correction = Utils.ShowTareCorrectionDialog(ViewModel.ActualTare, ViewModel.TargetTare);
if (correction == null) return;
ViewModel.Weight += lastCorrection - correction;
if (ViewModel.WeighingData is string s) {
if (ViewModel.Weight != null && ViewModel.WeighingData is string s) {
ViewModel.TargetTare = correction == 0 ? null : (ViewModel.ActualTare ?? 0) + correction;
ViewModel.Tare = ViewModel.TargetTare ?? ViewModel.ActualTare;
var obj = JsonNode.Parse(s)!.AsObject();
@@ -1514,7 +1514,7 @@ namespace Elwig.Windows {
}
private void WeightInput_TextChanged(object sender, TextChangedEventArgs evt) {
InputTextChanged((TextBox)sender);
InputTextChanged((TextBox)sender, new ValidationResult(ViewModel.Weight > 0, null));
}
private void TemperatureAcidInput_TextChanged(object sender, TextChangedEventArgs evt) {
+9 -5
View File
@@ -110,7 +110,7 @@
Click="Menu_CreditNote_Email_Click"/>
</MenuItem>
<MenuItem Header="Mitgliederliste" x:Name="Menu_List">
<MenuItem x:Name="Menu_List_SaveActive" Header="...mit Aktiven speichern (Excel)"
<MenuItem x:Name="Menu_List_SaveActive" Header="...mit Aktiven speichern... (Excel)"
Click="Menu_List_SaveActive_Click" InputGestureText="Strg+L"/>
<MenuItem x:Name="Menu_List_ShowActive" Header="...mit Aktiven anzeigen (PDF)"
Click="Menu_List_ShowActive_Click" InputGestureText="Strg+O"/>
@@ -119,7 +119,7 @@
<MenuItem x:Name="Menu_List_PrintActive" Header="...mit Aktiven drucken"
Click="Menu_List_PrintActive_Click" InputGestureText="Strg+Shift+O"/>
<Separator/>
<MenuItem x:Name="Menu_List_SaveFilters" Header="...aus Filtern speichern (Excel)"
<MenuItem x:Name="Menu_List_SaveFilters" Header="...aus Filtern speichern... (Excel)"
Click="Menu_List_SaveFilters_Click"/>
<MenuItem x:Name="Menu_List_ShowFilters" Header="...aus Filtern anzeigen (PDF)"
Click="Menu_List_ShowFilters_Click"/>
@@ -128,7 +128,7 @@
<MenuItem x:Name="Menu_List_PrintFilters" Header="...aus Filtern drucken"
Click="Menu_List_PrintFilters_Click"/>
<Separator/>
<MenuItem x:Name="Menu_List_SaveAll" Header="...mit allen speichern (Excel)"
<MenuItem x:Name="Menu_List_SaveAll" Header="...mit allen speichern... (Excel)"
Click="Menu_List_SaveAll_Click"/>
<MenuItem x:Name="Menu_List_ShowAll" Header="...mit allen anzeigen (PDF)"
Click="Menu_List_ShowAll_Click"/>
@@ -147,6 +147,10 @@
IsCheckable="True" IsChecked="{Binding MemberListOrderByOrt, Mode=TwoWay}"
Click="Menu_List_Order_Click"/>
</MenuItem>
<MenuItem Header="Geschäftsanteile" x:Name="Menu_BusinessShares">
<MenuItem x:Name="Menu_BusinessShares_SavePending" Header="Ausstehende Mitlg.-Bewegungen speichern... (Excel)"
Click="Menu_BusinessShares_SavePending_Click"/>
</MenuItem>
<MenuItem Header="Export">
<MenuItem x:Name="Menu_Export_ExportSelected" Header="...von ausgewähltem Mitglied speichern..." IsEnabled="False"
Click="Menu_Export_ExportSelected_Click"/>
@@ -378,7 +382,7 @@
Width="42" Grid.Column="1" HorizontalAlignment="Left"
TextChanged="PlzInput_TextChanged" LostFocus="PlzInput_LostFocus" Tag="PLZ"/>
<ComboBox x:Name="OrtInput" SelectedItem="{Binding Ort, Mode=TwoWay}" ItemsSource="{Binding OrtSource, Mode=TwoWay}"
ItemTemplate="{StaticResource PostalDestTemplate}" TextSearch.TextPath="Ort.Name"
DisplayMemberPath="FullDest" TextSearch.TextPath="Ort.Name"
SelectionChanged="OrtInput_SelectionChanged"
Margin="47,160,10,0" Grid.Column="1" Grid.ColumnSpan="3"/>
</Grid>
@@ -611,7 +615,7 @@
Margin="0,70,0,0" Width="42" Grid.Column="1" HorizontalAlignment="Left"
TextChanged="PlzInput_TextChanged" LostFocus="PlzInput_LostFocus" Tag="PLZ"/>
<ComboBox x:Name="BillingOrtInput" SelectedItem="{Binding BillingOrt, Mode=TwoWay}" ItemsSource="{Binding BillingOrtSource, Mode=TwoWay}"
ItemTemplate="{StaticResource PostalDestTemplate}" TextSearch.TextPath="Ort.Name"
DisplayMemberPath="FullDest" TextSearch.TextPath="Ort.Name"
SelectionChanged="OrtInput_SelectionChanged"
Margin="47,70,10,0" Grid.Column="1"/>
</Grid>
+6
View File
@@ -1,6 +1,7 @@
using Elwig.Dialogs;
using Elwig.Documents;
using Elwig.Helpers;
using Elwig.Helpers.Export;
using Elwig.Models.Entities;
using Elwig.Services;
using Elwig.ViewModels;
@@ -114,6 +115,7 @@ namespace Elwig.Windows {
}
if (!App.Client.EnableMemberHistory) {
Menu_BusinessShares.Visibility = Visibility.Collapsed;
BusinessSharesButton.Visibility = Visibility.Hidden;
}
@@ -809,6 +811,10 @@ namespace Elwig.Windows {
await App.Client.UpdateValues();
}
private async void Menu_BusinessShares_SavePending_Click(object sender, RoutedEventArgs evt) {
await MemberBusinessSharesService.GenerateMemberMovements(MemberBusinessSharesService.ExportSubject.Pending, ExportMode.SaveList);
}
private void FocusSearchInput(object sender, RoutedEventArgs evt) {
if (!IsEditing && !IsCreating) {
SearchInput.Focus();