[#3] Elwig: Add user-friendly sync method
All checks were successful
Test / Run tests (push) Successful in 2m57s

This commit is contained in:
2024-07-26 14:58:15 +02:00
parent b6afb94246
commit b49c9c65b1
7 changed files with 517 additions and 102 deletions

View File

@ -12,6 +12,8 @@ using Microsoft.EntityFrameworkCore;
namespace Elwig.Helpers.Export {
public static class ElwigData {
public enum ImportMode { Auto, Interactively, FromBranches }
public static readonly string ImportedTxt = Path.Combine(App.DataPath, "imported.txt");
public static async Task<string[]> GetImportedFiles() {
@ -26,36 +28,61 @@ namespace Elwig.Helpers.Export {
await File.AppendAllLinesAsync(ImportedTxt, filenames, Utils.UTF8);
}
public static Task Import(string filename, bool interactive) => Import([filename], interactive);
public static Task Import(string filename, ImportMode mode) => Import([filename], mode);
public static async Task Import(IEnumerable<string> filenames, bool interactive) {
public static async Task Import(IEnumerable<string> filenames, ImportMode mode) {
try {
using var ctx = new AppDbContext();
var branches = await ctx.Branches.ToDictionaryAsync(b => b.ZwstId);
var currentDids = await ctx.Deliveries
.GroupBy(d => d.Year)
.ToDictionaryAsync(g => g.Key, g => g.Max(d => d.DId));
var currentWbRde = await ctx.WbRde
.GroupBy(r => r.KgNr)
.ToDictionaryAsync(g => g.Key, g => g.ToList());
var deliveries = new List<Delivery>();
var deliveryParts = new List<DeliveryPart>();
var modifiers = new List<DeliveryPartModifier>();
var data = new List<(
List<Member> Members,
List<BillingAddr> BillingAddresses,
List<MemberTelNr> TelephoneNumbers,
List<MemberEmailAddr> EmailAddresses,
List<AreaCom> AreaCommitments,
List<WbRd> Riede,
List<Delivery> Deliveries,
List<DeliveryPart> DeliveryParts,
List<DeliveryPartModifier> Modifiers)>();
var metaData = new List<(string Name, int DeliveryNum, string Filters)>();
var metaData = new List<(string FileName, string ZwstId, string Device,
int? MemberNum, string? MemberFilters,
int? AreaComNum, string? AreaComFilters,
int? DeliveryNum, string? DeliveryFilters)>();
foreach (var filename in filenames) {
// TODO read encrypted files
using var zip = ZipFile.Open(filename, ZipArchiveMode.Read);
var version = zip.GetEntry("version");
using (var reader = new StreamReader(version!.Open(), Utils.UTF8)) {
if (await reader.ReadToEndAsync() != "elwig:1")
throw new FileFormatException("Ungültige Export-Datei");
throw new FileFormatException($"Ungültige Export-Datei ({filename})");
}
var metaJson = zip.GetEntry("meta.json");
var meta = await JsonNode.ParseAsync(metaJson!.Open());
var deliveryCount = meta!["deliveries"]?["count"]!.AsValue().GetValue<int>();
var deliveryFilters = meta!["deliveries"]?["filters"]!.AsArray().Select(f => f!.AsValue().GetValue<string>()).ToArray();
if (deliveryCount != null && deliveryFilters != null)
metaData.Add((Path.GetFileName(filename), (int)deliveryCount, string.Join(" / ", deliveryFilters)));
var memberCount = meta!["members"]?["count"]?.AsValue().GetValue<int>();
var memberFilters = meta!["members"]?["filters"]?.AsArray().Select(f => f!.AsValue().GetValue<string>()).ToArray();
var areaComCount = meta!["area_commitments"]?["count"]?.AsValue().GetValue<int>();
var areaComFilters = meta!["area_commitments"]?["filters"]?.AsArray().Select(f => f!.AsValue().GetValue<string>()).ToArray();
var deliveryCount = meta!["deliveries"]?["count"]?.AsValue().GetValue<int>();
var deliveryFilters = meta!["deliveries"]?["filters"]?.AsArray().Select(f => f!.AsValue().GetValue<string>()).ToArray();
metaData.Add((Path.GetFileName(filename),
meta["zwstid"]!.AsValue().GetValue<string>(), meta["device"]!.AsValue().GetValue<string>(),
memberCount, memberFilters != null ? string.Join(" / ", memberFilters) : null,
areaComCount, areaComFilters != null ? string.Join(" / ", areaComFilters) : null,
deliveryCount, deliveryFilters != null ? string.Join(" / ", deliveryFilters) : null));
data.Add(new([], [], [], [], [], [], [], new([], [])));
var r = data[^1];
var membersJson = zip.GetEntry("members.json");
if (membersJson != null) {
@ -63,7 +90,11 @@ namespace Elwig.Helpers.Export {
string? line;
while ((line = await reader.ReadLineAsync()) != null) {
var obj = JsonNode.Parse(line)!.AsObject();
// TODO import members.json
var (m, b, telNrs, emailAddrs) = obj.ToMember();
r.Members.Add(m);
if (b != null) data[^1].BillingAddresses.Add(b);
r.TelephoneNumbers.AddRange(telNrs);
r.EmailAddresses.AddRange(emailAddrs);
}
}
@ -73,7 +104,9 @@ namespace Elwig.Helpers.Export {
string? line;
while ((line = await reader.ReadLineAsync()) != null) {
var obj = JsonNode.Parse(line)!.AsObject();
// TODO import area_commitments.json
var (areaCom, wbrd) = obj.ToAreaCom(currentWbRde);
r.AreaCommitments.Add(areaCom);
if (wbrd != null) r.Riede.Add(wbrd);
}
}
@ -83,85 +116,399 @@ namespace Elwig.Helpers.Export {
string? line;
while ((line = await reader.ReadLineAsync()) != null) {
var obj = JsonNode.Parse(line)!.AsObject();
var (d, parts, mods) = JsonToDelivery(obj, currentDids);
deliveries.Add(d);
deliveryParts.AddRange(parts);
modifiers.AddRange(mods);
var (d, parts, mods) = obj.ToDelivery(currentDids);
r.Deliveries.Add(d);
r.DeliveryParts.AddRange(parts);
r.Modifiers.AddRange(mods);
}
}
}
var lsnrs = deliveries.Select(d => d.LsNr).ToList();
var duplicateLsNrs = await ctx.Deliveries
.Where(d => lsnrs.Contains(d.LsNr))
.Select(d => d.LsNr)
.ToListAsync();
var duplicateDIds = deliveries
.Where(d => duplicateLsNrs.Contains(d.LsNr))
.Select(d => (d.Year, d.DId))
.ToList();
bool overwriteDelivieries = false;
if (duplicateLsNrs.Count > 0) {
var res = MessageBox.Show($"Sollen {duplicateLsNrs.Count} Lieferungen überschreiben werden?", "Lieferungen überschreiben",
MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No);
overwriteDelivieries = res == MessageBoxResult.Yes;
var importedMembers = new List<(string FileName, string ZwstId, string Device, int New, int Overwritten, int NotImported, string Filters)>();
var importedDeliveries = new List<(string FileName, string ZwstId, string Device, int New, int Overwritten, int NotImported, string Filters)>();
foreach (var ((members, billingAddresses, telephoneNumbers, emailAddresses, areaCommitments, riede, deliveries, deliveryParts, modifiers), meta) in data.Zip(metaData)) {
var branch = branches[meta.ZwstId];
var device = meta.Device;
var mgnrs = members.Select(m => m.MgNr).ToList();
var duplicateMgNrs = await ctx.Members
.Where(m => mgnrs.Contains(m.MgNr))
.Select(m => m.MgNr)
.ToListAsync();
bool importNewMembers = false, importDuplicateMembers = false;
if (mode == ImportMode.Interactively) {
if (mgnrs.Count - duplicateMgNrs.Count > 0)
importNewMembers = ImportQuestion(branch.Name, device, "Mitglieder", false, mgnrs.Count - duplicateMgNrs.Count);
} else {
importNewMembers = true;
}
if (duplicateMgNrs.Count > 0)
importDuplicateMembers = ImportQuestion(branch.Name, device, "Mitglieder", true, duplicateMgNrs.Count);
var lsnrs = deliveries.Select(d => d.LsNr).ToList();
var duplicateLsNrs = await ctx.Deliveries
.Where(d => lsnrs.Contains(d.LsNr))
.Select(d => d.LsNr)
.ToListAsync();
var duplicateDIds = deliveries
.Where(d => duplicateLsNrs.Contains(d.LsNr))
.Select(d => (d.Year, d.DId))
.ToList();
var allowedDuplicateLsNrs = new List<string>();
bool importNewDeliveries = false, importDuplicateDeliveries = false;
if (mode == ImportMode.Interactively) {
if (lsnrs.Count - duplicateLsNrs.Count > 0)
importNewDeliveries = ImportQuestion(branch.Name, device, "Lieferungen", false, lsnrs.Count - duplicateLsNrs.Count);
if (duplicateLsNrs.Count > 0)
importDuplicateDeliveries = ImportQuestion(branch.Name, device, "Lieferungen", true, duplicateLsNrs.Count);
} else if (mode == ImportMode.FromBranches) {
importNewDeliveries = true;
if (duplicateLsNrs.Count > 0) {
allowedDuplicateLsNrs = await ctx.Deliveries
.Where(d => lsnrs.Contains(d.LsNr) && d.ZwstId == branch.ZwstId)
.Select(d => d.LsNr)
.ToListAsync();
if (duplicateLsNrs.Count - allowedDuplicateLsNrs.Count > 0)
importDuplicateDeliveries = ImportQuestion(branch.Name, device, "Lieferungen", true, duplicateLsNrs.Count - allowedDuplicateLsNrs.Count);
}
} else {
importNewDeliveries = true;
if (duplicateLsNrs.Count > 0)
importDuplicateDeliveries = ImportQuestion(branch.Name, device, "Lieferungen", true, duplicateLsNrs.Count);
}
if (importDuplicateMembers) {
ctx.RemoveRange(ctx.BillingAddresses.Where(a => duplicateMgNrs.Contains(a.MgNr)));
ctx.RemoveRange(ctx.MemberTelephoneNrs.Where(n => duplicateMgNrs.Contains(n.MgNr)));
ctx.RemoveRange(ctx.MemberEmailAddrs.Where(a => duplicateMgNrs.Contains(a.MgNr)));
ctx.UpdateRange(members.Where(m => duplicateMgNrs.Contains(m.MgNr)));
ctx.AddRange(billingAddresses.Where(a => duplicateMgNrs.Contains(a.MgNr)));
ctx.AddRange(telephoneNumbers.Where(n => duplicateMgNrs.Contains(n.MgNr)));
ctx.AddRange(emailAddresses.Where(a => duplicateMgNrs.Contains(a.MgNr)));
}
if (importNewMembers) {
ctx.AddRange(members.Where(m => !duplicateMgNrs.Contains(m.MgNr)));
ctx.AddRange(billingAddresses.Where(a => !duplicateMgNrs.Contains(a.MgNr)));
ctx.AddRange(telephoneNumbers.Where(n => !duplicateMgNrs.Contains(n.MgNr)));
ctx.AddRange(emailAddresses.Where(a => !duplicateMgNrs.Contains(a.MgNr)));
}
if (members.Count > 0) {
var n = importNewMembers ? members.Count - duplicateMgNrs.Count : 0;
var o = importDuplicateDeliveries ? duplicateMgNrs.Count : 0;
importedMembers.Add((meta.FileName, meta.ZwstId, meta.Device, n, o, members.Count - n - o, meta.MemberFilters));
}
if (allowedDuplicateLsNrs.Count > 0) {
var dids = deliveries
.Where(d => allowedDuplicateLsNrs.Contains(d.LsNr))
.Select(d => (d.Year, d.DId))
.ToList();
ctx.RemoveRange(ctx.DeliveryParts.Where(p => allowedDuplicateLsNrs.Contains(p.Delivery.LsNr)));
ctx.UpdateRange(deliveries.Where(d => dids.Contains((d.Year, d.DId))));
ctx.AddRange(deliveryParts.Where(p => dids.Contains((p.Year, p.DId))));
ctx.AddRange(modifiers.Where(m => dids.Contains((m.Year, m.DId))));
}
if (importDuplicateDeliveries) {
var l = duplicateLsNrs.Except(allowedDuplicateLsNrs).ToList();
var dids = deliveries
.Where(d => l.Contains(d.LsNr))
.Select(d => (d.Year, d.DId))
.ToList();
ctx.RemoveRange(ctx.DeliveryParts.Where(p => l.Contains(p.Delivery.LsNr)));
ctx.UpdateRange(deliveries.Where(d => dids.Contains((d.Year, d.DId))));
ctx.AddRange(deliveryParts.Where(p => dids.Contains((p.Year, p.DId))));
ctx.AddRange(modifiers.Where(m => dids.Contains((m.Year, m.DId))));
}
if (importNewDeliveries) {
ctx.AddRange(deliveries.Where(d => !duplicateDIds.Contains((d.Year, d.DId))));
ctx.AddRange(deliveryParts.Where(p => !duplicateDIds.Contains((p.Year, p.DId))));
ctx.AddRange(modifiers.Where(m => !duplicateDIds.Contains((m.Year, m.DId))));
}
if (deliveries.Count > 0) {
var n = importNewDeliveries ? deliveries.Count - duplicateDIds.Count : 0;
var o = allowedDuplicateLsNrs.Count + (importDuplicateDeliveries ? duplicateDIds.Count - allowedDuplicateLsNrs.Count : 0);
importedDeliveries.Add((meta.FileName, meta.ZwstId, meta.Device, n, o, deliveries.Count - n - o, meta.DeliveryFilters));
}
try {
await ctx.SaveChangesAsync();
} catch (DbUpdateConcurrencyException) { }
await AddImportedFiles(filenames.Select(f => Path.GetFileName(f)));
}
if (overwriteDelivieries) {
ctx.RemoveRange(ctx.Deliveries.Where(d => duplicateLsNrs.Contains(d.LsNr)));
ctx.AddRange(deliveries);
ctx.AddRange(deliveryParts);
ctx.AddRange(modifiers);
} else {
ctx.AddRange(deliveries.Where(d => !duplicateDIds.Contains((d.Year, d.DId))));
ctx.AddRange(deliveryParts.Where(p => !duplicateDIds.Contains((p.Year, p.DId))));
ctx.AddRange(modifiers.Where(m => !duplicateDIds.Contains((m.Year, m.DId))));
}
await ctx.SaveChangesAsync();
await AddImportedFiles(filenames.Select(f => Path.GetFileName(f)));
await App.HintContextChange();
MessageBox.Show(
$"Das importieren der Daten war erfolgreich!\n" +
$"Folgendes wurde importiert:\n" +
$" Lieferungen: {deliveries.Count}\n" +
string.Join("\n", metaData.Select(d => $" {d.Name} ({d.DeliveryNum})\n {d.Filters}")) +
"\n", "Importieren erfolgreich",
string.Join("\n", [
$"Mitglieder: {importedMembers.Sum(d => d.New + d.Overwritten)}",
..importedMembers.Select(d =>
$" {d.FileName} ({d.New + d.Overwritten})\n" +
$" ({d.New} neu, {d.Overwritten} überschrieben, {d.NotImported} nicht importiert)\n" +
$" Zweigstelle: {branches[d.ZwstId].Name} (Gerät {d.Device})\n" +
$" Filter: {d.Filters}"),
$"Lieferungen: {importedDeliveries.Sum(d => d.New + d.Overwritten)}",
..importedDeliveries.Select(d =>
$" {d.FileName} ({d.New + d.Overwritten})\n" +
$" ({d.New} neu, {d.Overwritten} überschr., {d.NotImported} nicht importiert)\n" +
$" Zwst.: {branches[d.ZwstId].Name} (Gerät {d.Device})\n" +
$" Filter: {d.Filters}")
]),
"Importieren erfolgreich",
MessageBoxButton.OK, MessageBoxImage.Information);
} catch (Exception exc) {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
public static async Task ExportDeliveries(string filename, IEnumerable<Delivery> deliveries, IEnumerable<string> filters) {
File.Delete(filename);
using var zip = ZipFile.Open(filename, ZipArchiveMode.Create);
private static bool ImportQuestion(string branch, string device, string subject, bool duplicate, int number) {
return MessageBox.Show(
$"Sollen {number} {(duplicate ? "" : "neue ")}{subject} durch die Zweigstelle\n" +
$"{branch} (Gerät {device}) {(duplicate ? "überschrieben" : "importiert")} werden?",
$"{subject} importieren",
MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.Yes
) == MessageBoxResult.Yes;
}
var version = zip.CreateEntry("version", CompressionLevel.NoCompression);
using (var writer = new StreamWriter(version.Open(), Utils.UTF8)) {
await writer.WriteAsync("elwig:1");
}
public static Task Export(string filename, IEnumerable<Member> members, IEnumerable<string> filters) {
return new ElwigExport {
Members = (members, filters)
}.Export(filename);
}
var meta = zip.CreateEntry("meta.json", CompressionLevel.NoCompression);
using (var writer = new StreamWriter(meta.Open(), Utils.UTF8)) {
await writer.WriteAsync(
$"{{\"timestamp\": \"{DateTime.UtcNow:yyyy-MM-ddTHH:mm:ssZ}\", " +
$"\"zwstid\": \"{App.ZwstId}\", \"device\": \"{Environment.MachineName}\", " +
$"\"deliveries\": {{" +
$"\"count\": {deliveries.Count()}, " +
$"\"parts\": {deliveries.Sum(d => d.Parts.Count)}, " +
$"\"filters\": [{string.Join(", ", filters.Select(f => '"' + f + '"'))}]" +
$"}}}}");
}
public static Task Export(string filename, IEnumerable<Delivery> deliveries, IEnumerable<string> filters) {
return new ElwigExport {
Deliveries = (deliveries, filters)
}.Export(filename);
}
var json = zip.CreateEntry("deliveries.json");
using (var writer = new StreamWriter(json.Open(), Utils.UTF8)) {
foreach (var d in deliveries) {
await writer.WriteLineAsync(DeliveryToJson(d).ToJsonString());
public class ElwigExport {
public (IEnumerable<Member> Members, IEnumerable<string> Filters)? Members { get; set; }
public (IEnumerable<AreaCom> AreaComs, IEnumerable<string> Filters)? AreaComs { get; set; }
public (IEnumerable<Delivery> Deliveries, IEnumerable<string> Filters)? Deliveries { get; set; }
public async Task Export(string filename) {
File.Delete(filename);
using var zip = ZipFile.Open(filename, ZipArchiveMode.Create);
var version = zip.CreateEntry("version", CompressionLevel.NoCompression);
using (var writer = new StreamWriter(version.Open(), Utils.UTF8)) {
await writer.WriteAsync("elwig:1");
}
var meta = zip.CreateEntry("meta.json", CompressionLevel.NoCompression);
using (var writer = new StreamWriter(meta.Open(), Utils.UTF8)) {
var obj = new JsonObject {
["timestamp"] = $"{DateTime.UtcNow:yyyy-MM-ddTHH:mm:ssZ}",
["zwstid"] = App.ZwstId,
["device"] = Environment.MachineName,
};
if (Members != null)
obj["members"] = new JsonObject {
["count"] = Members.Value.Members.Count(),
["filters"] = new JsonArray(Members.Value.Filters.Select(f => (JsonNode)f).ToArray()),
};
if (AreaComs != null)
obj["area_commitments"] = new JsonObject {
["count"] = AreaComs.Value.AreaComs.Count(),
["filters"] = new JsonArray(AreaComs.Value.Filters.Select(f => (JsonNode)f).ToArray()),
};
if (Deliveries != null)
obj["deliveries"] = new JsonObject {
["count"] = Deliveries.Value.Deliveries.Count(),
["parts"] = Deliveries.Value.Deliveries.Sum(d => d.Parts.Count),
["filters"] = new JsonArray(Deliveries.Value.Filters.Select(f => (JsonNode)f).ToArray()),
};
await writer.WriteAsync(obj.ToJsonString());
}
// TODO encrypt files
if (Members != null) {
var json = zip.CreateEntry("members.json", CompressionLevel.SmallestSize);
using var writer = new StreamWriter(json.Open(), Utils.UTF8);
foreach (var m in Members.Value.Members) {
await writer.WriteLineAsync(m.ToJson().ToJsonString());
}
}
if (AreaComs != null) {
var json = zip.CreateEntry("area_commitments.json", CompressionLevel.SmallestSize);
using var writer = new StreamWriter(json.Open(), Utils.UTF8);
foreach (var c in AreaComs.Value.AreaComs) {
await writer.WriteLineAsync(c.ToJson().ToJsonString());
}
}
if (Deliveries != null) {
var json = zip.CreateEntry("deliveries.json", CompressionLevel.SmallestSize);
using var writer = new StreamWriter(json.Open(), Utils.UTF8);
foreach (var d in Deliveries.Value.Deliveries) {
await writer.WriteLineAsync(d.ToJson().ToJsonString());
}
}
}
}
public static JsonObject DeliveryToJson(Delivery d) {
public static JsonObject ToJson(this Member m) {
return new JsonObject {
["mgnr"] = m.MgNr,
["predecessor_mgnr"] = m.PredecessorMgNr,
["prefix"] = m.Prefix,
["given_name"] = m.GivenName,
["middle_names"] = m.MiddleName,
["family_name"] = m.FamilyName,
["suffix"] = m.Suffix,
["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,
["business_shares"] = m.BusinessShares,
["accounting_nr"] = m.AccountingNr,
["zwstid"] = m.ZwstId,
["lfbis_nr"] = m.LfbisNr,
["ustid_nr"] = m.UstIdNr,
["volllieferant"] = m.IsVollLieferant,
["buchführend"] = m.IsBuchführend,
["organic"] = m.IsOrganic,
["funktionär"] = m.IsFunktionär,
["active"] = m.IsActive,
["deceased"] = m.IsDeceased,
["iban"] = m.Iban,
["bic"] = m.Bic,
["default_kgnr"] = m.DefaultKgNr,
["contact_postal"] = m.ContactViaPost,
["contact_email"] = m.ContactViaEmail,
["address"] = new JsonObject {
["address"] = m.Address,
["postal_dest"] = m.PostalDestId,
["country"] = m.CountryNum,
},
["billing_address"] = m.BillingAddress != null ? new JsonObject {
["name"] = m.BillingAddress.Name,
["address"] = m.BillingAddress.Address,
["postal_dest"] = m.BillingAddress.PostalDestId,
["country"] = m.BillingAddress.CountryNum,
} : null,
["telephone_numbers"] = new JsonArray(m.TelephoneNumbers.OrderBy(n => n.Nr).Select(n => {
var obj = new JsonObject {
["number"] = n.Number,
["type"] = n.Type,
};
if (n.Comment != null) obj["comment"] = n.Comment;
return obj;
}).ToArray()),
["email_addresses"] = new JsonArray(m.EmailAddresses.OrderBy(a => a.Nr).Select(a => {
var obj = new JsonObject {
["address"] = a.Address,
};
if (a.Comment != null) obj["comment"] = a.Comment;
return obj;
}).ToArray()),
["comment"] = m.Comment,
};
}
public static (Member, BillingAddr?, List<MemberTelNr>, List<MemberEmailAddr>) ToMember(this JsonNode json) {
var mgnr = json["mgnr"]!.AsValue().GetValue<int>();
return (new Member {
MgNr = mgnr,
PredecessorMgNr = json["predecessor_mgnr"]?.AsValue().GetValue<int>(),
Prefix = json["prefix"]?.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>(),
Birthday = json["birthday"]?.AsValue().GetValue<string>(),
EntryDateString = json["entry_date"]?.AsValue().GetValue<string>(),
ExitDateString = json["exit_date"]?.AsValue().GetValue<string>(),
BusinessShares = json["business_shares"]?.AsValue().GetValue<int>() ?? 0,
AccountingNr = json["accounting_nr"]?.AsValue().GetValue<string>(),
ZwstId = json["zwstid"]?.AsValue().GetValue<string>(),
LfbisNr = json["lfbis_nr"]?.AsValue().GetValue<string>(),
UstIdNr = json["ustid_nr"]?.AsValue().GetValue<string>(),
IsVollLieferant = json["volllieferant"]?.AsValue().GetValue<bool>() ?? false,
IsBuchführend = json["buchführend"]?.AsValue().GetValue<bool>() ?? false,
IsOrganic = json["organic"]?.AsValue().GetValue<bool>() ?? false,
IsFunktionär = json["funktionär"]?.AsValue().GetValue<bool>() ?? false,
IsActive = json["active"]?.AsValue().GetValue<bool>() ?? false,
IsDeceased = json["deceased"]?.AsValue().GetValue<bool>() ?? false,
Iban = json["iban"]?.AsValue().GetValue<string>(),
Bic = json["bic"]?.AsValue().GetValue<string>(),
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>(),
ContactViaPost = json["contact_postal"]?.AsValue().GetValue<bool>() ?? false,
ContactViaEmail = json["contact_email"]?.AsValue().GetValue<bool>() ?? false,
Comment = json["comment"]?.AsValue().GetValue<string>(),
}, json["billing_address"] is JsonObject a ? new BillingAddr {
MgNr = mgnr,
Name = a["name"]!.AsValue().GetValue<string>(),
CountryNum = a["country"]!.AsValue().GetValue<int>(),
PostalDestId = a["postal_dest"]!.AsValue().GetValue<string>(),
Address = a["address"]!.AsValue().GetValue<string>(),
} : null, json["telephone_numbers"]!.AsArray().Select(n => n!.AsObject()).Select((n, i) => new MemberTelNr {
MgNr = mgnr,
Nr = i + 1,
Type = n["type"]!.AsValue().GetValue<string>(),
Number = n["number"]!.AsValue().GetValue<string>(),
Comment = n["comment"]?.AsValue().GetValue<string>(),
}).ToList(), json["email_addresses"]!.AsArray().Select(a => a!.AsObject()).Select((a, i) => new MemberEmailAddr {
MgNr = mgnr,
Nr = i + 1,
Address = a["address"]!.AsValue().GetValue<string>(),
Comment = a["comment"]?.AsValue().GetValue<string>(),
}).ToList());
}
public static JsonObject ToJson(this AreaCom c) {
return new JsonObject {
["fbnr"] = c.FbNr,
["mgnr"] = c.MgNr,
["vtrgid"] = c.VtrgId,
["cultid"] = c.CultId,
["area"] = c.Area,
["kgnr"] = c.KgNr,
["gstnr"] = c.GstNr,
["ried"] = c.Rd?.Name,
["year_from"] = c.YearFrom,
["year_to"] = c.YearTo,
["comment"] = c.Comment,
};
}
public static (AreaCom, WbRd?) ToAreaCom(this JsonNode json, 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");
rd = rde.FirstOrDefault(r => r.Name == ried);
if (rd == null) {
newRd = true;
rd = new WbRd {
KgNr = kgnr,
RdNr = (rde.Count == 0 ? 0 : rde.Max(r => r.RdNr)) + 1,
Name = ried,
};
rde.Add(rd);
}
}
return (new AreaCom {
FbNr = json["fbnr"]!.AsValue().GetValue<int>(),
MgNr = json["mgnr"]!.AsValue().GetValue<int>(),
VtrgId = json["vtrgid"]!.AsValue().GetValue<string>(),
CultId = json["cultid"]?.AsValue().GetValue<string>(),
Area = json["area"]!.AsValue().GetValue<int>(),
KgNr = kgnr,
GstNr = json["gstnr"]?.AsValue().GetValue<string>() ?? "-",
RdNr = rd?.RdNr,
YearFrom = json["year_from"]!.AsValue().GetValue<int>(),
YearTo = json["year_to"]?.AsValue().GetValue<int>(),
Comment = json["comment"]?.AsValue().GetValue<string>(),
}, newRd ? rd : null);
}
public static JsonObject ToJson(this Delivery d) {
return new JsonObject {
["lsnr"] = d.LsNr,
["year"] = d.Year,
@ -202,7 +549,7 @@ namespace Elwig.Helpers.Export {
};
}
public static (Delivery, List<DeliveryPart>, List<DeliveryPartModifier>) JsonToDelivery(JsonNode json, Dictionary<int, int> currentDids) {
public static (Delivery, List<DeliveryPart>, List<DeliveryPartModifier>) ToDelivery(this JsonNode json, Dictionary<int, int> currentDids) {
var year = json["year"]!.AsValue().GetValue<int>();
var did = ++currentDids[year];
return (new Delivery {