Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
163fe0fac8 | ||
|
|
edf3678154 | ||
|
|
f450dc35b1 | ||
|
|
0c4611024f | ||
|
|
46e596ae23 | ||
|
|
3366cc25eb | ||
|
|
ff71e9fb7f | ||
|
|
7d5d7d9307 | ||
|
|
b468bbce31 | ||
|
|
a79631c586 | ||
|
|
20b6e11b7f | ||
|
|
77e812f5e8 | ||
|
|
58bfb4f56d | ||
|
|
e6e140dc08 | ||
|
|
eaddf0c3cb | ||
|
|
fc5ad82686 | ||
|
|
b76367f73a | ||
|
|
76ea3513ac | ||
|
|
07b197958d | ||
|
|
470c6e09e5 | ||
|
|
20b19775b1 | ||
|
|
f13a836ebd | ||
|
|
2bf926c84c |
@@ -2,7 +2,7 @@ name: Test
|
||||
on:
|
||||
push:
|
||||
branches: ["**"]
|
||||
paths: ["Elwig/**", "Tests/**", "Installer/Files/*.exe", ".gitea/workflows/test.yaml"]
|
||||
paths: ["Elwig/**", "Tests/**", ".gitea/workflows/test.yaml"]
|
||||
jobs:
|
||||
test:
|
||||
name: Run tests
|
||||
|
||||
+101
-1
@@ -2,6 +2,106 @@
|
||||
Changelog
|
||||
=========
|
||||
|
||||
[v1.1.1.2][v1.1.1.2] (2026-08-25) {#v1.1.1.2}
|
||||
---------------------------------------------
|
||||
|
||||
### Sonstiges {#v1.1.1.2-misc}
|
||||
|
||||
* In Matzen werden für Planenw./Kipper und Lesewagen die Klassen automatisch gesetzt. (3366cc25eb)
|
||||
* Im Lieferungen-Fenster (`DeliveryAdminWindow`) wird für "Nur heute" nicht mehr nur das Datum, sondern die letzten zusammenhängenden Lieferungen verwendet. (46e596ae23)
|
||||
* Für Pamhagen wird als standard Wiege-Methode "brutto" verwendet. (0c4611024f)
|
||||
* Für Waagen kann das automatische setzen von Datum und Uhrzeit nun per Opt-out ausgeschalten werden (Konfigurationsdatei -> `[scale.X]` -> `synctime = false`). (f450dc35b1)
|
||||
|
||||
### Behobene Fehler {#v1.1.1.2-bugfixes}
|
||||
|
||||
* Auf Lieferscheinen (`DeliveryNote`) waren die Mengenangaben nicht rechtsbündig. (ff71e9fb7f)
|
||||
* Beim Importieren von Mitgliedern mit Stamm-KG ohne Großlage kam es zu einem Fehler, obwohl die Großlage automatisch hätte zugewiesen werden müssen. (edf3678154)
|
||||
|
||||
[v1.1.1.2]: https://git.necronda.net/winzer/elwig/releases/tag/v1.1.1.2
|
||||
|
||||
|
||||
|
||||
|
||||
[v1.1.1.1][v1.1.1.1] (2026-08-24) {#v1.1.1.1}
|
||||
---------------------------------------------
|
||||
|
||||
### Sonstiges {#v1.1.1.1-misc}
|
||||
|
||||
* Beim Export der Flächenbindungen im Haupt-Fenster (`MainWindow`) werden neben der zusammengefassten gebundenen Fläche nun auch die jeweiligen Flächenindungen exportiert. (b468bbce31)
|
||||
|
||||
[v1.1.1.1]: https://git.necronda.net/winzer/elwig/releases/tag/v1.1.1.1
|
||||
|
||||
|
||||
|
||||
|
||||
[v1.1.1.0][v1.1.1.0] (2026-08-19) {#v1.1.1.0}
|
||||
---------------------------------------------
|
||||
|
||||
### Sonstiges {#v1.1.1.0-misc}
|
||||
|
||||
* Bei der BKI-Traubentransportscheinliste werden Volllieferanten/Vollablieferer nun auch als solche markiert. (20b6e11b7f)
|
||||
|
||||
[v1.1.1.0]: https://git.necronda.net/winzer/elwig/releases/tag/v1.1.1.0
|
||||
|
||||
|
||||
|
||||
|
||||
[v1.1.0.3][v1.1.0.3] (2026-08-17) {#v1.1.0.3}
|
||||
---------------------------------------------
|
||||
|
||||
### Sonstiges {#v1.1.0.3-misc}
|
||||
|
||||
* Beim Drucken mehrerer Kopien einer PDF-Datei wird nun nur mehr ein einzelner Druck-Auftrag verwendet. (fc5ad82686)
|
||||
* Beim Synchronisieren können Geräte als Hauptgerät festgelegt werden. (eaddf0c3cb)
|
||||
* Abhängigkeiten aktualisiert. (e6e140dc08, 58bfb4f56d)
|
||||
|
||||
[v1.1.0.3]: https://git.necronda.net/winzer/elwig/releases/tag/v1.1.0.3
|
||||
|
||||
|
||||
|
||||
|
||||
[v1.1.0.2][v1.1.0.2] (2026-08-11) {#v1.1.0.2}
|
||||
---------------------------------------------
|
||||
|
||||
### Neue Funktionen {#v1.1.0.2-features}
|
||||
|
||||
* Es ist nun möglich zwischen dem Senden von E-Mail einige Sekunden zu warten (Konfigurationsdatei -> `[smtp]` -> `wait = 0.5`). (76ea3513ac)
|
||||
|
||||
### Behobene Fehler {#v1.1.0.2-bugfixes}
|
||||
|
||||
* Beim Drucken von Dokumenten waren die Seitenränder nicht korrekt. (f13a836ebd, 20b19775b1, 470c6e09e5, 07b197958d)
|
||||
|
||||
[v1.1.0.2]: https://git.necronda.net/winzer/elwig/releases/tag/v1.1.0.2
|
||||
|
||||
|
||||
|
||||
|
||||
[v1.1.0.1][v1.1.0.1] (2026-08-05) {#v1.1.0.1}
|
||||
---------------------------------------------
|
||||
|
||||
### Neue Funktionen {#v1.1.0.1-features}
|
||||
|
||||
* Auf Lieferscheinen sind nun Waage und Terminal angegeben. (309f118739)
|
||||
* Beim Starten von Elwig wird Datum/Uhrzeit auf allen angeschlossenen Waagen gesetzt. (2a3999f300)
|
||||
|
||||
### Behobene Fehler {#v1.1.0.1-bugfixes}
|
||||
|
||||
* Im Stammdaten-Fenster (`BaseDataWindow`) war es nach einem Fehler beim Bearbeiten bis zum Schließen des Fensters nicht mehr möglich zu speichern. ([#82][i82])
|
||||
|
||||
### Sonstiges {#v1.1.0.1-misc}
|
||||
|
||||
* Im Auszahlungsvarianten-Fenster (`PaymentVariantsWindow`)...
|
||||
* wurde auf 3 Knöpfen das Symbol "in neuem Fenster öffnen" hinzugefügt. (88616b2c0b)
|
||||
* wird beim "Speichern" die Variante automatisch auch berechnet um Fehler/Missverständnisse zu vermeiden. ([#83][i83])
|
||||
* Abhängigkeiten aktualisiert. (b445928c4d, 668030fbff, a8cc3c9cb9)
|
||||
|
||||
[v1.1.0.1]: https://git.necronda.net/winzer/elwig/releases/tag/v1.1.0.1
|
||||
[i82]: https://git.necronda.net/winzer/elwig/issues/82
|
||||
[i83]: https://git.necronda.net/winzer/elwig/issues/83
|
||||
|
||||
|
||||
|
||||
|
||||
[v1.1.0.0][v1.1.0.0] (2026-07-09) {#v1.1.0.0}
|
||||
---------------------------------------------
|
||||
|
||||
@@ -290,7 +390,7 @@ Changelog
|
||||
|
||||
[v1.0.3.0]: https://git.necronda.net/winzer/elwig/releases/tag/v1.0.3.0
|
||||
[i50]: https://git.necronda.net/winzer/elwig/issues/50
|
||||
[i66]: https://git.necronda.net/winzer/elwig/issues/60
|
||||
[i66]: https://git.necronda.net/winzer/elwig/issues/66
|
||||
[i71]: https://git.necronda.net/winzer/elwig/issues/71
|
||||
[i73]: https://git.necronda.net/winzer/elwig/issues/73
|
||||
|
||||
|
||||
@@ -16,14 +16,7 @@
|
||||
|
||||
<dependency>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity
|
||||
type="win32"
|
||||
name="Microsoft.Windows.Common-Controls"
|
||||
version="6.0.0.0"
|
||||
processorArchitecture="*"
|
||||
publicKeyToken="6595b64144ccf1df"
|
||||
language="*"
|
||||
/>
|
||||
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*" />
|
||||
</dependentAssembly>
|
||||
</dependency>
|
||||
</assembly>
|
||||
+2
-2
@@ -146,7 +146,7 @@ namespace Elwig {
|
||||
foreach (var s in Config.Scales) {
|
||||
try {
|
||||
var scale = Scale.FromConfig(s);
|
||||
if (scale is ICommandScale cmd) {
|
||||
if (s.SyncTime && scale is ICommandScale cmd) {
|
||||
try {
|
||||
await cmd.SetDateAndTime(DateTime.Now);
|
||||
} catch { }
|
||||
@@ -179,7 +179,7 @@ namespace Elwig {
|
||||
Config.WeighingMode = WeighingMode.Net;
|
||||
} else if (Client.IsHaugsdorf || Client.IsSitzendorf) {
|
||||
Config.WeighingMode = WeighingMode.Box;
|
||||
} else if (Client.IsBaden || Client.IsGrInzersdorf) {
|
||||
} else if (Client.IsBaden || Client.IsGrInzersdorf || Client.IsPamhagen) {
|
||||
Config.WeighingMode = WeighingMode.Gross;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ namespace Elwig.Documents {
|
||||
.AddCell(NewDeliveryMainTd(part.Quality.Name))
|
||||
.AddCell(NewDeliveryMainTd($"{part.Oe:N0}", center: true))
|
||||
.AddCell(NewDeliveryMainTd($"{part.Kmw:N1}", center: true))
|
||||
.AddCell(NewDeliveryMainTd($"{part.Weight:N0}", center: true));
|
||||
.AddCell(NewDeliveryMainTd($"{part.Weight:N0}", right: true));
|
||||
|
||||
if (part.Cultivation != null) {
|
||||
var cult = new KernedParagraph(8);
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace Elwig.Documents {
|
||||
public Document(string title) {
|
||||
Title = title;
|
||||
Author = App.Client.NameFull;
|
||||
Date = DateOnly.FromDateTime(Utils.Today);
|
||||
Date = DateOnly.FromDateTime(DateTime.Today);
|
||||
}
|
||||
|
||||
~Document() {
|
||||
|
||||
+8
-8
@@ -9,10 +9,10 @@
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<PreserveCompilationContext>true</PreserveCompilationContext>
|
||||
<ApplicationIcon>Resources\Images\Elwig.ico</ApplicationIcon>
|
||||
<Version>1.1.0.0</Version>
|
||||
<Version>1.1.1.2</Version>
|
||||
<SatelliteResourceLanguages>de-AT</SatelliteResourceLanguages>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
<ApplicationManifest>App.manifest</ApplicationManifest>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -23,21 +23,21 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="bblanchon.PDFium.Win32" Version="153.0.7988" />
|
||||
<PackageReference Include="bblanchon.PDFium.Win32" Version="153.0.8009" />
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.2" />
|
||||
<PackageReference Include="itext" Version="9.7.0" />
|
||||
<PackageReference Include="itext.bouncy-castle-adapter" Version="9.7.0" />
|
||||
<PackageReference Include="LinqKit" Version="1.3.11" />
|
||||
<PackageReference Include="MailKit" Version="4.17.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.10" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Ini" Version="10.0.10" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.11" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Ini" Version="10.0.11" />
|
||||
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.4129.50" />
|
||||
<PackageReference Include="NJsonSchema" Version="11.6.1" />
|
||||
<PackageReference Include="ScottPlot.WPF" Version="5.1.59" />
|
||||
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="3.0.5" />
|
||||
<PackageReference Include="System.IO.Hashing" Version="10.0.10" />
|
||||
<PackageReference Include="System.IO.Ports" Version="10.0.10" />
|
||||
<PackageReference Include="System.Management" Version="10.0.10" />
|
||||
<PackageReference Include="System.IO.Hashing" Version="10.0.11" />
|
||||
<PackageReference Include="System.IO.Ports" Version="10.0.11" />
|
||||
<PackageReference Include="System.Management" Version="10.0.11" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -69,7 +69,8 @@ namespace Elwig.Helpers {
|
||||
public DbSet<OverUnderDeliveryRow> OverUnderDeliveryRows { get; private set; }
|
||||
public DbSet<AreaComUnderDeliveryRowSingle> AreaComUnderDeliveryRows { get; private set; }
|
||||
public DbSet<MemberDeliveryPerVarietyRowSingle> MemberDeliveryPerVariantRows { get; private set; }
|
||||
public DbSet<MemberAreaComsRowSingle> MemberAreaComsRows { get; private set; }
|
||||
public DbSet<MemberAreaComTotalsRowSingle> MemberAreaComTotalsRows { get; private set; }
|
||||
public DbSet<MemberAreaComsRow> MemberAreaComsRows { get; private set; }
|
||||
public DbSet<CreditNoteDeliveryRowSingle> CreditNoteDeliveryRows { get; private set; }
|
||||
public DbSet<CreditNoteRowSingle> CreditNoteRows { get; private set; }
|
||||
public DbSet<WeightBreakdownRow> WeightBreakDownRows { get; private set; }
|
||||
|
||||
@@ -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 = 40;
|
||||
public static readonly int RequiredSchemaVersion = 41;
|
||||
|
||||
private static int VersionOffset = 0;
|
||||
|
||||
|
||||
+12
-4
@@ -17,10 +17,11 @@ namespace Elwig.Helpers {
|
||||
public string? Filling;
|
||||
public string? Limit;
|
||||
public bool Required;
|
||||
public bool SyncTime;
|
||||
public string? Log;
|
||||
public string? _Log;
|
||||
|
||||
public ScaleConfig(string id, string? type, string? model, string? cnx, string? empty, string? filling, string? limit, bool? required, string? log) {
|
||||
public ScaleConfig(string id, string? type, string? model, string? cnx, string? empty, string? filling, string? limit, bool? required, bool? syncTime, string? log) {
|
||||
Id = id;
|
||||
Type = type;
|
||||
Model = model;
|
||||
@@ -29,6 +30,7 @@ namespace Elwig.Helpers {
|
||||
Filling = filling;
|
||||
Limit = limit;
|
||||
Required = required ?? true;
|
||||
SyncTime = syncTime ?? true;
|
||||
_Log = log;
|
||||
Log = log != null ? Path.Combine(App.DataPath, log) : null;
|
||||
}
|
||||
@@ -37,11 +39,12 @@ namespace Elwig.Helpers {
|
||||
public class Config {
|
||||
|
||||
private static readonly string[] TrueValues = ["1", "true", "yes", "on"];
|
||||
private static readonly string[] FalseValues = ["0", "false", "no", "off"];
|
||||
|
||||
private readonly string FileName;
|
||||
|
||||
public bool Debug;
|
||||
public string DatabaseFile = App.DataPath + "database.sqlite3";
|
||||
public string DatabaseFile = Path.Combine(App.DataPath, "database.sqlite3");
|
||||
public string? DatabaseLog = null;
|
||||
public string? Branch = null;
|
||||
public WeighingMode? WeighingMode;
|
||||
@@ -50,6 +53,7 @@ namespace Elwig.Helpers {
|
||||
public string? SyncUrl = null;
|
||||
public string SyncUsername = "";
|
||||
public string SyncPassword = "";
|
||||
public bool SyncMain = false;
|
||||
|
||||
public string? SmtpHost = null;
|
||||
public int? SmtpPort = null;
|
||||
@@ -57,9 +61,10 @@ namespace Elwig.Helpers {
|
||||
public string? SmtpUsername = null;
|
||||
public string? SmtpPassword = null;
|
||||
public string? SmtpFrom = null;
|
||||
public (string Host, int Port, string Mode, string Username, string Password, string From)? Smtp =>
|
||||
public double SmtpWait = 0;
|
||||
public (string Host, int Port, string Mode, string Username, string Password, string From, double Wait)? Smtp =>
|
||||
SmtpHost == null || SmtpPort == null || SmtpMode == null || SmtpUsername == null || SmtpPassword == null || SmtpFrom == null ?
|
||||
null : (SmtpHost, (int)SmtpPort, SmtpMode, SmtpUsername, SmtpPassword, SmtpFrom);
|
||||
null : (SmtpHost, (int)SmtpPort, SmtpMode, SmtpUsername, SmtpPassword, SmtpFrom, SmtpWait);
|
||||
|
||||
public IList<ScaleConfig> Scales;
|
||||
private readonly List<ScaleConfig> ScaleList = [];
|
||||
@@ -85,6 +90,7 @@ namespace Elwig.Helpers {
|
||||
SyncUrl = config["sync:url"];
|
||||
SyncUsername = config["sync:username"] ?? "";
|
||||
SyncPassword = config["sync:password"] ?? "";
|
||||
SyncMain = TrueValues.Contains(config["sync:main"]?.ToLower());
|
||||
|
||||
SmtpHost = config["smtp:host"];
|
||||
SmtpPort = config["smtp:port"]?.All(char.IsAsciiDigit) == true && config["smtp:port"]?.Length > 0 ? int.Parse(config["smtp:port"]!) : null;
|
||||
@@ -92,6 +98,7 @@ namespace Elwig.Helpers {
|
||||
SmtpUsername = config["smtp:username"];
|
||||
SmtpPassword = config["smtp:password"];
|
||||
SmtpFrom = config["smtp:from"];
|
||||
SmtpWait = double.TryParse(config["smtp:wait"], out var res) ? res : 0;
|
||||
|
||||
var scales = config.AsEnumerable().Where(i => i.Key.StartsWith("scale.")).GroupBy(i => i.Key.Split(':')[0][6..]).Select(i => i.Key).Order();
|
||||
ScaleList.Clear();
|
||||
@@ -101,6 +108,7 @@ namespace Elwig.Helpers {
|
||||
s, config[$"scale.{s}:type"], config[$"scale.{s}:model"], config[$"scale.{s}:connection"],
|
||||
config[$"scale.{s}:empty"], config[$"scale.{s}:filling"], config[$"scale.{s}:limit"],
|
||||
config[$"scale.{s}:required"] != null ? TrueValues.Contains(config[$"scale.{s}:required"]?.ToLower()) : null,
|
||||
config[$"scale.{s}:synctime"] != null ? !FalseValues.Contains(config[$"scale.{s}:synctime"]?.ToLower()) : null,
|
||||
config[$"scale.{s}:log"]
|
||||
));
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ using System;
|
||||
|
||||
namespace Elwig.Helpers.Export {
|
||||
|
||||
using Row = Tuple<(string?, string?, string?, string?, string, int, string, int), (string, int, string, string, string, int, string, double, double)>;
|
||||
using Row = Tuple<(string?, string?, string?, string?, string, int, string, bool, int), (string, int, string, string, string, int, string, double, double)>;
|
||||
|
||||
public class Bki : Csv<Row> {
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace Elwig.Helpers.Export {
|
||||
using var cnx = await AppDbContext.ConnectAsync();
|
||||
using var cmd = cnx.CreateCommand();
|
||||
cmd.CommandText = $"""
|
||||
SELECT lfbis_nr, name, other_names, billing_name, address, plz, ort, area,
|
||||
SELECT lfbis_nr, name, other_names, billing_name, address, plz, ort, vollablieferer, area,
|
||||
date, weight, type, sortid, qualid, year, hkid, kmw, oe
|
||||
FROM v_bki_delivery
|
||||
WHERE year = {year}
|
||||
@@ -38,8 +38,8 @@ namespace Elwig.Helpers.Export {
|
||||
List<Row> rows = [];
|
||||
while (await r.ReadAsync()) {
|
||||
rows.Add(new(
|
||||
(r.IsDBNull(0) ? null : r.GetString(0), r.IsDBNull(1) ? null : r.GetString(1), r.IsDBNull(2) ? null : r.GetString(2), r.IsDBNull(3) ? null : r.GetString(3), r.GetString(4), r.GetInt32(5), r.GetString(6), r.GetInt32(7)),
|
||||
(r.GetString(8), r.GetInt32(9), r.GetString(10), r.GetString(11), r.GetString(12), r.GetInt32(13), r.GetString(14), r.GetDouble(15), r.GetDouble(16))
|
||||
(r.IsDBNull(0) ? null : r.GetString(0), r.IsDBNull(1) ? null : r.GetString(1), r.IsDBNull(2) ? null : r.GetString(2), r.IsDBNull(3) ? null : r.GetString(3), r.GetString(4), r.GetInt32(5), r.GetString(6), r.GetBoolean(7), r.GetInt32(8)),
|
||||
(r.GetString(9), r.GetInt32(10), r.GetString(11), r.GetString(12), r.GetString(13), r.GetInt32(14), r.GetString(15), r.GetDouble(16), r.GetDouble(17))
|
||||
));
|
||||
}
|
||||
|
||||
@@ -52,14 +52,14 @@ namespace Elwig.Helpers.Export {
|
||||
|
||||
public override string FormatRow(Row row) {
|
||||
var (member, delivery) = row;
|
||||
var (lfBisNr, familyName, name, billingName, address, plz, ort, area) = member;
|
||||
var (lfBisNr, familyName, name, billingName, address, plz, ort, vollablieferer, area) = member;
|
||||
var (date, weight, type, sortid, qualid, year, hkid, kmw, oe) = delivery;
|
||||
|
||||
var (n1, n2) = billingName == null ? (familyName, name) : Utils.SplitName(billingName, familyName);
|
||||
var (a1, a2) = Utils.SplitAddress(address);
|
||||
var memberData = $"{lfBisNr};{n1};{n2};{a1};\t{a2};{plz};{ort}";
|
||||
var deliveryData = $"{string.Join(".", date.Split("-").Reverse())};{weight};TB;{(type == "W" ? "J" : "")};{(type == "R" ? "J" : "")};{sortid};;;{qualid};{year};{hkid};{kmw:0.0};{oe:0}";
|
||||
var vollData = $"N;;;{area / 10_000.0}";
|
||||
var vollData = $"{(vollablieferer ? "J" : "N")};{(vollablieferer ? area / 10_000.0 : null):N4};{(vollablieferer ? area / 10_000.0 : null):N4};{area / 10_000.0:N4}";
|
||||
|
||||
return $"{_clientData};{memberData};{deliveryData};{vollData}";
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
|
||||
namespace Elwig.Helpers.Export {
|
||||
public static class ElwigData {
|
||||
@@ -36,14 +35,16 @@ namespace Elwig.Helpers.Export {
|
||||
public static async Task Import(IEnumerable<string> filenames, ImportMode mode) {
|
||||
try {
|
||||
Dictionary<string, Branch> branches;
|
||||
Dictionary<int, AT_Kg> kgs;
|
||||
Dictionary<int, int> currentDids;
|
||||
Dictionary<string, int> currentLsNrs;
|
||||
Dictionary<int, List<WbRd>> currentWbRde;
|
||||
Dictionary<int, AT_Kg> kgs;
|
||||
Dictionary<int, WbKg> currentWbKgs;
|
||||
List<WbGl> currentWbGls;
|
||||
|
||||
using (var ctx = new AppDbContext()) {
|
||||
branches = await ctx.FetchBranches().ToDictionaryAsync(b => b.ZwstId);
|
||||
kgs = await ctx.Katastralgemeinden.ToDictionaryAsync(k => k.KgNr);
|
||||
currentDids = await ctx.Deliveries
|
||||
.GroupBy(d => d.Year)
|
||||
.ToDictionaryAsync(g => g.Key, g => g.Max(d => d.DId));
|
||||
@@ -52,8 +53,8 @@ namespace Elwig.Helpers.Export {
|
||||
currentWbRde = await ctx.WbRde
|
||||
.GroupBy(r => r.KgNr)
|
||||
.ToDictionaryAsync(g => g.Key, g => g.ToList());
|
||||
currentWbKgs = await ctx.WbKgs.ToDictionaryAsync(k => k.KgNr);
|
||||
currentWbGls = await ctx.WbGls.ToListAsync();
|
||||
kgs = await ctx.Katastralgemeinden.Include(k => k.WbKg).ToDictionaryAsync(k => k.KgNr);
|
||||
}
|
||||
|
||||
var data = new List<(
|
||||
@@ -122,6 +123,7 @@ namespace Elwig.Helpers.Export {
|
||||
var obj = JsonNode.Parse(line)!.AsObject();
|
||||
var (k, g) = obj.ToWbKg(currentWbGls);
|
||||
r.WbKgs.Add(k);
|
||||
currentWbKgs[k.KgNr] = k;
|
||||
if (g != null) {
|
||||
currentWbGls[g.GlNr] = g;
|
||||
r.WbGls.Add(g);
|
||||
@@ -135,7 +137,7 @@ namespace Elwig.Helpers.Export {
|
||||
string? line;
|
||||
while ((line = await reader.ReadLineAsync()) != null) {
|
||||
var obj = JsonNode.Parse(line)!.AsObject();
|
||||
var (m, b, telNrs, emailAddrs, timestamps) = obj.ToMember(kgs);
|
||||
var (m, b, telNrs, emailAddrs, timestamps) = obj.ToMember(kgs, currentWbKgs);
|
||||
r.Members.Add(m);
|
||||
if (b != null) r.BillingAddresses.Add(b);
|
||||
r.TelephoneNumbers.AddRange(telNrs);
|
||||
@@ -163,7 +165,7 @@ namespace Elwig.Helpers.Export {
|
||||
string? line;
|
||||
while ((line = await reader.ReadLineAsync()) != null) {
|
||||
var obj = JsonNode.Parse(line)!.AsObject();
|
||||
var (contract, areaCom, wbrd, timestamps) = obj.ToAreaCom(currentWbRde);
|
||||
var (contract, areaCom, wbrd, timestamps) = obj.ToAreaCom(kgs, currentWbKgs, currentWbRde);
|
||||
r.Contracts.Add(contract);
|
||||
r.AreaCommitments.Add(areaCom);
|
||||
if (wbrd != null) {
|
||||
@@ -182,7 +184,7 @@ namespace Elwig.Helpers.Export {
|
||||
string? line;
|
||||
while ((line = await reader.ReadLineAsync()) != null) {
|
||||
var obj = JsonNode.Parse(line)!.AsObject();
|
||||
var (contract, areaComs, wbrd, timestamps) = obj.ToAreaComContract(currentWbRde);
|
||||
var (contract, areaComs, wbrd, timestamps) = obj.ToAreaComContract(kgs, currentWbKgs, currentWbRde);
|
||||
r.Contracts.Add(contract);
|
||||
r.AreaCommitments.AddRange(areaComs.Select(v => v.Item1));
|
||||
if (wbrd != null) {
|
||||
@@ -203,7 +205,7 @@ namespace Elwig.Helpers.Export {
|
||||
string? line;
|
||||
while ((line = await reader.ReadLineAsync()) != null) {
|
||||
var obj = JsonNode.Parse(line)!.AsObject();
|
||||
var (d, parts, mods, rde, timestamps) = obj.ToDelivery(currentLsNrs, currentDids, kgs, currentWbRde);
|
||||
var (d, parts, mods, rde, timestamps) = obj.ToDelivery(currentLsNrs, currentDids, kgs, currentWbKgs, currentWbRde);
|
||||
r.Deliveries.Add(d);
|
||||
r.DeliveryParts.AddRange(parts.Select(p => p.Item1));
|
||||
r.Modifiers.AddRange(mods);
|
||||
@@ -680,11 +682,11 @@ namespace Elwig.Helpers.Export {
|
||||
};
|
||||
}
|
||||
|
||||
public static (Member, BillingAddr?, List<MemberTelNr>, List<MemberEmailAddr>, (DateTime CreatedAt, DateTime ModifiedAt)?) ToMember(this JsonNode json, Dictionary<int, AT_Kg> kgs) {
|
||||
public static (Member, BillingAddr?, List<MemberTelNr>, List<MemberEmailAddr>, (DateTime CreatedAt, DateTime ModifiedAt)?) ToMember(this JsonNode json, Dictionary<int, AT_Kg> kgs, Dictionary<int, WbKg> currentWbKgs) {
|
||||
var mgnr = json["mgnr"]!.AsValue().GetValue<int>();
|
||||
var kgnr = json["default_kgnr"]?.AsValue().GetValue<int>();
|
||||
if (kgnr != null && !kgs.Values.Any(k => k.WbKg?.KgNr == kgnr)) {
|
||||
throw new ArgumentException($"Für KG {(kgs.TryGetValue(kgnr.Value, out var k) ? k.Name : "?")} ({kgnr:00000}) ist noch keine Großlage festgelegt!\n(Stammdaten → Herkunftshierarchie)");
|
||||
if (kgnr != null && !currentWbKgs.Values.Any(k => k.KgNr == kgnr)) {
|
||||
throw new KeyNotFoundException($"Für KG {(kgs.TryGetValue(kgnr.Value, out var k) ? k.Name : "?")} ({kgnr:00000}) ist noch keine Großlage festgelegt!\n(Stammdaten \u2192 Herkunftshierarchie)");
|
||||
}
|
||||
var createdAt = json["created_at"]?.AsValue().GetValue<string>();
|
||||
var modifiedAt = json["modified_at"]?.AsValue().GetValue<string>();
|
||||
@@ -815,10 +817,13 @@ namespace Elwig.Helpers.Export {
|
||||
};
|
||||
}
|
||||
|
||||
public static (AreaComContract, List<(AreaCom, (DateTime CreatedAt, DateTime ModifiedAt)?)>, WbRd?, (DateTime CreatedAt, DateTime ModifiedAt)?) ToAreaComContract(this JsonNode json, Dictionary<int, List<WbRd>> riede) {
|
||||
public static (AreaComContract, List<(AreaCom, (DateTime CreatedAt, DateTime ModifiedAt)?)>, WbRd?, (DateTime CreatedAt, DateTime ModifiedAt)?) ToAreaComContract(this JsonNode json, Dictionary<int, AT_Kg> kgs, Dictionary<int, WbKg> currentWbKgs, Dictionary<int, List<WbRd>> riede) {
|
||||
var kgnr = json["kgnr"]!.AsValue().GetValue<int>();
|
||||
var ried = json["ried"]?.AsValue().GetValue<string>();
|
||||
var fbnr = json["fbnr"]!.AsValue()!.GetValue<int>();
|
||||
if (!currentWbKgs.Values.Any(k => k.KgNr == kgnr)) {
|
||||
throw new KeyNotFoundException($"Für KG {(kgs.TryGetValue(kgnr, out var k) ? k.Name : "?")} ({kgnr:00000}) ist noch keine Großlage festgelegt!\n(Stammdaten \u2192 Herkunftshierarchie)");
|
||||
}
|
||||
WbRd? rd = null;
|
||||
bool newRd = false;
|
||||
if (ried != null) {
|
||||
@@ -866,9 +871,12 @@ namespace Elwig.Helpers.Export {
|
||||
DateTime.ParseExact(modifiedAt, "yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture, DateTimeStyles.None)));
|
||||
}
|
||||
|
||||
public static (AreaComContract, AreaCom, WbRd?, (DateTime CreatedAt, DateTime ModifiedAt)?) ToAreaCom(this JsonNode json, Dictionary<int, List<WbRd>> riede) {
|
||||
public static (AreaComContract, AreaCom, WbRd?, (DateTime CreatedAt, DateTime ModifiedAt)?) ToAreaCom(this JsonNode json, Dictionary<int, AT_Kg> kgs, Dictionary<int, WbKg> currentWbKgs, Dictionary<int, List<WbRd>> riede) {
|
||||
var kgnr = json["kgnr"]!.AsValue().GetValue<int>();
|
||||
var ried = json["ried"]?.AsValue().GetValue<string>();
|
||||
if (!currentWbKgs.Values.Any(k => k.KgNr == kgnr)) {
|
||||
throw new KeyNotFoundException($"Für KG {(kgs.TryGetValue(kgnr, out var k) ? k.Name : "?")} ({kgnr:00000}) ist noch keine Großlage festgelegt!\n(Stammdaten \u2192 Herkunftshierarchie)");
|
||||
}
|
||||
WbRd? rd = null;
|
||||
bool newRd = false;
|
||||
if (ried != null) {
|
||||
@@ -957,7 +965,7 @@ namespace Elwig.Helpers.Export {
|
||||
return obj;
|
||||
}
|
||||
|
||||
public static (Delivery, List<(DeliveryPart, (DateTime CreatedAt, DateTime ModifiedAt)?)>, List<DeliveryPartModifier>, List<WbRd>, (DateTime CreatedAt, DateTime ModifiedAt)?) ToDelivery(this JsonNode json, Dictionary<string, int> currentLsNrs, Dictionary<int, int> currentDids, Dictionary<int, AT_Kg> kgs, Dictionary<int, List<WbRd>> riede) {
|
||||
public static (Delivery, List<(DeliveryPart, (DateTime CreatedAt, DateTime ModifiedAt)?)>, List<DeliveryPartModifier>, List<WbRd>, (DateTime CreatedAt, DateTime ModifiedAt)?) ToDelivery(this JsonNode json, Dictionary<string, int> currentLsNrs, Dictionary<int, int> currentDids, Dictionary<int, AT_Kg> kgs, Dictionary<int, WbKg> currentWbKgs, Dictionary<int, List<WbRd>> riede) {
|
||||
var year = json["year"]!.AsValue().GetValue<int>();
|
||||
var lsnr = json["lsnr"]!.AsValue().GetValue<string>();
|
||||
var did = currentLsNrs.GetValueOrDefault(lsnr, -1);
|
||||
@@ -983,6 +991,9 @@ namespace Elwig.Helpers.Export {
|
||||
}, [.. json["parts"]!.AsArray().Select(p => p!.AsObject()).Select<JsonObject, (DeliveryPart, (DateTime, DateTime)?)>(p => {
|
||||
var kgnr = p["kgnr"]?.AsValue().GetValue<int>();
|
||||
var ried = p["ried"]?.AsValue().GetValue<string>();
|
||||
if (kgnr != null && !currentWbKgs.Values.Any(k => k.KgNr == kgnr)) {
|
||||
throw new KeyNotFoundException($"Für KG {(kgs.TryGetValue(kgnr.Value, out var k) ? k.Name : "?")} ({kgnr:00000}) ist noch keine Großlage festgelegt!\n(Stammdaten \u2192 Herkunftshierarchie)");
|
||||
}
|
||||
WbRd? rd = null;
|
||||
if (ried != null && kgnr != null) {
|
||||
var rde = riede.GetValueOrDefault(kgnr.Value, []);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using Elwig.Services;
|
||||
using Elwig.Windows;
|
||||
using System;
|
||||
using System.Drawing.Printing;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Elwig.Helpers.Printing {
|
||||
@@ -32,20 +31,10 @@ namespace Elwig.Helpers.Printing {
|
||||
});
|
||||
}
|
||||
|
||||
public static async Task Print(string path, int copies = 1, bool doublePaged = false) {
|
||||
await Print(path, new() {
|
||||
Copies = (short)copies,
|
||||
Collate = true,
|
||||
Duplex = doublePaged ? Duplex.Vertical : Duplex.Simplex,
|
||||
});
|
||||
}
|
||||
|
||||
public static Task Print(string path, PrinterSettings settings) {
|
||||
public static Task Print(string path, int copies = 1, bool doublePaged = false) {
|
||||
try {
|
||||
using var printDoc = new PdfPrintDocument(path) {
|
||||
PrinterSettings = settings,
|
||||
};
|
||||
printDoc.Print();
|
||||
var printer = new PdfPrinter();
|
||||
printer.Print(path, copies, doublePaged);
|
||||
} catch (Exception exc) {
|
||||
InteractionService.ShowException("Fehler beim Drucken", "Beim Drucken ist ein Fehler aufgetreten", exc);
|
||||
}
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Drawing.Printing;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Elwig.Helpers.Printing {
|
||||
public class PdfPrintDocument : PrintDocument {
|
||||
|
||||
private readonly IntPtr _handle;
|
||||
private readonly int _pageCount;
|
||||
private readonly double _dpi;
|
||||
|
||||
private int _currentPage;
|
||||
|
||||
public PdfPrintDocument(string path, string? password = null, double dpi = 300.0) :
|
||||
base() {
|
||||
_handle = PdfiumNative.FPDF_LoadDocument(path, password);
|
||||
_pageCount = PdfiumNative.FPDF_GetPageCount(_handle);
|
||||
_dpi = dpi;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing) {
|
||||
PdfiumNative.FPDF_CloseDocument(_handle);
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
protected override void OnBeginPrint(PrintEventArgs evt) {
|
||||
_currentPage = (PrinterSettings.FromPage != 0) ? (PrinterSettings.FromPage - 1) : 0;
|
||||
base.OnBeginPrint(evt);
|
||||
}
|
||||
|
||||
protected override void OnPrintPage(PrintPageEventArgs evt) {
|
||||
if (_currentPage < _pageCount) {
|
||||
IntPtr page = PdfiumNative.FPDF_LoadPage(_handle, _currentPage);
|
||||
double width = PdfiumNative.FPDF_GetPageWidth(page);
|
||||
double height = PdfiumNative.FPDF_GetPageHeight(page);
|
||||
int pixelWidth = (int)(width / 72.0 * _dpi);
|
||||
int pixelHeight = (int)(height / 72.0 * _dpi);
|
||||
|
||||
IntPtr bitmap = PdfiumNative.FPDFBitmap_Create(pixelWidth, pixelHeight, 1);
|
||||
PdfiumNative.FPDF_RenderPageBitmap(bitmap, page, 0, 0, pixelWidth, pixelHeight, 0, 0);
|
||||
|
||||
IntPtr buffer = PdfiumNative.FPDFBitmap_GetBuffer(bitmap);
|
||||
int stride = PdfiumNative.FPDFBitmap_GetStride(bitmap);
|
||||
using (var bmp = new Bitmap(pixelWidth, pixelHeight, stride, PixelFormat.Format32bppArgb, buffer)) {
|
||||
evt.Graphics?.DrawImage(bmp, evt.PageBounds);
|
||||
}
|
||||
_currentPage++;
|
||||
|
||||
PdfiumNative.FPDFBitmap_Destroy(bitmap);
|
||||
PdfiumNative.FPDF_ClosePage(page);
|
||||
}
|
||||
evt.HasMorePages = _currentPage < ((PrinterSettings.ToPage == 0) ? _pageCount : Math.Min(PrinterSettings.ToPage, _pageCount));
|
||||
base.OnPrintPage(evt);
|
||||
}
|
||||
}
|
||||
|
||||
internal partial class PdfiumNative {
|
||||
[LibraryImport("pdfium.dll")]
|
||||
public static partial void FPDF_InitLibrary();
|
||||
|
||||
[LibraryImport("pdfium.dll")]
|
||||
public static partial void FPDF_DestroyLibrary();
|
||||
|
||||
[LibraryImport("pdfium.dll", StringMarshalling = StringMarshalling.Utf8)]
|
||||
public static partial IntPtr FPDF_LoadDocument(string filePath, string? password);
|
||||
|
||||
[LibraryImport("pdfium.dll")]
|
||||
public static partial void FPDF_CloseDocument(IntPtr document);
|
||||
|
||||
[LibraryImport("pdfium.dll")]
|
||||
public static partial int FPDF_GetPageCount(IntPtr document);
|
||||
|
||||
[LibraryImport("pdfium.dll")]
|
||||
public static partial IntPtr FPDF_LoadPage(IntPtr document, int pageIndex);
|
||||
|
||||
[LibraryImport("pdfium.dll")]
|
||||
public static partial void FPDF_ClosePage(IntPtr page);
|
||||
|
||||
[LibraryImport("pdfium.dll")]
|
||||
public static partial double FPDF_GetPageWidth(IntPtr page);
|
||||
|
||||
[LibraryImport("pdfium.dll")]
|
||||
public static partial double FPDF_GetPageHeight(IntPtr page);
|
||||
|
||||
[LibraryImport("pdfium.dll")]
|
||||
public static partial IntPtr FPDFBitmap_Create(int width, int height, int alpha);
|
||||
|
||||
[LibraryImport("pdfium.dll")]
|
||||
public static partial void FPDFBitmap_Destroy(IntPtr bitmap);
|
||||
|
||||
[LibraryImport("pdfium.dll")]
|
||||
public static partial IntPtr FPDFBitmap_GetBuffer(IntPtr bitmap);
|
||||
|
||||
[LibraryImport("pdfium.dll")]
|
||||
public static partial int FPDFBitmap_GetStride(IntPtr bitmap);
|
||||
|
||||
[LibraryImport("pdfium.dll")]
|
||||
public static partial void FPDF_RenderPageBitmap(IntPtr bitmap, IntPtr page, int start_x, int start_y, int size_x, int size_y, int rotate, int flags);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Printing;
|
||||
|
||||
namespace Elwig.Helpers.Printing {
|
||||
public class PdfPrinter {
|
||||
|
||||
public string PrinterName { get; init; }
|
||||
|
||||
public PdfPrinter(string? printerName = null) {
|
||||
PrinterName = printerName ?? GetDefaultPrinterName() ?? throw new InvalidOperationException("No default Windows printer is configured.");
|
||||
}
|
||||
|
||||
public void Print(string pdfPath, int copies = 1, bool doublePaged = false) {
|
||||
if (!File.Exists(pdfPath)) throw new FileNotFoundException("PDF file not found.", pdfPath);
|
||||
|
||||
IntPtr document = PdfiumNative.FPDF_LoadDocument(pdfPath, null);
|
||||
if (document == IntPtr.Zero) throw new InvalidOperationException("PDFium could not open the PDF.");
|
||||
|
||||
try {
|
||||
int pageCount = PdfiumNative.FPDF_GetPageCount(document);
|
||||
if (pageCount <= 0)
|
||||
return;
|
||||
|
||||
using var printer = new Win32Printer.Printer(PrinterName);
|
||||
printer.TrySetDuplex(doublePaged ? Duplexing.TwoSidedLongEdge : Duplexing.OneSided);
|
||||
printer.StartDocument(Path.GetFileName(pdfPath));
|
||||
bool documentStarted = true;
|
||||
try {
|
||||
for (int i = 0; i < copies; i++) {
|
||||
for (int j = 0; j < pageCount; j++) {
|
||||
PrintPage(document, printer, j);
|
||||
}
|
||||
}
|
||||
printer.EndDocument();
|
||||
documentStarted = false;
|
||||
} finally {
|
||||
if (documentStarted) printer.AbortDocument();
|
||||
}
|
||||
} finally {
|
||||
PdfiumNative.FPDF_CloseDocument(document);
|
||||
}
|
||||
}
|
||||
|
||||
private static void PrintPage(IntPtr document, Win32Printer.Printer printer, int pageIndex) {
|
||||
if (!PdfiumNative.FPDF_GetPageSizeByIndex(document, pageIndex, out double pageWidthPt, out double pageHeightPt)) {
|
||||
throw new InvalidOperationException($"Unable to obtain PDF page {pageIndex} size.");
|
||||
}
|
||||
|
||||
IntPtr page = PdfiumNative.FPDF_LoadPage(document, pageIndex);
|
||||
if (page == IntPtr.Zero)
|
||||
throw new InvalidOperationException($"Unable to load PDF page {pageIndex}.");
|
||||
|
||||
try {
|
||||
int renderWidth = (int)Math.Round(pageWidthPt / 72.0 * printer.DpiX);
|
||||
int renderHeight = (int)Math.Round(pageHeightPt / 72.0 * printer.DpiY);
|
||||
int offsetX = (printer.PrintableWidth - renderWidth) / 2;
|
||||
int offsetY = (printer.PrintableHeight - renderHeight) / 2;
|
||||
|
||||
printer.StartPage();
|
||||
try {
|
||||
PdfiumNative.FPDF_RenderPage(printer.Hdc, page, offsetX, offsetY, renderWidth, renderHeight, 0, PdfiumNative.FPDF_PRINTING | PdfiumNative.FPDF_ANNOT);
|
||||
} finally {
|
||||
printer.EndPage();
|
||||
}
|
||||
} finally {
|
||||
PdfiumNative.FPDF_ClosePage(page);
|
||||
}
|
||||
}
|
||||
|
||||
private static string? GetDefaultPrinterName() {
|
||||
using var key = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows NT\CurrentVersion\Windows");
|
||||
string? printer = key?.GetValue("Device") as string;
|
||||
if (string.IsNullOrWhiteSpace(printer))
|
||||
return null;
|
||||
|
||||
// Device has the form:
|
||||
// Printer Name,winspool,PORT
|
||||
int comma = printer.IndexOf(',');
|
||||
return comma >= 0 ? printer[..comma] : printer;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Elwig.Helpers.Printing {
|
||||
internal partial class PdfiumNative {
|
||||
|
||||
public const int FPDF_ANNOT = 0x01;
|
||||
public const int FPDF_PRINTING = 0x800;
|
||||
|
||||
[LibraryImport("pdfium.dll")]
|
||||
public static partial void FPDF_InitLibrary();
|
||||
|
||||
[LibraryImport("pdfium.dll")]
|
||||
public static partial void FPDF_DestroyLibrary();
|
||||
|
||||
[LibraryImport("pdfium.dll", StringMarshalling = StringMarshalling.Utf8)]
|
||||
public static partial IntPtr FPDF_LoadDocument(string filePath, string? password);
|
||||
|
||||
[LibraryImport("pdfium.dll")]
|
||||
public static partial void FPDF_CloseDocument(IntPtr document);
|
||||
|
||||
[LibraryImport("pdfium.dll")]
|
||||
public static partial int FPDF_GetPageCount(IntPtr document);
|
||||
|
||||
[LibraryImport("pdfium.dll")]
|
||||
public static partial IntPtr FPDF_LoadPage(IntPtr document, int pageIndex);
|
||||
|
||||
[LibraryImport("pdfium.dll")]
|
||||
public static partial void FPDF_ClosePage(IntPtr page);
|
||||
|
||||
[LibraryImport("pdfium.dll")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static partial bool FPDF_GetPageSizeByIndex(IntPtr document, int pageIndex, out double width, out double height);
|
||||
|
||||
[LibraryImport("pdfium.dll")]
|
||||
public static partial void FPDF_RenderPage(IntPtr hdc, IntPtr page, int startX, int startY, int sizeX, int sizeY, int rotate, int flags);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,239 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Printing;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Elwig.Helpers.Printing {
|
||||
public partial class Win32Printer {
|
||||
|
||||
private const int DM_OUT_BUFFER = 2;
|
||||
|
||||
private const int HORZRES = 8;
|
||||
private const int VERTRES = 10;
|
||||
private const int LOGPIXELSX = 88;
|
||||
private const int LOGPIXELSY = 90;
|
||||
private const int PHYSICALWIDTH = 110;
|
||||
private const int PHYSICALHEIGHT = 111;
|
||||
private const int PHYSICALOFFSETX = 112;
|
||||
private const int PHYSICALOFFSETY = 113;
|
||||
|
||||
private const int DM_DUPLEX = 0x1000;
|
||||
private const short DMDUP_SIMPLEX = 1;
|
||||
private const short DMDUP_VERTICAL = 2;
|
||||
private const short DMDUP_HORIZONTAL = 3;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||
private struct DOCINFO {
|
||||
public int cbSize;
|
||||
|
||||
[MarshalAs(UnmanagedType.LPWStr)]
|
||||
public string? lpszDocName;
|
||||
|
||||
[MarshalAs(UnmanagedType.LPWStr)]
|
||||
public string? lpszOutput;
|
||||
|
||||
[MarshalAs(UnmanagedType.LPWStr)]
|
||||
public string? lpszDatatype;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||
private struct DEVMODE {
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
|
||||
public string dmDeviceName;
|
||||
|
||||
public short dmSpecVersion;
|
||||
public short dmDriverVersion;
|
||||
public short dmSize;
|
||||
public short dmDriverExtra;
|
||||
public int dmFields;
|
||||
|
||||
public short dmOrientation;
|
||||
public short dmPaperSize;
|
||||
public short dmPaperLength;
|
||||
public short dmPaperWidth;
|
||||
public short dmScale;
|
||||
public short dmCopies;
|
||||
public short dmDefaultSource;
|
||||
public short dmPrintQuality;
|
||||
public short dmColor;
|
||||
public short dmDuplex;
|
||||
public short dmYResolution;
|
||||
public short dmTTOption;
|
||||
public short dmCollate;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
|
||||
public string dmFormName;
|
||||
|
||||
public short dmLogPixels;
|
||||
public int dmBitsPerPel;
|
||||
public int dmPelsWidth;
|
||||
public int dmPelsHeight;
|
||||
public int dmDisplayFlags;
|
||||
public int dmDisplayFrequency;
|
||||
public int dmICMMethod;
|
||||
public int dmICMIntent;
|
||||
public int dmMediaType;
|
||||
public int dmDitherType;
|
||||
public int dmReserved1;
|
||||
public int dmReserved2;
|
||||
public int dmPanningWidth;
|
||||
public int dmPanningHeight;
|
||||
}
|
||||
|
||||
[DllImport("winspool.drv", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
private static extern bool OpenPrinter(string pPrinterName, out IntPtr phPrinter, IntPtr pDefault);
|
||||
|
||||
[DllImport("winspool.drv", SetLastError = true)]
|
||||
private static extern bool ClosePrinter(IntPtr hPrinter);
|
||||
|
||||
[DllImport("winspool.drv", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
private static extern int DocumentProperties(IntPtr hwnd, IntPtr hPrinter, string pDeviceName, IntPtr pDevModeOutput, IntPtr pDevModeInput, int fMode);
|
||||
|
||||
[DllImport("gdi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
private static extern IntPtr CreateDC(string? pDriver, string? pDevice, string? pOutput, IntPtr pInitData);
|
||||
|
||||
[DllImport("gdi32.dll", SetLastError = true)]
|
||||
private static extern bool DeleteDC(IntPtr hdc);
|
||||
|
||||
[DllImport("gdi32.dll", SetLastError = true)]
|
||||
private static extern int GetDeviceCaps(IntPtr hdc, int index);
|
||||
|
||||
[DllImport("gdi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
private static extern int StartDoc(IntPtr hdc, ref DOCINFO lpdi);
|
||||
|
||||
[DllImport("gdi32.dll", SetLastError = true)]
|
||||
private static extern int EndDoc(IntPtr hdc);
|
||||
|
||||
[DllImport("gdi32.dll", SetLastError = true)]
|
||||
private static extern int AbortDoc(IntPtr hdc);
|
||||
|
||||
[DllImport("gdi32.dll", SetLastError = true)]
|
||||
private static extern int StartPage(IntPtr hdc);
|
||||
|
||||
[DllImport("gdi32.dll", SetLastError = true)]
|
||||
private static extern int EndPage(IntPtr hdc);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
private static extern IntPtr GlobalAlloc(uint uFlags, UIntPtr dwBytes);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
private static extern IntPtr GlobalFree(IntPtr hMem);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
private static extern IntPtr GlobalLock(IntPtr hMem);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
private static extern bool GlobalUnlock(IntPtr hMem);
|
||||
|
||||
public class Printer : IDisposable {
|
||||
private readonly string _printerName;
|
||||
private readonly IntPtr _printerHandle;
|
||||
private readonly IntPtr _devMode;
|
||||
private readonly IntPtr _hdc;
|
||||
|
||||
public IntPtr Hdc => _hdc;
|
||||
|
||||
public int PrintableWidth => GetDeviceCaps(_hdc, HORZRES);
|
||||
public int PrintableHeight => GetDeviceCaps(_hdc, VERTRES);
|
||||
public int DpiX => GetDeviceCaps(_hdc, LOGPIXELSX);
|
||||
public int DpiY => GetDeviceCaps(_hdc, LOGPIXELSY);
|
||||
public int PhysicalWidth => GetDeviceCaps(_hdc, PHYSICALWIDTH);
|
||||
public int PhysicalHeight => GetDeviceCaps(_hdc, PHYSICALHEIGHT);
|
||||
public int PhysicalOffsetX => GetDeviceCaps(_hdc, PHYSICALOFFSETX);
|
||||
public int PhysicalOffsetY => GetDeviceCaps(_hdc, PHYSICALOFFSETY);
|
||||
|
||||
public Printer(string printerName) {
|
||||
_printerName = printerName;
|
||||
|
||||
if (!OpenPrinter(_printerName, out _printerHandle, IntPtr.Zero)) {
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error(), $"Unable to open printer '{printerName}'.");
|
||||
}
|
||||
|
||||
try {
|
||||
_devMode = CreateDevMode();
|
||||
_hdc = CreateDC(null, _printerName, null, _devMode);
|
||||
if (_hdc == IntPtr.Zero)
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error(), $"Unable to create printer DC for '{_printerName}'.");
|
||||
} catch {
|
||||
if (_devMode != IntPtr.Zero) Marshal.FreeHGlobal(_devMode);
|
||||
ClosePrinter(_printerHandle);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public bool TrySetDuplex(Duplexing duplex) {
|
||||
var devMode = Marshal.PtrToStructure<DEVMODE>(_devMode);
|
||||
switch (duplex) {
|
||||
case Duplexing.OneSided: devMode.dmDuplex = DMDUP_SIMPLEX; break;
|
||||
case Duplexing.TwoSidedShortEdge: devMode.dmDuplex = DMDUP_HORIZONTAL; break;
|
||||
case Duplexing.TwoSidedLongEdge: devMode.dmDuplex = DMDUP_VERTICAL; break;
|
||||
}
|
||||
if ((devMode.dmFields & DM_DUPLEX) != 0) {
|
||||
Marshal.StructureToPtr(devMode, _devMode, false);
|
||||
return true;
|
||||
} else {
|
||||
devMode.dmFields |= DM_DUPLEX;
|
||||
Marshal.StructureToPtr(devMode, _devMode, false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private IntPtr CreateDevMode() {
|
||||
int size = DocumentProperties(IntPtr.Zero, _printerHandle, _printerName, IntPtr.Zero, IntPtr.Zero, 0);
|
||||
if (size <= 0)
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error(), "DocumentProperties failed.");
|
||||
|
||||
IntPtr devMode = Marshal.AllocHGlobal(size);
|
||||
int result = DocumentProperties(IntPtr.Zero, _printerHandle, _printerName, devMode, IntPtr.Zero, DM_OUT_BUFFER);
|
||||
if (result < 0) {
|
||||
Marshal.FreeHGlobal(devMode);
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error(), "Unable to obtain printer DEVMODE.");
|
||||
}
|
||||
|
||||
return devMode;
|
||||
}
|
||||
|
||||
public void StartDocument(string documentName) {
|
||||
var docInfo = new DOCINFO {
|
||||
cbSize = Marshal.SizeOf<DOCINFO>(),
|
||||
lpszDocName = documentName,
|
||||
lpszDatatype = null,
|
||||
lpszOutput = null
|
||||
};
|
||||
|
||||
if (StartDoc(_hdc, ref docInfo) <= 0)
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error(), "StartDoc failed.");
|
||||
}
|
||||
|
||||
public void StartPage() {
|
||||
if (Win32Printer.StartPage(_hdc) <= 0)
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error(), "StartPage failed.");
|
||||
}
|
||||
|
||||
public void EndPage() {
|
||||
if (Win32Printer.EndPage(_hdc) <= 0)
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error(), "EndPage failed.");
|
||||
}
|
||||
|
||||
public void EndDocument() {
|
||||
if (EndDoc(_hdc) <= 0)
|
||||
throw new Win32Exception( Marshal.GetLastWin32Error(), "EndDoc failed.");
|
||||
}
|
||||
|
||||
public void AbortDocument() {
|
||||
AbortDoc(_hdc);
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
if (_hdc != IntPtr.Zero)
|
||||
DeleteDC(_hdc);
|
||||
|
||||
if (_devMode != IntPtr.Zero)
|
||||
Marshal.FreeHGlobal(_devMode);
|
||||
|
||||
if (_printerHandle != IntPtr.Zero)
|
||||
ClosePrinter(_printerHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -45,7 +45,6 @@ namespace Elwig.Helpers {
|
||||
public static int CurrentNextSeason => DateTime.Now.Year - (DateTime.Now.Month <= 3 ? 1 : 0);
|
||||
public static int CurrentLastSeason => DateTime.Now.Year - (DateTime.Now.Month <= 6 ? 1 : 0);
|
||||
public static int FollowingSeason => DateTime.Now.Year + (DateTime.Now.Month >= 11 ? 1 : 0);
|
||||
public static DateTime Today => (DateTime.Now.Hour >= 3) ? DateTime.Today : DateTime.Today.AddDays(-1);
|
||||
|
||||
[GeneratedRegex("^serial://([A-Za-z0-9]+):([0-9]+)(,([5-9]),([NOEMSnoems]),(0|1|1\\.5|2|))?$", RegexOptions.Compiled)]
|
||||
private static partial Regex GeneratedSerialRegex();
|
||||
@@ -516,7 +515,7 @@ namespace Elwig.Helpers {
|
||||
public static async Task<SmtpClient?> GetSmtpClient() {
|
||||
if (App.Config.Smtp == null)
|
||||
return null;
|
||||
var (host, port, mode, username, password, _) = App.Config.Smtp.Value;
|
||||
var (host, port, mode, username, password, _, _) = App.Config.Smtp.Value;
|
||||
var client = new SmtpClient();
|
||||
await client.ConnectAsync(host, port, mode == "starttls" ? SecureSocketOptions.StartTls : SecureSocketOptions.None);
|
||||
await client.AuthenticateAsync(username, password);
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Elwig.Models.Dtos {
|
||||
class MemberAreaComTotalsData : DataTable<MemberAreaComTotalsRow> {
|
||||
|
||||
private static readonly (string, string, string?, int)[] FieldNames = [
|
||||
("MgNr", "MgNr.", null, 12),
|
||||
("Name1", "Name", null, 40),
|
||||
("Name2", "Vorname", null, 40),
|
||||
("Address", "Adresse", null, 60),
|
||||
("Plz", "PLZ", null, 10),
|
||||
("Locality", "Ort", null, 60),
|
||||
("SortIds", "Sorte", null, 12),
|
||||
("AttrIds", "Attribut", null, 16),
|
||||
("Areas", "Fläche", "m²", 22),
|
||||
("DeliveryObligations", "Lieferpflicht", "kg", 22),
|
||||
("DeliveryRights", "Lieferrecht", "kg", 22),
|
||||
];
|
||||
|
||||
public MemberAreaComTotalsData(IEnumerable<MemberAreaComTotalsRow> rows, int year) :
|
||||
base($"Gebundene Fläche", $"Gebundene Fläche pro Mitglied {year}", rows, FieldNames) {
|
||||
}
|
||||
|
||||
public static async Task<MemberAreaComTotalsData> ForSeason(DbSet<MemberAreaComTotalsRowSingle> table, int year) {
|
||||
return new MemberAreaComTotalsData(
|
||||
(await FromDbSet(table, year)).GroupBy(
|
||||
r => r.MgNr,
|
||||
(k, g) => new MemberAreaComTotalsRow(g)
|
||||
), year);
|
||||
}
|
||||
|
||||
private static async Task<IEnumerable<MemberAreaComTotalsRowSingle>> FromDbSet(DbSet<MemberAreaComTotalsRowSingle> table, int year) {
|
||||
return await table.FromSql($"""
|
||||
SELECT m.mgnr, m.name AS name_1,
|
||||
COALESCE(m.prefix || ' ', '') || m.given_name ||
|
||||
COALESCE(' ' || m.middle_names, '') || COALESCE(' ' || m.suffix, '') AS name_2,
|
||||
p.plz, o.name AS ort, m.address,
|
||||
c.bucket, c.area, c.min_kg, c.max_kg
|
||||
FROM v_area_commitment_bucket_strict c
|
||||
LEFT JOIN member m ON m.mgnr = c.mgnr
|
||||
LEFT JOIN AT_plz_dest p ON p.id = m.postal_dest
|
||||
LEFT JOIN AT_ort o ON o.okz = p.okz
|
||||
WHERE c.year = {year}
|
||||
ORDER BY m.mgnr, c.bucket
|
||||
""").ToListAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public class MemberAreaComTotalsRow {
|
||||
public int MgNr;
|
||||
public string Name1;
|
||||
public string? Name2;
|
||||
public string Address;
|
||||
public int Plz;
|
||||
public string Locality;
|
||||
public string[] SortIds;
|
||||
public string[] AttrIds;
|
||||
public int[] Areas;
|
||||
public int[] DeliveryObligations;
|
||||
public int[] DeliveryRights;
|
||||
|
||||
public MemberAreaComTotalsRow(IEnumerable<MemberAreaComTotalsRowSingle> rows) {
|
||||
var f = rows.First();
|
||||
MgNr = f.MgNr;
|
||||
Name1 = f.Name1;
|
||||
Name2 = f.Name2;
|
||||
Address = f.Address;
|
||||
Plz = f.Plz;
|
||||
Locality = f.Locality.Split(",")[0];
|
||||
SortIds = [.. rows.Select(r => r.VtrgId[..2])];
|
||||
AttrIds = [.. rows.Select(r => r.VtrgId[2..])];
|
||||
Areas = [.. rows.Select(r => r.Area)];
|
||||
DeliveryObligations = [.. rows.Select(r => r.MinKg)];
|
||||
DeliveryRights = [.. rows.Select(r => r.MaxKg)];
|
||||
}
|
||||
}
|
||||
|
||||
[Keyless]
|
||||
public class MemberAreaComTotalsRowSingle {
|
||||
[Column("mgnr")]
|
||||
public int MgNr { get; set; }
|
||||
[Column("name_1")]
|
||||
public required string Name1 { get; set; }
|
||||
[Column("name_2")]
|
||||
public string? Name2 { get; set; }
|
||||
[Column("address")]
|
||||
public required string Address { get; set; }
|
||||
[Column("plz")]
|
||||
public int Plz { get; set; }
|
||||
[Column("ort")]
|
||||
public required string Locality { get; set; }
|
||||
[Column("bucket")]
|
||||
public required string VtrgId { get; set; }
|
||||
[Column("area")]
|
||||
public int Area { get; set; }
|
||||
[Column("min_kg")]
|
||||
public int MinKg { get; set; }
|
||||
[Column("max_kg")]
|
||||
public int MaxKg { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -14,73 +14,49 @@ namespace Elwig.Models.Dtos {
|
||||
("Address", "Adresse", null, 60),
|
||||
("Plz", "PLZ", null, 10),
|
||||
("Locality", "Ort", null, 60),
|
||||
("SortIds", "Sorte", null, 12),
|
||||
("AttrIds", "Attribut", null, 16),
|
||||
("Areas", "Fläche", "m²", 22),
|
||||
("DeliveryObligations", "Lieferpflicht", "kg", 22),
|
||||
("DeliveryRights", "Lieferrecht", "kg", 22),
|
||||
("SortId", "Sorte", null, 12),
|
||||
("AttrId", "Attribut", null, 16),
|
||||
("CultId", "Bewirt.", null, 16),
|
||||
("GstNr", "Parzelle(n)", null, 25),
|
||||
("Area", "Fläche", "m²", 22),
|
||||
("MinKg", "Lieferpflicht", "kg", 22),
|
||||
("MaxKg", "Lieferrecht", "kg", 22),
|
||||
];
|
||||
|
||||
public MemberAreaComsData(IEnumerable<MemberAreaComsRow> rows, int year) :
|
||||
base($"Flächenbindungen", $"Flächenbindungen pro Mitglied {year}", rows, FieldNames) {
|
||||
}
|
||||
|
||||
public static async Task<MemberAreaComsData> ForSeason(DbSet<MemberAreaComsRowSingle> table, int year) {
|
||||
return new MemberAreaComsData(
|
||||
(await FromDbSet(table, year)).GroupBy(
|
||||
r => r.MgNr,
|
||||
(k, g) => new MemberAreaComsRow(g)
|
||||
), year);
|
||||
public static async Task<MemberAreaComsData> ForSeason(DbSet<MemberAreaComsRow> table, int year) {
|
||||
return new MemberAreaComsData(await FromDbSet(table, year), year);
|
||||
}
|
||||
|
||||
private static async Task<IEnumerable<MemberAreaComsRowSingle>> FromDbSet(DbSet<MemberAreaComsRowSingle> table, int year) {
|
||||
private static async Task<IEnumerable<MemberAreaComsRow>> FromDbSet(DbSet<MemberAreaComsRow> table, int year) {
|
||||
return await table.FromSql($"""
|
||||
SELECT m.mgnr, m.name AS name_1,
|
||||
COALESCE(m.prefix || ' ', '') || m.given_name ||
|
||||
COALESCE(' ' || m.middle_names, '') || COALESCE(' ' || m.suffix, '') AS name_2,
|
||||
p.plz, o.name AS ort, m.address,
|
||||
c.bucket, c.area, c.min_kg, c.max_kg
|
||||
FROM v_area_commitment_bucket_strict c
|
||||
t.sortid, t.attrid, c.cultid,
|
||||
c.gstnr, c.area,
|
||||
CAST(ROUND(area * COALESCE(t.min_kg_per_ha, 0) / 10000.0, 0) AS INTEGER) AS min_kg,
|
||||
CAST(ROUND(area * MIN(COALESCE(a.max_kg_per_ha, s.max_kg_per_ha), s.max_kg_per_ha) / 10000.0, 0) AS INTEGER) AS max_kg
|
||||
FROM v_virtual_season s, area_commitment c
|
||||
JOIN area_commitment_type t ON t.vtrgid = c.vtrgid
|
||||
LEFT JOIN wine_attribute a ON a.attrid = t.attrid
|
||||
LEFT JOIN member m ON m.mgnr = c.mgnr
|
||||
LEFT JOIN AT_plz_dest p ON p.id = m.postal_dest
|
||||
LEFT JOIN AT_ort o ON o.okz = p.okz
|
||||
WHERE c.year = {year}
|
||||
ORDER BY m.mgnr, c.bucket
|
||||
WHERE s.year = {year} AND
|
||||
(year_from IS NULL OR year_from <= s.year) AND
|
||||
(year_to IS NULL OR year_to >= s.year)
|
||||
ORDER BY c.mgnr, t.sortid, t.attrid, c.cultid, c.gstnr;
|
||||
""").ToListAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public class MemberAreaComsRow {
|
||||
public int MgNr;
|
||||
public string Name1;
|
||||
public string? Name2;
|
||||
public string Address;
|
||||
public int Plz;
|
||||
public string Locality;
|
||||
public string[] SortIds;
|
||||
public string[] AttrIds;
|
||||
public int[] Areas;
|
||||
public int[] DeliveryObligations;
|
||||
public int[] DeliveryRights;
|
||||
|
||||
public MemberAreaComsRow(IEnumerable<MemberAreaComsRowSingle> rows) {
|
||||
var f = rows.First();
|
||||
MgNr = f.MgNr;
|
||||
Name1 = f.Name1;
|
||||
Name2 = f.Name2;
|
||||
Address = f.Address;
|
||||
Plz = f.Plz;
|
||||
Locality = f.Locality.Split(",")[0];
|
||||
SortIds = rows.Select(r => r.VtrgId[..2]).ToArray();
|
||||
AttrIds = rows.Select(r => r.VtrgId[2..]).ToArray();
|
||||
Areas = rows.Select(r => r.Area).ToArray();
|
||||
DeliveryObligations = rows.Select(r => r.MinKg).ToArray();
|
||||
DeliveryRights = rows.Select(r => r.MaxKg).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
[Keyless]
|
||||
public class MemberAreaComsRowSingle {
|
||||
public class MemberAreaComsRow {
|
||||
[Column("mgnr")]
|
||||
public int MgNr { get; set; }
|
||||
[Column("name_1")]
|
||||
@@ -93,8 +69,14 @@ namespace Elwig.Models.Dtos {
|
||||
public int Plz { get; set; }
|
||||
[Column("ort")]
|
||||
public required string Locality { get; set; }
|
||||
[Column("bucket")]
|
||||
public required string VtrgId { get; set; }
|
||||
[Column("sortid")]
|
||||
public required string SortId { get; set; }
|
||||
[Column("attrid")]
|
||||
public string? AttrId { get; set; }
|
||||
[Column("cultid")]
|
||||
public string? CultId { get; set; }
|
||||
[Column("gstnr")]
|
||||
public required string GstNr { get; set; }
|
||||
[Column("area")]
|
||||
public int Area { get; set; }
|
||||
[Column("min_kg")]
|
||||
|
||||
@@ -118,7 +118,7 @@ namespace Elwig.Models.Entities {
|
||||
[Column("acid")]
|
||||
public double? Acid { get; set; }
|
||||
|
||||
[Column("scale_id")]
|
||||
[Column("scale_terminal")]
|
||||
public string? ScaleTerminalId { get; set; }
|
||||
|
||||
[Column("weighing_data")]
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
-- schema version 40 to 41
|
||||
|
||||
PRAGMA writable_schema = ON;
|
||||
|
||||
UPDATE sqlite_schema SET sql = REPLACE(sql, 'scale_id ', 'scale_terminal')
|
||||
WHERE type = 'table' AND name = 'delivery_part';
|
||||
|
||||
DROP VIEW v_bki_delivery;
|
||||
DROP VIEW v_bki_member;
|
||||
|
||||
CREATE VIEW v_bki_member AS
|
||||
SELECT s.year, m.mgnr, m.lfbis_nr, m.name,
|
||||
(COALESCE(m.prefix || ' ', '') || m.given_name || COALESCE(' ' || m.middle_names, '') || COALESCE(' ' || m.suffix, '')) AS other_names,
|
||||
a.name AS billing_name, COALESCE(a.address, m.address) AS address,
|
||||
COALESCE(a.country, m.country) AS country, COALESCE(a.postal_dest, m.postal_dest) AS postal_dest,
|
||||
m.volllieferant AS vollablieferer,
|
||||
SUM(COALESCE(IIF((c.year_from IS NULL OR c.year_from <= s.year) AND (c.year_to IS NULL OR c.year_to >= s.year), c.area, NULL), 0)) AS area
|
||||
FROM season s, member m
|
||||
LEFT JOIN member_billing_address a ON a.mgnr = m.mgnr
|
||||
LEFT JOIN area_commitment c ON c.mgnr = m.mgnr
|
||||
GROUP BY s.year, m.mgnr;
|
||||
|
||||
CREATE VIEW v_bki_delivery AS
|
||||
SELECT m.lfbis_nr, m.name, m.other_names, m.billing_name,
|
||||
m.address, plz.plz, IIF(INSTR(o.name, ',') = 0, o.name, SUBSTR(o.name, 1, INSTR(o.name, ',') - 1)) AS ort,
|
||||
d.date, d.weight, v.type, v.sortid, d.qualid, d.year, d.hkid, d.kmw, d.oe,
|
||||
m.vollablieferer, m.area
|
||||
FROM v_delivery d
|
||||
JOIN v_bki_member m ON (m.year, m.mgnr) = (d.year, d.mgnr)
|
||||
JOIN postal_dest pd ON (pd.country, pd.id) = (m.country, m.postal_dest)
|
||||
LEFT JOIN AT_plz_dest ap ON (ap.country, ap.id) = (pd.country, pd.id)
|
||||
LEFT JOIN AT_plz plz ON plz.plz = ap.plz
|
||||
LEFT JOIN AT_ort o ON o.okz = ap.okz
|
||||
JOIN wine_variety v ON v.sortid = d.sortid
|
||||
ORDER BY d.date, d.time;
|
||||
|
||||
PRAGMA writable_schema = OFF;
|
||||
@@ -45,7 +45,7 @@ namespace Elwig.Services {
|
||||
deliveryAncmtQuery = deliveryAncmtQuery.Where(a => a.Year == s.Year && a.DsNr == s.DsNr);
|
||||
filterNames.Add($"{s.Date:dd.MM.yyyy} – {s.Branch.Name} – {s.Description}");
|
||||
} else {
|
||||
deliveryAncmtQuery = deliveryAncmtQuery.Where(a => a.Year == vm.FilterSeason && (!vm.FilterOnlyUpcoming || a.Schedule.DateString.CompareTo(Utils.Today.ToString("yyyy-MM-dd")) >= 0));
|
||||
deliveryAncmtQuery = deliveryAncmtQuery.Where(a => a.Year == vm.FilterSeason && (!vm.FilterOnlyUpcoming || a.Schedule.DateString.CompareTo(DateTime.Today.ToString("yyyy-MM-dd")) >= 0));
|
||||
filterNames.Add($"{vm.FilterSeason}");
|
||||
}
|
||||
|
||||
|
||||
@@ -49,8 +49,8 @@ namespace Elwig.Services {
|
||||
filterNames.Add($"{vm.FilterSeason}");
|
||||
}
|
||||
if (vm.FilterOnlyUpcoming) {
|
||||
deliveryScheduleQuery = deliveryScheduleQuery.Where(s => s.DateString.CompareTo(Utils.Today.ToString("yyyy-MM-dd")) >= 0);
|
||||
filterNames.Add($"ab {Utils.Today:dd.MM.yyyy}");
|
||||
deliveryScheduleQuery = deliveryScheduleQuery.Where(s => s.DateString.CompareTo(DateTime.Today.ToString("yyyy-MM-dd")) >= 0);
|
||||
filterNames.Add($"ab {DateTime.Today:dd.MM.yyyy}");
|
||||
}
|
||||
|
||||
var filterVar = new List<string>();
|
||||
|
||||
@@ -72,6 +72,31 @@ namespace Elwig.Services {
|
||||
vm.ManualWeighingReason = p.WeighingReason;
|
||||
}
|
||||
|
||||
private static async Task<(Expression<Func<Delivery, bool>>, string)> GetFilterToday(AppDbContext ctx) {
|
||||
var today = DateTime.Today;
|
||||
var timestamps = (await ctx.Deliveries
|
||||
.Where(d => d.DateString.CompareTo(today.AddDays(-1).ToString("yyyy-MM-dd")) >= 0)
|
||||
.OrderBy(d => d.DateString).ThenBy(d => d.TimeString)
|
||||
.Select(d => d.DateString + " " + d.TimeString)
|
||||
.ToListAsync())
|
||||
.Select(s => DateTime.TryParseExact(s, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.None, out var dt) ? (DateTime?)dt : null)
|
||||
.Where(t => t.HasValue)
|
||||
.Cast<DateTime>()
|
||||
.ToArray();
|
||||
if (timestamps.Length > 0) {
|
||||
var latest = timestamps.Last();
|
||||
var since = timestamps.Cast<DateTime>().Reverse().Aggregate(latest, (s, c) => s.Subtract(c).TotalHours <= 6 ? c : s);
|
||||
latest += new TimeSpan(0, 1, -latest.Minute, -latest.Second, -latest.Millisecond, -latest.Microsecond);
|
||||
since += new TimeSpan(0, 0, -since.Minute, -since.Second, -since.Millisecond, -since.Microsecond);
|
||||
|
||||
return (d => (d.DateString == since.ToString("yyyy-MM-dd") && (d.TimeString == null || d.TimeString.CompareTo(since.ToString("HH:mm:ss")) >= 0)) ||
|
||||
(d.DateString.CompareTo(since.ToString("yyyy-MM-dd")) > 0),
|
||||
since.Date == latest.Date ? since.ToString("dd.MM.yyyy") : $"{since:dd.MM.yyyy \\a\\b HH:mm} / {latest:dd.MM.yyyy \\b\\i\\s HH:mm}");
|
||||
} else {
|
||||
return (_ => false, today.ToString("dd.MM.yyyy"));
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<(List<string>, IQueryable<Delivery>, IQueryable<DeliveryPart>, Predicate<DeliveryPart>, List<string>)> GetFilters(this DeliveryAdminViewModel vm, AppDbContext ctx) {
|
||||
List<string> filterNames = [];
|
||||
IQueryable<Delivery> deliveryQuery = ctx.Deliveries;
|
||||
@@ -84,10 +109,9 @@ namespace Elwig.Services {
|
||||
filterNames.Add(vm.FilterMember.AdministrativeName);
|
||||
}
|
||||
if (vm.FilterTodayOnly) {
|
||||
deliveryQuery = deliveryQuery
|
||||
.Where(d => (d.DateString == Utils.Today.ToString("yyyy-MM-dd") && (d.TimeString == null || d.TimeString.CompareTo("03:00:00") > 0)) ||
|
||||
(d.DateString == Utils.Today.AddDays(1).ToString("yyyy-MM-dd") && (d.TimeString == null || d.TimeString.CompareTo("03:00:00") <= 0)));
|
||||
filterNames.Add(Utils.Today.ToString("dd.MM.yyyy"));
|
||||
var (pred, name) = await GetFilterToday(ctx);
|
||||
deliveryQuery = deliveryQuery.Where(pred);
|
||||
filterNames.Add(name);
|
||||
} else if (!vm.FilterAllSeasons) {
|
||||
deliveryQuery = deliveryQuery.Where(d => d.Year == vm.FilterSeason);
|
||||
filterNames.Add($"{vm.FilterSeason}");
|
||||
@@ -730,10 +754,9 @@ namespace Elwig.Services {
|
||||
query = q;
|
||||
filterNames.AddRange(f);
|
||||
} else if (subject == ExportSubject.FromToday) {
|
||||
var date = $"{Utils.Today:yyyy-MM-dd}";
|
||||
query = ctx.DeliveryParts
|
||||
.Where(p => p.Delivery.DateString == date);
|
||||
filterNames.Add($"{Utils.Today:dd.MM.yyyy}");
|
||||
var (pred, name) = await GetFilterToday(ctx);
|
||||
query = ctx.Deliveries.Where(pred).SelectMany(d => d.Parts);
|
||||
filterNames.Add(name);
|
||||
} else if (subject == ExportSubject.FromSeasonAndBranch) {
|
||||
query = ctx.DeliveryParts
|
||||
.Where(p => p.Year == Utils.CurrentLastSeason && p.Delivery.ZwstId == App.ZwstId);
|
||||
@@ -805,10 +828,9 @@ namespace Elwig.Services {
|
||||
query = q;
|
||||
filterNames.AddRange(f);
|
||||
} else if (subject == ExportSubject.FromToday) {
|
||||
var date = $"{Utils.Today:yyyy-MM-dd}";
|
||||
query = ctx.DeliveryParts
|
||||
.Where(p => p.Delivery.DateString == date);
|
||||
filterNames.Add($"{Utils.Today:dd.MM.yyyy}");
|
||||
var (pred, name) = await GetFilterToday(ctx);
|
||||
query = ctx.Deliveries.Where(pred).SelectMany(d => d.Parts);
|
||||
filterNames.Add(name);
|
||||
} else {
|
||||
throw new ArgumentException("Invalid value for ExportSubject");
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using Elwig.Models;
|
||||
using Elwig.Models.Entities;
|
||||
using Elwig.ViewModels;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -11,7 +12,7 @@ namespace Elwig.Services {
|
||||
|
||||
public static async Task InitInputs(this MemberBusinessSharesViewModel vm) {
|
||||
using var ctx = new AppDbContext();
|
||||
vm.DateNoticeString = $"{Utils.Today:dd.MM.yyyy}";
|
||||
vm.DateNoticeString = $"{DateTime.Today:dd.MM.yyyy}";
|
||||
vm.ValuePerShare = (await ctx.Seasons.OrderBy(s => s.Year).LastOrDefaultAsync())?.BusinessShareValue;
|
||||
}
|
||||
|
||||
|
||||
@@ -214,7 +214,7 @@ namespace Elwig.Services {
|
||||
];
|
||||
}
|
||||
|
||||
public static async Task Download(string url, string username, string password) {
|
||||
public static async Task Download(string url, string username, string password, bool confirmImports) {
|
||||
try {
|
||||
var import = await GetFilesToImport(url, username, password);
|
||||
var paths = new List<string>();
|
||||
@@ -226,7 +226,7 @@ namespace Elwig.Services {
|
||||
paths.Add(filename);
|
||||
}
|
||||
}
|
||||
await ElwigData.Import(paths, ElwigData.ImportMode.FromBranches);
|
||||
await ElwigData.Import(paths, confirmImports ? ElwigData.ImportMode.Interactively : ElwigData.ImportMode.FromBranches);
|
||||
} catch (HttpRequestException exc) {
|
||||
InteractionService.ShowException("Daten herunterladen", "Eventuell Internetverbindung prüfen!", exc);
|
||||
} catch (TaskCanceledException exc) {
|
||||
@@ -264,5 +264,14 @@ namespace Elwig.Services {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<bool> ChangesAvailable(AppDbContext ctx, string url, string username, string password, int? year = null) {
|
||||
try {
|
||||
year ??= Utils.CurrentLastSeason;
|
||||
return await ctx.Deliveries.Where(d => d.ZwstId == App.ZwstId && d.Year == year).Where(ChangedDeliveries).AnyAsync() || (Utils.HasInternetConnectivity() && (await GetFilesToImport(url, username, password)).Count > 0);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ namespace Elwig.Windows {
|
||||
if (await ctx.FetchSeasons(Utils.CurrentYear).SingleOrDefaultAsync() == null) {
|
||||
InteractionService.ShowWarning("Saison noch nicht erstellt",
|
||||
"Die Saison für das aktuelle Jahr wurde noch nicht erstellt. Neue Lieferungen können nicht abgespeichert werden.\n\n" +
|
||||
"(Stammdaten -> Saisons -> Neu anlegen...)");
|
||||
"(Stammdaten \u2192 Saisons \u2192 Neu anlegen...)");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -685,7 +685,7 @@ namespace Elwig.Windows {
|
||||
private async void TodayOnlyInput_Changed(object sender, RoutedEventArgs evt) {
|
||||
if (!HasContextLoaded) return;
|
||||
if (TodayOnlyInput.IsChecked == true && AllSeasonsInput.IsChecked == false) {
|
||||
ViewModel.FilterSeason = Utils.Today.Year;
|
||||
ViewModel.FilterSeason = DateTime.Today.Year;
|
||||
ViewModel.FilterTodayOnly = true;
|
||||
}
|
||||
await RefreshList();
|
||||
@@ -1379,7 +1379,7 @@ namespace Elwig.Windows {
|
||||
var kl = mod.Where(m => m.Name.StartsWith("Klasse ")).Select(m => m.ModId).LastOrDefault("_")[0];
|
||||
if (ViewModel.IsUnloadingPumped && (kl == 'A' || kl == '_')) {
|
||||
kl = 'B';
|
||||
} else if (ViewModel.IsUnloadingDumper && kl == '_') {
|
||||
} else if (ViewModel.IsUnloadingDumper && (kl == 'B' || kl == '_')) {
|
||||
kl = 'A';
|
||||
} else {
|
||||
kl = '_';
|
||||
|
||||
@@ -92,7 +92,7 @@ namespace Elwig.Windows {
|
||||
list.ForEach(v => v.Schedule.AnnouncedWeightOverride = v.AnnouncedWeight);
|
||||
var deliverySchedules = list.Select(v => v.Schedule).ToList();
|
||||
ControlUtils.RenewItemsSource(DeliveryScheduleList, deliverySchedules
|
||||
.Where(s => !ViewModel.FilterOnlyUpcoming || s.DateString.CompareTo(Utils.Today.ToString("yyyy-MM-dd")) >= 0)
|
||||
.Where(s => !ViewModel.FilterOnlyUpcoming || s.DateString.CompareTo(DateTime.Today.ToString("yyyy-MM-dd")) >= 0)
|
||||
.ToList(), DeliveryScheduleList_SelectionChanged, ViewModel.FilterFromAllSchedules ? ControlUtils.RenewSourceDefault.None : ControlUtils.RenewSourceDefault.First);
|
||||
ControlUtils.RenewItemsSource(DeliveryScheduleInput, deliverySchedules, DeliveryScheduleInput_SelectionChanged);
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ namespace Elwig.Windows {
|
||||
public MailWindow(int? year = null) {
|
||||
InitializeComponent();
|
||||
using (var ctx = new AppDbContext()) {
|
||||
Year = year ?? ctx.Seasons.OrderByDescending(s => s.Year).FirstOrDefault()?.Year ?? Utils.Today.Year;
|
||||
Year = year ?? ctx.Seasons.OrderByDescending(s => s.Year).FirstOrDefault()?.Year ?? DateTime.Today.Year;
|
||||
Title = $"Rundschreiben - Lese {Year} - Elwig";
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ namespace Elwig.Windows {
|
||||
PostalSender1.Text = App.Client.Sender1;
|
||||
PostalSender2.Text = App.Client.Sender2;
|
||||
PostalLocation.Text = App.BranchLocation;
|
||||
PostalDate.Text = $"{Utils.Today:dd.MM.yyyy}";
|
||||
PostalDate.Text = $"{DateTime.Today:dd.MM.yyyy}";
|
||||
EmailSubjectInput.Text = App.Client.TextEmailSubject ?? "Rundschreiben";
|
||||
EmailBodyInput.Text = App.Client.TextEmailBody ?? "Sehr geehrtes Mitglied,\n\nim Anhang finden Sie das aktuelle Rundschreiben.\n\nIhre Winzergenossenschaft\n";
|
||||
}
|
||||
@@ -438,7 +438,7 @@ namespace Elwig.Windows {
|
||||
|
||||
private void Date_LostFocus(object sender, RoutedEventArgs evt) {
|
||||
var res = Validator.CheckDate((TextBox)sender, true);
|
||||
if (!res.IsValid) ((TextBox)sender).Text = $"{Utils.Today:dd.MM.yyyy}";
|
||||
if (!res.IsValid) ((TextBox)sender).Text = $"{DateTime.Today:dd.MM.yyyy}";
|
||||
}
|
||||
|
||||
private async Task UpdateRecipients(AppDbContext ctx) {
|
||||
@@ -958,6 +958,7 @@ namespace Elwig.Windows {
|
||||
m.EmailAddresses.OrderBy(a => a.Nr).Select(a => a.Address).ToArray(),
|
||||
subject, docs.Select(d => d.Title).ToArray()
|
||||
)]);
|
||||
await Task.Delay((int)(App.Config.SmtpWait * 1000));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -162,7 +162,7 @@ namespace Elwig.Windows {
|
||||
|
||||
private async void Menu_Database_Backup_Click(object sender, RoutedEventArgs evt) {
|
||||
try {
|
||||
var filename = InteractionService.SaveFile("Datenbank-Sicherung", $"database_{Utils.Today:yyyy-MM-dd}", "sql.zip");
|
||||
var filename = InteractionService.SaveFile("Datenbank-Sicherung", $"database_{DateTime.Today:yyyy-MM-dd}", "sql.zip");
|
||||
if (filename != null) {
|
||||
if (!filename.EndsWith(".sql.zip")) filename += ".sql.zip";
|
||||
Mouse.OverrideCursor = Cursors.Wait;
|
||||
@@ -200,8 +200,13 @@ namespace Elwig.Windows {
|
||||
return;
|
||||
Mouse.OverrideCursor = Cursors.Wait;
|
||||
await Task.Run(async () => {
|
||||
await SyncService.Download(App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
|
||||
if (App.Config.SyncMain) {
|
||||
await SyncService.Download(App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword, true);
|
||||
await SyncService.UploadModified(App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
|
||||
} else {
|
||||
await SyncService.Download(App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword, false);
|
||||
await SyncService.UploadBranchDeliveries(App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
|
||||
}
|
||||
});
|
||||
Mouse.OverrideCursor = null;
|
||||
}
|
||||
@@ -211,7 +216,7 @@ namespace Elwig.Windows {
|
||||
return;
|
||||
Mouse.OverrideCursor = Cursors.Wait;
|
||||
await Task.Run(async () => {
|
||||
await SyncService.Download(App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
|
||||
await SyncService.Download(App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword, App.Config.SyncMain);
|
||||
});
|
||||
Mouse.OverrideCursor = null;
|
||||
}
|
||||
@@ -229,6 +234,10 @@ namespace Elwig.Windows {
|
||||
private async void Menu_Sync_UploadModified_Click(object sender, RoutedEventArgs evt) {
|
||||
if (App.Config.SyncUrl == null)
|
||||
return;
|
||||
if (!App.Config.SyncMain) {
|
||||
InteractionService.ShowInformation("Mitglieder und Lieferungen hochladen", "Hochladen nicht möglich: Dieses Gerät ist nicht das Hauptgerät!");
|
||||
return;
|
||||
}
|
||||
Mouse.OverrideCursor = Cursors.Wait;
|
||||
await Task.Run(async () => {
|
||||
await SyncService.UploadModified(App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
|
||||
@@ -296,6 +305,11 @@ namespace Elwig.Windows {
|
||||
if (App.Config.SyncUrl == null)
|
||||
return;
|
||||
|
||||
if (!App.Config.SyncMain) {
|
||||
InteractionService.ShowInformation("Datenbank hochladen", "Hochladen nicht möglich: Dieses Gerät ist nicht das Hauptgerät!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!InteractionService.AskContinue("Datenbank hochladen", "Sind Sie wirklich sicher, dass Sie die Datenbank dieses\nGerätes hochladen möchten? Das sollte nur vom Hauptgerät aus passieren!"))
|
||||
return;
|
||||
|
||||
@@ -367,7 +381,11 @@ namespace Elwig.Windows {
|
||||
await Task.Delay(delay);
|
||||
var ch = false;
|
||||
using (var ctx = new AppDbContext()) {
|
||||
if (App.Config.SyncMain) {
|
||||
ch = await SyncService.ChangesAvailable(ctx, App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
|
||||
} else {
|
||||
ch = await SyncService.ChangesAvailable(ctx, App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword, default);
|
||||
}
|
||||
}
|
||||
await App.MainDispatcher.BeginInvoke(() => {
|
||||
if (ch) {
|
||||
@@ -520,9 +538,11 @@ namespace Elwig.Windows {
|
||||
App.HintContextChange();
|
||||
|
||||
using var ctx = new AppDbContext();
|
||||
var tbl = await MemberAreaComsData.ForSeason(ctx.MemberAreaComsRows, year);
|
||||
var tbl1 = await MemberAreaComTotalsData.ForSeason(ctx.MemberAreaComTotalsRows, year);
|
||||
var tbl2 = await MemberAreaComsData.ForSeason(ctx.MemberAreaComsRows, year);
|
||||
using var ods = new OdsFile(filename);
|
||||
await ods.AddTable(tbl);
|
||||
await ods.AddTable(tbl1);
|
||||
await ods.AddTable(tbl2);
|
||||
} catch (Exception exc) {
|
||||
InteractionService.ShowException(exc);
|
||||
}
|
||||
|
||||
@@ -198,7 +198,7 @@ namespace Elwig.Windows {
|
||||
|
||||
int mgnr;
|
||||
try {
|
||||
mgnr = await ViewModel.UpdateMemberHistory(ViewModel.SelectedHistoryEntry?.HistNr, IsEditing || ViewModel.DateNotice >= DateOnly.FromDateTime(Utils.Today).AddDays(-14));
|
||||
mgnr = await ViewModel.UpdateMemberHistory(ViewModel.SelectedHistoryEntry?.HistNr, IsEditing || ViewModel.DateNotice >= DateOnly.FromDateTime(DateTime.Today).AddDays(-14));
|
||||
App.HintContextChange();
|
||||
} catch (Exception exc) {
|
||||
InteractionService.ShowDbException("Geschäftsanteilbewegung aktualisieren", exc);
|
||||
|
||||
@@ -26,6 +26,7 @@ auto = true
|
||||
;username = ""
|
||||
;password = ""
|
||||
;from = mail@wg.at
|
||||
;wait = 0.5
|
||||
|
||||
;[scale.1]
|
||||
;type = SysTec-IT
|
||||
@@ -37,6 +38,8 @@ auto = true
|
||||
;limit = 3500
|
||||
; Enables scale logging
|
||||
;log = waage.log
|
||||
; Opt-out of auto time synchronization at startup
|
||||
;synctime = false
|
||||
|
||||
;[scale.B]
|
||||
;type = Avery-Async
|
||||
|
||||
@@ -13,7 +13,7 @@ About
|
||||
**Product:** Elwig
|
||||
**Description:** Electronic Management for Vintners' Cooperatives
|
||||
**Type:** ERP system
|
||||
**Version:** 1.1.0.0 ([Changelog](./CHANGELOG.md))
|
||||
**Version:** 1.1.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
|
||||
@@ -33,7 +33,7 @@ Packaging: [WiX Toolset](https://www.firegiant.com/wixtoolset/)
|
||||
**Produkt:** Elwig
|
||||
**Beschreibung:** Elektronische Winzergenossenschaftsverwaltung
|
||||
**Typ:** Warenwirtschaftssystem (ERP-System)
|
||||
**Version:** 1.1.0.0 ([Änderungsprotokoll](./CHANGELOG.md))
|
||||
**Version:** 1.1.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
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace Tests.E2ETests {
|
||||
Session.App.FindElement(By.Name("Rundschreiben")).Click();
|
||||
Thread.Sleep(Utils.WINDOW_OPEN_SLEEP);
|
||||
var window = Session.CreateWindowDriver("MailWindow");
|
||||
Assert.That(window.Title, Is.EqualTo($"Rundschreiben - Lese {Elwig.Helpers.Utils.Today.Year} - Elwig"));
|
||||
Assert.That(window.Title, Is.EqualTo($"Rundschreiben - Lese {DateTime.Today.Year} - Elwig"));
|
||||
window.Close();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ INSERT INTO delivery (mgnr, year, did, date, time, zwstid, lnr) VALUES
|
||||
(101, 2020, 1, '2020-10-01', NULL, 'X', 1),
|
||||
(101, 2020, 2, '2020-10-01', NULL, 'X', 2),
|
||||
(101, 2020, 3, '2020-10-01', NULL, 'X', 3);
|
||||
INSERT INTO delivery_part (year, did, dpnr, sortid, attrid, cultid, weight, kmw, qualid, hkid, kgnr, net_weight, manual_weighing, spl_check, scale_id, weighing_data, weighing_reason) VALUES
|
||||
INSERT INTO delivery_part (year, did, dpnr, sortid, attrid, cultid, weight, kmw, qualid, hkid, kgnr, net_weight, manual_weighing, spl_check, scale_terminal, weighing_data, weighing_reason) VALUES
|
||||
(2020, 1, 1, 'GV', 'K', NULL, 4000, 17, 'KAB', 'WLNO', 06109, TRUE, FALSE, FALSE, NULL, NULL, NULL),
|
||||
(2020, 1, 2, 'GV', NULL, NULL, 4000, 16, 'QUW', 'WLNO', 06109, TRUE, FALSE, FALSE, NULL, NULL, NULL),
|
||||
(2020, 2, 1, 'GV', NULL, 'B', 4000, 15, 'QUW', 'WLNO', 06109, TRUE, FALSE, FALSE, NULL, NULL, NULL),
|
||||
@@ -60,7 +60,7 @@ INSERT INTO delivery (mgnr, year, did, date, time, zwstid, lnr) VALUES
|
||||
(101, 2021, 1, '2021-10-01', NULL, 'X', 1),
|
||||
(101, 2021, 2, '2021-10-01', NULL, 'X', 2),
|
||||
(101, 2021, 3, '2021-10-01', NULL, 'X', 3);
|
||||
INSERT INTO delivery_part (year, did, dpnr, sortid, attrid, cultid, weight, kmw, qualid, hkid, kgnr, gebunden, net_weight, manual_weighing, spl_check, scale_id, weighing_data, weighing_reason) VALUES
|
||||
INSERT INTO delivery_part (year, did, dpnr, sortid, attrid, cultid, weight, kmw, qualid, hkid, kgnr, gebunden, net_weight, manual_weighing, spl_check, scale_terminal, weighing_data, weighing_reason) VALUES
|
||||
(2021, 1, 1, 'GV', 'K', NULL, 4000, 17, 'KAB', 'WLNO', 06109, TRUE, TRUE, FALSE, FALSE, NULL, NULL, NULL),
|
||||
(2021, 1, 2, 'GV', NULL, NULL, 4000, 16, 'QUW', 'WLNO', 06109, FALSE, TRUE, FALSE, FALSE, NULL, NULL, NULL),
|
||||
(2021, 2, 1, 'GV', NULL, 'B', 4000, 15, 'QUW', 'WLNO', 06109, TRUE, TRUE, FALSE, FALSE, NULL, NULL, NULL),
|
||||
|
||||
@@ -39,7 +39,7 @@ INSERT INTO delivery (mgnr, year, did, date, time, zwstid, lnr) VALUES
|
||||
(104, 2020, 11, '2020-10-03', '14:39:22', 'X', 2),
|
||||
(104, 2020, 12, '2020-10-03', '15:15:41', 'X', 3);
|
||||
|
||||
INSERT INTO delivery_part (year, did, dpnr, sortid, attrid, cultid, weight, kmw, qualid, hkid, kgnr, net_weight, manual_weighing, spl_check, scale_id, weighing_data, weighing_reason) VALUES
|
||||
INSERT INTO delivery_part (year, did, dpnr, sortid, attrid, cultid, weight, kmw, qualid, hkid, kgnr, net_weight, manual_weighing, spl_check, scale_terminal, weighing_data, weighing_reason) VALUES
|
||||
(2020, 1, 1, 'GV', NULL, NULL, 3219, 15.0, 'QUW', 'WLNO', 06109, TRUE, FALSE, FALSE, '1', '{"id":"321","nr":321,"gross_weight":3219,"tare_weight":0,"net_weight":3219,"date":"2020-10-01","time":"09:02:46"}', NULL),
|
||||
(2020, 2, 1, 'GV', 'K', NULL, 2987, 17.5, 'KAB', 'WLNO', 06109, TRUE, FALSE, FALSE, NULL, NULL, NULL),
|
||||
(2020, 2, 2, 'GV', 'K', NULL, 1873, 17.7, 'KAB', 'WLNO', 06109, TRUE, FALSE, FALSE, NULL, NULL, NULL),
|
||||
|
||||
@@ -76,7 +76,7 @@ INSERT INTO delivery (mgnr, year, did, date, time, zwstid, lnr) VALUES
|
||||
(101, 2023, 18, '2023-10-10', NULL, 'X', 2),
|
||||
(101, 2023, 19, '2023-10-10', NULL, 'X', 3);
|
||||
|
||||
INSERT INTO delivery_part (year, did, dpnr, sortid, attrid, cultid, weight, kmw, qualid, hkid, kgnr, net_weight, manual_weighing, spl_check, scale_id, weighing_data, weighing_reason) VALUES
|
||||
INSERT INTO delivery_part (year, did, dpnr, sortid, attrid, cultid, weight, kmw, qualid, hkid, kgnr, net_weight, manual_weighing, spl_check, scale_terminal, weighing_data, weighing_reason) VALUES
|
||||
(2021, 1, 1, 'GV', NULL, NULL, 3500, 15.0, 'QUW', 'WLNO', 15224, TRUE, FALSE, FALSE, NULL, NULL, NULL),
|
||||
(2021, 2, 1, 'GV', NULL, NULL, 4000, 17.0, 'KAB', 'WLNO', 15224, TRUE, FALSE, FALSE, NULL, NULL, NULL),
|
||||
(2021, 2, 2, 'GV', NULL, NULL, 4000, 16.0, 'QUW', 'WLNO', 15224, TRUE, FALSE, FALSE, NULL, NULL, NULL),
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@
|
||||
</Target>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.8.1" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.9.0" />
|
||||
<PackageReference Include="Appium.WebDriver" Version="4.4.5" />
|
||||
<PackageReference Include="NReco.PdfRenderer" Version="1.6.0" />
|
||||
<PackageReference Include="NUnit" Version="4.6.1" />
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace Tests.UnitTests.DocumentTests {
|
||||
"""));
|
||||
Assert.That(text, Contains.Substring("0123463")); // Betriebsnummer
|
||||
Assert.That(text, Contains.Substring("pauschaliert"));
|
||||
Assert.That(text, Contains.Substring($"Wolkersdorf, am {Elwig.Helpers.Utils.Today:dd.MM.yyyy}"));
|
||||
Assert.That(text, Contains.Substring($"Wolkersdorf, am {DateTime.Today:dd.MM.yyyy}"));
|
||||
Assert.That(text, Contains.Substring("Traubengutschrift Max Mustermann – Probevariante"));
|
||||
Assert.That(text, Contains.Substring("AT81 1234 5678 9012 3457"));
|
||||
Assert.That(text, Contains.Substring("""
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace Tests.UnitTests.DocumentTests {
|
||||
"""));
|
||||
Assert.That(text, Contains.Substring("0123463")); // Betriebsnummer
|
||||
Assert.That(text, Contains.Substring("pauschaliert"));
|
||||
Assert.That(text, Contains.Substring($"Wolkersdorf, am {Elwig.Helpers.Utils.Today:dd.MM.yyyy}"));
|
||||
Assert.That(text, Contains.Substring($"Wolkersdorf, am {DateTime.Today:dd.MM.yyyy}"));
|
||||
Assert.That(text, Contains.Substring("Anlieferungsbestätigung 2020"));
|
||||
Assert.That(text, Contains.Substring("""
|
||||
20201001X001 1 Grüner Veltliner QUW 73 15,0 ungeb.: 3 219 3 219 ☑
|
||||
|
||||
@@ -1 +1 @@
|
||||
curl --fail -s -L "https://elwig.at/files/create.sql?v=40" -u "elwig:ganzGeheim123!" -o "Resources\Sql\Create.sql"
|
||||
curl --fail -s -L "https://elwig.at/files/create.sql?v=41" -u "elwig:ganzGeheim123!" -o "Resources\Sql\Create.sql"
|
||||
|
||||
Reference in New Issue
Block a user