[#3] Elwig: Add user-friendly sync method
All checks were successful
Test / Run tests (push) Successful in 2m57s
All checks were successful
Test / Run tests (push) Successful in 2m57s
This commit is contained in:
@ -29,10 +29,11 @@ namespace Elwig {
|
|||||||
private readonly DispatcherTimer _autoUpdateTimer = new() { Interval = TimeSpan.FromHours(1) };
|
private readonly DispatcherTimer _autoUpdateTimer = new() { Interval = TimeSpan.FromHours(1) };
|
||||||
|
|
||||||
public static readonly string DataPath = @"C:\ProgramData\Elwig\";
|
public static readonly string DataPath = @"C:\ProgramData\Elwig\";
|
||||||
|
public static readonly string ConfigPath = Path.Combine(DataPath, "config.ini");
|
||||||
public static readonly string ExePath = @"C:\Program Files\Elwig\";
|
public static readonly string ExePath = @"C:\Program Files\Elwig\";
|
||||||
public static readonly string TempPath = Path.Combine(Path.GetTempPath(), "Elwig");
|
public static readonly string TempPath = Path.Combine(Path.GetTempPath(), "Elwig");
|
||||||
|
|
||||||
public static Config Config { get; private set; } = new(Path.Combine(DataPath, "config.ini"));
|
public static Config Config { get; private set; } = new(ConfigPath);
|
||||||
public static int VersionMajor { get; private set; }
|
public static int VersionMajor { get; private set; }
|
||||||
public static int VersionMinor { get; private set; }
|
public static int VersionMinor { get; private set; }
|
||||||
public static int VersionPatch { get; private set; }
|
public static int VersionPatch { get; private set; }
|
||||||
|
@ -12,6 +12,8 @@ using Microsoft.EntityFrameworkCore;
|
|||||||
namespace Elwig.Helpers.Export {
|
namespace Elwig.Helpers.Export {
|
||||||
public static class ElwigData {
|
public static class ElwigData {
|
||||||
|
|
||||||
|
public enum ImportMode { Auto, Interactively, FromBranches }
|
||||||
|
|
||||||
public static readonly string ImportedTxt = Path.Combine(App.DataPath, "imported.txt");
|
public static readonly string ImportedTxt = Path.Combine(App.DataPath, "imported.txt");
|
||||||
|
|
||||||
public static async Task<string[]> GetImportedFiles() {
|
public static async Task<string[]> GetImportedFiles() {
|
||||||
@ -26,36 +28,61 @@ namespace Elwig.Helpers.Export {
|
|||||||
await File.AppendAllLinesAsync(ImportedTxt, filenames, Utils.UTF8);
|
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 {
|
try {
|
||||||
using var ctx = new AppDbContext();
|
using var ctx = new AppDbContext();
|
||||||
|
var branches = await ctx.Branches.ToDictionaryAsync(b => b.ZwstId);
|
||||||
var currentDids = await ctx.Deliveries
|
var currentDids = await ctx.Deliveries
|
||||||
.GroupBy(d => d.Year)
|
.GroupBy(d => d.Year)
|
||||||
.ToDictionaryAsync(g => g.Key, g => g.Max(d => d.DId));
|
.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 data = new List<(
|
||||||
var deliveryParts = new List<DeliveryPart>();
|
List<Member> Members,
|
||||||
var modifiers = new List<DeliveryPartModifier>();
|
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) {
|
foreach (var filename in filenames) {
|
||||||
|
// TODO read encrypted files
|
||||||
using var zip = ZipFile.Open(filename, ZipArchiveMode.Read);
|
using var zip = ZipFile.Open(filename, ZipArchiveMode.Read);
|
||||||
|
|
||||||
var version = zip.GetEntry("version");
|
var version = zip.GetEntry("version");
|
||||||
using (var reader = new StreamReader(version!.Open(), Utils.UTF8)) {
|
using (var reader = new StreamReader(version!.Open(), Utils.UTF8)) {
|
||||||
if (await reader.ReadToEndAsync() != "elwig:1")
|
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 metaJson = zip.GetEntry("meta.json");
|
||||||
var meta = await JsonNode.ParseAsync(metaJson!.Open());
|
var meta = await JsonNode.ParseAsync(metaJson!.Open());
|
||||||
var deliveryCount = meta!["deliveries"]?["count"]!.AsValue().GetValue<int>();
|
var memberCount = meta!["members"]?["count"]?.AsValue().GetValue<int>();
|
||||||
var deliveryFilters = meta!["deliveries"]?["filters"]!.AsArray().Select(f => f!.AsValue().GetValue<string>()).ToArray();
|
var memberFilters = meta!["members"]?["filters"]?.AsArray().Select(f => f!.AsValue().GetValue<string>()).ToArray();
|
||||||
if (deliveryCount != null && deliveryFilters != null)
|
var areaComCount = meta!["area_commitments"]?["count"]?.AsValue().GetValue<int>();
|
||||||
metaData.Add((Path.GetFileName(filename), (int)deliveryCount, string.Join(" / ", deliveryFilters)));
|
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");
|
var membersJson = zip.GetEntry("members.json");
|
||||||
if (membersJson != null) {
|
if (membersJson != null) {
|
||||||
@ -63,7 +90,11 @@ namespace Elwig.Helpers.Export {
|
|||||||
string? line;
|
string? line;
|
||||||
while ((line = await reader.ReadLineAsync()) != null) {
|
while ((line = await reader.ReadLineAsync()) != null) {
|
||||||
var obj = JsonNode.Parse(line)!.AsObject();
|
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;
|
string? line;
|
||||||
while ((line = await reader.ReadLineAsync()) != null) {
|
while ((line = await reader.ReadLineAsync()) != null) {
|
||||||
var obj = JsonNode.Parse(line)!.AsObject();
|
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,14 +116,36 @@ namespace Elwig.Helpers.Export {
|
|||||||
string? line;
|
string? line;
|
||||||
while ((line = await reader.ReadLineAsync()) != null) {
|
while ((line = await reader.ReadLineAsync()) != null) {
|
||||||
var obj = JsonNode.Parse(line)!.AsObject();
|
var obj = JsonNode.Parse(line)!.AsObject();
|
||||||
var (d, parts, mods) = JsonToDelivery(obj, currentDids);
|
var (d, parts, mods) = obj.ToDelivery(currentDids);
|
||||||
deliveries.Add(d);
|
r.Deliveries.Add(d);
|
||||||
deliveryParts.AddRange(parts);
|
r.DeliveryParts.AddRange(parts);
|
||||||
modifiers.AddRange(mods);
|
r.Modifiers.AddRange(mods);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 lsnrs = deliveries.Select(d => d.LsNr).ToList();
|
||||||
var duplicateLsNrs = await ctx.Deliveries
|
var duplicateLsNrs = await ctx.Deliveries
|
||||||
.Where(d => lsnrs.Contains(d.LsNr))
|
.Where(d => lsnrs.Contains(d.LsNr))
|
||||||
@ -100,39 +155,140 @@ namespace Elwig.Helpers.Export {
|
|||||||
.Where(d => duplicateLsNrs.Contains(d.LsNr))
|
.Where(d => duplicateLsNrs.Contains(d.LsNr))
|
||||||
.Select(d => (d.Year, d.DId))
|
.Select(d => (d.Year, d.DId))
|
||||||
.ToList();
|
.ToList();
|
||||||
bool overwriteDelivieries = false;
|
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) {
|
if (duplicateLsNrs.Count > 0) {
|
||||||
var res = MessageBox.Show($"Sollen {duplicateLsNrs.Count} Lieferungen überschreiben werden?", "Lieferungen überschreiben",
|
allowedDuplicateLsNrs = await ctx.Deliveries
|
||||||
MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No);
|
.Where(d => lsnrs.Contains(d.LsNr) && d.ZwstId == branch.ZwstId)
|
||||||
overwriteDelivieries = res == MessageBoxResult.Yes;
|
.Select(d => d.LsNr)
|
||||||
|
.ToListAsync();
|
||||||
|
if (duplicateLsNrs.Count - allowedDuplicateLsNrs.Count > 0)
|
||||||
|
importDuplicateDeliveries = ImportQuestion(branch.Name, device, "Lieferungen", true, duplicateLsNrs.Count - allowedDuplicateLsNrs.Count);
|
||||||
}
|
}
|
||||||
if (overwriteDelivieries) {
|
|
||||||
ctx.RemoveRange(ctx.Deliveries.Where(d => duplicateLsNrs.Contains(d.LsNr)));
|
|
||||||
ctx.AddRange(deliveries);
|
|
||||||
ctx.AddRange(deliveryParts);
|
|
||||||
ctx.AddRange(modifiers);
|
|
||||||
} else {
|
} 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(deliveries.Where(d => !duplicateDIds.Contains((d.Year, d.DId))));
|
||||||
ctx.AddRange(deliveryParts.Where(p => !duplicateDIds.Contains((p.Year, p.DId))));
|
ctx.AddRange(deliveryParts.Where(p => !duplicateDIds.Contains((p.Year, p.DId))));
|
||||||
ctx.AddRange(modifiers.Where(m => !duplicateDIds.Contains((m.Year, m.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();
|
await ctx.SaveChangesAsync();
|
||||||
|
} catch (DbUpdateConcurrencyException) { }
|
||||||
await AddImportedFiles(filenames.Select(f => Path.GetFileName(f)));
|
await AddImportedFiles(filenames.Select(f => Path.GetFileName(f)));
|
||||||
|
}
|
||||||
await App.HintContextChange();
|
await App.HintContextChange();
|
||||||
|
|
||||||
MessageBox.Show(
|
MessageBox.Show(
|
||||||
$"Das importieren der Daten war erfolgreich!\n" +
|
$"Das importieren der Daten war erfolgreich!\n" +
|
||||||
$"Folgendes wurde importiert:\n" +
|
$"Folgendes wurde importiert:\n" +
|
||||||
$" Lieferungen: {deliveries.Count}\n" +
|
string.Join("\n", [
|
||||||
string.Join("\n", metaData.Select(d => $" {d.Name} ({d.DeliveryNum})\n {d.Filters}")) +
|
$"Mitglieder: {importedMembers.Sum(d => d.New + d.Overwritten)}",
|
||||||
"\n", "Importieren erfolgreich",
|
..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);
|
MessageBoxButton.OK, MessageBoxImage.Information);
|
||||||
} catch (Exception exc) {
|
} catch (Exception exc) {
|
||||||
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task ExportDeliveries(string filename, IEnumerable<Delivery> deliveries, IEnumerable<string> filters) {
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Task Export(string filename, IEnumerable<Member> members, IEnumerable<string> filters) {
|
||||||
|
return new ElwigExport {
|
||||||
|
Members = (members, filters)
|
||||||
|
}.Export(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Task Export(string filename, IEnumerable<Delivery> deliveries, IEnumerable<string> filters) {
|
||||||
|
return new ElwigExport {
|
||||||
|
Deliveries = (deliveries, filters)
|
||||||
|
}.Export(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
File.Delete(filename);
|
||||||
using var zip = ZipFile.Open(filename, ZipArchiveMode.Create);
|
using var zip = ZipFile.Open(filename, ZipArchiveMode.Create);
|
||||||
|
|
||||||
@ -143,25 +299,216 @@ namespace Elwig.Helpers.Export {
|
|||||||
|
|
||||||
var meta = zip.CreateEntry("meta.json", CompressionLevel.NoCompression);
|
var meta = zip.CreateEntry("meta.json", CompressionLevel.NoCompression);
|
||||||
using (var writer = new StreamWriter(meta.Open(), Utils.UTF8)) {
|
using (var writer = new StreamWriter(meta.Open(), Utils.UTF8)) {
|
||||||
await writer.WriteAsync(
|
var obj = new JsonObject {
|
||||||
$"{{\"timestamp\": \"{DateTime.UtcNow:yyyy-MM-ddTHH:mm:ssZ}\", " +
|
["timestamp"] = $"{DateTime.UtcNow:yyyy-MM-ddTHH:mm:ssZ}",
|
||||||
$"\"zwstid\": \"{App.ZwstId}\", \"device\": \"{Environment.MachineName}\", " +
|
["zwstid"] = App.ZwstId,
|
||||||
$"\"deliveries\": {{" +
|
["device"] = Environment.MachineName,
|
||||||
$"\"count\": {deliveries.Count()}, " +
|
};
|
||||||
$"\"parts\": {deliveries.Sum(d => d.Parts.Count)}, " +
|
if (Members != null)
|
||||||
$"\"filters\": [{string.Join(", ", filters.Select(f => '"' + f + '"'))}]" +
|
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());
|
||||||
}
|
}
|
||||||
|
|
||||||
var json = zip.CreateEntry("deliveries.json");
|
// TODO encrypt files
|
||||||
using (var writer = new StreamWriter(json.Open(), Utils.UTF8)) {
|
if (Members != null) {
|
||||||
foreach (var d in deliveries) {
|
var json = zip.CreateEntry("members.json", CompressionLevel.SmallestSize);
|
||||||
await writer.WriteLineAsync(DeliveryToJson(d).ToJsonString());
|
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 {
|
return new JsonObject {
|
||||||
["lsnr"] = d.LsNr,
|
["lsnr"] = d.LsNr,
|
||||||
["year"] = d.Year,
|
["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 year = json["year"]!.AsValue().GetValue<int>();
|
||||||
var did = ++currentDids[year];
|
var did = ++currentDids[year];
|
||||||
return (new Delivery {
|
return (new Delivery {
|
||||||
|
@ -529,16 +529,16 @@ namespace Elwig.Services {
|
|||||||
var (f, _, q, _, _) = await vm.GetFilters(ctx);
|
var (f, _, q, _, _) = await vm.GetFilters(ctx);
|
||||||
query = q;
|
query = q;
|
||||||
filterNames.AddRange(f);
|
filterNames.AddRange(f);
|
||||||
|
} else if (modeWho == 2) {
|
||||||
|
query = ctx.DeliveryParts
|
||||||
|
.Where(p => p.Year == Utils.CurrentLastSeason && p.Delivery.ZwstId == App.ZwstId);
|
||||||
|
filterNames.AddRange([$"{Utils.CurrentLastSeason}", $"Zweigstelle {App.BranchName}"]);
|
||||||
} else {
|
} else {
|
||||||
var date = $"{Utils.Today:yyyy-MM-dd}";
|
var date = $"{Utils.Today:yyyy-MM-dd}";
|
||||||
query = ctx.DeliveryParts
|
query = ctx.DeliveryParts
|
||||||
.Where(p => p.Delivery.DateString == date);
|
.Where(p => p.Delivery.DateString == date);
|
||||||
filterNames.Add($"{Utils.Today:dd.MM.yyyy}");
|
filterNames.Add($"{Utils.Today:dd.MM.yyyy}");
|
||||||
}
|
}
|
||||||
if (exportMode == ExportMode.Upload && !filterNames.Contains($"Zweigstelle {App.BranchName}")) {
|
|
||||||
query = query.Where(p => p.Delivery.ZwstId == App.ZwstId);
|
|
||||||
filterNames.Add($"Zweigstelle {App.BranchName}");
|
|
||||||
}
|
|
||||||
|
|
||||||
query = query
|
query = query
|
||||||
.OrderBy(p => p.Delivery.DateString)
|
.OrderBy(p => p.Delivery.DateString)
|
||||||
@ -566,7 +566,7 @@ namespace Elwig.Services {
|
|||||||
}
|
}
|
||||||
} else if (exportMode == ExportMode.Export) {
|
} else if (exportMode == ExportMode.Export) {
|
||||||
var d = new SaveFileDialog() {
|
var d = new SaveFileDialog() {
|
||||||
FileName = $"Lieferungen.zip",
|
FileName = $"Lieferungen_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{App.ZwstId}.zip",
|
||||||
DefaultExt = "zip",
|
DefaultExt = "zip",
|
||||||
Filter = "ZIP-Datei (*.zip)|*.zip",
|
Filter = "ZIP-Datei (*.zip)|*.zip",
|
||||||
Title = $"{DeliveryJournal.Name} speichern unter - Elwig"
|
Title = $"{DeliveryJournal.Name} speichern unter - Elwig"
|
||||||
@ -574,7 +574,13 @@ namespace Elwig.Services {
|
|||||||
if (d.ShowDialog() == true) {
|
if (d.ShowDialog() == true) {
|
||||||
Mouse.OverrideCursor = Cursors.AppStarting;
|
Mouse.OverrideCursor = Cursors.AppStarting;
|
||||||
try {
|
try {
|
||||||
await ElwigData.ExportDeliveries(d.FileName, await query.Select(p => p.Delivery).Distinct().ToListAsync(), filterNames);
|
await ElwigData.Export(d.FileName, await query
|
||||||
|
.Select(p => p.Delivery)
|
||||||
|
.Distinct()
|
||||||
|
.Include(d => d.Parts)
|
||||||
|
.ThenInclude(p => p.PartModifiers)
|
||||||
|
.AsSplitQuery()
|
||||||
|
.ToListAsync(), filterNames);
|
||||||
} catch (Exception exc) {
|
} catch (Exception exc) {
|
||||||
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
}
|
}
|
||||||
@ -585,12 +591,18 @@ namespace Elwig.Services {
|
|||||||
try {
|
try {
|
||||||
var filename = $"{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{App.ZwstId}.zip";
|
var filename = $"{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{App.ZwstId}.zip";
|
||||||
var path = Path.Combine(App.TempPath, filename);
|
var path = Path.Combine(App.TempPath, filename);
|
||||||
var list = await query.Select(p => p.Delivery).Distinct().ToListAsync();
|
var list = await query
|
||||||
|
.Select(p => p.Delivery)
|
||||||
|
.Distinct()
|
||||||
|
.Include(d => d.Parts)
|
||||||
|
.ThenInclude(p => p.PartModifiers)
|
||||||
|
.AsSplitQuery()
|
||||||
|
.ToListAsync();
|
||||||
if (list.Count == 0) {
|
if (list.Count == 0) {
|
||||||
MessageBox.Show("Es wurden keine Lieferungen zum Hochladen ausgewählt!", "Fehler",
|
MessageBox.Show("Es wurden keine Lieferungen zum Hochladen ausgewählt!", "Lieferungen hochladen",
|
||||||
MessageBoxButton.OK, MessageBoxImage.Error);
|
MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
} else {
|
} else {
|
||||||
await ElwigData.ExportDeliveries(path, list, filterNames);
|
await ElwigData.Export(path, list, filterNames);
|
||||||
await Utils.UploadExportData(path, App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
|
await Utils.UploadExportData(path, App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
|
||||||
MessageBox.Show($"Lieferungen erfolgreich hochgeladen!", "Lieferungen hochgeladen",
|
MessageBox.Show($"Lieferungen erfolgreich hochgeladen!", "Lieferungen hochgeladen",
|
||||||
MessageBoxButton.OK, MessageBoxImage.Information);
|
MessageBoxButton.OK, MessageBoxImage.Information);
|
||||||
|
@ -129,10 +129,10 @@
|
|||||||
<MenuItem x:Name="Menu_Export_UploadFilters" Header="...aus Filtern hochladen"
|
<MenuItem x:Name="Menu_Export_UploadFilters" Header="...aus Filtern hochladen"
|
||||||
Click="Menu_Export_UploadFilters_Click"/>
|
Click="Menu_Export_UploadFilters_Click"/>
|
||||||
<Separator/>
|
<Separator/>
|
||||||
<MenuItem x:Name="Menu_Export_ExportToday" Header="...von heute speichern..."
|
<MenuItem x:Name="Menu_Export_ExportSeason" Header="...von Saison/Zweigstelle speichern..."
|
||||||
Click="Menu_Export_ExportToday_Click"/>
|
Click="Menu_Export_ExportSeason_Click"/>
|
||||||
<MenuItem x:Name="Menu_Export_UploadToday" Header="...von heute hochladen"
|
<MenuItem x:Name="Menu_Export_UploadSeason" Header="...von Saison/Zweigstelle hochladen"
|
||||||
Click="Menu_Export_UploadToday_Click" InputGestureText="Strg+H"/>
|
Click="Menu_Export_UploadSeason_Click"/>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="Einstellungen">
|
<MenuItem Header="Einstellungen">
|
||||||
<MenuItem x:Name="Menu_Settings_EnableFreeEditing" Header="Freie Bearbeitung aktivieren"
|
<MenuItem x:Name="Menu_Settings_EnableFreeEditing" Header="Freie Bearbeitung aktivieren"
|
||||||
|
@ -29,7 +29,6 @@ namespace Elwig.Windows {
|
|||||||
private readonly RoutedCommand CtrlO = new("CtrlO", typeof(DeliveryAdminWindow), [new KeyGesture(Key.O, ModifierKeys.Control)]);
|
private readonly RoutedCommand CtrlO = new("CtrlO", typeof(DeliveryAdminWindow), [new KeyGesture(Key.O, ModifierKeys.Control)]);
|
||||||
private readonly RoutedCommand CtrlJ = new("CtrlJ", typeof(DeliveryAdminWindow), [new KeyGesture(Key.J, ModifierKeys.Control)]);
|
private readonly RoutedCommand CtrlJ = new("CtrlJ", typeof(DeliveryAdminWindow), [new KeyGesture(Key.J, ModifierKeys.Control)]);
|
||||||
private readonly RoutedCommand CtrlQ = new("CtrlQ", typeof(DeliveryAdminWindow), [new KeyGesture(Key.Q, ModifierKeys.Control)]);
|
private readonly RoutedCommand CtrlQ = new("CtrlQ", typeof(DeliveryAdminWindow), [new KeyGesture(Key.Q, ModifierKeys.Control)]);
|
||||||
private readonly RoutedCommand CtrlH = new("CtrlH", typeof(DeliveryAdminWindow), [new KeyGesture(Key.H, ModifierKeys.Control)]);
|
|
||||||
private readonly RoutedCommand CtrlShiftP = new("CtrlShiftP", typeof(DeliveryAdminWindow), [new KeyGesture(Key.P, ModifierKeys.Control | ModifierKeys.Shift)]);
|
private readonly RoutedCommand CtrlShiftP = new("CtrlShiftP", typeof(DeliveryAdminWindow), [new KeyGesture(Key.P, ModifierKeys.Control | ModifierKeys.Shift)]);
|
||||||
private readonly RoutedCommand CtrlShiftO = new("CtrlShiftO", typeof(DeliveryAdminWindow), [new KeyGesture(Key.O, ModifierKeys.Control | ModifierKeys.Shift)]);
|
private readonly RoutedCommand CtrlShiftO = new("CtrlShiftO", typeof(DeliveryAdminWindow), [new KeyGesture(Key.O, ModifierKeys.Control | ModifierKeys.Shift)]);
|
||||||
|
|
||||||
@ -43,7 +42,6 @@ namespace Elwig.Windows {
|
|||||||
CommandBindings.Add(new CommandBinding(CtrlO, Menu_DeliveryJournal_ShowFilters_Click));
|
CommandBindings.Add(new CommandBinding(CtrlO, Menu_DeliveryJournal_ShowFilters_Click));
|
||||||
CommandBindings.Add(new CommandBinding(CtrlJ, Menu_DeliveryJournal_PrintToday_Click));
|
CommandBindings.Add(new CommandBinding(CtrlJ, Menu_DeliveryJournal_PrintToday_Click));
|
||||||
CommandBindings.Add(new CommandBinding(CtrlQ, Menu_WineQualityStatistics_PrintToday_Click));
|
CommandBindings.Add(new CommandBinding(CtrlQ, Menu_WineQualityStatistics_PrintToday_Click));
|
||||||
CommandBindings.Add(new CommandBinding(CtrlH, Menu_Export_UploadToday_Click));
|
|
||||||
CommandBindings.Add(new CommandBinding(CtrlShiftP, Menu_DeliveryNote_Print_Click));
|
CommandBindings.Add(new CommandBinding(CtrlShiftP, Menu_DeliveryNote_Print_Click));
|
||||||
CommandBindings.Add(new CommandBinding(CtrlShiftO, Menu_DeliveryJournal_PrintFilters_Click));
|
CommandBindings.Add(new CommandBinding(CtrlShiftO, Menu_DeliveryJournal_PrintFilters_Click));
|
||||||
RequiredInputs = [
|
RequiredInputs = [
|
||||||
@ -113,7 +111,7 @@ namespace Elwig.Windows {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Menu_Export_UploadFilters.IsEnabled = App.Config.SyncUrl != null;
|
Menu_Export_UploadFilters.IsEnabled = App.Config.SyncUrl != null;
|
||||||
Menu_Export_UploadToday.IsEnabled = App.Config.SyncUrl != null;
|
Menu_Export_UploadSeason.IsEnabled = App.Config.SyncUrl != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DeliveryAdminWindow(int mgnr) : this() {
|
public DeliveryAdminWindow(int mgnr) : this() {
|
||||||
@ -180,7 +178,7 @@ namespace Elwig.Windows {
|
|||||||
private async void Menu_DeliveryJournal_SaveToday_Click(object sender, RoutedEventArgs evt) { await ViewModel.GenerateDeliveryJournal(1, ExportMode.SaveList); }
|
private async void Menu_DeliveryJournal_SaveToday_Click(object sender, RoutedEventArgs evt) { await ViewModel.GenerateDeliveryJournal(1, ExportMode.SaveList); }
|
||||||
private async void Menu_DeliveryJournal_SavePdfToday_Click(object sender, RoutedEventArgs evt) { await ViewModel.GenerateDeliveryJournal(1, ExportMode.SavePdf); }
|
private async void Menu_DeliveryJournal_SavePdfToday_Click(object sender, RoutedEventArgs evt) { await ViewModel.GenerateDeliveryJournal(1, ExportMode.SavePdf); }
|
||||||
private async void Menu_DeliveryJournal_ShowToday_Click(object sender, RoutedEventArgs evt) { await ViewModel.GenerateDeliveryJournal(1, ExportMode.Show); }
|
private async void Menu_DeliveryJournal_ShowToday_Click(object sender, RoutedEventArgs evt) { await ViewModel.GenerateDeliveryJournal(1, ExportMode.Show); }
|
||||||
private async void Menu_Export_ExportToday_Click(object sender, RoutedEventArgs evt) { await ViewModel.GenerateDeliveryJournal(1, ExportMode.Export); }
|
private async void Menu_Export_ExportSeason_Click(object sender, RoutedEventArgs evt) { await ViewModel.GenerateDeliveryJournal(2, ExportMode.Export); }
|
||||||
private async void Menu_DeliveryJournal_PrintToday_Click(object sender, RoutedEventArgs evt) { await ViewModel.GenerateDeliveryJournal(1, ExportMode.Print); }
|
private async void Menu_DeliveryJournal_PrintToday_Click(object sender, RoutedEventArgs evt) { await ViewModel.GenerateDeliveryJournal(1, ExportMode.Print); }
|
||||||
private async void Menu_DeliveryJournal_SaveFilters_Click(object sender, RoutedEventArgs evt) { await ViewModel.GenerateDeliveryJournal(0, ExportMode.SaveList); }
|
private async void Menu_DeliveryJournal_SaveFilters_Click(object sender, RoutedEventArgs evt) { await ViewModel.GenerateDeliveryJournal(0, ExportMode.SaveList); }
|
||||||
private async void Menu_DeliveryJournal_SavePdfFilters_Click(object sender, RoutedEventArgs evt) { await ViewModel.GenerateDeliveryJournal(0, ExportMode.SavePdf); }
|
private async void Menu_DeliveryJournal_SavePdfFilters_Click(object sender, RoutedEventArgs evt) { await ViewModel.GenerateDeliveryJournal(0, ExportMode.SavePdf); }
|
||||||
@ -188,9 +186,9 @@ namespace Elwig.Windows {
|
|||||||
private async void Menu_DeliveryJournal_PrintFilters_Click(object sender, RoutedEventArgs evt) { await ViewModel.GenerateDeliveryJournal(0, ExportMode.Print); }
|
private async void Menu_DeliveryJournal_PrintFilters_Click(object sender, RoutedEventArgs evt) { await ViewModel.GenerateDeliveryJournal(0, ExportMode.Print); }
|
||||||
private async void Menu_Export_ExportFilters_Click(object sender, RoutedEventArgs evt) { await ViewModel.GenerateDeliveryJournal(0, ExportMode.Export); }
|
private async void Menu_Export_ExportFilters_Click(object sender, RoutedEventArgs evt) { await ViewModel.GenerateDeliveryJournal(0, ExportMode.Export); }
|
||||||
|
|
||||||
private async void Menu_Export_UploadToday_Click(object sender, RoutedEventArgs evt) {
|
private async void Menu_Export_UploadSeason_Click(object sender, RoutedEventArgs evt) {
|
||||||
if (App.Config.SyncUrl == null) return;
|
if (App.Config.SyncUrl == null) return;
|
||||||
await ViewModel.GenerateDeliveryJournal(1, ExportMode.Upload);
|
await ViewModel.GenerateDeliveryJournal(2, ExportMode.Upload);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void Menu_Export_UploadFilters_Click(object sender, RoutedEventArgs evt) {
|
private async void Menu_Export_UploadFilters_Click(object sender, RoutedEventArgs evt) {
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
<MenuItem Header="Datenbank">
|
<MenuItem Header="Datenbank">
|
||||||
<MenuItem Header="Daten exportieren..." Click="Menu_Database_Export_Click"/>
|
<MenuItem Header="Daten exportieren..." Click="Menu_Database_Export_Click"/>
|
||||||
<MenuItem Header="Daten importieren..." Click="Menu_Database_Import_Click"/>
|
<MenuItem Header="Daten importieren..." Click="Menu_Database_Import_Click"/>
|
||||||
<MenuItem x:Name="Menu_Database_Sync" Header="Daten synchronisieren" Click="Menu_Database_Sync_Click"/>
|
|
||||||
<Separator/>
|
<Separator/>
|
||||||
<MenuItem Header="Abfragen stellen" Click="Menu_Database_Query_Click"/>
|
<MenuItem Header="Abfragen stellen" Click="Menu_Database_Query_Click"/>
|
||||||
<MenuItem Header="Speicherort öffnen..." Click="Menu_Database_Open_Click"/>
|
<MenuItem Header="Speicherort öffnen..." Click="Menu_Database_Open_Click"/>
|
||||||
@ -30,7 +29,9 @@
|
|||||||
<MenuItem Header="Über"/>
|
<MenuItem Header="Über"/>
|
||||||
<MenuItem x:Name="Menu_Help_Update" Header="Nach Updates suchen" Click="Menu_Help_Update_Click"/>
|
<MenuItem x:Name="Menu_Help_Update" Header="Nach Updates suchen" Click="Menu_Help_Update_Click"/>
|
||||||
<MenuItem x:Name="Menu_Help_Smtp" Header="E-Mail-Einstellungen testen" Click="Menu_Help_Smtp_Click"/>
|
<MenuItem x:Name="Menu_Help_Smtp" Header="E-Mail-Einstellungen testen" Click="Menu_Help_Smtp_Click"/>
|
||||||
<MenuItem x:Name="Menu_Help_Config" Header="Konfigurationsspeicherort öffnen..." Click="Menu_Help_Config_Click"/>
|
<Separator/>
|
||||||
|
<MenuItem x:Name="Menu_Help_Config" Header="Konfigurationsdatei öffnen..." Click="Menu_Help_Config_Click"/>
|
||||||
|
<MenuItem x:Name="Menu_Help_Directory" Header="Konfigurationsspeicherort öffnen..." Click="Menu_Help_Directory_Click"/>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
</Menu>
|
</Menu>
|
||||||
|
|
||||||
@ -66,6 +67,15 @@
|
|||||||
<Button x:Name="RegistrationButton" Content="Anmeldungen" IsEnabled="False"
|
<Button x:Name="RegistrationButton" Content="Anmeldungen" IsEnabled="False"
|
||||||
Margin="205,250,0,0"/>
|
Margin="205,250,0,0"/>
|
||||||
|
|
||||||
|
<Button x:Name="DownloadButton" Click="DownloadButton_Click"
|
||||||
|
Margin="310,135,0,0" Padding="1.5,0,0,0" Height="30" Width="30"
|
||||||
|
Content="" FontFamily="Segoe MDL2 Assets" FontSize="16"
|
||||||
|
ToolTip="Lieferungen und Mitgliederdaten anderer Zweigstellen herunterladen"/>
|
||||||
|
<Button x:Name="UploadButton" Click="UploadButton_Click"
|
||||||
|
Margin="375,135,0,0" Padding="1.5,0,0,0" Height="30" Width="30"
|
||||||
|
Content="" FontFamily="Segoe MDL2 Assets" FontSize="16"
|
||||||
|
ToolTip="Lieferungen dieser Zweigstelle hochladen"/>
|
||||||
|
|
||||||
<Expander x:Name="SeasonFinish" Header="Leseabschluss" SnapsToDevicePixels="True"
|
<Expander x:Name="SeasonFinish" Header="Leseabschluss" SnapsToDevicePixels="True"
|
||||||
Expanded="SeasonFinish_Expanded" Collapsed="SeasonFinish_Collapsed"
|
Expanded="SeasonFinish_Expanded" Collapsed="SeasonFinish_Collapsed"
|
||||||
HorizontalAlignment="Center" Width="407" Margin="0,290,0,0" VerticalAlignment="Top">
|
HorizontalAlignment="Center" Width="407" Margin="0,290,0,0" VerticalAlignment="Top">
|
||||||
|
@ -11,6 +11,7 @@ using System.Diagnostics;
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Net.Http;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
@ -27,7 +28,8 @@ namespace Elwig.Windows {
|
|||||||
if (App.Client.Client == null) VersionField.Text += " (Unbekannt)";
|
if (App.Client.Client == null) VersionField.Text += " (Unbekannt)";
|
||||||
Menu_Help_Update.IsEnabled = App.Config.UpdateUrl != null;
|
Menu_Help_Update.IsEnabled = App.Config.UpdateUrl != null;
|
||||||
Menu_Help_Smtp.IsEnabled = App.Config.Smtp != null;
|
Menu_Help_Smtp.IsEnabled = App.Config.Smtp != null;
|
||||||
Menu_Database_Sync.IsEnabled = App.Config.SyncUrl != null;
|
DownloadButton.Visibility = App.Config.SyncUrl != null ? Visibility.Visible : Visibility.Hidden;
|
||||||
|
UploadButton.Visibility = App.Config.SyncUrl != null ? Visibility.Visible : Visibility.Hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Window_Loaded(object sender, RoutedEventArgs evt) {
|
private void Window_Loaded(object sender, RoutedEventArgs evt) {
|
||||||
@ -62,8 +64,21 @@ namespace Elwig.Windows {
|
|||||||
Mouse.OverrideCursor = null;
|
Mouse.OverrideCursor = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Menu_Help_Config_Click(object sender, RoutedEventArgs evt) {
|
private void Menu_Help_Directory_Click(object sender, RoutedEventArgs evt) {
|
||||||
|
try {
|
||||||
Process.Start("explorer.exe", App.DataPath);
|
Process.Start("explorer.exe", App.DataPath);
|
||||||
|
} catch { }
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Menu_Help_Config_Click(object sender, RoutedEventArgs evt) {
|
||||||
|
try {
|
||||||
|
Process.Start(new ProcessStartInfo {
|
||||||
|
FileName = "notepad.exe",
|
||||||
|
Arguments = App.ConfigPath,
|
||||||
|
Verb = "runas",
|
||||||
|
UseShellExecute = true,
|
||||||
|
});
|
||||||
|
} catch { }
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Menu_Database_Query_Click(object sender, RoutedEventArgs evt) {
|
private void Menu_Database_Query_Click(object sender, RoutedEventArgs evt) {
|
||||||
@ -84,7 +99,7 @@ namespace Elwig.Windows {
|
|||||||
// TODO Menu_Database_Import_Click
|
// TODO Menu_Database_Import_Click
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void Menu_Database_Sync_Click(object sender, RoutedEventArgs evt) {
|
private async void DownloadButton_Click(object sender, RoutedEventArgs evt) {
|
||||||
if (App.Config.SyncUrl == null)
|
if (App.Config.SyncUrl == null)
|
||||||
return;
|
return;
|
||||||
Mouse.OverrideCursor = Cursors.AppStarting;
|
Mouse.OverrideCursor = Cursors.AppStarting;
|
||||||
@ -94,20 +109,17 @@ namespace Elwig.Windows {
|
|||||||
.Select(f => new {
|
.Select(f => new {
|
||||||
Name = f!["name"]!.AsValue().GetValue<string>(),
|
Name = f!["name"]!.AsValue().GetValue<string>(),
|
||||||
Timestamp = f!["timestamp"] != null && DateTime.TryParseExact(f!["timestamp"]!.AsValue().GetValue<string>(), "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None, out var dt) ? dt : (DateTime?)null,
|
Timestamp = f!["timestamp"] != null && DateTime.TryParseExact(f!["timestamp"]!.AsValue().GetValue<string>(), "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None, out var dt) ? dt : (DateTime?)null,
|
||||||
ZwstId = f!["zwstid"]?.AsValue().GetValue<string>(),
|
ZwstId = f!["meta"]?["zwstid"]?.AsValue().GetValue<string>() ?? f!["zwstid"]?.AsValue().GetValue<string>(),
|
||||||
DeliveryNum = f!["meta"]?["deliveries"]?["count"]!.AsValue().GetValue<int>(),
|
|
||||||
DeliveryPartNum = f!["meta"]?["deliveries"]?["parts"]!.AsValue().GetValue<int>(),
|
|
||||||
Filters = f!["meta"]?["deliveries"]?["filters"]!.AsArray().Select(i => i!.AsValue().GetValue<string>()).ToArray(),
|
|
||||||
Device = f!["meta"]?["device"]!.AsValue().GetValue<string>(),
|
Device = f!["meta"]?["device"]!.AsValue().GetValue<string>(),
|
||||||
Url = f!["url"]!.AsValue().GetValue<string>(),
|
Url = f!["url"]!.AsValue().GetValue<string>(),
|
||||||
Size = f!["size"]!.AsValue().GetValue<long>(),
|
Size = f!["size"]!.AsValue().GetValue<long>(),
|
||||||
})
|
})
|
||||||
.Where(f => f.DeliveryNum > 0 && f.Timestamp >= new DateTime(Utils.CurrentLastSeason, 7, 1))
|
.Where(f => f.Timestamp >= new DateTime(Utils.CurrentLastSeason, 7, 1))
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
var imported = await ElwigData.GetImportedFiles();
|
var imported = await ElwigData.GetImportedFiles();
|
||||||
var import = files
|
var import = files
|
||||||
.Where(f => f.Filters != null && f.Filters.Length > 0 && f.Device != Environment.MachineName && !imported.Contains(f.Name))
|
.Where(f => f.Device != Environment.MachineName && !imported.Contains(f.Name))
|
||||||
.ToList();
|
.ToList();
|
||||||
var paths = new List<string>();
|
var paths = new List<string>();
|
||||||
using (var client = Utils.GetHttpClient(App.Config.SyncUsername, App.Config.SyncPassword)) {
|
using (var client = Utils.GetHttpClient(App.Config.SyncUsername, App.Config.SyncPassword)) {
|
||||||
@ -118,13 +130,48 @@ namespace Elwig.Windows {
|
|||||||
paths.Add(filename);
|
paths.Add(filename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await ElwigData.Import(paths, false);
|
await ElwigData.Import(paths, ElwigData.ImportMode.FromBranches);
|
||||||
|
} catch (HttpRequestException exc) {
|
||||||
|
MessageBox.Show(exc.Message + "\n\nEventuell Internetverbindung prüfen!", "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
} catch (Exception exc) {
|
} catch (Exception exc) {
|
||||||
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
}
|
}
|
||||||
Mouse.OverrideCursor = null;
|
Mouse.OverrideCursor = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async void UploadButton_Click(object sender, RoutedEventArgs evt) {
|
||||||
|
if (App.Config.SyncUrl == null)
|
||||||
|
return;
|
||||||
|
Mouse.OverrideCursor = Cursors.AppStarting;
|
||||||
|
try {
|
||||||
|
var path = Path.Combine(App.TempPath, $"{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{App.ZwstId}.zip");
|
||||||
|
using var ctx = new AppDbContext();
|
||||||
|
var deliveries = await ctx.Deliveries
|
||||||
|
.Where(d => d.Year == Utils.CurrentLastSeason && d.ZwstId == App.ZwstId)
|
||||||
|
.Include(d => d.Parts)
|
||||||
|
.ThenInclude(p => p.PartModifiers)
|
||||||
|
.OrderBy(d => d.DateString)
|
||||||
|
.ThenBy(d => d.TimeString)
|
||||||
|
.ThenBy(d => d.LsNr)
|
||||||
|
.AsSplitQuery()
|
||||||
|
.ToListAsync();
|
||||||
|
if (deliveries.Count == 0) {
|
||||||
|
MessageBox.Show("Es gibt keine Lieferungen, die hochgeladen werden können!", "Lieferungen hochladen",
|
||||||
|
MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
|
} else {
|
||||||
|
await ElwigData.Export(path, deliveries, [$"{Utils.CurrentLastSeason}", $"Zweigstelle {App.BranchName}"]);
|
||||||
|
await Utils.UploadExportData(path, App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
|
||||||
|
MessageBox.Show($"Hochladen von {deliveries.Count} Lieferungen erfolgreich!", "Lieferungen hochladen",
|
||||||
|
MessageBoxButton.OK, MessageBoxImage.Information);
|
||||||
|
}
|
||||||
|
} catch (HttpRequestException exc) {
|
||||||
|
MessageBox.Show(exc.Message + "\n\nEventuell Internetverbindung prüfen!", "Lieferungen hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
|
} catch (Exception exc) {
|
||||||
|
MessageBox.Show(exc.Message, "Lieferungen hochladen", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
|
}
|
||||||
|
Mouse.OverrideCursor = null;
|
||||||
|
}
|
||||||
|
|
||||||
private void MemberAdminButton_Click(object sender, RoutedEventArgs evt) {
|
private void MemberAdminButton_Click(object sender, RoutedEventArgs evt) {
|
||||||
var w = new MemberAdminWindow();
|
var w = new MemberAdminWindow();
|
||||||
w.Show();
|
w.Show();
|
||||||
|
Reference in New Issue
Block a user