diff --git a/Elwig/Helpers/AppDbUpdater.cs b/Elwig/Helpers/AppDbUpdater.cs index ab734da..a9beb66 100644 --- a/Elwig/Helpers/AppDbUpdater.cs +++ b/Elwig/Helpers/AppDbUpdater.cs @@ -9,7 +9,7 @@ namespace Elwig.Helpers { public static class AppDbUpdater { // Don't forget to update value in Tests/fetch-resources.bat! - public static readonly int RequiredSchemaVersion = 31; + public static readonly int RequiredSchemaVersion = 32; private static int VersionOffset = 0; diff --git a/Elwig/Helpers/Export/ElwigData.cs b/Elwig/Helpers/Export/ElwigData.cs index 0faf36a..70f6d4b 100644 --- a/Elwig/Helpers/Export/ElwigData.cs +++ b/Elwig/Helpers/Export/ElwigData.cs @@ -1,14 +1,15 @@ -using System.IO.Compression; -using System.IO; -using System.Threading.Tasks; using Elwig.Models.Entities; -using System.Collections.Generic; -using System; -using System.Text.Json.Nodes; -using System.Linq; -using System.Windows; using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.IO.Compression; +using System.Linq; using System.Text.Json; +using System.Text.Json.Nodes; +using System.Threading.Tasks; +using System.Windows; namespace Elwig.Helpers.Export { public static class ElwigData { @@ -63,7 +64,8 @@ namespace Elwig.Helpers.Export { List Riede, List Deliveries, List DeliveryParts, - List Modifiers)>(); + List Modifiers, + Dictionary> Timestamps)>(); var metaData = new List<(string FileName, string ZwstId, string Device, int? MemberNum, string? MemberFilters, @@ -94,7 +96,11 @@ namespace Elwig.Helpers.Export { areaComCount, areaComFilters != null ? string.Join(" / ", areaComFilters) : null, deliveryCount, deliveryFilters != null ? string.Join(" / ", deliveryFilters) : null)); - data.Add(new([], [], [], [], [], [], [], new([], []))); + data.Add(new([], [], [], [], [], [], [], new([], [], new() { + ["member"] = [], + ["area_commitment"] = [], + ["delivery"] = [], + }))); var r = data[^1]; var membersJson = zip.GetEntry("members.json"); @@ -103,11 +109,13 @@ 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(kgs); + var (m, b, telNrs, emailAddrs, timestamps) = obj.ToMember(kgs); r.Members.Add(m); if (b != null) r.BillingAddresses.Add(b); r.TelephoneNumbers.AddRange(telNrs); r.EmailAddresses.AddRange(emailAddrs); + if (timestamps.HasValue) + r.Timestamps["member"].Add((m.MgNr, 0, timestamps.Value.CreatedAt, timestamps.Value.ModifiedAt)); } } @@ -117,12 +125,14 @@ namespace Elwig.Helpers.Export { string? line; while ((line = await reader.ReadLineAsync()) != null) { var obj = JsonNode.Parse(line)!.AsObject(); - var (areaCom, wbrd) = obj.ToAreaCom(kgs, currentWbRde); + var (areaCom, wbrd, timestamps) = obj.ToAreaCom(kgs, currentWbRde); r.AreaCommitments.Add(areaCom); if (wbrd != null) { currentWbRde[wbrd.KgNr].Add(wbrd); r.Riede.Add(wbrd); } + if (timestamps.HasValue) + r.Timestamps["area_commitment"].Add((areaCom.FbNr, 0, timestamps.Value.CreatedAt, timestamps.Value.ModifiedAt)); } } @@ -132,10 +142,12 @@ namespace Elwig.Helpers.Export { string? line; while ((line = await reader.ReadLineAsync()) != null) { var obj = JsonNode.Parse(line)!.AsObject(); - var (d, parts, mods) = obj.ToDelivery(currentLsNrs, currentDids); + var (d, parts, mods, timestamps) = obj.ToDelivery(currentLsNrs, currentDids); r.Deliveries.Add(d); r.DeliveryParts.AddRange(parts); r.Modifiers.AddRange(mods); + if (timestamps.HasValue) + r.Timestamps["delivery"].Add((d.Year, d.DId, timestamps.Value.CreatedAt, timestamps.Value.ModifiedAt)); } } } @@ -144,7 +156,7 @@ namespace Elwig.Helpers.Export { var importedAreaComs = new List<(string FileName, string ZwstId, string Device, int Imported, 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)) { + foreach (var ((members, billingAddresses, telephoneNumbers, emailAddresses, areaCommitments, riede, deliveries, deliveryParts, modifiers, timestamps), meta) in data.Zip(metaData)) { var branch = branches[meta.ZwstId]; var device = meta.Device; @@ -272,6 +284,26 @@ namespace Elwig.Helpers.Export { } await ctx.SaveChangesAsync(); + + var primaryKeys = new Dictionary() { + ["member"] = "mgnr, 0", + ["area_commitment"] = "fbnr, 0", + ["delivery"] = "year, did", + }; + var updateStmts = timestamps + .SelectMany(e => e.Value.Select(m => $"UPDATE {e.Key} " + + $"SET ctime = {((DateTimeOffset)m.CreatedAt.ToUniversalTime()).ToUnixTimeSeconds()}, " + + $"mtime = {((DateTimeOffset)m.ModifiedAt.ToUniversalTime()).ToUnixTimeSeconds()} " + + $"WHERE ({primaryKeys[e.Key]}) = ({m.Id1}, {m.Id2});")); + using var cnx = AppDbContext.Connect(); + await AppDbContext.ExecuteBatch(cnx, $""" + BEGIN; + UPDATE client_parameter SET value = '0' WHERE param = 'ENABLE_TIME_TRIGGERS'; + {string.Join("\n", updateStmts)} + UPDATE client_parameter SET value = '1' WHERE param = 'ENABLE_TIME_TRIGGERS'; + COMMIT; + """); + await AddImportedFiles(Path.GetFileName(meta.FileName)); } App.HintContextChange(); @@ -460,15 +492,19 @@ namespace Elwig.Helpers.Export { return obj; }).ToArray()), ["comment"] = m.Comment, + ["created_at"] = $"{m.CreatedAt:yyyy-MM-ddTHH:mm:ssK}", + ["modified_at"] = $"{m.ModifiedAt:yyyy-MM-ddTHH:mm:ssK}", }; } - public static (Member, BillingAddr?, List, List) ToMember(this JsonNode json, Dictionary kgs) { + public static (Member, BillingAddr?, List, List, (DateTime CreatedAt, DateTime ModifiedAt)?) ToMember(this JsonNode json, Dictionary kgs) { var mgnr = json["mgnr"]!.AsValue().GetValue(); var kgnr = json["default_kgnr"]?.AsValue().GetValue(); 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)"); } + var createdAt = json["created_at"]?.AsValue().GetValue(); + var modifiedAt = json["modified_at"]?.AsValue().GetValue(); return (new Member { MgNr = mgnr, PredecessorMgNr = json["predecessor_mgnr"]?.AsValue().GetValue(), @@ -502,6 +538,7 @@ namespace Elwig.Helpers.Export { ContactViaPost = json["contact_postal"]?.AsValue().GetValue() ?? false, ContactViaEmail = json["contact_email"]?.AsValue().GetValue() ?? false, Comment = json["comment"]?.AsValue().GetValue(), + ImportedAt = DateTime.Now, }, json["billing_address"] is JsonObject a ? new BillingAddr { MgNr = mgnr, FullName = a["name"]!.AsValue().GetValue(), @@ -519,7 +556,10 @@ namespace Elwig.Helpers.Export { Nr = i + 1, Address = a["address"]!.AsValue().GetValue(), Comment = a["comment"]?.AsValue().GetValue(), - }).ToList()); + }).ToList(), + createdAt == null || modifiedAt == null ? null : + (DateTime.ParseExact(createdAt, "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None), + DateTime.ParseExact(modifiedAt, "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None))); } public static JsonObject ToJson(this AreaCom c) { @@ -535,10 +575,12 @@ namespace Elwig.Helpers.Export { ["year_from"] = c.YearFrom, ["year_to"] = c.YearTo, ["comment"] = c.Comment, + ["created_at"] = $"{c.CreatedAt:yyyy-MM-ddTHH:mm:ssK}", + ["modified_at"] = $"{c.ModifiedAt:yyyy-MM-ddTHH:mm:ssK}", }; } - public static (AreaCom, WbRd?) ToAreaCom(this JsonNode json, Dictionary kgs, Dictionary> riede) { + public static (AreaCom, WbRd?, (DateTime CreatedAt, DateTime ModifiedAt)?) ToAreaCom(this JsonNode json, Dictionary kgs, Dictionary> riede) { var kgnr = json["kgnr"]!.AsValue().GetValue(); var ried = json["ried"]?.AsValue().GetValue(); WbRd? rd = null; @@ -556,6 +598,8 @@ namespace Elwig.Helpers.Export { rde.Add(rd); } } + var createdAt = json["created_at"]?.AsValue().GetValue(); + var modifiedAt = json["modified_at"]?.AsValue().GetValue(); return (new AreaCom { FbNr = json["fbnr"]!.AsValue().GetValue(), MgNr = json["mgnr"]!.AsValue().GetValue(), @@ -568,7 +612,11 @@ namespace Elwig.Helpers.Export { YearFrom = json["year_from"]?.AsValue().GetValue(), YearTo = json["year_to"]?.AsValue().GetValue(), Comment = json["comment"]?.AsValue().GetValue(), - }, newRd ? rd : null); + ImportedAt = DateTime.Now, + }, newRd ? rd : null, + createdAt == null || modifiedAt == null ? null : + (DateTime.ParseExact(createdAt, "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None), + DateTime.ParseExact(modifiedAt, "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None))); } public static JsonObject ToJson(this Delivery d) { @@ -596,6 +644,8 @@ namespace Elwig.Helpers.Export { ["manual_weighing"] = p.IsManualWeighing, ["modids"] = new JsonArray(p.Modifiers.Select(m => (JsonNode)m.ModId).ToArray()), ["comment"] = p.Comment, + ["created_at"] = $"{p.CreatedAt:yyyy-MM-ddTHH:mm:ssK}", + ["modified_at"] = $"{p.ModifiedAt:yyyy-MM-ddTHH:mm:ssK}", }; if (p.IsSplCheck) obj["spl_check"] = p.IsSplCheck; if (p.IsHandPicked != null) obj["hand_picked"] = p.IsHandPicked; @@ -609,10 +659,12 @@ namespace Elwig.Helpers.Export { return obj; }).ToArray()), ["comment"] = d.Comment, + ["created_at"] = $"{d.CreatedAt:yyyy-MM-ddTHH:mm:ssK}", + ["modified_at"] = $"{d.ModifiedAt:yyyy-MM-ddTHH:mm:ssK}", }; } - public static (Delivery, List, List) ToDelivery(this JsonNode json, Dictionary currentLsNrs, Dictionary currentDids) { + public static (Delivery, List, List, (DateTime CreatedAt, DateTime ModifiedAt)?) ToDelivery(this JsonNode json, Dictionary currentLsNrs, Dictionary currentDids) { var year = json["year"]!.AsValue().GetValue(); var lsnr = json["lsnr"]!.AsValue().GetValue(); var did = currentLsNrs.GetValueOrDefault(lsnr, -1); @@ -621,6 +673,8 @@ namespace Elwig.Helpers.Export { did = ++currentDids[year]; } currentLsNrs[lsnr] = did; + var createdAt = json["created_at"]?.AsValue().GetValue(); + var modifiedAt = json["modified_at"]?.AsValue().GetValue(); return (new Delivery { Year = year, DId = did, @@ -631,6 +685,7 @@ namespace Elwig.Helpers.Export { LsNr = lsnr, MgNr = json["mgnr"]!.AsValue().GetValue(), Comment = json["comment"]?.AsValue().GetValue(), + ImportedAt = DateTime.Now, }, json["parts"]!.AsArray().Select(p => p!.AsObject()).Select(p => new DeliveryPart { Year = year, DId = did, @@ -661,7 +716,10 @@ namespace Elwig.Helpers.Export { DId = did, DPNr = p["dpnr"]!.AsValue().GetValue(), ModId = m!.AsValue().GetValue(), - })).ToList()); + })).ToList(), + createdAt == null || modifiedAt == null ? null : + (DateTime.ParseExact(createdAt, "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None), + DateTime.ParseExact(modifiedAt, "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None))); } } } diff --git a/Elwig/Models/Dtos/DeliveryAncmtListData.cs b/Elwig/Models/Dtos/DeliveryAncmtListData.cs index d10e5d8..5165d12 100644 --- a/Elwig/Models/Dtos/DeliveryAncmtListData.cs +++ b/Elwig/Models/Dtos/DeliveryAncmtListData.cs @@ -18,8 +18,8 @@ namespace Elwig.Models.Dtos { ("DefaultKg", "Ort", null, 40), ("SortId", "Sorte", null, 10), ("Weight", "Menge", "kg", 20), - ("CreatedTimestamp", "Angemeldet", null, 35), - ("ModifiedTimestamp", "Geändert", null, 35), + ("CreatedAt", "Angemeldet", null, 35), + ("ModifiedAt", "Geändert", null, 35), ("Status", "Status", null, 20), ]; @@ -47,8 +47,8 @@ namespace Elwig.Models.Dtos { public string? DefaultKg; public string SortId; public string Variety; - public DateTime CreatedTimestamp; - public DateTime? ModifiedTimestamp; + public DateTime CreatedAt; + public DateTime? ModifiedAt; public int Weight; public string? Status; @@ -65,10 +65,10 @@ namespace Elwig.Models.Dtos { DefaultKg = m.DefaultKg?.Name; SortId = a.SortId; Variety = a.Variety.Name; - CreatedTimestamp = a.CreatedTimestamp; - ModifiedTimestamp = a.ModifiedTimestamp == a.CreatedTimestamp ? null : a.ModifiedTimestamp; + CreatedAt = a.CreatedAt; + ModifiedAt = a.ModifiedAt == a.CreatedAt ? null : a.ModifiedAt; Weight = a.Weight; - Status = s.AncmtTo == null ? null : a.CreatedTimestamp >= s.AncmtTo ? "verspät." : "ok"; + Status = s.AncmtTo == null ? null : a.CreatedAt >= s.AncmtTo ? "verspät." : "ok"; } } } diff --git a/Elwig/Models/Entities/AreaCom.cs b/Elwig/Models/Entities/AreaCom.cs index 4ff65e8..763c2e9 100644 --- a/Elwig/Models/Entities/AreaCom.cs +++ b/Elwig/Models/Entities/AreaCom.cs @@ -41,14 +41,36 @@ namespace Elwig.Models.Entities { public string? Comment { get; set; } [Column("ctime"), DatabaseGenerated(DatabaseGeneratedOption.Computed)] - public long CTime { get; private set; } + public long CTime { get; set; } [NotMapped] - public DateTime CreatedTimestamp => DateTimeOffset.FromUnixTimeSeconds(CTime).LocalDateTime; + public DateTime CreatedAt { + get => DateTimeOffset.FromUnixTimeSeconds(CTime).LocalDateTime; + set => CTime = ((DateTimeOffset)value.ToUniversalTime()).ToUnixTimeSeconds(); + } [Column("mtime"), DatabaseGenerated(DatabaseGeneratedOption.Computed)] - public long MTime { get; private set; } + public long MTime { get; set; } [NotMapped] - public DateTime ModifiedTimestamp => DateTimeOffset.FromUnixTimeSeconds(MTime).LocalDateTime; + public DateTime ModifiedAt { + get => DateTimeOffset.FromUnixTimeSeconds(MTime).LocalDateTime; + set => MTime = ((DateTimeOffset)value.ToUniversalTime()).ToUnixTimeSeconds(); + } + + [Column("xtime")] + public long? XTime { get; set; } + [NotMapped] + public DateTime? ExportedAt { + get => XTime == null ? null : DateTimeOffset.FromUnixTimeSeconds(XTime.Value).LocalDateTime; + set => XTime = value == null ? null : ((DateTimeOffset)value.Value.ToUniversalTime()).ToUnixTimeSeconds(); + } + + [Column("itime")] + public long? ITime { get; set; } + [NotMapped] + public DateTime? ImportedAt { + get => ITime == null ? null : DateTimeOffset.FromUnixTimeSeconds(ITime.Value).LocalDateTime; + set => ITime = value == null ? null : ((DateTimeOffset)value.Value.ToUniversalTime()).ToUnixTimeSeconds(); + } [ForeignKey("MgNr")] public virtual Member Member { get; private set; } = null!; diff --git a/Elwig/Models/Entities/Credit.cs b/Elwig/Models/Entities/Credit.cs index d257363..6bb1673 100644 --- a/Elwig/Models/Entities/Credit.cs +++ b/Elwig/Models/Entities/Credit.cs @@ -84,14 +84,36 @@ namespace Elwig.Models.Entities { } [Column("ctime"), DatabaseGenerated(DatabaseGeneratedOption.Computed)] - public long CTime { get; private set; } + public long CTime { get; set; } [NotMapped] - public DateTime CreatedTimestamp => DateTimeOffset.FromUnixTimeSeconds(CTime).LocalDateTime; + public DateTime CreatedAt { + get => DateTimeOffset.FromUnixTimeSeconds(CTime).LocalDateTime; + set => CTime = ((DateTimeOffset)value.ToUniversalTime()).ToUnixTimeSeconds(); + } [Column("mtime"), DatabaseGenerated(DatabaseGeneratedOption.Computed)] - public long MTime { get; private set; } + public long MTime { get; set; } [NotMapped] - public DateTime ModifiedTimestamp => DateTimeOffset.FromUnixTimeSeconds(MTime).LocalDateTime; + public DateTime ModifiedAt { + get => DateTimeOffset.FromUnixTimeSeconds(MTime).LocalDateTime; + set => MTime = ((DateTimeOffset)value.ToUniversalTime()).ToUnixTimeSeconds(); + } + + [Column("xtime")] + public long? XTime { get; set; } + [NotMapped] + public DateTime? ExportedAt { + get => XTime == null ? null : DateTimeOffset.FromUnixTimeSeconds(XTime.Value).LocalDateTime; + set => XTime = value == null ? null : ((DateTimeOffset)value.Value.ToUniversalTime()).ToUnixTimeSeconds(); + } + + [Column("itime")] + public long? ITime { get; set; } + [NotMapped] + public DateTime? ImportedAt { + get => ITime == null ? null : DateTimeOffset.FromUnixTimeSeconds(ITime.Value).LocalDateTime; + set => ITime = value == null ? null : ((DateTimeOffset)value.Value.ToUniversalTime()).ToUnixTimeSeconds(); + } [ForeignKey("Year, AvNr, MgNr")] public virtual PaymentMember Payment { get; private set; } = null!; diff --git a/Elwig/Models/Entities/Delivery.cs b/Elwig/Models/Entities/Delivery.cs index 929e95d..15b3883 100644 --- a/Elwig/Models/Entities/Delivery.cs +++ b/Elwig/Models/Entities/Delivery.cs @@ -62,14 +62,36 @@ namespace Elwig.Models.Entities { public string? Comment { get; set; } [Column("ctime"), DatabaseGenerated(DatabaseGeneratedOption.Computed)] - public long CTime { get; private set; } + public long CTime { get; set; } [NotMapped] - public DateTime CreatedTimestamp => DateTimeOffset.FromUnixTimeSeconds(CTime).LocalDateTime; + public DateTime CreatedAt { + get => DateTimeOffset.FromUnixTimeSeconds(CTime).LocalDateTime; + set => CTime = ((DateTimeOffset)value.ToUniversalTime()).ToUnixTimeSeconds(); + } [Column("mtime"), DatabaseGenerated(DatabaseGeneratedOption.Computed)] - public long MTime { get; private set; } + public long MTime { get; set; } [NotMapped] - public DateTime ModifiedTimestamp => DateTimeOffset.FromUnixTimeSeconds(MTime).LocalDateTime; + public DateTime ModifiedAt { + get => DateTimeOffset.FromUnixTimeSeconds(MTime).LocalDateTime; + set => MTime = ((DateTimeOffset)value.ToUniversalTime()).ToUnixTimeSeconds(); + } + + [Column("xtime")] + public long? XTime { get; set; } + [NotMapped] + public DateTime? ExportedAt { + get => XTime == null ? null : DateTimeOffset.FromUnixTimeSeconds(XTime.Value).LocalDateTime; + set => XTime = value == null ? null : ((DateTimeOffset)value.Value.ToUniversalTime()).ToUnixTimeSeconds(); + } + + [Column("itime")] + public long? ITime { get; set; } + [NotMapped] + public DateTime? ImportedAt { + get => ITime == null ? null : DateTimeOffset.FromUnixTimeSeconds(ITime.Value).LocalDateTime; + set => ITime = value == null ? null : ((DateTimeOffset)value.Value.ToUniversalTime()).ToUnixTimeSeconds(); + } [ForeignKey("Year")] public virtual Season Season { get; private set; } = null!; diff --git a/Elwig/Models/Entities/DeliveryAncmt.cs b/Elwig/Models/Entities/DeliveryAncmt.cs index 05f5e89..cacf0e9 100644 --- a/Elwig/Models/Entities/DeliveryAncmt.cs +++ b/Elwig/Models/Entities/DeliveryAncmt.cs @@ -27,14 +27,36 @@ namespace Elwig.Models.Entities { public required string Type { get; set; } [Column("ctime"), DatabaseGenerated(DatabaseGeneratedOption.Computed)] - public long CTime { get; private set; } + public long CTime { get; set; } [NotMapped] - public DateTime CreatedTimestamp => DateTimeOffset.FromUnixTimeSeconds(CTime).LocalDateTime; + public DateTime CreatedAt { + get => DateTimeOffset.FromUnixTimeSeconds(CTime).LocalDateTime; + set => CTime = ((DateTimeOffset)value.ToUniversalTime()).ToUnixTimeSeconds(); + } [Column("mtime"), DatabaseGenerated(DatabaseGeneratedOption.Computed)] - public long MTime { get; private set; } + public long MTime { get; set; } [NotMapped] - public DateTime ModifiedTimestamp => DateTimeOffset.FromUnixTimeSeconds(MTime).LocalDateTime; + public DateTime ModifiedAt { + get => DateTimeOffset.FromUnixTimeSeconds(MTime).LocalDateTime; + set => MTime = ((DateTimeOffset)value.ToUniversalTime()).ToUnixTimeSeconds(); + } + + [Column("xtime")] + public long? XTime { get; set; } + [NotMapped] + public DateTime? ExportedAt { + get => XTime == null ? null : DateTimeOffset.FromUnixTimeSeconds(XTime.Value).LocalDateTime; + set => XTime = value == null ? null : ((DateTimeOffset)value.Value.ToUniversalTime()).ToUnixTimeSeconds(); + } + + [Column("itime")] + public long? ITime { get; set; } + [NotMapped] + public DateTime? ImportedAt { + get => ITime == null ? null : DateTimeOffset.FromUnixTimeSeconds(ITime.Value).LocalDateTime; + set => ITime = value == null ? null : ((DateTimeOffset)value.Value.ToUniversalTime()).ToUnixTimeSeconds(); + } [ForeignKey("Year, DsNr")] public virtual DeliverySchedule Schedule { get; private set; } = null!; diff --git a/Elwig/Models/Entities/DeliveryPart.cs b/Elwig/Models/Entities/DeliveryPart.cs index 2fd2834..f4ab189 100644 --- a/Elwig/Models/Entities/DeliveryPart.cs +++ b/Elwig/Models/Entities/DeliveryPart.cs @@ -129,14 +129,36 @@ namespace Elwig.Models.Entities { public string? Comment { get; set; } [Column("ctime"), DatabaseGenerated(DatabaseGeneratedOption.Computed)] - public long CTime { get; private set; } + public long CTime { get; set; } [NotMapped] - public DateTime CreatedTimestamp => DateTimeOffset.FromUnixTimeSeconds(CTime).LocalDateTime; + public DateTime CreatedAt { + get => DateTimeOffset.FromUnixTimeSeconds(CTime).LocalDateTime; + set => CTime = ((DateTimeOffset)value.ToUniversalTime()).ToUnixTimeSeconds(); + } [Column("mtime"), DatabaseGenerated(DatabaseGeneratedOption.Computed)] - public long MTime { get; private set; } + public long MTime { get; set; } [NotMapped] - public DateTime ModifiedTimestamp => DateTimeOffset.FromUnixTimeSeconds(MTime).LocalDateTime; + public DateTime ModifiedAt { + get => DateTimeOffset.FromUnixTimeSeconds(MTime).LocalDateTime; + set => MTime = ((DateTimeOffset)value.ToUniversalTime()).ToUnixTimeSeconds(); + } + + [Column("xtime")] + public long? XTime { get; set; } + [NotMapped] + public DateTime? ExportedAt { + get => XTime == null ? null : DateTimeOffset.FromUnixTimeSeconds(XTime.Value).LocalDateTime; + set => XTime = value == null ? null : ((DateTimeOffset)value.Value.ToUniversalTime()).ToUnixTimeSeconds(); + } + + [Column("itime")] + public long? ITime { get; set; } + [NotMapped] + public DateTime? ImportedAt { + get => ITime == null ? null : DateTimeOffset.FromUnixTimeSeconds(ITime.Value).LocalDateTime; + set => ITime = value == null ? null : ((DateTimeOffset)value.Value.ToUniversalTime()).ToUnixTimeSeconds(); + } [InverseProperty(nameof(DeliveryPartModifier.Part))] public virtual ICollection PartModifiers { get; private set; } = null!; diff --git a/Elwig/Models/Entities/Member.cs b/Elwig/Models/Entities/Member.cs index a23564f..3c5e7f7 100644 --- a/Elwig/Models/Entities/Member.cs +++ b/Elwig/Models/Entities/Member.cs @@ -145,14 +145,36 @@ namespace Elwig.Models.Entities { public AT_Kg? DefaultKg => DefaultWbKg?.AtKg; [Column("ctime"), DatabaseGenerated(DatabaseGeneratedOption.Computed)] - public long CTime { get; private set; } + public long CTime { get; set; } [NotMapped] - public DateTime CreatedTimestamp => DateTimeOffset.FromUnixTimeSeconds(CTime).LocalDateTime; + public DateTime CreatedAt { + get => DateTimeOffset.FromUnixTimeSeconds(CTime).LocalDateTime; + set => CTime = ((DateTimeOffset)value.ToUniversalTime()).ToUnixTimeSeconds(); + } [Column("mtime"), DatabaseGenerated(DatabaseGeneratedOption.Computed)] - public long MTime { get; private set; } + public long MTime { get; set; } [NotMapped] - public DateTime ModifiedTimestamp => DateTimeOffset.FromUnixTimeSeconds(MTime).LocalDateTime; + public DateTime ModifiedAt { + get => DateTimeOffset.FromUnixTimeSeconds(MTime).LocalDateTime; + set => MTime = ((DateTimeOffset)value.ToUniversalTime()).ToUnixTimeSeconds(); + } + + [Column("xtime")] + public long? XTime { get; set; } + [NotMapped] + public DateTime? ExportedAt { + get => XTime == null ? null : DateTimeOffset.FromUnixTimeSeconds(XTime.Value).LocalDateTime; + set => XTime = value == null ? null : ((DateTimeOffset)value.Value.ToUniversalTime()).ToUnixTimeSeconds(); + } + + [Column("itime")] + public long? ITime { get; set; } + [NotMapped] + public DateTime? ImportedAt { + get => ITime == null ? null : DateTimeOffset.FromUnixTimeSeconds(ITime.Value).LocalDateTime; + set => ITime = value == null ? null : ((DateTimeOffset)value.Value.ToUniversalTime()).ToUnixTimeSeconds(); + } [ForeignKey("ZwstId")] public virtual Branch? Branch { get; private set; } diff --git a/Elwig/Models/Entities/PaymentVar.cs b/Elwig/Models/Entities/PaymentVar.cs index 616a616..2c6a058 100644 --- a/Elwig/Models/Entities/PaymentVar.cs +++ b/Elwig/Models/Entities/PaymentVar.cs @@ -46,14 +46,36 @@ namespace Elwig.Models.Entities { public required string Data { get; set; } [Column("ctime"), DatabaseGenerated(DatabaseGeneratedOption.Computed)] - public long CTime { get; private set; } + public long CTime { get; set; } [NotMapped] - public DateTime CreatedTimestamp => DateTimeOffset.FromUnixTimeSeconds(CTime).LocalDateTime; + public DateTime CreatedAt { + get => DateTimeOffset.FromUnixTimeSeconds(CTime).LocalDateTime; + set => CTime = ((DateTimeOffset)value.ToUniversalTime()).ToUnixTimeSeconds(); + } [Column("mtime"), DatabaseGenerated(DatabaseGeneratedOption.Computed)] - public long MTime { get; private set; } + public long MTime { get; set; } [NotMapped] - public DateTime ModifiedTimestamp => DateTimeOffset.FromUnixTimeSeconds(MTime).LocalDateTime; + public DateTime ModifiedAt { + get => DateTimeOffset.FromUnixTimeSeconds(MTime).LocalDateTime; + set => MTime = ((DateTimeOffset)value.ToUniversalTime()).ToUnixTimeSeconds(); + } + + [Column("xtime")] + public long? XTime { get; set; } + [NotMapped] + public DateTime? ExportedAt { + get => XTime == null ? null : DateTimeOffset.FromUnixTimeSeconds(XTime.Value).LocalDateTime; + set => XTime = value == null ? null : ((DateTimeOffset)value.Value.ToUniversalTime()).ToUnixTimeSeconds(); + } + + [Column("itime")] + public long? ITime { get; set; } + [NotMapped] + public DateTime? ImportedAt { + get => ITime == null ? null : DateTimeOffset.FromUnixTimeSeconds(ITime.Value).LocalDateTime; + set => ITime = value == null ? null : ((DateTimeOffset)value.Value.ToUniversalTime()).ToUnixTimeSeconds(); + } [ForeignKey("Year")] public virtual Season Season { get; private set; } = null!; diff --git a/Elwig/Resources/Sql/31-32.sql b/Elwig/Resources/Sql/31-32.sql new file mode 100644 index 0000000..79e7987 --- /dev/null +++ b/Elwig/Resources/Sql/31-32.sql @@ -0,0 +1,33 @@ +-- schema version 31 to 32 + +INSERT INTO client_parameter (param, value) VALUES ('ENABLE_TIME_TRIGGERS', '1'); + +ALTER TABLE member ADD COLUMN xtime INTEGER DEFAULT NULL; +ALTER TABLE member ADD COLUMN itime INTEGER DEFAULT NULL; +ALTER TABLE area_commitment ADD COLUMN xtime INTEGER DEFAULT NULL; +ALTER TABLE area_commitment ADD COLUMN itime INTEGER DEFAULT NULL; +ALTER TABLE delivery_announcement ADD COLUMN xtime INTEGER DEFAULT NULL; +ALTER TABLE delivery_announcement ADD COLUMN itime INTEGER DEFAULT NULL; +ALTER TABLE delivery ADD COLUMN xtime INTEGER DEFAULT NULL; +ALTER TABLE delivery ADD COLUMN itime INTEGER DEFAULT NULL; +ALTER TABLE delivery_part ADD COLUMN xtime INTEGER DEFAULT NULL; +ALTER TABLE delivery_part ADD COLUMN itime INTEGER DEFAULT NULL; +ALTER TABLE payment_variant ADD COLUMN xtime INTEGER DEFAULT NULL; +ALTER TABLE payment_variant ADD COLUMN itime INTEGER DEFAULT NULL; +ALTER TABLE credit ADD COLUMN xtime INTEGER DEFAULT NULL; +ALTER TABLE credit ADD COLUMN itime INTEGER DEFAULT NULL; + +PRAGMA writable_schema = ON; + +UPDATE sqlite_schema SET sql = REPLACE(REPLACE(sql, +' WHEN', +' WHEN (SELECT value FROM client_parameter WHERE param = ''ENABLE_TIME_TRIGGERS'') = 1 AND'), +'FOR EACH ROW' || char(10) || +'BEGIN', +'FOR EACH ROW' || char(10) || +' WHEN (SELECT value FROM client_parameter WHERE param = ''ENABLE_TIME_TRIGGERS'') = 1' || char(10) || +'BEGIN') +WHERE type = 'trigger' AND name LIKE '%time%'; + +PRAGMA writable_schema = OFF; +PRAGMA schema_version = 3101; diff --git a/Elwig/Services/DeliveryAncmtService.cs b/Elwig/Services/DeliveryAncmtService.cs index f132439..363f992 100644 --- a/Elwig/Services/DeliveryAncmtService.cs +++ b/Elwig/Services/DeliveryAncmtService.cs @@ -37,8 +37,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}" : "-"; + vm.StatusAncmtCreated = $"{a.CreatedAt:dd.MM.yyyy, HH:mm} ({a.Type})"; + vm.StatusAncmtModified = a.ModifiedAt != a.CreatedAt ? $"{a.ModifiedAt:dd.MM.yyyy, HH:mm}" : "-"; } public static async Task<(List, IQueryable, List)> GetFilters(this DeliveryAncmtAdminViewModel vm, AppDbContext ctx) { diff --git a/Elwig/Services/MemberService.cs b/Elwig/Services/MemberService.cs index ad0a643..d0f6056 100644 --- a/Elwig/Services/MemberService.cs +++ b/Elwig/Services/MemberService.cs @@ -1,20 +1,20 @@ -using Elwig.Helpers; -using Elwig.Models.Entities; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using System; -using Microsoft.EntityFrameworkCore; using Elwig.Documents; -using System.Windows.Input; -using System.Windows; +using Elwig.Helpers; using Elwig.Helpers.Billing; -using Elwig.Models.Dtos; using Elwig.Helpers.Export; -using Microsoft.Win32; +using Elwig.Models.Dtos; +using Elwig.Models.Entities; using Elwig.ViewModels; +using Microsoft.EntityFrameworkCore; +using Microsoft.Win32; +using System; +using System.Collections.Generic; using System.IO; +using System.Linq; using System.Net.Http; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Input; namespace Elwig.Services { public static class MemberService { @@ -49,6 +49,11 @@ namespace Elwig.Services { vm.StatusAreaCommitmentInfo = $"{Utils.CurrentLastSeason}"; vm.StatusAreaCommitmentToolTip = null; vm.Age = "-"; + vm.CreatedAt = "-"; + vm.ModifiedAt = "-"; + vm.ModifiedAtShort = "-"; + vm.ExportedAt = "-"; + vm.ImportedAt = "-"; } public static void FillInputs(this MemberAdminViewModel vm, Member m) { @@ -137,6 +142,12 @@ namespace Elwig.Services { vm.ContactViaPost = m.ContactViaPost; vm.ContactViaEmail = m.ContactViaEmail; + vm.CreatedAt = $"{m.CreatedAt:dd.MM.yyyy, HH:mm:ss}"; + vm.ModifiedAt = $"{m.ModifiedAt:dd.MM.yyyy, HH:mm:ss}"; + vm.ModifiedAtShort = $"{m.ModifiedAt:dd.MM.yyyy, HH:mm}"; + vm.ExportedAt = m.ExportedAt == null ? "-" : $"{m.ExportedAt:dd.MM.yyyy, HH:mm:ss}"; + vm.ImportedAt = m.ImportedAt == null ? "-" : $"{m.ImportedAt:dd.MM.yyyy, HH:mm:ss}"; + vm.StatusDeliveriesLastSeasonInfo = $"{Utils.CurrentLastSeason - 1}"; vm.StatusDeliveriesLastSeason = "..."; vm.StatusDeliveriesLastSeasonToolTip = null; diff --git a/Elwig/ViewModels/MemberAdminViewModel.cs b/Elwig/ViewModels/MemberAdminViewModel.cs index ef6c14d..8d28889 100644 --- a/Elwig/ViewModels/MemberAdminViewModel.cs +++ b/Elwig/ViewModels/MemberAdminViewModel.cs @@ -153,6 +153,17 @@ namespace Elwig.ViewModels { [ObservableProperty] private bool _contactViaEmail; + [ObservableProperty] + private string _createdAt = "-"; + [ObservableProperty] + private string _modifiedAt = "-"; + [ObservableProperty] + private string _modifiedAtShort = "-"; + [ObservableProperty] + private string _exportedAt = "-"; + [ObservableProperty] + private string _importedAt = "-"; + public ObservableCollection EmailAddresses { get; private set; } = [null, null, null, null, null, null, null, null, null]; public partial class PhoneNr(int? type = null, string? number = null, string? comment = null) : ObservableObject { diff --git a/Elwig/Windows/MainWindow.xaml.cs b/Elwig/Windows/MainWindow.xaml.cs index f97c691..28f1fa6 100644 --- a/Elwig/Windows/MainWindow.xaml.cs +++ b/Elwig/Windows/MainWindow.xaml.cs @@ -212,7 +212,7 @@ namespace Elwig.Windows { } catch (HttpRequestException exc) { MessageBox.Show("Eventuell Internetverbindung prüfen!\n\n" + exc.Message, "Lieferungen 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, "Lieferungen hochladen", MessageBoxButton.OK, MessageBoxImage.Error); } catch (Exception exc) { MessageBox.Show(exc.Message, "Lieferungen hochladen", MessageBoxButton.OK, MessageBoxImage.Error); } diff --git a/Elwig/Windows/MemberAdminWindow.xaml b/Elwig/Windows/MemberAdminWindow.xaml index c98082d..a74fd12 100644 --- a/Elwig/Windows/MemberAdminWindow.xaml +++ b/Elwig/Windows/MemberAdminWindow.xaml @@ -653,13 +653,40 @@ TextChanged="TextBox_TextChanged" VerticalAlignment="Stretch" Height="auto" AcceptsReturn="True" TextWrapping="Wrap" VerticalScrollBarVisibility="Visible"/> -