Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
1b69fcb16a | |||
c8a95422af | |||
9d02f18bac | |||
f9ee2cb120 | |||
b27b89f599 | |||
bfbd0a6a22 | |||
e2de7a1f1c | |||
3f769eb7d7 | |||
8bc053053c | |||
a0dcaf7b4f | |||
844fc5217a |
45
CHANGELOG.md
45
CHANGELOG.md
@@ -2,6 +2,51 @@
|
||||
Changelog
|
||||
=========
|
||||
|
||||
[v1.0.1.2][v1.0.1.2] (2025-09-25) {#v1.0.1.2}
|
||||
---------------------------------------------
|
||||
|
||||
### Behobene Fehler {#v1.0.1.2-bugfixes}
|
||||
|
||||
* Beim automatischen Importieren/Synchronisieren wird bei einem Fehlerfall der Benutzer verständigt, aber der Vorgang nicht abgebrochen. (9d02f18bac)
|
||||
|
||||
### Sonstiges {#v1.0.1.2-misc}
|
||||
|
||||
* Beim Sichern der Datenbank werden Meta-Informationen in der ZIP-Datei gespeichert. (c8a95422af)
|
||||
|
||||
[v1.0.1.2]: https://git.necronda.net/winzer/elwig/releases/tag/v1.0.1.2
|
||||
|
||||
|
||||
|
||||
|
||||
[v1.0.1.1][v1.0.1.1] (2025-09-21) {#v1.0.1.1}
|
||||
---------------------------------------------
|
||||
|
||||
### Sonstiges {#v1.0.1.1-misc}
|
||||
|
||||
* Eingabe von Sorten und Qualitätsstufen im Übernahme-Fenster (`DeliveryAdminWindows`) verbessert. (e2de7a1f1c, b27b89f599)
|
||||
|
||||
[v1.0.1.1]: https://git.necronda.net/winzer/elwig/releases/tag/v1.0.1.1
|
||||
|
||||
|
||||
|
||||
|
||||
[v1.0.1.0][v1.0.1.0] (2025-09-18) {#v1.0.1.0}
|
||||
---------------------------------------------
|
||||
|
||||
### Neue Funktionen {#v1.0.1.0-features}
|
||||
|
||||
* Neue Weinsorten gemäß Kürzelliste der Bundeskellereiinspektion hinzugefügt. (a0dcaf7b4f)
|
||||
|
||||
### Sonstiges {#v1.0.1.0-misc}
|
||||
|
||||
* HTTP-Anfragen haben jetzt das Feld `User-Agent` gesetzt. (844fc5217a)
|
||||
* Auto-Update-Funktion wird auch beim Erlangen von Netzwerkverbindung ausgeführt. (8bc053053c)
|
||||
|
||||
[v1.0.1.0]: https://git.necronda.net/winzer/elwig/releases/tag/v1.0.1.0
|
||||
|
||||
|
||||
|
||||
|
||||
[v1.0.0.6][v1.0.0.6] (2025-09-17) {#v1.0.0.6}
|
||||
---------------------------------------------
|
||||
|
||||
|
@@ -35,7 +35,7 @@
|
||||
</DataTemplate>
|
||||
<DataTemplate x:Key="WineVarietyTemplateExpanded">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding SortId}" Foreground="{Binding Color}" MinWidth="36" Margin="0,0,10,0"/>
|
||||
<TextBlock Text="{Binding SortIdFormat}" Foreground="{Binding Color}" MinWidth="36" Margin="0,0,10,0"/>
|
||||
<TextBlock Text="{Binding Name}" Foreground="{Binding Color}"/>
|
||||
<TextBlock Text="{Binding CommentFormat}" FontSize="10" VerticalAlignment="Bottom" Margin="0,0,0,2"/>
|
||||
</StackPanel>
|
||||
|
@@ -11,6 +11,7 @@ using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
@@ -131,6 +132,7 @@ namespace Elwig {
|
||||
await CheckForUpdates();
|
||||
});
|
||||
}
|
||||
NetworkChange.NetworkAvailabilityChanged += OnNetworkAvailabilityChanged;
|
||||
_autoUpdateTimer.Tick += new EventHandler(OnAutoUpdateTimer);
|
||||
_autoUpdateTimer.Start();
|
||||
}
|
||||
@@ -228,6 +230,16 @@ namespace Elwig {
|
||||
}
|
||||
}
|
||||
|
||||
private void OnNetworkAvailabilityChanged(object? sender, NetworkAvailabilityEventArgs evt) {
|
||||
if (!evt.IsAvailable) return;
|
||||
if (Utils.HasInternetConnectivity()) {
|
||||
Utils.RunBackground("Auto Updater", async () => {
|
||||
await Task.Delay(500);
|
||||
await CheckForUpdates();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task CheckForUpdates(bool showAlert = false) {
|
||||
if (Config.UpdateUrl == null) return;
|
||||
var latest = await Utils.GetLatestInstallerUrl(Config.UpdateUrl);
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<UseWPF>true</UseWPF>
|
||||
<PreserveCompilationContext>true</PreserveCompilationContext>
|
||||
<ApplicationIcon>Resources\Images\Elwig.ico</ApplicationIcon>
|
||||
<Version>1.0.0.6</Version>
|
||||
<Version>1.0.1.2</Version>
|
||||
<SatelliteResourceLanguages>de-AT</SatelliteResourceLanguages>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
|
@@ -248,13 +248,6 @@ namespace Elwig.Helpers {
|
||||
return c + 1;
|
||||
}
|
||||
|
||||
public async Task<WineQualLevel> GetWineQualityLevel(double kmw) {
|
||||
return await WineQualityLevels
|
||||
.Where(q => !q.IsPredicate && (q.MinKmw == null || q.MinKmw <= kmw))
|
||||
.OrderBy(q => q.MinKmw)
|
||||
.LastAsync();
|
||||
}
|
||||
|
||||
public void UpdateDeliveryPartModifiers(DeliveryPart part, IEnumerable<Modifier> oldModifiers, IEnumerable<Modifier> newModifiers) {
|
||||
foreach (var m in Modifiers.Where(m => m.Year == part.Year)) {
|
||||
var mod = new DeliveryPartModifier {
|
||||
|
@@ -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 = 32;
|
||||
public static readonly int RequiredSchemaVersion = 33;
|
||||
|
||||
private static int VersionOffset = 0;
|
||||
|
||||
|
@@ -2,16 +2,48 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Elwig.Helpers.Export {
|
||||
public static class Database {
|
||||
|
||||
private static async Task<(long? ApplicationId, string? UserVersion, long? SchemaVersion, long FileSize)> GetMeta() {
|
||||
long size = new FileInfo(App.Config.DatabaseFile).Length;
|
||||
using var cnx = await AppDbContext.ConnectAsync();
|
||||
var applId = (long?)await AppDbContext.ExecuteScalar(cnx, "PRAGMA application_id");
|
||||
var userVers = (long?)await AppDbContext.ExecuteScalar(cnx, "PRAGMA user_version");
|
||||
var schemaVers = (long?)await AppDbContext.ExecuteScalar(cnx, "PRAGMA schema_version");
|
||||
return (applId, userVers != null ? $"{userVers >> 24}.{(userVers >> 16) & 0xFF}.{(userVers >> 8) & 0xFF}.{userVers & 0xFF}" : null, schemaVers, size);
|
||||
}
|
||||
|
||||
public static async Task ExportSqlite(string filename, bool zipFile) {
|
||||
if (zipFile) {
|
||||
File.Delete(filename);
|
||||
using var zip = ZipFile.Open(filename, ZipArchiveMode.Create);
|
||||
await zip.CheckIntegrity();
|
||||
|
||||
var version = zip.CreateEntry("version", CompressionLevel.NoCompression);
|
||||
using (var writer = new StreamWriter(version.Open(), Utils.UTF8)) {
|
||||
await writer.WriteAsync("elwig:1");
|
||||
}
|
||||
|
||||
var (applId, userVers, schemaVers, size) = await GetMeta();
|
||||
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,
|
||||
["database"] = new JsonObject {
|
||||
["application_id"] = applId,
|
||||
["user_version"] = userVers,
|
||||
["schema_version"] = schemaVers,
|
||||
["file_size"] = size,
|
||||
},
|
||||
};
|
||||
await writer.WriteAsync(obj.ToJsonString(Utils.JsonOpts));
|
||||
}
|
||||
|
||||
var db = zip.CreateEntryFromFile(App.Config.DatabaseFile, "database.sqlite3", CompressionLevel.SmallestSize);
|
||||
} else {
|
||||
File.Copy(App.Config.DatabaseFile, filename, true);
|
||||
@@ -22,10 +54,33 @@ namespace Elwig.Helpers.Export {
|
||||
if (zipFile) {
|
||||
File.Delete(filename);
|
||||
using var zip = ZipFile.Open(filename, ZipArchiveMode.Create);
|
||||
var entry = zip.CreateEntry("database.sql", CompressionLevel.SmallestSize);
|
||||
using var stream = entry.Open();
|
||||
using var writer = new StreamWriter(stream, Utils.UTF8);
|
||||
|
||||
var version = zip.CreateEntry("version", CompressionLevel.NoCompression);
|
||||
using (var writer = new StreamWriter(version.Open(), Utils.UTF8)) {
|
||||
await writer.WriteAsync("elwig:1");
|
||||
}
|
||||
|
||||
var (applId, userVers, schemaVers, size) = await GetMeta();
|
||||
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,
|
||||
["database"] = new JsonObject {
|
||||
["application_id"] = applId,
|
||||
["user_version"] = userVers,
|
||||
["schema_version"] = schemaVers,
|
||||
["file_size"] = size,
|
||||
},
|
||||
};
|
||||
await writer.WriteAsync(obj.ToJsonString(Utils.JsonOpts));
|
||||
}
|
||||
|
||||
var sql = zip.CreateEntry("database.sql", CompressionLevel.SmallestSize);
|
||||
using (var writer = new StreamWriter(sql.Open(), Utils.UTF8)) {
|
||||
await ExportSql(writer);
|
||||
}
|
||||
} else {
|
||||
using var stream = File.OpenWrite(filename);
|
||||
using var writer = new StreamWriter(stream, Utils.UTF8);
|
||||
|
@@ -6,7 +6,6 @@ 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;
|
||||
@@ -18,8 +17,6 @@ namespace Elwig.Helpers.Export {
|
||||
|
||||
public static readonly string ImportedTxt = Path.Combine(App.DataPath, "imported.txt");
|
||||
|
||||
private static readonly JsonSerializerOptions JsonOpts = new() { Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping };
|
||||
|
||||
public static async Task<string[]> GetImportedFiles() {
|
||||
try {
|
||||
return await File.ReadAllLinesAsync(ImportedTxt, Utils.UTF8);
|
||||
@@ -77,6 +74,14 @@ namespace Elwig.Helpers.Export {
|
||||
int? DeliveryNum, string? DeliveryFilters)>();
|
||||
|
||||
foreach (var filename in filenames) {
|
||||
try {
|
||||
data.Add(new([], [], [], [], [], [], [], new([], [], [], [], new() {
|
||||
["member"] = [],
|
||||
["area_commitment"] = [],
|
||||
["delivery"] = [],
|
||||
})));
|
||||
var r = data[^1];
|
||||
|
||||
// TODO read encrypted files
|
||||
using var zip = ZipFile.Open(filename, ZipArchiveMode.Read);
|
||||
await zip.CheckIntegrity();
|
||||
@@ -84,7 +89,7 @@ namespace Elwig.Helpers.Export {
|
||||
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 ({filename})");
|
||||
throw new FileFormatException($"Ungültige Elwig-Export-Datei ({filename})");
|
||||
}
|
||||
|
||||
var metaJson = zip.GetEntry("meta.json");
|
||||
@@ -101,13 +106,6 @@ namespace Elwig.Helpers.Export {
|
||||
areaComCount, areaComFilters != null ? string.Join(" / ", areaComFilters) : null,
|
||||
deliveryCount, deliveryFilters != null ? string.Join(" / ", deliveryFilters) : null));
|
||||
|
||||
data.Add(new([], [], [], [], [], [], [], new([], [], [], [], new() {
|
||||
["member"] = [],
|
||||
["area_commitment"] = [],
|
||||
["delivery"] = [],
|
||||
})));
|
||||
var r = data[^1];
|
||||
|
||||
var wbKgsJson = zip.GetEntry("wb_kgs.json");
|
||||
if (wbKgsJson != null) {
|
||||
using var reader = new StreamReader(wbKgsJson.Open(), Utils.UTF8);
|
||||
@@ -170,6 +168,25 @@ namespace Elwig.Helpers.Export {
|
||||
r.Timestamps["delivery"].Add((d.Year, d.DId, timestamps.Value.CreatedAt, timestamps.Value.ModifiedAt));
|
||||
}
|
||||
}
|
||||
} catch (Exception exc) when (
|
||||
exc is InvalidDataException ||
|
||||
exc is FileFormatException ||
|
||||
exc is FileNotFoundException ||
|
||||
exc is IOException) {
|
||||
data.RemoveAt(data.Count - 1);
|
||||
var str = $"Die Elwig-Export-Datei '{Path.GetFileName(filename)}' konnte nicht verarbeitet werden und wird übersprungen.\n\n" + exc.Message;
|
||||
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
|
||||
MessageBox.Show(str, "Fehler beim Importieren", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
await AddImportedFiles(Path.GetFileName(filename));
|
||||
} catch (Exception exc) {
|
||||
data.RemoveAt(data.Count - 1);
|
||||
var str = $"Die Elwig-Export-Datei '{Path.GetFileName(filename)}' konnte nicht verarbeitet werden. Soll sie in Zukunft übersprungen werden?\n\n" + exc.Message;
|
||||
if (exc.InnerException != null) str += "\n\n" + exc.InnerException.Message;
|
||||
var r = MessageBox.Show(str, "Fehler beim Importieren", MessageBoxButton.YesNo, MessageBoxImage.Error, MessageBoxResult.No);
|
||||
if (r == MessageBoxResult.Yes) {
|
||||
await AddImportedFiles(Path.GetFileName(filename));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var importedMembers = new List<(string FileName, string ZwstId, string Device, int New, int Overwritten, int NotImported, string Filters)>();
|
||||
@@ -449,7 +466,7 @@ namespace Elwig.Helpers.Export {
|
||||
["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(JsonOpts));
|
||||
await writer.WriteAsync(obj.ToJsonString(Utils.JsonOpts));
|
||||
}
|
||||
|
||||
// TODO encrypt files
|
||||
@@ -457,28 +474,28 @@ namespace Elwig.Helpers.Export {
|
||||
var json = zip.CreateEntry("wb_kgs.json", CompressionLevel.SmallestSize);
|
||||
using var writer = new StreamWriter(json.Open(), Utils.UTF8);
|
||||
foreach (var k in WbKgs.Value.WbKgs) {
|
||||
await writer.WriteLineAsync(k.ToJson().ToJsonString(JsonOpts));
|
||||
await writer.WriteLineAsync(k.ToJson().ToJsonString(Utils.JsonOpts));
|
||||
}
|
||||
}
|
||||
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(JsonOpts));
|
||||
await writer.WriteLineAsync(m.ToJson().ToJsonString(Utils.JsonOpts));
|
||||
}
|
||||
}
|
||||
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(JsonOpts));
|
||||
await writer.WriteLineAsync(c.ToJson().ToJsonString(Utils.JsonOpts));
|
||||
}
|
||||
}
|
||||
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(JsonOpts));
|
||||
await writer.WriteLineAsync(d.ToJson().ToJsonString(Utils.JsonOpts));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -806,7 +823,7 @@ namespace Elwig.Helpers.Export {
|
||||
Temperature = p["temperature"]?.AsValue().GetValue<double>(),
|
||||
Acid = p["acid"]?.AsValue().GetValue<double>(),
|
||||
ScaleId = p["scale_id"]?.AsValue().GetValue<string>(),
|
||||
WeighingData = p["weighing_data"]?.AsObject().ToJsonString(JsonOpts),
|
||||
WeighingData = p["weighing_data"]?.AsObject().ToJsonString(Utils.JsonOpts),
|
||||
WeighingReason = p["weighing_reason"]?.AsValue().GetValue<string>(),
|
||||
};
|
||||
}).ToList(), json["parts"]!.AsArray().SelectMany(p => p!["modids"]!.AsArray().Select(m => new DeliveryPartModifier {
|
||||
|
@@ -1,41 +1,42 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Diagnostics;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.IO.Ports;
|
||||
using System.Net.Sockets;
|
||||
using Elwig.Dialogs;
|
||||
using System.Text;
|
||||
using System.Numerics;
|
||||
using Elwig.Models.Entities;
|
||||
using Elwig.Documents;
|
||||
using Elwig.Helpers.Billing;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Net.Http;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.IO;
|
||||
using Elwig.Models;
|
||||
using Elwig.Models.Entities;
|
||||
using LinqKit;
|
||||
using MailKit.Net.Smtp;
|
||||
using MailKit.Security;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Reflection;
|
||||
using System.Collections;
|
||||
using Elwig.Documents;
|
||||
using MimeKit;
|
||||
using System.Windows.Input;
|
||||
using LinqKit;
|
||||
using System.Linq.Expressions;
|
||||
using Elwig.Models;
|
||||
using Microsoft.Win32;
|
||||
using MimeKit;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.IO.Ports;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Net.Http;
|
||||
using System.Net.Sockets;
|
||||
using System.Numerics;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Markup;
|
||||
|
||||
namespace Elwig.Helpers {
|
||||
public static partial class Utils {
|
||||
|
||||
public static readonly Encoding UTF8 = new UTF8Encoding(false, true);
|
||||
public static readonly JsonSerializerOptions JsonOpts = new() { Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping };
|
||||
|
||||
public static int CurrentYear => DateTime.Now.Year;
|
||||
public static int CurrentNextSeason => DateTime.Now.Year - (DateTime.Now.Month <= 3 ? 1 : 0);
|
||||
@@ -430,6 +431,8 @@ namespace Elwig.Helpers {
|
||||
var client = new HttpClient() {
|
||||
Timeout = TimeSpan.FromSeconds(5),
|
||||
};
|
||||
client.DefaultRequestHeaders.UserAgent.Clear();
|
||||
client.DefaultRequestHeaders.UserAgent.ParseAdd($"Elwig/{App.Version} ({App.Client.NameToken}, {App.BranchName}, {Environment.MachineName}, {Environment.OSVersion})");
|
||||
client.DefaultRequestHeaders.Accept.Clear();
|
||||
if (accept != null)
|
||||
client.DefaultRequestHeaders.Accept.Add(new(accept));
|
||||
|
@@ -11,16 +11,24 @@ namespace Elwig.Models.Entities {
|
||||
[Column("type")]
|
||||
public string Type { get; private set; } = null!;
|
||||
|
||||
[Column("max_qualid")]
|
||||
public string MaxQualId { get; private set; } = null!;
|
||||
|
||||
[ForeignKey("MaxQualId")]
|
||||
public virtual WineQualLevel MaxQualityLevel { get; private set; } = null!;
|
||||
|
||||
[Column("name")]
|
||||
public string Name { get; private set; } = null!;
|
||||
|
||||
[Column("comment")]
|
||||
public string? Comment { get; private set; }
|
||||
|
||||
public string SortIdFormat => IsQuw ? SortId : $"({SortId})";
|
||||
public string CommentFormat => (Comment != null) ? $" ({Comment})" : "";
|
||||
|
||||
public bool IsRed => Type == "R";
|
||||
public bool IsWhite => Type == "W";
|
||||
public bool IsQuw => MaxQualId == "QUW";
|
||||
public Brush? Color => IsWhite ? Brushes.DarkGreen : IsRed ? Brushes.DarkRed : null;
|
||||
|
||||
public WineVar() { }
|
||||
@@ -28,6 +36,7 @@ namespace Elwig.Models.Entities {
|
||||
public WineVar(string sortId, string name) {
|
||||
SortId = sortId;
|
||||
Name = name;
|
||||
MaxQualId = "QUW";
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
|
17
Elwig/Resources/Sql/32-33.sql
Normal file
17
Elwig/Resources/Sql/32-33.sql
Normal file
@@ -0,0 +1,17 @@
|
||||
-- schema version 32 to 33
|
||||
|
||||
ALTER TABLE wine_variety ADD COLUMN max_qualid TEXT NOT NULL DEFAULT 'QUW';
|
||||
UPDATE wine_quality_level SET qualid = 'ALW' WHERE qualid = 'AUL';
|
||||
UPDATE wine_variety SET comment = 'Muscato' WHERE sortid = 'MO';
|
||||
|
||||
INSERT INTO wine_variety (sortid, type, max_qualid, name, comment) VALUES
|
||||
('DR', 'W', 'QUW', 'Donauriesling', NULL),
|
||||
('DV', 'W', 'QUW', 'Donauveltliner', NULL),
|
||||
('BN', 'W', 'RSW', 'Bronner', NULL),
|
||||
('CB', 'W', 'RSW', 'Cabernet Blanc', NULL),
|
||||
('CJ', 'R', 'RSW', 'Cabernet Jura', NULL),
|
||||
('JO', 'W', 'RSW', 'Johanniter', NULL),
|
||||
('OR', 'W', 'RSW', 'Orangetraube', NULL),
|
||||
('PI', 'R', 'RSW', 'Pinot Nova', NULL),
|
||||
('RE', 'R', 'RSW', 'Regent', NULL),
|
||||
('SI', 'W', 'RSW', 'Solaris', NULL);
|
@@ -9,7 +9,7 @@
|
||||
<TextBlock Margin="20,10" FontSize="12">
|
||||
<Bold>Produkt:</Bold> Elwig<LineBreak/>
|
||||
<Bold>Beschreibung:</Bold> Elektronische Winzergenossenschaftsverwaltung<LineBreak/>
|
||||
<Bold>Typ:</Bold> Warenwirschaftssystem<LineBreak/>
|
||||
<Bold>Typ:</Bold> Warenwirtschaftssystem (ERP-System)<LineBreak/>
|
||||
<Bold>Version:</Bold> <Run x:Name="Version">0.0.0.0</Run> (<Hyperlink NavigateUri="https://elwig.at/changelog" RequestNavigate="Hyperlink_RequestNavigate">Änderungsprotokoll</Hyperlink>)<LineBreak/>
|
||||
<Bold>Lizenz:</Bold> <Hyperlink NavigateUri="https://www.gnu.org/licenses/gpl-3.0.html" RequestNavigate="Hyperlink_RequestNavigate">GNU General Public License 3.0 (GPLv3)</Hyperlink><LineBreak/>
|
||||
<Bold>Website:</Bold> <Hyperlink NavigateUri="https://elwig.at/" RequestNavigate="Hyperlink_RequestNavigate">https://elwig.at/</Hyperlink><LineBreak/>
|
||||
|
@@ -8,6 +8,7 @@ using Elwig.ViewModels;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Win32;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
@@ -34,6 +35,8 @@ namespace Elwig.Windows {
|
||||
|
||||
private readonly Button[] WeighingButtons;
|
||||
|
||||
private List<WineQualLevel> WineQualityLevels = [];
|
||||
|
||||
public DeliveryAdminWindow(bool receipt = false) {
|
||||
InitializeComponent();
|
||||
CommandBindings.Add(new CommandBinding(CtrlF, FocusSearchInput));
|
||||
@@ -483,7 +486,8 @@ namespace Elwig.Windows {
|
||||
var cultList = await ctx.WineCultivations.OrderBy(a => a.Name).Cast<object>().ToListAsync();
|
||||
cultList.Insert(0, new NullItem(""));
|
||||
ControlUtils.RenewItemsSource(CultivationInput, cultList, null, ControlUtils.RenewSourceDefault.First);
|
||||
ControlUtils.RenewItemsSource(WineQualityLevelInput, await ctx.WineQualityLevels.ToListAsync());
|
||||
WineQualityLevels = await ctx.WineQualityLevels.ToListAsync();
|
||||
ControlUtils.RenewItemsSource(WineQualityLevelInput, WineQualityLevels);
|
||||
ControlUtils.RenewItemsSource(ModifiersInput, await ctx.Modifiers
|
||||
.Where(m => m.Year == y && (!IsCreating || m.IsActive))
|
||||
.OrderBy(m => m.Ordering)
|
||||
@@ -1207,6 +1211,7 @@ namespace Elwig.Windows {
|
||||
AttributeInput.SelectedIndex = 0;
|
||||
CultivationInput.SelectedIndex = 0;
|
||||
}
|
||||
UpdateWineQualityLevels();
|
||||
}
|
||||
|
||||
private void SortIdInput_TextChanged(object sender, TextChangedEventArgs evt) {
|
||||
@@ -1220,19 +1225,39 @@ namespace Elwig.Windows {
|
||||
private void WineVarietyInput_SelectionChanged(object sender, SelectionChangedEventArgs evt) {
|
||||
if (WineVarietyInput.SelectedItem is WineVar s)
|
||||
ViewModel.SortId = s.SortId;
|
||||
UpdateWineQualityLevels();
|
||||
if (!ViewModel.WineVar?.IsQuw ?? false) {
|
||||
App.MainDispatcher.BeginInvoke(() => {
|
||||
MessageBox.Show("Die eingegebene Sorte darf nicht als Qualitätswein\nübernommen werden!", "Kein Qualitätswein",
|
||||
MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private WineQualLevel GetWineQualityLevel(double kmw, string? maxQualId = null) {
|
||||
return WineQualityLevels
|
||||
.Where(q => !q.IsPredicate && (q.MinKmw == null || q.MinKmw <= kmw))
|
||||
.Where(q => maxQualId == null || q.QualId == "WEI" || q.QualId == maxQualId)
|
||||
.OrderBy(q => q.MinKmw)
|
||||
.Last();
|
||||
}
|
||||
|
||||
private void UpdateWineQualityLevels() {
|
||||
using var ctx = new AppDbContext();
|
||||
if (!GetInputValid(GradationKmwInput)) {
|
||||
UnsetDefaultValue(WineQualityLevelInput);
|
||||
ComboBox_SelectionChanged(WineQualityLevelInput, null);
|
||||
WineQualityLevelInput.ItemsSource = ctx.WineQualityLevels.Where(q => q.QualId == "WEI").ToList();
|
||||
WineQualityLevelInput.ItemsSource = WineQualityLevels;
|
||||
WineQualityLevelInput.SelectedItem = null;
|
||||
return;
|
||||
}
|
||||
var kmw = (double)ViewModel.GradationKmw!;
|
||||
WineQualityLevelInput.ItemsSource = ctx.WineQualityLevels.Where(q => q.MinKmw == null || q.MinKmw <= kmw).ToList();
|
||||
var qual = ctx.GetWineQualityLevel(kmw).GetAwaiter().GetResult();
|
||||
var max = ViewModel.WineVar?.MaxQualId;
|
||||
var quw = ViewModel.WineVar?.IsQuw ?? true;
|
||||
WineQualityLevelInput.ItemsSource = WineQualityLevels
|
||||
.Where(q => q.MinKmw == null || q.MinKmw <= kmw)
|
||||
.Where(q => quw || q.QualId == "WEI" || q.QualId == max)
|
||||
.ToList();
|
||||
var qual = GetWineQualityLevel(kmw, !quw ? max : null);
|
||||
SetDefaultValue(WineQualityLevelInput, qual);
|
||||
if (WineQualityLevelInput.SelectedItem == null || (WineQualityLevelInput.SelectedItem is WineQualLevel selected && !selected.IsPredicate)) {
|
||||
ControlUtils.SelectItem(WineQualityLevelInput, qual);
|
||||
@@ -1372,8 +1397,7 @@ namespace Elwig.Windows {
|
||||
AbgewertetInput.IsChecked = false;
|
||||
return;
|
||||
}
|
||||
using var ctx = new AppDbContext();
|
||||
var defQual = ctx.GetWineQualityLevel(double.Parse(GradationKmwInput.Text)).GetAwaiter().GetResult();
|
||||
var defQual = GetWineQualityLevel(ViewModel.GradationKmw!.Value, !(ViewModel.WineVar?.IsQuw ?? true) ? ViewModel.WineVar?.MaxQualId : null);
|
||||
AbgewertetInput.IsChecked = !qual.IsPredicate && defQual != qual;
|
||||
}
|
||||
|
||||
|
40
README.md
40
README.md
@@ -5,3 +5,43 @@ Elwig
|
||||
**El**ektronische **Wi**nzer**g**enossenschaftsverwaltung (Electronic Management for Vintners' Cooperatives).
|
||||
|
||||
Further information may be found on [the website](https://elwig.at).
|
||||
|
||||
|
||||
About
|
||||
=====
|
||||
|
||||
**Product:** Elwig
|
||||
**Description:** Electronic Management for Vintners' Cooperatives
|
||||
**Type:** ERP system
|
||||
**Version:** 1.0.1.2 ([Changelog](./CHANGELOG.md))
|
||||
**License:** [GNU General Public License 3.0 (GPLv3)](./LICENSE)
|
||||
**Website:** https://elwig.at/
|
||||
**Source code:** https://git.necronda.net/winzer/elwig
|
||||
**Developement period:** 2022–2025
|
||||
|
||||
**Technology Stack:**
|
||||
Language: C#
|
||||
Framework: Windows Presentation Framework (WPF)
|
||||
Database: [SQLite](https://sqlite.org/)
|
||||
PDF creation: [WeasyPrint](https://weasyprint.org/), [RazorLight](https://github.com/toddams/RazorLight), [PdfiumViewer](https://github.com/pvginkel/PdfiumViewer)
|
||||
Packaging: [WiX Toolset](https://www.firegiant.com/wixtoolset/)
|
||||
|
||||
|
||||
Über
|
||||
====
|
||||
|
||||
**Produkt:** Elwig
|
||||
**Beschreibung:** Elektronische Winzergenossenschaftsverwaltung
|
||||
**Typ:** Warenwirtschaftssystem (ERP-System)
|
||||
**Version:** 1.0.1.2 ([Änderungsprotokoll](./CHANGELOG.md))
|
||||
**Lizenz:** [GNU General Public License 3.0 (GPLv3)](./LICENSE)
|
||||
**Website:** https://elwig.at/
|
||||
**Quellcode:** https://git.necronda.net/winzer/elwig
|
||||
**Entwicklungszeitraum:** 2022–2025
|
||||
|
||||
**Verwendete Technologien:**
|
||||
Programmiersprache: C#
|
||||
Framework: Windows Presentation Framework (WPF)
|
||||
Datenbank: [SQLite](https://sqlite.org/)
|
||||
PDF-Erstellung: [WeasyPrint](https://weasyprint.org/), [RazorLight](https://github.com/toddams/RazorLight), [PdfiumViewer](https://github.com/pvginkel/PdfiumViewer)
|
||||
Paketierung: [WiX Toolset](https://www.firegiant.com/wixtoolset/)
|
||||
|
@@ -1 +1 @@
|
||||
curl --fail -s -L "https://elwig.at/files/create.sql?v=32" -u "elwig:ganzGeheim123!" -o "Resources\Sql\Create.sql"
|
||||
curl --fail -s -L "https://elwig.at/files/create.sql?v=33" -u "elwig:ganzGeheim123!" -o "Resources\Sql\Create.sql"
|
||||
|
Reference in New Issue
Block a user