Compare commits
15 Commits
Author | SHA1 | Date | |
---|---|---|---|
94db0723c5 | |||
f54677d429 | |||
49e4b65c27 | |||
ada5085cae | |||
85931e62e8 | |||
39956cbcbd | |||
84d8d0cecb | |||
fe7f9d675b | |||
9d1ee8638c | |||
cd40075702 | |||
204dfe8745 | |||
f97dfc3c72 | |||
d3839c288a | |||
2764a0ca21 | |||
48970de652 |
61
CHANGELOG.md
61
CHANGELOG.md
@ -3,6 +3,67 @@ Changelog
|
||||
=========
|
||||
|
||||
|
||||
[v0.10.4][v0.10.4] (2024-08-22) {#v0.10.4}
|
||||
------------------------------------------
|
||||
|
||||
### Sonstiges {#v0.10.4-misc}
|
||||
|
||||
* Im Anmeldungen-Fenster (`DeliveryAncmtAdminWindow`) wird der Wochentag auch beim Bearbeiten angezeigt. (85931e62e8)
|
||||
* Im Mitglieder-Fenster (`MemberAdminWindow`) werden Anzahl der Mitglieder und Geschäftsanteile nicht mehr von allen aktiven angezeigt, sonder von den momentan gefilterten. (49e4b65c27)
|
||||
* Statusleiste im Anmeldungen-Fenster (`DeliveryAncmtAdminWindow`). (f54677d429)
|
||||
|
||||
[v0.10.4]: https://git.necronda.net/winzer/elwig/releases/tag/v0.10.4
|
||||
|
||||
|
||||
|
||||
|
||||
[v0.10.3][v0.10.3] (2024-08-21) {#v0.10.3}
|
||||
------------------------------------------
|
||||
|
||||
### Behobene Fehler {#v0.10.3-bugfixes}
|
||||
|
||||
* Datum für _Anmeldungen bis_ im Leseplan-Fenster (`DeliveryScheduleAdminWindow`) ab jetzt änderbar. (84d8d0cecb)
|
||||
|
||||
### Sonstiges {#v0.10.3-misc}
|
||||
|
||||
* Wochentag bei Leseplan-Liste im Anmeldungen-Fenster (`DeliveryAncmtAdminWindow`) anzeigen. (fe7f9d675b)
|
||||
|
||||
[v0.10.3]: https://git.necronda.net/winzer/elwig/releases/tag/v0.10.3
|
||||
|
||||
|
||||
|
||||
|
||||
[v0.10.2][v0.10.2] (2024-08-16) {#v0.10.2}
|
||||
------------------------------------------
|
||||
|
||||
### Behobene Fehler {#v0.10.2-bugfixes}
|
||||
|
||||
* Beim Hochladen der Mitgliederdaten sind Flächenbindungen nicht mitexportiert worden. (204dfe8745)
|
||||
* Beim Importieren von älteren Exportdaten kam es zu einem Fehler. (cd40075702)
|
||||
|
||||
[v0.10.2]: https://git.necronda.net/winzer/elwig/releases/tag/v0.10.2
|
||||
|
||||
|
||||
|
||||
|
||||
[v0.10.1][v0.10.1] (2024-08-14) {#v0.10.1}
|
||||
------------------------------------------
|
||||
|
||||
### Neue Funktionen {#v0.10.1-features}
|
||||
|
||||
* In der Mitglieder-Liste (PDF und Excel) werden ggf. gefilterte Flächenbindungen angegeben. (d3839c288a)
|
||||
|
||||
### Behobene Fehler {#v0.10.1-bugfixes}
|
||||
|
||||
* Fehler beim Berechnen...
|
||||
* falls in Saison keine Lieferungen vorhanden sind. (48970de652)
|
||||
* falls der Vorname eines Mitgliedes nicht gesetzt ist. (2764a0ca21)
|
||||
|
||||
[v0.10.1]: https://git.necronda.net/winzer/elwig/releases/tag/v0.10.1
|
||||
|
||||
|
||||
|
||||
|
||||
[v0.10.0][v0.10.0] (2024-08-13) {#v0.10.0}
|
||||
------------------------------------------
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
using Elwig.Models.Dtos;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Elwig.Documents {
|
||||
public class MemberList : Document {
|
||||
@ -9,9 +10,17 @@ namespace Elwig.Documents {
|
||||
public string Filter;
|
||||
public IEnumerable<MemberListRow> Members;
|
||||
|
||||
public string[] AreaComFilters;
|
||||
public bool FilterAreaComs => AreaComFilters.Length > 0;
|
||||
|
||||
public MemberList(string filter, IEnumerable<MemberListRow> members) : base(Name) {
|
||||
Filter = filter;
|
||||
Members = members;
|
||||
AreaComFilters = [..members
|
||||
.SelectMany(m => m.AreaCommitmentsFiltered)
|
||||
.Select(c => c.VtrgId)
|
||||
.Distinct()
|
||||
.Order()];
|
||||
}
|
||||
|
||||
public MemberList(string filter, MemberListData data) :
|
||||
|
@ -8,30 +8,61 @@
|
||||
<h2>@Model.Filter</h2>
|
||||
<table class="members">
|
||||
<colgroup>
|
||||
<col style="width: 8mm;"/>
|
||||
<col style="width: 42mm;"/>
|
||||
<col style="width: 40mm;"/>
|
||||
<col style="width: 8mm;"/>
|
||||
<col style="width: 20mm;"/>
|
||||
@if (Model.AreaComFilters.Length > 1) {
|
||||
<col style="width: 38mm;"/>
|
||||
} else {
|
||||
<col style="width: 42mm;"/>
|
||||
}
|
||||
@if (Model.AreaComFilters.Length > 1) {
|
||||
<col style="width: 36mm;"/>
|
||||
} else {
|
||||
<col style="width: 40mm;"/>
|
||||
}
|
||||
<col style="width: 8mm;"/>
|
||||
@if (Model.AreaComFilters.Length > 1) {
|
||||
<col style="width: 18mm;"/>
|
||||
} else {
|
||||
<col style="width: 20mm;"/>
|
||||
}
|
||||
<col style="width: 12mm;"/>
|
||||
<col style="width: 5mm;" />
|
||||
<col style="width: 18mm;"/>
|
||||
<col style="width: 5mm;"/>
|
||||
@if (Model.AreaComFilters.Length > 1) {
|
||||
<col style="width: 16mm;"/>
|
||||
} else {
|
||||
<col style="width: 18mm;"/>
|
||||
}
|
||||
<col style="width: 12mm;"/>
|
||||
@if (Model.AreaComFilters.Length > 1) {
|
||||
<col style="width: 12mm;"/>
|
||||
}
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th rowspan="2">Nr.</th>
|
||||
<th rowspan="2" style="text-align: left;">Name</th>
|
||||
<th rowspan="2" style="text-align: left;">Adresse</th>
|
||||
<th rowspan="2">PLZ</th>
|
||||
<th rowspan="2" style="text-align: left;">Ort</th>
|
||||
<th rowspan="2">Betr.-Nr.</th>
|
||||
<th rowspan="2">GA</th>
|
||||
<th rowspan="2" style="text-align: left;">Stamm-KG</th>
|
||||
<th>Geb. Fl.</th>
|
||||
@{
|
||||
var headerSpan = Model.FilterAreaComs ? 3 : 2;
|
||||
}
|
||||
<th rowspan="@headerSpan">Nr.</th>
|
||||
<th rowspan="@headerSpan" style="text-align: left;">Name</th>
|
||||
<th rowspan="@headerSpan" style="text-align: left;">Adresse</th>
|
||||
<th rowspan="@headerSpan">PLZ</th>
|
||||
<th rowspan="@headerSpan" style="text-align: left;">Ort</th>
|
||||
<th rowspan="@headerSpan">Betr.-Nr.</th>
|
||||
<th rowspan="@headerSpan">GA</th>
|
||||
<th rowspan="@headerSpan" style="text-align: left;">Stamm-KG</th>
|
||||
<th colspan="@(Model.FilterAreaComs ? Model.AreaComFilters.Length : 1)">Geb. Fl.</th>
|
||||
</tr>
|
||||
@if (Model.FilterAreaComs) {
|
||||
<tr>
|
||||
@foreach (var vtrgId in Model.AreaComFilters) {
|
||||
<th>@vtrgId</th>
|
||||
}
|
||||
</tr>
|
||||
}
|
||||
<tr>
|
||||
<th class="unit">[m²]</th>
|
||||
@for (int i = 0; i < Math.Max(Model.AreaComFilters.Length, 1); i++) {
|
||||
<th class="unit">[m²]</th>
|
||||
}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="small">
|
||||
@ -40,22 +71,28 @@
|
||||
}
|
||||
@foreach (var m in Model.Members) {
|
||||
if (lastBranch != null && m.Branch != lastBranch) {
|
||||
<tr class="spacing"><td colspan="9"></td></tr>
|
||||
<tr class="spacing"><td colspan="@(8 + Math.Max(Model.AreaComFilters.Length, 1))"></td></tr>
|
||||
<tr class="header">
|
||||
<th colspan="9">@m.Branch</th>
|
||||
<th colspan="@(8 + Math.Max(Model.AreaComFilters.Length, 1))">@m.Branch</th>
|
||||
</tr>
|
||||
lastBranch = m.Branch;
|
||||
}
|
||||
<tr>
|
||||
<td class="number" rowspan="@(m.BillingName != null ? 2 : 1)">@m.MgNr</td>
|
||||
<td>@m.Name1.Replace('ß', 'ẞ').ToUpper() @m.Name2</td>
|
||||
<td>@m.AdminName1 @m.Name2</td>
|
||||
<td>@m.Address</td>
|
||||
<td>@m.Plz</td>
|
||||
<td class="tiny">@m.Locality</td>
|
||||
<td>@m.LfbisNr</td>
|
||||
<td class="number">@m.BusinessShares</td>
|
||||
<td class="tiny">@m.DefaultKg</td>
|
||||
<td class="number">@($"{m.AreaCommitment:N0}")</td>
|
||||
@if (Model.AreaComFilters.Length > 0) {
|
||||
foreach (var v in Model.AreaComFilters) {
|
||||
<td class="number">@($"{m.AreaCommitmentsFiltered.FirstOrDefault(c => c.VtrgId == v).Area:N0}")</td>
|
||||
}
|
||||
} else {
|
||||
<td class="number">@($"{m.AreaCommitment:N0}")</td>
|
||||
}
|
||||
</tr>
|
||||
if (m.BillingName != null) {
|
||||
<tr>
|
||||
|
@ -7,7 +7,7 @@
|
||||
<UseWPF>true</UseWPF>
|
||||
<PreserveCompilationContext>true</PreserveCompilationContext>
|
||||
<ApplicationIcon>Resources\Images\Elwig.ico</ApplicationIcon>
|
||||
<Version>0.10.0</Version>
|
||||
<Version>0.10.4</Version>
|
||||
<SatelliteResourceLanguages>de-AT</SatelliteResourceLanguages>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
|
@ -157,13 +157,15 @@ namespace Elwig.Helpers.Billing {
|
||||
lastMgNr = mgnr;
|
||||
}
|
||||
|
||||
await AppDbContext.ExecuteBatch(cnx, $"""
|
||||
UPDATE delivery_part_bucket SET value = 0 WHERE year = {Year};
|
||||
INSERT INTO delivery_part_bucket (year, did, dpnr, bktnr, discr, value)
|
||||
VALUES {string.Join(",\n ", inserts.Select(i => $"({Year}, {i.Item1}, {i.Item2}, {i.Item3}, '{i.Item4}', {i.Item5})"))}
|
||||
ON CONFLICT DO UPDATE
|
||||
SET discr = excluded.discr, value = value + excluded.value;
|
||||
""");
|
||||
await AppDbContext.ExecuteBatch(cnx, $"UPDATE delivery_part_bucket SET value = 0 WHERE year = {Year}");
|
||||
if (inserts.Count > 0) {
|
||||
await AppDbContext.ExecuteBatch(cnx, $"""
|
||||
INSERT INTO delivery_part_bucket (year, did, dpnr, bktnr, discr, value)
|
||||
VALUES {string.Join(",\n ", inserts.Select(i => $"({Year}, {i.Item1}, {i.Item2}, {i.Item3}, '{i.Item4}', {i.Item5})"))}
|
||||
ON CONFLICT DO UPDATE
|
||||
SET discr = excluded.discr, value = value + excluded.value;
|
||||
""");
|
||||
}
|
||||
|
||||
if (!avoidUnderDlvrs) {
|
||||
if (ownCnx) await cnx.DisposeAsync();
|
||||
|
@ -39,6 +39,7 @@ namespace Elwig.Helpers.Export {
|
||||
Dictionary<int, int> currentDids;
|
||||
Dictionary<string, int> currentLsNrs;
|
||||
Dictionary<int, List<WbRd>> currentWbRde;
|
||||
Dictionary<int, AT_Kg> kgs;
|
||||
|
||||
using (var ctx = new AppDbContext()) {
|
||||
branches = await ctx.Branches.ToDictionaryAsync(b => b.ZwstId);
|
||||
@ -50,6 +51,7 @@ namespace Elwig.Helpers.Export {
|
||||
currentWbRde = await ctx.WbRde
|
||||
.GroupBy(r => r.KgNr)
|
||||
.ToDictionaryAsync(g => g.Key, g => g.ToList());
|
||||
kgs = await ctx.Katastralgemeinden.Include(k => k.WbKg).ToDictionaryAsync(k => k.KgNr);
|
||||
}
|
||||
|
||||
var data = new List<(
|
||||
@ -101,9 +103,9 @@ namespace Elwig.Helpers.Export {
|
||||
string? line;
|
||||
while ((line = await reader.ReadLineAsync()) != null) {
|
||||
var obj = JsonNode.Parse(line)!.AsObject();
|
||||
var (m, b, telNrs, emailAddrs) = obj.ToMember();
|
||||
var (m, b, telNrs, emailAddrs) = obj.ToMember(kgs);
|
||||
r.Members.Add(m);
|
||||
if (b != null) data[^1].BillingAddresses.Add(b);
|
||||
if (b != null) r.BillingAddresses.Add(b);
|
||||
r.TelephoneNumbers.AddRange(telNrs);
|
||||
r.EmailAddresses.AddRange(emailAddrs);
|
||||
}
|
||||
@ -115,9 +117,12 @@ namespace Elwig.Helpers.Export {
|
||||
string? line;
|
||||
while ((line = await reader.ReadLineAsync()) != null) {
|
||||
var obj = JsonNode.Parse(line)!.AsObject();
|
||||
var (areaCom, wbrd) = obj.ToAreaCom(currentWbRde);
|
||||
var (areaCom, wbrd) = obj.ToAreaCom(kgs, currentWbRde);
|
||||
r.AreaCommitments.Add(areaCom);
|
||||
if (wbrd != null) r.Riede.Add(wbrd);
|
||||
if (wbrd != null) {
|
||||
currentWbRde[wbrd.KgNr].Add(wbrd);
|
||||
r.Riede.Add(wbrd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -223,6 +228,7 @@ namespace Elwig.Helpers.Export {
|
||||
importedMembers.Add((meta.FileName, meta.ZwstId, meta.Device, n, o, members.Count - n - o, meta.MemberFilters));
|
||||
}
|
||||
if (areaCommitments.Count > 0) {
|
||||
ctx.AddRange(riede);
|
||||
var imported = areaCommitments.Where(c => (importNewMembers && !duplicateMgNrs.Contains(c.MgNr)) || (importDuplicateMembers && duplicateMgNrs.Contains(c.MgNr))).ToList();
|
||||
importedAreaComs.Add((meta.FileName, meta.ZwstId, meta.Device, imported.Count, areaCommitments.Count - imported.Count, meta.AreaComFilters));
|
||||
}
|
||||
@ -457,12 +463,16 @@ namespace Elwig.Helpers.Export {
|
||||
};
|
||||
}
|
||||
|
||||
public static (Member, BillingAddr?, List<MemberTelNr>, List<MemberEmailAddr>) ToMember(this JsonNode json) {
|
||||
public static (Member, BillingAddr?, List<MemberTelNr>, List<MemberEmailAddr>) ToMember(this JsonNode json, Dictionary<int, AT_Kg> kgs) {
|
||||
var mgnr = json["mgnr"]!.AsValue().GetValue<int>();
|
||||
var kgnr = json["default_kgnr"]?.AsValue().GetValue<int>();
|
||||
if (kgnr != null && !kgs.Values.Any(k => k.WbKg?.KgNr == kgnr)) {
|
||||
throw new ArgumentException($"Für KG {(kgs.TryGetValue(kgnr.Value, out var k) ? k.Name : "?")} ({kgnr:00000}) ist noch keine Großlage festgelegt!\n(Stammdaten → Herkunftshierarchie)");
|
||||
}
|
||||
return (new Member {
|
||||
MgNr = mgnr,
|
||||
PredecessorMgNr = json["predecessor_mgnr"]?.AsValue().GetValue<int>(),
|
||||
Name = json["name"]!.AsValue().GetValue<string>(),
|
||||
Name = json["name"]?.AsValue().GetValue<string>() ?? json["family_name"]!.AsValue().GetValue<string>(),
|
||||
Prefix = json["prefix"]?.AsValue().GetValue<string>(),
|
||||
GivenName = json["given_name"]?.AsValue().GetValue<string>(),
|
||||
MiddleName = json["middle_names"]?.AsValue().GetValue<string>(),
|
||||
@ -488,7 +498,7 @@ namespace Elwig.Helpers.Export {
|
||||
CountryNum = json["address"]!["country"]!.AsValue().GetValue<int>(),
|
||||
PostalDestId = json["address"]!["postal_dest"]!.AsValue().GetValue<string>(),
|
||||
Address = json["address"]!["address"]!.AsValue().GetValue<string>(),
|
||||
DefaultKgNr = json["default_kgnr"]?.AsValue().GetValue<int>(),
|
||||
DefaultKgNr = kgnr,
|
||||
ContactViaPost = json["contact_postal"]?.AsValue().GetValue<bool>() ?? false,
|
||||
ContactViaEmail = json["contact_email"]?.AsValue().GetValue<bool>() ?? false,
|
||||
Comment = json["comment"]?.AsValue().GetValue<string>(),
|
||||
@ -528,13 +538,13 @@ namespace Elwig.Helpers.Export {
|
||||
};
|
||||
}
|
||||
|
||||
public static (AreaCom, WbRd?) ToAreaCom(this JsonNode json, Dictionary<int, List<WbRd>> riede) {
|
||||
public static (AreaCom, WbRd?) ToAreaCom(this JsonNode json, Dictionary<int, AT_Kg> kgs, Dictionary<int, List<WbRd>> riede) {
|
||||
var kgnr = json["kgnr"]!.AsValue().GetValue<int>();
|
||||
var ried = json["ried"]?.AsValue().GetValue<string>();
|
||||
WbRd? rd = null;
|
||||
bool newRd = false;
|
||||
if (ried != null) {
|
||||
var rde = riede[kgnr] ?? throw new ArgumentException($"KG {kgnr:00000} is no WbKg");
|
||||
var rde = riede[kgnr] ?? throw new ArgumentException($"Für KG {(kgs.TryGetValue(kgnr, out var k) ? k.Name : "?")} ({kgnr:00000}) ist noch keine Großlage festgelegt!\n(Stammdaten → Herkunftshierarchie)");
|
||||
rd = rde.FirstOrDefault(r => r.Name == ried);
|
||||
if (rd == null) {
|
||||
newRd = true;
|
||||
|
@ -8,7 +8,7 @@ namespace Elwig.Helpers {
|
||||
public static class Validator {
|
||||
|
||||
private static readonly Dictionary<string, string[][]> PHONE_NRS = new() {
|
||||
{ "43", new string[][] {
|
||||
{ "43", [
|
||||
[],
|
||||
["57", "59"],
|
||||
[
|
||||
@ -17,17 +17,17 @@ namespace Elwig.Helpers {
|
||||
"650", "651", "652", "653", "655", "657", "659", "660", "661",
|
||||
"663", "664", "665", "666", "667", "668", "669", "67", "68", "69"
|
||||
]
|
||||
} },
|
||||
{ "49", Array.Empty<string[]>() },
|
||||
{ "48", Array.Empty<string[]>() },
|
||||
{ "420", Array.Empty<string[]>() },
|
||||
{ "421", Array.Empty<string[]>() },
|
||||
{ "36", Array.Empty<string[]>() },
|
||||
{ "386", Array.Empty<string[]>() },
|
||||
{ "39", Array.Empty<string[]>() },
|
||||
{ "33", Array.Empty<string[]>() },
|
||||
{ "41", Array.Empty<string[]>() },
|
||||
{ "423", Array.Empty<string[]>() },
|
||||
] },
|
||||
{ "49", [] },
|
||||
{ "48", [] },
|
||||
{ "420", [] },
|
||||
{ "421", [] },
|
||||
{ "36", [] },
|
||||
{ "386", [] },
|
||||
{ "39", [] },
|
||||
{ "33", [] },
|
||||
{ "41", [] },
|
||||
{ "423", [] },
|
||||
};
|
||||
|
||||
public static ValidationResult CheckInteger(TextBox input, bool required) {
|
||||
|
@ -54,7 +54,7 @@ namespace Elwig.Models.Dtos {
|
||||
public class AreaComUnderDeliveryRow {
|
||||
public int MgNr;
|
||||
public string Name1;
|
||||
public string Name2;
|
||||
public string? Name2;
|
||||
public string Address;
|
||||
public int Plz;
|
||||
public string Locality;
|
||||
@ -88,7 +88,7 @@ namespace Elwig.Models.Dtos {
|
||||
[Column("name_1")]
|
||||
public required string Name1 { get; set; }
|
||||
[Column("name_2")]
|
||||
public required string Name2 { get; set; }
|
||||
public string? Name2 { get; set; }
|
||||
[Column("address")]
|
||||
public required string Address { get; set; }
|
||||
[Column("plz")]
|
||||
|
@ -79,7 +79,7 @@ namespace Elwig.Models.Dtos {
|
||||
public class CreditNoteRow {
|
||||
public int MgNr;
|
||||
public string Name1;
|
||||
public string Name2;
|
||||
public string? Name2;
|
||||
public string Address;
|
||||
public int Plz;
|
||||
public string Locality;
|
||||
@ -144,7 +144,7 @@ namespace Elwig.Models.Dtos {
|
||||
[Column("name_1")]
|
||||
public required string Name1 { get; set; }
|
||||
[Column("name_2")]
|
||||
public required string Name2 { get; set; }
|
||||
public string? Name2 { get; set; }
|
||||
[Column("address")]
|
||||
public required string Address { get; set; }
|
||||
[Column("plz")]
|
||||
|
@ -38,7 +38,7 @@ namespace Elwig.Models.Dtos {
|
||||
public string Branch;
|
||||
public int MgNr;
|
||||
public string Name1;
|
||||
public string Name2;
|
||||
public string? Name2;
|
||||
public string AdministrativeName;
|
||||
public string SortId;
|
||||
public string Variety;
|
||||
|
@ -58,7 +58,7 @@ namespace Elwig.Models.Dtos {
|
||||
public string DeliveryBranch;
|
||||
public int MgNr;
|
||||
public string Name1;
|
||||
public string Name2;
|
||||
public string? Name2;
|
||||
public string AdministrativeName;
|
||||
public string? MemberBranch;
|
||||
public string SortId;
|
||||
|
@ -72,7 +72,7 @@ namespace Elwig.Models.Dtos {
|
||||
public class MemberDeliveryPerVariantRow {
|
||||
public int MgNr;
|
||||
public string Name1;
|
||||
public string Name2;
|
||||
public string? Name2;
|
||||
public string Address;
|
||||
public int Plz;
|
||||
public string Locality;
|
||||
@ -104,7 +104,7 @@ namespace Elwig.Models.Dtos {
|
||||
[Column("name_1")]
|
||||
public required string Name1 { get; set; }
|
||||
[Column("name_2")]
|
||||
public required string Name2 { get; set; }
|
||||
public string? Name2 { get; set; }
|
||||
[Column("address")]
|
||||
public required string Address { get; set; }
|
||||
[Column("plz")]
|
||||
|
@ -31,6 +31,7 @@ namespace Elwig.Models.Dtos {
|
||||
("EntryDate", "Eintritt", null, 20),
|
||||
("ExitDate", "Austritt", null, 20),
|
||||
("AreaCommitment", "geb. Fläche", "m²", 20),
|
||||
("AreaCommitmentsFiltered", "geb. Fläche", "Vtrg.|m²", 30),
|
||||
("UstIdNr", "UID", null, 25),
|
||||
("Iban", "IBAN", null, 45),
|
||||
("Bic", "BIC", null, 30),
|
||||
@ -45,8 +46,8 @@ namespace Elwig.Models.Dtos {
|
||||
base(MemberList.Name, MemberList.Name, string.Join(" / ", filterNames), rows, FieldNames) {
|
||||
}
|
||||
|
||||
public static async Task<MemberListData> FromQuery(IQueryable<Member> query, List<string> filterNames) {
|
||||
var areaCom = await query.ToDictionaryAsync(m => m.MgNr, m => Utils.ActiveAreaCommitments(m.AreaCommitments).Sum(c => c.Area));
|
||||
public static async Task<MemberListData> FromQuery(IQueryable<Member> query, List<string> filterNames, IEnumerable<string> filterAreaCom) {
|
||||
var areaComs = await query.ToDictionaryAsync(m => m.MgNr, m => Utils.ActiveAreaCommitments(m.AreaCommitments));
|
||||
return new((await query
|
||||
.Include(m => m.DefaultWbKg!.AtKg)
|
||||
.Include(m => m.Branch)
|
||||
@ -55,13 +56,17 @@ namespace Elwig.Models.Dtos {
|
||||
.Include(m => m.TelephoneNumbers)
|
||||
.Include(m => m.EmailAddresses)
|
||||
.AsSplitQuery()
|
||||
.ToListAsync()).Select(m => new MemberListRow(m, areaCom[m.MgNr])), filterNames);
|
||||
.ToListAsync()).Select(m => new MemberListRow(m,
|
||||
areaComs[m.MgNr].Sum(c => c.Area),
|
||||
areaComs[m.MgNr].Where(c => filterAreaCom.Contains(c.VtrgId)).GroupBy(c => c.VtrgId).ToDictionary(g => g.Key, g => g.Sum(c => c.Area)))),
|
||||
filterNames);
|
||||
}
|
||||
}
|
||||
|
||||
public class MemberListRow {
|
||||
public int MgNr;
|
||||
public string? Name1;
|
||||
public string? AdminName1;
|
||||
public string? Name2;
|
||||
public string? DefaultKg;
|
||||
public string? Branch;
|
||||
@ -78,6 +83,7 @@ namespace Elwig.Models.Dtos {
|
||||
public string? Iban;
|
||||
public string? Bic;
|
||||
public int? AreaCommitment;
|
||||
public (string VtrgId, int Area)[] AreaCommitmentsFiltered;
|
||||
public bool IsBuchführend;
|
||||
public bool IsOrganic;
|
||||
public bool IsActive;
|
||||
@ -89,9 +95,10 @@ namespace Elwig.Models.Dtos {
|
||||
public string? AdditionalContact;
|
||||
public string? Comment;
|
||||
|
||||
public MemberListRow(Member m, int? areaCom = null) {
|
||||
public MemberListRow(Member m, int? areaCom = null, Dictionary<string, int>? filtered = null) {
|
||||
MgNr = m.MgNr;
|
||||
Name1 = m.Name;
|
||||
AdminName1 = m.AdministrativeName1;
|
||||
Name2 = m.AdministrativeName2;
|
||||
DefaultKg = m.DefaultKg?.Name;
|
||||
Branch = m.Branch?.Name;
|
||||
@ -125,6 +132,7 @@ namespace Elwig.Models.Dtos {
|
||||
.Concat(m.EmailAddresses.OrderBy(a => a.Nr).Select(a => a.Address).Except([EmailAddress])));
|
||||
Comment = m.Comment;
|
||||
AreaCommitment = areaCom == 0 ? null : areaCom;
|
||||
AreaCommitmentsFiltered = filtered != null ? filtered.OrderBy(f => f.Key).Select(f => (f.Key, f.Value)).ToArray() : [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ namespace Elwig.Models.Dtos {
|
||||
[Column("name_1")]
|
||||
public required string Name1 { get; set; }
|
||||
[Column("name_2")]
|
||||
public required string Name2 { get; set; }
|
||||
public string? Name2 { get; set; }
|
||||
[Column("address")]
|
||||
public required string Address { get; set; }
|
||||
[Column("plz")]
|
||||
|
@ -9,7 +9,6 @@ using Elwig.Documents;
|
||||
using Elwig.Helpers.Export;
|
||||
using Elwig.Models.Dtos;
|
||||
using Microsoft.Win32;
|
||||
using System.Net.Http;
|
||||
using System.Windows.Input;
|
||||
using System.Windows;
|
||||
using System;
|
||||
@ -27,6 +26,8 @@ namespace Elwig.Services {
|
||||
}
|
||||
|
||||
public static void ClearInputs(this DeliveryAncmtAdminViewModel vm) {
|
||||
vm.StatusAncmtCreated = "-";
|
||||
vm.StatusAncmtModified = "-";
|
||||
}
|
||||
|
||||
public static async Task FillInputs(this DeliveryAncmtAdminViewModel vm, DeliveryAncmt a) {
|
||||
@ -34,6 +35,8 @@ namespace Elwig.Services {
|
||||
vm.DeliverySchedule = (DeliverySchedule?)ControlUtils.GetItemFromSourceWithPk(vm.DeliveryScheduleSource, a.Year, a.DsNr);
|
||||
vm.SortId = a.SortId;
|
||||
vm.Weight = a.Weight;
|
||||
vm.StatusAncmtCreated = $"{a.CreatedTimestamp:dd.MM.yyyy, HH:mm} ({a.Type})";
|
||||
vm.StatusAncmtModified = a.ModifiedTimestamp != a.CreatedTimestamp ? $"{a.ModifiedTimestamp:dd.MM.yyyy, HH:mm}" : "-";
|
||||
}
|
||||
|
||||
public static async Task<(List<string>, IQueryable<DeliveryAncmt>, List<string>)> GetFilters(this DeliveryAncmtAdminViewModel vm, AppDbContext ctx) {
|
||||
|
@ -420,7 +420,7 @@ namespace Elwig.Services {
|
||||
if (d.ShowDialog() == true) {
|
||||
Mouse.OverrideCursor = Cursors.AppStarting;
|
||||
try {
|
||||
var data = await MemberListData.FromQuery(query, filterNames);
|
||||
var data = await MemberListData.FromQuery(query, filterNames, filterNames.Where(f => f.StartsWith("Flächenbindung")).Select(f => f.Split(' ')[^1]));
|
||||
using var ods = new OdsFile(d.FileName);
|
||||
await ods.AddTable(data);
|
||||
} catch (Exception exc) {
|
||||
@ -460,26 +460,30 @@ namespace Elwig.Services {
|
||||
try {
|
||||
var filename = $"{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{App.ZwstId}.elwig.zip";
|
||||
var path = Path.Combine(App.TempPath, filename);
|
||||
var list = await query
|
||||
var members = await query
|
||||
.OrderBy(m => m.MgNr)
|
||||
.Include(m => m.BillingAddress)
|
||||
.Include(m => m.TelephoneNumbers)
|
||||
.Include(m => m.EmailAddresses)
|
||||
.AsSplitQuery()
|
||||
.ToListAsync();
|
||||
if (list.Count == 0) {
|
||||
var areaComs = await query
|
||||
.SelectMany(m => m.AreaCommitments)
|
||||
.Include(c => c.Rd)
|
||||
.ToListAsync();
|
||||
if (members.Count == 0) {
|
||||
MessageBox.Show("Es wurden keine Mitglieder zum Hochladen ausgewählt!", "Mitglieder hochladen",
|
||||
MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
} else {
|
||||
await ElwigData.Export(path, list, filterNames);
|
||||
await ElwigData.Export(path, members, areaComs, filterNames);
|
||||
await Utils.UploadExportData(path, App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
|
||||
MessageBox.Show($"Hochladen von {list.Count} Mitgliedern erfolgreich!", "Mitglieder hochgeladen",
|
||||
MessageBox.Show($"Hochladen von {members.Count} Mitgliedern erfolgreich!", "Mitglieder hochgeladen",
|
||||
MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
} catch (HttpRequestException exc) {
|
||||
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Lieferungen hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Mitglieder hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
} catch (TaskCanceledException exc) {
|
||||
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Mitglieder hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
} catch (Exception exc) {
|
||||
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
@ -487,7 +491,7 @@ namespace Elwig.Services {
|
||||
} else {
|
||||
Mouse.OverrideCursor = Cursors.AppStarting;
|
||||
try {
|
||||
var data = await MemberListData.FromQuery(query, filterNames);
|
||||
var data = await MemberListData.FromQuery(query, filterNames, filterNames.Where(f => f.StartsWith("Flächenbindung")).Select(f => f.Split(' ')[^1]));
|
||||
using var doc = new MemberList(string.Join(" / ", filterNames), data);
|
||||
await Utils.ExportDocument(doc, mode);
|
||||
} catch (Exception exc) {
|
||||
|
@ -62,6 +62,15 @@ namespace Elwig.ViewModels {
|
||||
set => WeightString = $"{value}";
|
||||
}
|
||||
|
||||
[ObservableProperty]
|
||||
private string _statusAncmts = "-";
|
||||
[ObservableProperty]
|
||||
private string _statusWeight = "-";
|
||||
[ObservableProperty]
|
||||
private string _statusAncmtCreated = "-";
|
||||
[ObservableProperty]
|
||||
private string _statusAncmtModified = "-";
|
||||
|
||||
[ObservableProperty]
|
||||
private Visibility _controlButtonsVisibility = Visibility.Visible;
|
||||
[ObservableProperty]
|
||||
|
@ -61,7 +61,7 @@
|
||||
<RowDefinition Height="24"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*" MinWidth="250"/>
|
||||
<ColumnDefinition Width="1.25*" MinWidth="250"/>
|
||||
<ColumnDefinition Width="5"/>
|
||||
<ColumnDefinition Width="1*" MinWidth="300"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
@ -123,6 +123,7 @@
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding Date, StringFormat='ddd.'}" Width="24"/>
|
||||
<TextBlock Text="{Binding Date, StringFormat='dd.MM.'}" Width="32"/>
|
||||
<TextBlock Text="{Binding ZwstId}" Width="25" TextAlignment="Center"/>
|
||||
<TextBlock Text="{Binding Description}" Width="200"/>
|
||||
@ -267,6 +268,7 @@
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding Date, StringFormat='ddd.'}" Width="28"/>
|
||||
<TextBlock Text="{Binding Date, StringFormat='dd.MM.'}" Width="35"/>
|
||||
<TextBlock Text="{Binding ZwstId}" Width="30" TextAlignment="Center"/>
|
||||
<TextBlock Text="{Binding Description}"/>
|
||||
@ -305,9 +307,11 @@
|
||||
<ItemsPanelTemplate>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="150"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="200"/>
|
||||
<ColumnDefinition Width="1.125*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="1*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
@ -315,7 +319,27 @@
|
||||
</ItemsPanelTemplate>
|
||||
</StatusBar.ItemsPanel>
|
||||
<StatusBarItem>
|
||||
|
||||
<TextBlock>
|
||||
Anmeldungen: <Run Text="{Binding StatusAncmts}"/>
|
||||
</TextBlock>
|
||||
</StatusBarItem>
|
||||
<Separator Grid.Column="1"/>
|
||||
<StatusBarItem Grid.Column="2">
|
||||
<TextBlock>
|
||||
Gewicht: <Run Text="{Binding StatusWeight}"/>
|
||||
</TextBlock>
|
||||
</StatusBarItem>
|
||||
<Separator Grid.Column="3"/>
|
||||
<StatusBarItem Grid.Column="4">
|
||||
<TextBlock>
|
||||
Anmldg. erstellt: <Run Text="{Binding StatusAncmtCreated}"/>
|
||||
</TextBlock>
|
||||
</StatusBarItem>
|
||||
<Separator Grid.Column="5"/>
|
||||
<StatusBarItem Grid.Column="6">
|
||||
<TextBlock>
|
||||
Anmldg. geändert: <Run Text="{Binding StatusAncmtModified}"/>
|
||||
</TextBlock>
|
||||
</StatusBarItem>
|
||||
</StatusBar>
|
||||
</Grid>
|
||||
|
@ -127,6 +127,9 @@ namespace Elwig.Windows {
|
||||
DeliveryAncmtList_SelectionChanged, ViewModel.TextFilter.Count > 0 ? ControlUtils.RenewSourceDefault.IfOnly : ControlUtils.RenewSourceDefault.None, !updateSort);
|
||||
if (updateSort && DeliveryAncmtList.SelectedItem != null)
|
||||
DeliveryAncmtList.ScrollIntoView(DeliveryAncmtList.SelectedItem);
|
||||
|
||||
ViewModel.StatusAncmts = $"{deliveryAncmts.Count:N0}";
|
||||
ViewModel.StatusWeight = $"{deliveryAncmts.Sum(a => a.Weight):N0} kg";
|
||||
}
|
||||
|
||||
private async Task RefreshInputs(bool validate = false) {
|
||||
|
@ -200,7 +200,7 @@
|
||||
<Label Content="Datum/Zwst.:" Margin="10,10,0,10"/>
|
||||
<TextBox x:Name="DateInput" Text="{Binding DateString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
Margin="0,10,10,10" Width="77" Grid.Column="1" HorizontalAlignment="Left" TextAlignment="Right"
|
||||
TextChanged="DateInput_TextChanged" LostFocus="DateInput_LostFocus"/>
|
||||
TextChanged="ScheduleDateInput_TextChanged" LostFocus="DateInput_LostFocus"/>
|
||||
<ComboBox x:Name="BranchInput" SelectedItem="{Binding Branch, Mode=TwoWay}" ItemsSource="{Binding BranchSource, Mode=TwoWay}"
|
||||
DisplayMemberPath="Name" TextSearch.TextPath="Name"
|
||||
Margin="82,10,10,10" Width="150" Grid.Column="1" HorizontalAlignment="Left"/>
|
||||
|
@ -297,8 +297,8 @@ namespace Elwig.Windows {
|
||||
ViewModel.ControlButtonsVisibility = Visibility.Hidden;
|
||||
}
|
||||
|
||||
private new void DateInput_TextChanged(object sender, TextChangedEventArgs evt) {
|
||||
base.DateInput_TextChanged(sender, evt);
|
||||
private void ScheduleDateInput_TextChanged(object sender, TextChangedEventArgs evt) {
|
||||
DateInput_TextChanged(sender, evt);
|
||||
if (ViewModel.Date is DateOnly date) {
|
||||
ViewModel.AncmtToDate = date.AddDays(-2);
|
||||
}
|
||||
|
@ -150,6 +150,9 @@ namespace Elwig.Windows {
|
||||
MemberList_SelectionChanged, ViewModel.TextFilter.Count > 0 ? ControlUtils.RenewSourceDefault.IfOnly : ControlUtils.RenewSourceDefault.None, !updateSort);
|
||||
if (updateSort && MemberList.SelectedItem != null)
|
||||
MemberList.ScrollIntoView(MemberList.SelectedItem);
|
||||
|
||||
ViewModel.StatusMembers = $"{members.Count:N0} ({await ctx.Members.CountAsync():N0})";
|
||||
ViewModel.StatusBusinessShares = $"{members.Sum(m => m.BusinessShares):N0} ({await ctx.Members.SumAsync(m => m.BusinessShares):N0})";
|
||||
}
|
||||
|
||||
private async Task RefreshInputs(bool validate = false) {
|
||||
@ -237,7 +240,6 @@ namespace Elwig.Windows {
|
||||
var mM = Math.Max(mA.Length, Math.Max(mI.Length, mT.Length));
|
||||
var mS = mM > 3;
|
||||
if (mS) mM--;
|
||||
ViewModel.StatusMembers = $"{mA} ({mT})";
|
||||
ViewModel.StatusMembersToolTip =
|
||||
$"{new string(s1, Math.Max(0, mM - mA.Length))}{(mS && mA.Length < 4 ? s2 : "")}{mA} aktive Mitglieder\n" +
|
||||
$"{new string(s1, Math.Max(0, mM - mI.Length))}{(mS && mI.Length < 4 ? s2 : "")}{mI} nicht aktive Mitglieder\n" +
|
||||
@ -249,7 +251,6 @@ namespace Elwig.Windows {
|
||||
var bM = Math.Max(bA.Length, Math.Max(bI.Length, bT.Length));
|
||||
var bS = bM > 3;
|
||||
if (bS) bM--;
|
||||
ViewModel.StatusBusinessShares = $"{bA} ({bT})";
|
||||
ViewModel.StatusBusinessSharesToolTip =
|
||||
$"{new string(s1, Math.Max(0, bM - bA.Length))}{(bS && bA.Length < 4 ? s2 : "")}{bA} Geschäftsanteile von aktiven Mitgliedern\n" +
|
||||
$"{new string(s1, Math.Max(0, bM - bI.Length))}{(bS && bI.Length < 4 ? s2 : "")}{bI} Geschäftsanteile von nicht aktiven Mitgliedern\n" +
|
||||
|
@ -9,7 +9,7 @@ namespace Tests.DocumentTests {
|
||||
[Test]
|
||||
public async Task Test_01_TwoMembers() {
|
||||
using var ctx = new AppDbContext();
|
||||
var data = await MemberListData.FromQuery(ctx.Members, []);
|
||||
var data = await MemberListData.FromQuery(ctx.Members, [], []);
|
||||
using var doc = new MemberList("Alle Mitglieder", data);
|
||||
var text = await Utils.GeneratePdfText(doc, true);
|
||||
var table = Utils.ExtractTable(text);
|
||||
|
Reference in New Issue
Block a user