[#54] Member: Add IsJuridicalPerson
All checks were successful
Test / Run tests (push) Successful in 2m49s

This commit is contained in:
2024-08-12 15:18:34 +02:00
parent 025ff08d84
commit f48c6a02cb
37 changed files with 225 additions and 116 deletions

View File

@ -32,7 +32,7 @@ namespace Elwig.Documents {
get {
IAddress addr = (Member.BillingAddress != null && UseBillingAddress) ? Member.BillingAddress : Member;
var plz = addr.PostalDest.AtPlz;
return (addr is BillingAddr ? $"{addr.Name}\n" : "") + $"{Member.AdministrativeName}\n{addr.Address}\n{plz?.Plz} {plz?.Ort.Name.Split(",")[0]}\n{addr.PostalDest.Country.Name}";
return string.Join("\n", ((string?[])[Member.BillingAddress?.FullName, Member.AdministrativeName, Member.ForTheAttentionOf, addr.Address, $"{plz?.Plz} {plz?.Ort.Name.Split(",")[0]}", addr.PostalDest.Country.Name]).Where(s => !string.IsNullOrWhiteSpace(s)));
}
}

View File

@ -33,7 +33,7 @@ namespace Elwig.Documents {
bool considerCustomModifiers,
Dictionary<string, UnderDelivery>? underDeliveries = null
) :
base($"{Name} {(p.Credit != null ? $"Nr. {p.Credit.Year}/{p.Credit.TgNr:000}" : p.Member.Name)} {p.Variant.Name}", p.Member) {
base($"{Name} {(p.Credit != null ? $"Nr. {p.Credit.Year}/{p.Credit.TgNr:000}" : p.Member.FullName)} {p.Variant.Name}", p.Member) {
UseBillingAddress = true;
ShowDateAndLocation = true;
Data = data;

View File

@ -158,7 +158,7 @@ namespace Elwig.Documents {
public void Show() {
if (_pdfFile == null) throw new InvalidOperationException("Pdf file has not been generated yet");
Pdf.Show(_pdfFile.NewReference(), Title + (this is BusinessDocument b ? $" - {b.Member.Name}" : ""));
Pdf.Show(_pdfFile.NewReference(), Title + (this is BusinessDocument b ? $" - {b.Member.FullName}" : ""));
}
public MimePart AsEmailAttachment(string filename) {

View File

@ -2,7 +2,7 @@ using Elwig.Models.Entities;
namespace Elwig.Documents {
public class Letterhead : BusinessDocument {
public Letterhead(Member m) : base($"Briefkopf {m.Name}", m, true) {
public Letterhead(Member m) : base($"Briefkopf {m.FullName}", m, true) {
Aside = "";
}
}

View File

@ -18,21 +18,31 @@
<tbody>
<tr class="sectionheading"><th colspan="6">Persönliche Daten</th></tr>
<tr>
<th class="small">Titel (vorangestellt)</th>
<th class="small">Vorname</th>
<th colspan="3" class="small">Nachname</th>
<th class="small">Titel (nachgestellt)</th>
@if (Model.Member.IsJuridicalPerson) {
<th colspan="3" class="small">Name</th>
<th colspan="3" class="small">Zu Handen</th>
} else {
<th class="small">Titel (vorangestellt)</th>
<th class="small">Vorname</th>
<th colspan="3" class="small">Nachname</th>
<th class="small">Titel (nachgestellt)</th>
}
</tr>
<tr>
<td class="large">@Model.Member.Prefix</td>
<td class="large">@Model.Member.GivenName @Model.Member.MiddleName</td>
<td class="large" colspan="3">@Model.Member.FamilyName</td>
<td class="large">@Model.Member.Suffix</td>
@if (Model.Member.IsJuridicalPerson) {
<td colspan="3" class="large">@Model.Member.Name</td>
<td colspan="3" class="large">@Model.Member.ForTheAttentionOf</td>
} else {
<td class="large">@Model.Member.Prefix</td>
<td class="large">@Model.Member.GivenName @Model.Member.MiddleName</td>
<td class="large" colspan="3">@Model.Member.Name</td>
<td class="large">@Model.Member.Suffix</td>
}
</tr>
<tr>
<th>Mitglieds-Nr.:</th>
<td>@Model.Member.MgNr</td>
<th colspan="2">Geburtsjahr/-tag:</th>
<th colspan="2">@(Model.Member.IsJuridicalPerson ? "Gründungsjahr/-tag" : "Geburtsjahr/-tag"):</th>
<td colspan="2">@(string.Join('.', Model.Member.Birthday?.Split('-')?.Reverse() ?? Array.Empty<string>()))</td>
</tr>
<tr>
@ -50,7 +60,7 @@
<tr class="sectionheading"><th colspan="6">Rechnungsadresse (optional)</th></tr>
<tr>
<th>Name:</th>
<td colspan="5">@Model.Member.BillingAddress?.Name</td>
<td colspan="5">@Model.Member.BillingAddress?.FullName</td>
</tr>
<tr>
<th>Adresse:</th>

View File

@ -9,7 +9,7 @@ namespace Elwig.Helpers {
public static class AppDbUpdater {
// Don't forget to update value in Tests/fetch-resources.bat!
public static readonly int RequiredSchemaVersion = 26;
public static readonly int RequiredSchemaVersion = 27;
private static int VersionOffset = 0;

View File

@ -29,7 +29,7 @@ namespace Elwig.Helpers.Export {
using var cnx = await AppDbContext.ConnectAsync();
using var cmd = cnx.CreateCommand();
cmd.CommandText = $"""
SELECT lfbis_nr, family_name, name, billing_name, address, plz, ort, area,
SELECT lfbis_nr, name, other_names, billing_name, address, plz, ort, area,
date, weight, type, sortid, qualid, year, hkid, kmw, oe
FROM v_bki_delivery
WHERE year = {year}

View File

@ -83,7 +83,7 @@ namespace Elwig.Helpers.Export {
<PmtId><EndToEndId>{id}</EndToEndId></PmtId>
<Amt><InstdAmt Ccy="{tx.Currency}">{Transaction.FormatAmount(tx.Amount)}</InstdAmt></Amt>
<Cdtr>
<Nm>{SecurityElement.Escape(a.Name[..Math.Min(140, a.Name.Length)])}</Nm>
<Nm>{SecurityElement.Escape(a.FullName[..Math.Min(140, a.FullName.Length)])}</Nm>
""");
if (ShowAddresses != AddressMode.Omit) {
var full = ShowAddresses == AddressMode.Full;

View File

@ -401,11 +401,12 @@ namespace Elwig.Helpers.Export {
return new JsonObject {
["mgnr"] = m.MgNr,
["predecessor_mgnr"] = m.PredecessorMgNr,
["name"] = m.Name,
["prefix"] = m.Prefix,
["given_name"] = m.GivenName,
["middle_names"] = m.MiddleName,
["family_name"] = m.FamilyName,
["suffix"] = m.Suffix,
["attn"] = m.ForTheAttentionOf,
["birthday"] = m.Birthday,
["entry_date"] = m.EntryDate != null ? $"{m.EntryDate:yyyy-MM-dd}" : null,
["exit_date"] = m.ExitDate != null ? $"{m.ExitDate:yyyy-MM-dd}" : null,
@ -414,6 +415,7 @@ namespace Elwig.Helpers.Export {
["zwstid"] = m.ZwstId,
["lfbis_nr"] = m.LfbisNr,
["ustid_nr"] = m.UstIdNr,
["juridical_pers"] = m.IsJuridicalPerson,
["volllieferant"] = m.IsVollLieferant,
["buchführend"] = m.IsBuchführend,
["organic"] = m.IsOrganic,
@ -431,7 +433,7 @@ namespace Elwig.Helpers.Export {
["country"] = m.CountryNum,
},
["billing_address"] = m.BillingAddress != null ? new JsonObject {
["name"] = m.BillingAddress.Name,
["name"] = m.BillingAddress.FullName,
["address"] = m.BillingAddress.Address,
["postal_dest"] = m.BillingAddress.PostalDestId,
["country"] = m.BillingAddress.CountryNum,
@ -460,11 +462,12 @@ namespace Elwig.Helpers.Export {
return (new Member {
MgNr = mgnr,
PredecessorMgNr = json["predecessor_mgnr"]?.AsValue().GetValue<int>(),
Name = json["name"]!.AsValue().GetValue<string>(),
Prefix = json["prefix"]?.AsValue().GetValue<string>(),
GivenName = json["given_name"]!.AsValue().GetValue<string>(),
GivenName = json["given_name"]?.AsValue().GetValue<string>(),
MiddleName = json["middle_names"]?.AsValue().GetValue<string>(),
FamilyName = json["family_name"]!.AsValue().GetValue<string>(),
Suffix = json["suffix"]?.AsValue().GetValue<string>(),
ForTheAttentionOf = json["attn"]?.AsValue().GetValue<string>(),
Birthday = json["birthday"]?.AsValue().GetValue<string>(),
EntryDateString = json["entry_date"]?.AsValue().GetValue<string>(),
ExitDateString = json["exit_date"]?.AsValue().GetValue<string>(),
@ -473,6 +476,7 @@ namespace Elwig.Helpers.Export {
ZwstId = json["zwstid"]?.AsValue().GetValue<string>(),
LfbisNr = json["lfbis_nr"]?.AsValue().GetValue<string>(),
UstIdNr = json["ustid_nr"]?.AsValue().GetValue<string>(),
IsJuridicalPerson = json["juridical_pers"]?.AsValue().GetValue<bool>() ?? false,
IsVollLieferant = json["volllieferant"]?.AsValue().GetValue<bool>() ?? false,
IsBuchführend = json["buchführend"]?.AsValue().GetValue<bool>() ?? false,
IsOrganic = json["organic"]?.AsValue().GetValue<bool>() ?? false,
@ -490,7 +494,7 @@ namespace Elwig.Helpers.Export {
Comment = json["comment"]?.AsValue().GetValue<string>(),
}, json["billing_address"] is JsonObject a ? new BillingAddr {
MgNr = mgnr,
Name = a["name"]!.AsValue().GetValue<string>(),
FullName = a["name"]!.AsValue().GetValue<string>(),
CountryNum = a["country"]!.AsValue().GetValue<int>(),
PostalDestId = a["postal_dest"]!.AsValue().GetValue<string>(),
Address = a["address"]!.AsValue().GetValue<string>(),

View File

@ -35,7 +35,7 @@ namespace Elwig.Models.Dtos {
private static async Task<IEnumerable<AreaComUnderDeliveryRowSingle>> FromDbSet(DbSet<AreaComUnderDeliveryRowSingle> table, int year) {
return await table.FromSqlRaw($"""
SELECT m.mgnr, m.family_name AS name_1,
SELECT m.mgnr, m.name AS name_1,
COALESCE(m.prefix || ' ', '') || m.given_name ||
COALESCE(' ' || m.middle_names, '') || COALESCE(' ' || m.suffix, '') AS name_2,
p.plz, o.name AS ort, m.address,

View File

@ -50,7 +50,7 @@ namespace Elwig.Models.Dtos {
private static async Task<IEnumerable<CreditNoteRowSingle>> FromDbSet(DbSet<CreditNoteRowSingle> table, int year, int avnr) {
return await table.FromSqlRaw($"""
SELECT m.mgnr, m.family_name AS name_1,
SELECT m.mgnr, m.name AS name_1,
COALESCE(m.prefix || ' ', '') || m.given_name ||
COALESCE(' ' || m.middle_names, '') || COALESCE(' ' || m.suffix, '') AS name_2,
p.plz, o.name AS ort, m.address, m.iban, c.tgnr, s.year, s.precision,

View File

@ -88,7 +88,7 @@ namespace Elwig.Models.Dtos {
Time = d.Time;
DeliveryBranch = d.Branch.Name;
MgNr = m.MgNr;
Name1 = m.FamilyName;
Name1 = m.Name;
Name2 = m.AdministrativeName2;
AdministrativeName = m.AdministrativeName;
MemberBranch = m.Branch?.Name;

View File

@ -37,7 +37,7 @@ namespace Elwig.Models.Dtos {
private static async Task<IEnumerable<MemberDeliveryPerVariantRowSingle>> FromDbSet(DbSet<MemberDeliveryPerVariantRowSingle> table, int year) {
return await table.FromSqlRaw($"""
SELECT m.mgnr, m.family_name AS name_1,
SELECT m.mgnr, m.name AS name_1,
COALESCE(m.prefix || ' ', '') || m.given_name ||
COALESCE(' ' || m.middle_names, '') || COALESCE(' ' || m.suffix, '') AS name_2,
p.plz, o.name AS ort, m.address,

View File

@ -91,7 +91,7 @@ namespace Elwig.Models.Dtos {
public MemberListRow(Member m, int? areaCom = null) {
MgNr = m.MgNr;
Name1 = m.FamilyName;
Name1 = m.Name;
Name2 = m.AdministrativeName2;
DefaultKg = m.DefaultKg?.Name;
Branch = m.Branch?.Name;
@ -100,7 +100,7 @@ namespace Elwig.Models.Dtos {
Plz = m.PostalDest.AtPlz!.Plz;
Locality = m.PostalDest.AtPlz!.Ort.Name;
if (m.BillingAddress is BillingAddr a) {
BillingName = a.Name;
BillingName = a.FullName;
BillingAddress = a.Address;
BillingPlz = a.PostalDest.AtPlz!.Plz;
BillingLocality = a.PostalDest.AtPlz!.Ort.Name;

View File

@ -26,7 +26,7 @@ namespace Elwig.Models.Dtos {
public static async Task<OverUnderDeliveryData> ForSeason(DbSet<OverUnderDeliveryRow> table, int year) {
var rows = await table.FromSqlRaw($"""
SELECT m.mgnr, m.family_name AS name_1,
SELECT m.mgnr, m.name AS name_1,
COALESCE(m.prefix || ' ', '') || m.given_name ||
COALESCE(' ' || m.middle_names, '') || COALESCE(' ' || m.suffix, '') AS name_2,
p.plz, o.name AS ort, m.address, m.business_shares,

View File

@ -8,7 +8,7 @@ namespace Elwig.Models.Entities {
public int MgNr { get; set; }
[Column("name")]
public required string Name { get; set; }
public required string FullName { get; set; }
[Column("country")]
public int CountryNum { get; set; }

View File

@ -118,7 +118,7 @@ namespace Elwig.Models.Entities {
public int SearchScore(IEnumerable<string> keywords) {
var list = new string?[] {
LsNr, Time?.ToString("HH:mm"),
Member.FamilyName, Member.MiddleName, Member.GivenName, Member.BillingAddress?.Name,
Member.Name, Member.MiddleName, Member.GivenName, Member.BillingAddress?.FullName,
Comment
}.ToList();
list.AddRange(Parts.Select(p => p.Comment).Distinct());

View File

@ -48,8 +48,8 @@ namespace Elwig.Models.Entities {
public int SearchScore(IEnumerable<string> keywords) {
return Utils.GetSearchScore([
Schedule.Description,
Member.FamilyName, Member.MiddleName, Member.GivenName,
Member.BillingAddress?.Name,
Member.Name, Member.MiddleName, Member.GivenName,
Member.BillingAddress?.FullName,
], keywords);
}
}

View File

@ -14,11 +14,14 @@ namespace Elwig.Models.Entities {
[Column("predecessor_mgnr")]
public int? PredecessorMgNr { get; set; }
[Column("name")]
public required string Name { get; set; }
[Column("prefix")]
public string? Prefix { get; set; }
[Column("given_name")]
public required string GivenName { get; set; }
public string? GivenName { get; set; }
[Column("middle_names")]
public string? MiddleName { get; set; }
@ -28,30 +31,22 @@ namespace Elwig.Models.Entities {
set => MiddleName = (value.Length > 0) ? string.Join(" ", value) : null;
}
[Column("family_name")]
public required string FamilyName { get; set; }
[Column("suffix")]
public string? Suffix { get; set; }
public string Name =>
(Prefix != null ? Prefix + " " : "") +
GivenName + " " +
(MiddleName != null ? MiddleName + " " : "") +
FamilyName +
(Suffix != null ? " " + Suffix : "");
[Column("attn")]
public string? ForTheAttentionOf { get; set; }
public string ShortName => GivenName + " " + FamilyName;
public string AdministrativeName => AdministrativeName1 + " " + AdministrativeName2;
public string AdministrativeName1 => FamilyName.Replace('ß', 'ẞ').ToUpper();
public string AdministrativeName2 =>
(Prefix != null ? Prefix + " " : "") +
GivenName +
(MiddleName != null ? " " + MiddleName : "") +
(Suffix != null ? " " + Suffix : "");
[NotMapped]
public string FullName => IsJuridicalPerson ? Name : string.Join(" ", ((string?[])[Prefix, GivenName, MiddleName, Name, Suffix]).Where(s => !string.IsNullOrWhiteSpace(s)));
[NotMapped]
public string ShortName => (!string.IsNullOrWhiteSpace(GivenName) ? $"{GivenName} " : "") + Name;
[NotMapped]
public string AdministrativeName => AdministrativeName1 + (!string.IsNullOrWhiteSpace(AdministrativeName2) ? $" {AdministrativeName2}" : "");
[NotMapped]
public string AdministrativeName1 => IsJuridicalPerson ? Name : Name.Replace('ß', 'ẞ').ToUpper();
[NotMapped]
public string? AdministrativeName2 => IsJuridicalPerson ? null : string.Join(" ", ((string?[])[Prefix, GivenName, MiddleName, Suffix]).Where(s => !string.IsNullOrWhiteSpace(s)));
[Column("birthday")]
public string? Birthday { get; set; }
@ -87,6 +82,9 @@ namespace Elwig.Models.Entities {
[Column("ustid_nr")]
public string? UstIdNr { get; set; }
[Column("juridical_pers")]
public bool IsJuridicalPerson { get; set; }
[Column("volllieferant")]
public bool IsVollLieferant { get; set; }
@ -185,8 +183,8 @@ namespace Elwig.Models.Entities {
public int SearchScore(IEnumerable<string> keywords) {
return Utils.GetSearchScore([
FamilyName, MiddleName, GivenName,
BillingAddress?.Name,
Name, MiddleName, GivenName,
BillingAddress?.FullName,
Comment,
], keywords);
}

View File

@ -2,7 +2,7 @@ using Elwig.Models.Entities;
namespace Elwig.Models {
public interface IAddress {
string Name { get; }
string FullName { get; }
string Address { get; }
PostalDest PostalDest { get; }
}

View File

@ -1,4 +1,4 @@
-- schema version 24 to 25
-- schema version 25 to 26
CREATE TABLE delivery_schedule (
year INTEGER NOT NULL,

View File

@ -0,0 +1,48 @@
-- schema version 26 to 27
PRAGMA writable_schema = ON;
ALTER TABLE member RENAME COLUMN family_name TO name;
ALTER TABLE member ADD COLUMN attn TEXT DEFAULT NULL;
ALTER TABLE member ADD COLUMN juridical_pers INTEGER NOT NULL CHECK (juridical_pers IN (TRUE, FALSE)) DEFAULT FALSE;
UPDATE sqlite_schema SET sql = REPLACE(sql, 'given_name TEXT NOT NULL', 'given_name TEXT DEFAULT NULL')
WHERE type = 'table' AND name = 'member';
DROP VIEW v_bki_member;
CREATE VIEW v_bki_member AS
SELECT s.year, m.mgnr, m.lfbis_nr, m.name,
(COALESCE(m.prefix || ' ', '') || m.given_name || COALESCE(' ' || m.middle_names, '') || COALESCE(' ' || m.suffix, '')) AS other_names,
a.name AS billing_name, COALESCE(a.address, m.address) AS address,
COALESCE(a.country, m.country) AS country, COALESCE(a.postal_dest, m.postal_dest) AS postal_dest,
SUM(IIF(c.year_from <= s.year AND (c.year_to IS NULL OR c.year_to >= s.year), c.area, 0)) AS area
FROM season s, member m
LEFT JOIN member_billing_address a ON a.mgnr = m.mgnr
LEFT JOIN area_commitment c ON c.mgnr = m.mgnr
GROUP BY s.year, m.mgnr;
DROP VIEW v_bki_delivery;
CREATE VIEW v_bki_delivery AS
SELECT m.lfbis_nr, m.name, m.other_names, m.billing_name,
m.address, plz.plz, IIF(INSTR(o.name, ',') = 0, o.name, SUBSTR(o.name, 1, INSTR(o.name, ',') - 1)) AS ort,
d.date, d.weight, v.type, v.sortid, d.qualid, d.year, d.hkid, d.kmw, d.oe,
m.area
FROM v_delivery d
JOIN v_bki_member m ON (m.year, m.mgnr) = (d.year, d.mgnr)
JOIN postal_dest pd ON (pd.country, pd.id) = (m.country, m.postal_dest)
LEFT JOIN AT_plz_dest ap ON (ap.country, ap.id) = (pd.country, pd.id)
LEFT JOIN AT_plz plz ON plz.plz = ap.plz
LEFT JOIN AT_ort o ON o.okz = ap.okz
JOIN wine_variety v ON v.sortid = d.sortid
ORDER BY d.date, d.time;
PRAGMA schema_version = 2601;
PRAGMA writable_schema = OFF;
UPDATE member
SET name = a.name, juridical_pers = TRUE
FROM member_billing_address a
WHERE a.mgnr = member.mgnr AND member.name = '';
DELETE FROM member_billing_address
WHERE mgnr IN (SELECT mgnr FROM member WHERE name = member_billing_address.name)

View File

@ -145,7 +145,7 @@ namespace Elwig.Services {
.OrderBy(a => a.Schedule.DateString)
.ThenBy(a => a.Schedule.Branch.Name)
.ThenBy(a => a.Schedule.Description)
.ThenBy(a => a.Member.FamilyName)
.ThenBy(a => a.Member.Name)
.ThenBy(a => a.Member.GivenName)
.ThenBy(a => a.Member.MgNr);

View File

@ -55,11 +55,13 @@ namespace Elwig.Services {
vm.IsMemberSelected = true;
vm.MgNrString = $"{m.MgNr}";
vm.PredecessorMgNrString = $"{m.PredecessorMgNr}";
vm.IsJuridicalPerson = m.IsJuridicalPerson;
vm.EnableMemberReferenceButton = m.PredecessorMgNr != null;
vm.Prefix = m.Prefix;
vm.GivenName = m.GivenName;
vm.FamilyName = m.FamilyName;
vm.Name = m.Name;
vm.Suffix = m.Suffix;
vm.ForTheAttentionOf = m.ForTheAttentionOf;
vm.Birthday = (m.Birthday != null) ? string.Join(".", m.Birthday.Split("-").Reverse()) : null;
if (m.Birthday?.Length == 10) {
vm.Age = Utils.GetAge(DateOnly.ParseExact(m.Birthday, "yyyy-MM-dd")).ToString();
@ -109,7 +111,7 @@ namespace Elwig.Services {
var billingAddr = m.BillingAddress;
if (billingAddr != null) {
vm.BillingName = billingAddr.Name;
vm.BillingName = billingAddr.FullName;
vm.BillingAddress = billingAddr.Address;
if (billingAddr.PostalDest.AtPlz is AT_PlzDest b) {
vm.BillingPlzString = $"{b.Plz}";
@ -150,8 +152,12 @@ namespace Elwig.Services {
vm.StatusDeliveriesThisSeasonToolTip = d2Grid;
var c = m.ActiveAreaCommitments(ctx, Utils.CurrentLastSeason);
var s = await ctx.Seasons.FindAsync(await ctx.Seasons.MaxAsync(s => s.Year));
var (text, grid) = await AreaComService.GenerateToolTip(c, s?.MaxKgPerHa ?? 10_000);
int maxKgPerHa = 10_000;
try {
var s = await ctx.Seasons.FindAsync(await ctx.Seasons.MaxAsync(s => s.Year));
if (s != null) maxKgPerHa = s.MaxKgPerHa;
} catch { }
var (text, grid) = await AreaComService.GenerateToolTip(c, maxKgPerHa);
vm.StatusAreaCommitmentInfo = $"{Utils.CurrentLastSeason}";
vm.StatusAreaCommitment = text;
vm.StatusAreaCommitmentToolTip = grid;
@ -392,14 +398,14 @@ namespace Elwig.Services {
} else if (vm.MemberListOrderByName) {
query = query
.OrderBy(m => m.Branch!.Name)
.ThenBy(m => m.FamilyName)
.ThenBy(m => m.Name)
.ThenBy(m => m.GivenName)
.ThenBy(m => m.MgNr);
} else if (vm.MemberListOrderByOrt) {
query = query
.OrderBy(m => m.Branch!.Name)
.ThenBy(m => m.DefaultWbKg!.AtKg.Name)
.ThenBy(m => m.FamilyName)
.ThenBy(m => m.Name)
.ThenBy(m => m.GivenName)
.ThenBy(m => m.MgNr);
}
@ -497,10 +503,12 @@ namespace Elwig.Services {
var m = new Member {
MgNr = oldMgNr ?? newMgNr,
PredecessorMgNr = vm.PredecessorMgNr,
Prefix = string.IsNullOrEmpty(vm.Prefix) ? null : vm.Prefix,
GivenName = vm.GivenName!,
FamilyName = vm.FamilyName!,
Suffix = string.IsNullOrEmpty(vm.Suffix) ? null : vm.Suffix,
IsJuridicalPerson = vm.IsJuridicalPerson,
Prefix = vm.IsJuridicalPerson || string.IsNullOrWhiteSpace(vm.Prefix) ? null : vm.Prefix,
GivenName = vm.IsJuridicalPerson || string.IsNullOrWhiteSpace(vm.GivenName) ? null : vm.GivenName,
Name = vm.Name!,
Suffix = vm.IsJuridicalPerson || string.IsNullOrWhiteSpace(vm.Suffix) ? null : vm.Suffix,
ForTheAttentionOf = !vm.IsJuridicalPerson || string.IsNullOrWhiteSpace(vm.ForTheAttentionOf) ? null : vm.ForTheAttentionOf,
Birthday = string.IsNullOrEmpty(vm.Birthday) ? null : string.Join("-", vm.Birthday!.Split(".").Reverse()),
IsDeceased = vm.IsDeceased,
CountryNum = 40, // Austria AT AUT
@ -540,7 +548,7 @@ namespace Elwig.Services {
var p = vm.BillingOrt;
ctx.Add(new BillingAddr {
MgNr = m.MgNr,
Name = vm.BillingName,
FullName = vm.BillingName,
Address = vm.BillingAddress ?? "",
CountryNum = p.CountryNum,
PostalDestId = p.Id,

View File

@ -38,7 +38,7 @@ namespace Elwig.ViewModels {
[ObservableProperty]
private bool _enableSearchInputs = true;
[ObservableProperty]
public IEnumerable<bool> _memberHasDeliveries = [ .. Enumerable.Range(0, 9999).Select(i => false) ];
private IEnumerable<bool> _memberHasDeliveries = [ .. Enumerable.Range(0, 9999).Select(i => false) ];
[ObservableProperty]
private bool _memberListOrderByMgNr;
@ -54,14 +54,18 @@ namespace Elwig.ViewModels {
private string? _predecessorMgNrString;
public int? PredecessorMgNr => int.TryParse(PredecessorMgNrString, out var mgnr) ? mgnr : null;
[ObservableProperty]
private bool _isJuridicalPerson;
[ObservableProperty]
private string? _prefix;
[ObservableProperty]
private string? _givenName;
[ObservableProperty]
private string? _familyName;
private string? _name;
[ObservableProperty]
private string? _suffix;
[ObservableProperty]
private string? _forTheAttentionOf;
[ObservableProperty]
private string? _birthday;
[ObservableProperty]
private string? _age;
@ -176,5 +180,9 @@ namespace Elwig.ViewModels {
private Visibility _controlButtonsVisibility = Visibility.Visible;
[ObservableProperty]
private Visibility _editingButtonsVisibility = Visibility.Hidden;
[ObservableProperty]
private Visibility _personalNameVisibility = Visibility.Visible;
[ObservableProperty]
private Visibility _juridicalNameVisibility = Visibility.Hidden;
}
}

View File

@ -159,7 +159,10 @@ namespace Elwig.Windows {
protected void ValidateRequiredInputs() {
foreach (var input in RequiredInputs) {
if (input is TextBox tb && tb.Text.Length == 0) {
if (input is Control c && c.Visibility != Visibility.Visible) {
ControlUtils.ClearInputState(input);
Valid[input] = true;
} else if (input is TextBox tb && tb.Text.Length == 0) {
ControlUtils.SetInputInvalid(input);
Valid[input] = false;
} else if (input is ComboBox cb && cb.SelectedItem == null && cb.ItemsSource != null && cb.ItemsSource.Cast<object>().Any()) {

View File

@ -434,7 +434,7 @@ namespace Elwig.Windows {
.Where(m => m.IsActive || !IsCreating)
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.DefaultWbKg!.AtKg)
.OrderBy(m => m.FamilyName)
.OrderBy(m => m.Name)
.ThenBy(m => m.GivenName)
.ToListAsync());
ControlUtils.RenewItemsSource(BranchInput, await ctx.Branches.OrderBy(b => b.Name).ToListAsync());
@ -764,7 +764,7 @@ namespace Elwig.Windows {
.Where(m => m.IsActive || !ViewModel.IsReceipt)
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.DefaultWbKg!.AtKg)
.OrderBy(m => m.FamilyName)
.OrderBy(m => m.Name)
.ThenBy(m => m.GivenName)
.ToListAsync());
if (DeliveryList.SelectedItem is not Delivery d) {
@ -810,7 +810,7 @@ namespace Elwig.Windows {
.Where(m => m.IsActive || !ViewModel.IsReceipt)
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.DefaultWbKg!.AtKg)
.OrderBy(m => m.FamilyName)
.OrderBy(m => m.Name)
.ThenBy(m => m.GivenName)
.ToListAsync());
IsCreating = true;

View File

@ -288,7 +288,7 @@
</ComboBox.ItemTemplateSelector>
</ComboBox>
<Label Content="Gewicht" Margin="10,70,0,0" Grid.Column="0"/>
<Label Content="Gewicht:" Margin="10,70,0,0" Grid.Column="0"/>
<ctrl:UnitTextBox x:Name="WeightInput" Unit="kg" Text="{Binding WeightString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Grid.Column="1" Margin="0,70,10,10" Width="61" HorizontalAlignment="Left"
TextChanged="WeightInput_TextChanged" KeyUp="Input_KeyUp"/>

View File

@ -107,7 +107,7 @@ namespace Elwig.Windows {
var dict = deliveryAncmts.AsParallel()
.ToDictionary(a => a, a => a.SearchScore(filter))
.OrderByDescending(a => a.Value)
.ThenBy(a => a.Key.Member.FamilyName)
.ThenBy(a => a.Key.Member.Name)
.ThenBy(a => a.Key.Member.GivenName)
.ThenBy(a => a.Key.Member.MgNr);
var threshold = dict.Select(a => a.Value).Max() * 3 / 4;
@ -117,7 +117,7 @@ namespace Elwig.Windows {
.ToList();
} else {
deliveryAncmts = deliveryAncmts
.OrderBy(a => a.Member.FamilyName)
.OrderBy(a => a.Member.Name)
.ThenBy(a => a.Member.GivenName)
.ThenBy(a => a.Member.MgNr)
.ToList();
@ -160,7 +160,7 @@ namespace Elwig.Windows {
.Where(m => m.IsActive || !IsCreating)
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.DefaultWbKg!.AtKg)
.OrderBy(m => m.FamilyName)
.OrderBy(m => m.Name)
.ThenBy(m => m.GivenName)
.ThenBy(m => m.MgNr)
.ToListAsync());
@ -244,7 +244,7 @@ namespace Elwig.Windows {
.Where(m => m.IsActive || !IsCreating)
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.DefaultWbKg!.AtKg)
.OrderBy(m => m.FamilyName)
.OrderBy(m => m.Name)
.ThenBy(m => m.GivenName)
.ThenBy(m => m.MgNr)
.ToListAsync());
@ -361,7 +361,7 @@ namespace Elwig.Windows {
.Where(m => m.IsActive || !IsCreating)
.Include(m => m.PostalDest.AtPlz!.Ort)
.Include(m => m.DefaultWbKg!.AtKg)
.OrderBy(m => m.FamilyName)
.OrderBy(m => m.Name)
.ThenBy(m => m.GivenName)
.ThenBy(m => m.MgNr)
.ToListAsync());

View File

@ -166,7 +166,7 @@ namespace Elwig.Windows {
}
ControlUtils.RenewItemsSource(MemberCustomInput, await ctx.Members
.Where(m => m.IsActive)
.OrderBy(m => m.FamilyName)
.OrderBy(m => m.Name)
.ThenBy(m => m.GivenName)
.Include(m => m.Branch)
.Include(m => m.DefaultWbKg!.AtKg)
@ -438,7 +438,7 @@ namespace Elwig.Windows {
.ToList();
} else if (OrderNameInput.IsChecked == true) {
recipients = recipients
.OrderBy(m => m.FamilyName)
.OrderBy(m => m.Name)
.ThenBy(m => m.GivenName)
.ThenBy(m => m.MgNr)
.ToList();
@ -447,7 +447,7 @@ namespace Elwig.Windows {
recipients = recipients
.OrderBy(m => m.BillingAddress?.PostalDest.AtPlz?.Plz ?? m.PostalDest.AtPlz?.Plz)
.ThenBy(m => m.BillingAddress?.PostalDest.AtPlz?.Ort.Name ?? m.PostalDest.AtPlz?.Ort.Name)
.ThenBy(m => m.FamilyName)
.ThenBy(m => m.Name)
.ThenBy(m => m.GivenName)
.ThenBy(m => m.MgNr)
.ToList();
@ -455,7 +455,7 @@ namespace Elwig.Windows {
recipients = recipients
.OrderBy(m => m.PostalDest.AtPlz?.Plz)
.ThenBy(m => m.PostalDest.AtPlz?.Ort.Name)
.ThenBy(m => m.FamilyName)
.ThenBy(m => m.Name)
.ThenBy(m => m.GivenName)
.ThenBy(m => m.MgNr)
.ToList();

View File

@ -199,7 +199,7 @@
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Nachname" Binding="{Binding FamilyName}" Width="140"/>
<DataGridTextColumn Header="Nachname" Binding="{Binding Name}" Width="140"/>
<DataGridTextColumn Header="Vorname" Binding="{Binding GivenName}" Width="140"/>
<DataGridTextColumn Header="GA" Binding="{Binding BusinessShares, StringFormat='{}{0} '}" Width="40">
<DataGridTextColumn.CellStyle>
@ -208,7 +208,7 @@
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Rechnungsadresse" Binding="{Binding BillingAddress.Name}" Width="200"/>
<DataGridTextColumn Header="Rechnungsadresse" Binding="{Binding BillingAddress.FullName}" Width="200"/>
</DataGrid.Columns>
</DataGrid>
@ -285,6 +285,9 @@
<TextBox x:Name="MgNrInput" Text="{Binding MgNrString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,10,0,0" Width="48" Grid.Column="1" TextAlignment="Right" HorizontalAlignment="Left"
TextChanged="MgNrInput_TextChanged" LostFocus="MgNrInput_LostFocus"/>
<CheckBox x:Name="JuridicalPersonInput" Content="Juristische Person" IsChecked="{Binding IsJuridicalPerson}"
Checked="JuridicalPersonInput_Changed" Unchecked="JuridicalPersonInput_Changed"
Margin="53,15,0,0" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<Label Content="Vorg.:" Margin="10,10,0,0" Grid.Column="2"/>
<TextBox x:Name="PredecessorMgNrInput" Text="{Binding PredecessorMgNrString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
@ -294,27 +297,33 @@
Margin="53,10,10,10" VerticalAlignment="Top" HorizontalAlignment="Left" IsEnabled="{Binding EnableMemberReferenceButton}" ToolTip="Zu Vorgänger springen"
Click="MemberReferenceButton_Click"/>
<Label Content="Präfix:" Margin="10,40,0,0" Grid.Column="2"/>
<TextBox x:Name="PrefixInput" Text="{Binding Prefix, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
<Label Content="Präfix:" Margin="10,40,0,0" Grid.Column="2" Visibility="{Binding PersonalNameVisibility}"/>
<TextBox x:Name="PrefixInput" Text="{Binding Prefix, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Visibility="{Binding PersonalNameVisibility}"
Margin="0,40,10,0" Grid.Column="3"
TextChanged="TextBox_TextChanged"/>
<Label Content="Vorname:" Margin="10,40,0,0" Grid.Column="0"/>
<TextBox x:Name="GivenNameInput" Text="{Binding GivenName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
<Label Content="Name:" Margin="10,40,0,0" Grid.Column="0" Visibility="{Binding JuridicalNameVisibility}"/>
<Label Content="Vorname:" Margin="10,40,0,0" Grid.Column="0" Visibility="{Binding PersonalNameVisibility}"/>
<TextBox x:Name="GivenNameInput" Text="{Binding GivenName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Visibility="{Binding PersonalNameVisibility}"
Margin="0,40,0,0" Grid.Column="1"
TextChanged="TextBox_TextChanged"/>
<Label Content="Nachname:" Margin="10,70,0,0" Grid.Column="0"/>
<TextBox x:Name="FamilyNameInput" Text="{Binding FamilyName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
<Label Content="Nachname:" Margin="10,70,0,0" Grid.Column="0" Visibility="{Binding PersonalNameVisibility}"/>
<TextBox x:Name="NameInput" Text="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,70,0,0" Grid.Column="1"
TextChanged="TextBox_TextChanged"/>
<Label Content="Suffix:" Margin="10,70,0,0" Grid.Column="2"/>
<TextBox x:Name="SuffixInput" Text="{Binding Suffix, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
<Label Content="Zu Handen:" Margin="10,70,0,0" Grid.Column="0" Visibility="{Binding JuridicalNameVisibility}"/>
<TextBox x:Name="AttnInput" Text="{Binding ForTheAttentionOf, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Visibility="{Binding JuridicalNameVisibility}"
Margin="0,70,10,0" Grid.Column="1" Grid.ColumnSpan="3"
TextChanged="TextBox_TextChanged"/>
<Label Content="Suffix:" Margin="10,70,0,0" Grid.Column="2" Visibility="{Binding PersonalNameVisibility}"/>
<TextBox x:Name="SuffixInput" Text="{Binding Suffix, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Visibility="{Binding PersonalNameVisibility}"
Margin="0,70,10,0" Grid.Column="3"
TextChanged="TextBox_TextChanged"/>
<Label Content="Geburtstag:" Margin="10,100,0,0" Grid.Column="0"/>
<Label x:Name="BirthdayLabel" Content="Geburtstag:" Margin="10,100,0,0" Grid.Column="0"/>
<TextBox x:Name="BirthdayInput" Text="{Binding Birthday, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,100,0,0" Grid.Column="1" Width="78" TextAlignment="Right" HorizontalAlignment="Left"
TextChanged="PartialDateInput_TextChanged" LostFocus="PartialDateInput_LostFocus"/>

View File

@ -41,7 +41,7 @@ namespace Elwig.Windows {
SearchInput, ActiveMemberInput, MemberList,
];
RequiredInputs = [
MgNrInput, GivenNameInput, FamilyNameInput,
MgNrInput, GivenNameInput, NameInput,
AddressInput, PlzInput, OrtInput, BillingOrtInput,
BusinessSharesInput, BranchInput, DefaultKgInput
];
@ -130,7 +130,7 @@ namespace Elwig.Windows {
var dict = members.AsParallel()
.ToDictionary(m => m, m => m.SearchScore(filter))
.OrderByDescending(a => a.Value)
.ThenBy(a => a.Key.FamilyName)
.ThenBy(a => a.Key.Name)
.ThenBy(a => a.Key.GivenName)
.ThenBy(a => a.Key.MgNr);
var threshold = dict.Select(a => a.Value).Max() * 3 / 4;
@ -140,7 +140,7 @@ namespace Elwig.Windows {
.ToList();
} else {
members = members
.OrderBy(m => m.FamilyName)
.OrderBy(m => m.Name)
.ThenBy(m => m.GivenName)
.ThenBy(m => m.MgNr)
.ToList();
@ -738,7 +738,7 @@ namespace Elwig.Windows {
return;
var oldMember = (await ctx.Members.FindAsync(mgnr))!;
var newName = $"{ViewModel.FamilyName?.Replace('ß', 'ẞ').ToUpper()} " +
var newName = $"{ViewModel.Name?.Replace('ß', 'ẞ').ToUpper()} " +
$"{ViewModel.Prefix}{(!string.IsNullOrEmpty(ViewModel.Prefix) ? " " : "")}" +
$"{ViewModel.GivenName}{(!string.IsNullOrEmpty(ViewModel.GivenName) ? " " : "")}" +
$"{ViewModel.Suffix}{(!string.IsNullOrEmpty(ViewModel.Suffix) ? " " : "")}";
@ -782,7 +782,7 @@ namespace Elwig.Windows {
if (ViewModel.SelectedMember is not Member m) return;
var url = "https://www.easy-cert.com/htm/suchergebnis.htm?" +
//$"CustomerNumber={m.LfbisNr}&" +
$"Name={(m.BillingAddress?.Name ?? m.Name).Replace(' ', '+')}&" +
$"Name={(m.BillingAddress?.FullName ?? m.FullName).Replace(' ', '+')}&" +
$"PostalCode={(m.BillingAddress?.PostalDest ?? m.PostalDest).AtPlz?.Plz}";
Process.Start(new ProcessStartInfo(url) {
UseShellExecute = true,
@ -811,5 +811,26 @@ namespace Elwig.Windows {
}
CheckBox_Changed(sender, evt);
}
private void JuridicalPersonInput_Changed(object sender, RoutedEventArgs evt) {
CheckBox_Changed(sender, evt);
if (ViewModel.IsJuridicalPerson) {
ViewModel.PersonalNameVisibility = Visibility.Hidden;
ViewModel.JuridicalNameVisibility = Visibility.Visible;
NameInput.Margin = new(0, 40, 10, 0);
NameInput.SetValue(Grid.ColumnSpanProperty, 3);
BirthdayLabel.Content = "Gründung:";
DeceasedInput.Content = "Aufgelöst";
} else {
ViewModel.JuridicalNameVisibility = Visibility.Hidden;
ViewModel.PersonalNameVisibility = Visibility.Visible;
NameInput.Margin = new(0, 70, 0, 0);
NameInput.SetValue(Grid.ColumnSpanProperty, 1);
BirthdayLabel.Content = "Geburtstag:";
DeceasedInput.Content = "Verstorben";
}
ValidateRequiredInputs();
UpdateButtons();
}
}
}

View File

@ -74,7 +74,7 @@
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Nachname" Binding="{Binding FamilyName}" Width="100"/>
<DataGridTextColumn Header="Nachname" Binding="{Binding Name}" Width="100"/>
<DataGridTextColumn Header="Vorname" Binding="{Binding GivenName}" Width="90"/>
<DataGridTextColumn Header="GA" Binding="{Binding BusinessShares, StringFormat='{}{0:N0} '}" Width="35">
<DataGridTextColumn.CellStyle>

View File

@ -45,12 +45,12 @@ namespace Elwig.Windows {
var members = await ctx.Members
.Select(m => new {
m.MgNr,
m.FamilyName,
m.Name,
m.GivenName,
m.BusinessShares,
m.IsActive,
})
.OrderBy(m => m.FamilyName)
.OrderBy(m => m.Name)
.ThenBy(m => m.GivenName)
.ThenBy(m => m.MgNr)
.ToListAsync();
@ -70,7 +70,7 @@ namespace Elwig.Windows {
var list = members
.Select(m => new {
m.MgNr, m.FamilyName, m.GivenName,
m.MgNr, m.Name, m.GivenName,
m.IsActive,
BusinessShares = m.BusinessShares - history.GetValueOrDefault(m.MgNr, 0),
DeliveryObligation = (m.BusinessShares - history.GetValueOrDefault(m.MgNr, 0)) * season.MinKgPerBusinessShare,
@ -78,7 +78,7 @@ namespace Elwig.Windows {
Adjust = history.TryGetValue(m.MgNr, out int v2) ? (int?)v2 : null,
})
.Select(m => new {
m.MgNr, m.FamilyName, m.GivenName,
m.MgNr, m.Name, m.GivenName,
m.BusinessShares,
Weight = weight.GetValueOrDefault(m.MgNr, 0),
OverUnder = weight.TryGetValue(m.MgNr, out int v1) ?
@ -89,7 +89,7 @@ namespace Elwig.Windows {
AdjustAmount = m.Adjust * -season.BusinessShareValue,
})
.Select(m => new {
m.MgNr, m.FamilyName, m.GivenName,
m.MgNr, m.Name, m.GivenName,
m.BusinessShares, m.Weight, m.OverUnder,
PenaltyBs = m.OverUnder != null && m.OverUnder < 0 ?
(season.PenaltyPerKg * m.OverUnder ?? 0) +
@ -106,7 +106,7 @@ namespace Elwig.Windows {
Custom = CustomPayments!.GetValueOrDefault(m.MgNr, null)?.Amount,
})
.Select(m => new {
m.MgNr, m.FamilyName, m.GivenName,
m.MgNr, m.Name, m.GivenName,
m.BusinessShares, m.Weight, m.OverUnder,
PenaltyBs = m.PenaltyBs == null || m.PenaltyBs == 0 ? (decimal?)null : Math.Round((decimal)m.PenaltyBs, 2),
PenaltyAc = m.PenaltyAc == null ? (decimal?)null : Math.Round((decimal)m.PenaltyAc, 2),
@ -115,13 +115,13 @@ namespace Elwig.Windows {
m.Custom
})
.Select(m => new {
m.MgNr, m.FamilyName, m.GivenName,
m.MgNr, m.Name, m.GivenName,
m.BusinessShares, m.Weight, m.OverUnder,
m.PenaltyBs, m.PenaltyAc, m.Adjust, m.AdjustAmount, m.Custom,
Total = (m.PenaltyBs ?? 0) + (m.PenaltyAc ?? 0) + (m.AdjustAmount ?? 0) + (m.Custom ?? 0),
})
.Select(m => new {
m.MgNr, m.FamilyName, m.GivenName,
m.MgNr, m.Name, m.GivenName,
m.BusinessShares, m.Weight, m.OverUnder,
m.PenaltyBs, m.PenaltyAc, m.Adjust, m.AdjustAmount, m.Custom,
m.Total,
@ -130,7 +130,7 @@ namespace Elwig.Windows {
})
.Where(m => m.OverUnder != null || m.Adjust != null || m.PenaltyBs != null || m.PenaltyAc != null || m.Custom != null)
.OrderByDescending(m => m.OverUnder ?? 0)
.ThenBy(m => m.FamilyName)
.ThenBy(m => m.Name)
.ThenBy(m => m.GivenName)
.ThenBy(m => m.MgNr)
.ToList();
@ -146,7 +146,7 @@ namespace Elwig.Windows {
NonDeliveries.Text = $"{list.Count(r => r.Weight == 0):N0}";
ControlUtils.RenewItemsSource(MemberInput, await ctx.Members
.OrderBy(m => m.FamilyName)
.OrderBy(m => m.Name)
.ThenBy(m => m.GivenName)
.ThenBy(m => m.MgNr)
.ToListAsync());