MemberAdminWindow: Add pending member movement export
This commit is contained in:
@@ -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,21 +25,25 @@ 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))];
|
||||
_map = [.. colNames.Select(n => (n.Item2, _properties.FirstOrDefault(p => p?.Name == n.Item1, null), _fields.FirstOrDefault(f => f?.Name == n.Item1, 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;
|
||||
Sections = sections;
|
||||
ColumnFlatTypes = [.. ColumnTypes.SelectMany(type => {
|
||||
var elType = type?.GetElementType();
|
||||
return type != null && type.IsValueType && type.Name.StartsWith("ValueTuple") ? type.GetFields().Select(f => (Type?)f.FieldType) :
|
||||
@@ -50,44 +56,56 @@ namespace Elwig.Models.Dtos {
|
||||
type != null && elType != null && type.IsArray && elType.IsValueType && elType.Name.StartsWith("ValueTuple") ? elType.GetFields().Length :
|
||||
1;
|
||||
})];
|
||||
ColumnWidths = [.. colNames.Select(c => c.Item4)];
|
||||
ColumnUnits = [.. colNames.Select(c => c.Item3?.Split("|").Select(p => p.Length == 0 ? null : p).ToArray() ?? [])];
|
||||
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)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 = [];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user