Compare commits

..

36 Commits

Author SHA1 Message Date
lorenz.stechauner b58dee6d3f Bump version to 1.0.3.4
Deploy / Build and Deploy (push) Successful in 2m28s
2026-02-19 19:33:22 +01:00
lorenz.stechauner 0e2b004b0d Elwig: Update dependencies
Test / Run tests (push) Successful in 2m46s
2026-02-19 19:26:39 +01:00
lorenz.stechauner 19c3322ef2 Tests: Update dependencies 2026-02-19 19:26:29 +01:00
lorenz.stechauner 6f081811c4 MailWindow: Allow users to double click on avaiable/selected documents
Test / Run tests (push) Successful in 2m58s
2026-02-19 18:10:26 +01:00
lorenz.stechauner 432c511b85 Billing: Create credit notes only for members who receive a payment 2026-02-19 18:10:22 +01:00
lorenz.stechauner 7e22759c33 PaymentVariantsWindow: Never lock seasons
Test / Run tests (push) Successful in 2m27s
2026-02-19 16:12:54 +01:00
lorenz.stechauner a47904cf0b SyncService: Catch exceptions in ChangesAvailable()
Test / Run tests (push) Successful in 3m16s
2026-02-19 15:59:23 +01:00
lorenz.stechauner 6818491ae3 Export: Fix importing delivery parts with no kgnr 2026-02-19 15:58:51 +01:00
lorenz.stechauner 23db4de1ee Database: Fix xtime/mtime for delivery parts
Test / Run tests (push) Successful in 3m17s
2026-02-19 15:31:36 +01:00
lorenz.stechauner 9e5f709d42 DeliveryConfirmation: Show 'Davon abgewertet' below total sum 2026-02-19 15:26:09 +01:00
lorenz.stechauner 4cd7ef85a1 Printing: Replace PdfiumViewer with native pdfium.dll binary
Test / Run tests (push) Successful in 3m47s
2026-02-18 23:02:18 +01:00
lorenz.stechauner 2c0b000073 MainWindow: Fix Tooltip for 'Sorten-/Qual.aufschlüssel.' Button
Test / Run tests (push) Successful in 2m31s
2026-02-18 23:01:35 +01:00
lorenz.stechauner f1737af2a2 Bump version to 1.0.3.3
Test / Run tests (push) Successful in 2m26s
Deploy / Build and Deploy (push) Successful in 2m21s
2026-02-05 23:52:33 +01:00
thomas.hilscher 8f423e3e92 Pdfium: Use updated fork of PdfiumViewer
Test / Run tests (push) Successful in 2m46s
2026-02-05 23:21:28 +01:00
thomas.hilscher c8911c0acb Pdfium: Explicitly add WindowsForms after dotnet 10 upgrade
Test / Run tests (push) Successful in 3m5s
2026-02-05 22:50:06 +01:00
lorenz.stechauner baf598b76c Bump version to 1.0.3.2
Test / Run tests (push) Successful in 3m1s
Deploy / Build and Deploy (push) Successful in 2m3s
2026-02-04 16:34:52 +01:00
lorenz.stechauner 7adc9f89e4 Printing/Html: Try to hotfix null pointer error
Test / Run tests (push) Has been cancelled
2026-02-04 16:33:21 +01:00
lorenz.stechauner dde808df6a Bump version to 1.0.3.1
Test / Run tests (push) Successful in 2m28s
Deploy / Build and Deploy (push) Successful in 2m16s
2026-01-19 10:58:10 +01:00
lorenz.stechauner e63de0d867 Setup: Try to hotfix VC redist version incompatability
Deploy / Build and Deploy (push) Failing after 44s
2026-01-19 10:52:53 +01:00
lorenz.stechauner e9e90b1e98 Bump version to 1.0.3.0
Test / Run tests (push) Successful in 3m4s
Deploy / Build and Deploy (push) Successful in 2m8s
2026-01-16 14:43:52 +01:00
lorenz.stechauner 640dbf705e Printing/Pdf: Fix detection of WinziPrint.exe to isolate tests properly
Test / Run tests (push) Successful in 2m11s
2026-01-16 01:26:35 +01:00
lorenz.stechauner 42121fe7da Elwig: Update dependencies
Test / Run tests (push) Has been cancelled
2026-01-16 00:35:50 +01:00
lorenz.stechauner d45c3f867f Tests: Update dependencies 2026-01-16 00:35:38 +01:00
lorenz.stechauner a90be2644d [#50] MailWindow: Add button to cancel document generation
Test / Run tests (push) Has been cancelled
2026-01-16 00:22:11 +01:00
lorenz.stechauner 01739ba42e ClientParameters: Fix storing of MailSendPostal and MailSendEmail 2026-01-16 00:20:15 +01:00
lorenz.stechauner 7bea4d9ee0 BillingVariant: Fix NULL/0 error introduced in c7a2f2241d
Test / Run tests (push) Successful in 2m12s
2026-01-15 17:56:12 +01:00
lorenz.stechauner b6497fd422 PaymentVariantsWindow: Select last variant by default and ask user before deleting
Test / Run tests (push) Successful in 2m33s
2026-01-15 14:03:00 +01:00
lorenz.stechauner f141485537 Documents: Only show header and footer on BusinessDocuments 2026-01-15 14:01:21 +01:00
lorenz.stechauner b31603554a Document: Add IsPreview to indicate that a document may only be viewed by internal staff
Test / Run tests (push) Successful in 2m51s
2026-01-15 13:26:44 +01:00
lorenz.stechauner 90def81cc5 PaymentVariantSummary: Fix statistical sum for geb weight
Test / Run tests (push) Successful in 2m52s
2026-01-14 09:15:27 +01:00
lorenz.stechauner 87903227b5 [#66] Services: Add filters for import/export/upload 2026-01-03 20:49:00 +01:00
lorenz.stechauner 6d6776f0f9 DeliveryAdminWindow: Complete tooltip in search bar and warning when no season is found 2026-01-03 20:48:39 +01:00
lorenz.stechauner bf3cc2ea1e [#71] Weighing: Fix reconnection behaviour when COM port is connected/disconnected 2026-01-03 20:48:39 +01:00
lorenz.stechauner c1697dc4f3 [#66] MainWindow: Merge both sync buttons into a single one 2026-01-03 20:47:51 +01:00
lorenz.stechauner 3b335a568e AbbDbContext: Move SqliteConnection extensions to Extensions class 2026-01-03 20:47:45 +01:00
lorenz.stechauner beacdab54f [#66] Services: Add SyncService 2026-01-03 20:47:14 +01:00
43 changed files with 576 additions and 161 deletions
+105 -1
View File
@@ -2,6 +2,110 @@
Changelog
=========
[v1.0.3.4][v1.0.3.4] (2026-02-19) {#v1.0.3.4}
---------------------------------------------
### Neue Funktionen {#v1.0.3.4-features}
* Bei Anlieferungsbestätigungen (`DeliveryConfirmation`) wird nun auch die Summe aller abgewerteten Lieferungen angeführt. (9e5f709d42)
* Bei der Auszahlung werden Traubengutschriften (`CreditNote`) nur noch für Mitglieder erstellt, die einen positiven Betrag ausgezahlt bekommen. (432c511b85)
### Behobene Fehler {#v1.0.3.4-bugfixes}
* Im Haupt-Fenster (`MainWindow`) wurde der Tooltip für den Knopf _Sorten-/Qual.aufschlüssel_ korrigiert. (2c0b000073)
* Falsch gesetzte `xtime` und `mtime` bei Lieferungen korrigiert. (23db4de1ee)
* Beim Import von Lieferungen ohne `kgnr` tritt nun kein Fehler auf. (6818491ae3)
* Beim Abfragen von neuen Daten zum Synchronisieren werden alle Fehler abgefangen. (a47904cf0b)
### Sonstiges {#v1.0.3.4-misc}
* Pdfium wird nun direkt importiert (anstatt über PdfiumViewer). (4cd7ef85a1)
* Auszahlungsvarianten von vergangenen Saisons sind nun nicht mehr für eine Bearbeitung gesperrt. (7e22759c33)
* Im Rundschreiben-Fenster (`MailWindow`) ist es nun möglich Dokumente durch Doppelklick an-/abzuwählen. (6f081811c4)
* Abhängigkeiten aktualisiert. (19c3322ef2, 0e2b004b0d)
[v1.0.3.4]: https://git.necronda.net/winzer/elwig/releases/tag/v1.0.3.4
[v1.0.3.3][v1.0.3.3] (2026-02-05) {#v1.0.3.3}
---------------------------------------------
### Behobene Fehler {#v1.0.3.3-bugfixes}
* Hotfix: Probleme beim Drucken seit der Installation von [v1.0.3.0](#v1.0.3.0). (c8911c0acb, 8f423e3e92)
[v1.0.3.3]: https://git.necronda.net/winzer/elwig/releases/tag/v1.0.3.3
[v1.0.3.2][v1.0.3.2] (2026-02-04) {#v1.0.3.2}
---------------------------------------------
### Behobene Fehler {#v1.0.3.2-bugfixes}
* Hotfix: Probleme bei der Installation von [v1.0.3.0](#v1.0.3.0). (7adc9f89e4)
[v1.0.3.2]: https://git.necronda.net/winzer/elwig/releases/tag/v1.0.3.2
[v1.0.3.1][v1.0.3.1] (2026-01-19) {#v1.0.3.1}
---------------------------------------------
### Behobene Fehler {#v1.0.3.1-bugfixes}
* Hotfix: Probleme bei der Installation von [v1.0.3.0](#v1.0.3.0). (e63de0d867)
[v1.0.3.1]: https://git.necronda.net/winzer/elwig/releases/tag/v1.0.3.1
[v1.0.3.0][v1.0.3.0] (2026-01-16) {#v1.0.3.0}
---------------------------------------------
### Neue Funktionen {#v1.0.3.0-features}
* Bei Zu-/Abschlägen ist es nun möglich den konkreten Wert dieser auf Lieferscheinen nicht anzuzeigen (Stammdaten -> Saisons). (495aa8a691)
* Bei Teillieferungen kann nun die Art der Anlieferung angegeben werden: Planenwagen/Kipper, Lesewagen, Kiste(n). (bf6297f63b, 3419113dec, 6d6776f0f9)
* Im Lieferungen-Fenster (`DeliveryAdminWindow`) können nun die Gesamtmengen der gefilterten Lieferungen nach Mitglied und Sorte als Excel-Liste exportiert werden ("Liefermengen"). ([#73][i73], e97c29db43)
* Im Datenbankabfragen-Fenster (`QueryWindow`) gibt es die Möglichkeit die Ergebnisse als CSV-Datei zu exportieren. (9af498287d, 5cec5b3556)
* PDF-Dokumente wurden überarbeitet:
* Traubengutschriften können nur noch ausgedruckt bzw. verschickt werden, wenn die zugehörige Auszahlungsvariante festgesetzt ist. (b31603554a)
* Auf Dokumenten für interne Verwendung (alle außer an Mitglieder adressierte) wurden Kopf- und Fußzeile auf ein Minimum beschränkt. (f141485537)
* Das Synchronisieren zwischen Zweigstellen ist für den Benutzer nun wesentlich vereinfacht. Geänderte Daten von Mitgliedern, Flächenbindungen oder Lieferungen werden beim Synchronisieren automatsich hochgeladen bzw. heruntergeladen. ([#66][i66], 3b335a568e)
* Im Rundschreiben-Fenster (`MailWindow`) wurde ein Knopf zum Abbrechen des Generierens hinzugefügt. ([#50][i50])
### Behobene Fehler {#v1.0.3.0-bugfixes}
* Einzelne (nicht über das Rundschreiben-Fenster) verschickte E-Mails werde korrekt im Ausgangsprotokoll angeführt. (ac6d559e5d)
* Bei automatischen Datenbank-Updates sind auftretende Fehler ignoriert worden. (f228ba3019)
* Beim Aufteilen von Lieferungen sind Zu-/Abschläge nicht auf neu erstellen Teillieferungen übernommen worden. (da05a49e10)
* Das Verbinden und Trennen von Waagen mittels Serial-/COM-Port ist nun bei laufendem Programm möglich. ([#71][i71])
* In den Auszahlungsvarianten-Daten (`PaymentVariantSummary`) ist die statistische Summe der gebundenen und ungebundenen Menge ohne die Spalte _attributlos gebunden_ berechnet worden. (90def81cc5)
* Seit [v0.13.7](#v0.13.7) (2025-01-21) wurde auch bei der ersten Auszahlung der Saison ein "Bisher berücksichtigt: € 0,00" auf den Traubengutschriften angeführt. (7bea4d9ee0)
* Das Speichern der Parameter `MAIL_SEND_POSTAL` und `MAIL_SEND_EMAIL` war fehlerhaft. (01739ba42e)
* Bessere Isolation der automatisierten Dokumenten-Tests. (640dbf705e)
### Sonstiges {#v1.0.3.0-misc}
* Im Lieferungen-Fenster (`DeliveryAdminWindow`) wird bei Zu-/Abschlägen nur "Alle" angezeigt, wenn mehr als 1 ausgewählt sind. (811916a8b9)
* Im Auszahlungsvarianten-Fenster (`PaymentVariantsWindow`) wird die letzte Variante standardmäßig ausgewählt und beim Löschen wird um Bestätigung gebeten. (b6497fd422)
* Abhängigkeiten aktualisiert. (889a17b21c, 9b37330362, 3b6333a6a2, d45c3f867f, 42121fe7da)
[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
[i71]: https://git.necronda.net/winzer/elwig/issues/71
[i73]: https://git.necronda.net/winzer/elwig/issues/73
[v1.0.2.0][v1.0.2.0] (2025-11-10) {#v1.0.2.0}
---------------------------------------------
@@ -226,7 +330,7 @@ Changelog
* Bei Traubengutschriften (`CreditNote`) wurde der Rebelzuschlag immer angeführt, auch wenn dieser in der zugrundeliegenden Berechnung nicht berücksichtigt wurde. (336aef5c70)
* In den Variantendaten einer Auszahlungsvariante (`PaymentVariantSummary`) wurde neben den Spalten _gebunden_ und _ungebunden_ noch _attributlos gebunden_ hinzugefügt. Ohne diese neue Spalte wären die Werte der anderen beiden falsch. ([#58][i58])
* Das erste Laden des Ausgangs-Protokoll-Fensters (`MailLogWindow`) hat nicht funktioniert. ([#65][i65])
* Im Lieferungen-Fenster (`DeliveryAdminWindow`) und im Mitglieder-Fenster (`MemberAdminWindow`) wird der Tool-Tip für Gewicht/Gradation mit korrektem Layout angezeigt. (e9f389b885)
* Im Lieferungen-Fenster (`DeliveryAdminWindow`) und im Mitglieder-Fenster (`MemberAdminWindow`) wird der Tooltip für Gewicht/Gradation mit korrektem Layout angezeigt. (e9f389b885)
* Bei Traubengutschriften (`CreditNote`) werden längere Freitexte vollständig angezeigt statt abgeschnitten. ([#62][i62])
### Sonstiges {#v1.0.0.0-misc}
+10
View File
@@ -19,6 +19,16 @@ namespace Elwig.Documents {
Member = m;
Location = App.BranchLocation;
IncludeSender = includeSender;
var c = App.Client;
Header = $"<div class='name'>{c.Name}</div><div class='suffix'>{c.NameSuffix}</div><div class='type'>{c.NameTypeFull}</div>";
Footer = Utils.GenerateFooter("<br/>", " \u00b7 ")
.Item(c.NameFull).NextLine()
.Item(c.Address).Item($"{c.Plz} {c.Ort}").Item("Österreich").Item("Tel.", c.PhoneNr).Item("Fax", c.FaxNr).NextLine()
.Item(c.EmailAddress != null ? $"<a href=\"mailto:{c.Name} {c.NameSuffix} <{c.EmailAddress}>\">{c.EmailAddress}</a>" : null)
.Item(c.Website != null ? $"<a href=\"http://{c.Website}/\">{c.Website}</a>" : null)
.Item("Betriebs-Nr.", c.LfbisNr).Item("Bio-KSt.", c.OrganicAuthority).NextLine()
.Item("UID", c.UstIdNr).Item("BIC", c.Bic).Item("IBAN", c.Iban)
.ToString();
var uid = (m.UstIdNr ?? "-") + (m.IsBuchführend ? "" : " <i>(pauschaliert)</i>");
Aside = $"<table><colgroup><col span='1' style='width: 22.5mm;'/><col span='1' style='width: 42.5mm;'/></colgroup>" +
$"<thead><tr><th colspan='2'>Mitglied</th></tr></thead><tbody>" +
+1
View File
@@ -39,6 +39,7 @@ namespace Elwig.Documents {
Data = data;
Payment = p;
Credit = p.Credit;
IsPreview = Payment == null || Credit == null;
var season = p.Variant.Season;
if (considerCustomModifiers) {
CustomPayment = ctx.CustomPayments.Find(p.Year, p.MgNr);
+1 -1
View File
@@ -2,7 +2,7 @@
h1 {
text-align: center;
font-size: 24pt;
margin-top: 10mm;
margin-top: 0;
margin-bottom: 2mm;
}
@@ -100,6 +100,12 @@
<td></td>
<td></td>
</tr>
<tr>
<td colspan="8">Davon abgewertet:</td>
<td colspan="2" class="number">@($"{Model.Data.Rows.Where(p => p.IsDepreciated).Sum(p => p.Weight):N0}")</td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
@Raw(BusinessDocument.PrintSortenaufteilung(Model.MemberStats))
+1 -1
View File
@@ -2,7 +2,7 @@
h1 {
text-align: center;
font-size: 24pt;
margin-top: 10mm;
margin-top: 0;
margin-bottom: 2mm;
}
+1 -1
View File
@@ -2,7 +2,7 @@
h1 {
text-align: center;
font-size: 24pt;
margin-top: 10mm;
margin-top: 0;
margin-bottom: 2mm;
}
+44 -35
View File
@@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Linq;
using Elwig.Helpers.Printing;
using MimeKit;
using System.Threading;
namespace Elwig.Documents {
public abstract partial class Document : IDisposable {
@@ -18,10 +19,11 @@ namespace Elwig.Documents {
protected string? _pdfPath;
protected string? PdfPath => _pdfPath ?? _pdfFile?.FilePath;
public int? TotalPages { get; private set; }
public int? Pages => TotalPages / (DoublePaged ? 2 : 1);
public int? Pages => TotalPages / (IsDoublePaged ? 2 : 1);
public bool ShowFoldMarks = App.Config.Debug;
public bool DoublePaged = false;
public bool IsDoublePaged = false;
public bool IsPreview = false;
public string DocumentsPath;
public int CurrentNextSeason;
@@ -38,15 +40,8 @@ namespace Elwig.Documents {
CurrentNextSeason = Utils.CurrentNextSeason;
Title = title;
Author = c.NameFull;
Header = $"<div class='name'>{c.Name}</div><div class='suffix'>{c.NameSuffix}</div><div class='type'>{c.NameTypeFull}</div>";
Footer = Utils.GenerateFooter("<br/>", " \u00b7 ")
.Item(c.NameFull).NextLine()
.Item(c.Address).Item($"{c.Plz} {c.Ort}").Item("Österreich").Item("Tel.", c.PhoneNr).Item("Fax", c.FaxNr).NextLine()
.Item(c.EmailAddress != null ? $"<a href=\"mailto:{c.Name} {c.NameSuffix} <{c.EmailAddress}>\">{c.EmailAddress}</a>" : null)
.Item(c.Website != null ? $"<a href=\"http://{c.Website}/\">{c.Website}</a>" : null)
.Item("Betriebs-Nr.", c.LfbisNr).Item("Bio-KSt.", c.OrganicAuthority).NextLine()
.Item("UID", c.UstIdNr).Item("BIC", c.Bic).Item("IBAN", c.Iban)
.ToString();
Header = "";
Footer = Utils.GenerateFooter("<br/>", " \u00b7 ").Item(c.NameFull).ToString();
Date = DateOnly.FromDateTime(Utils.Today);
}
@@ -104,7 +99,7 @@ namespace Elwig.Documents {
return await Html.CompileRenderAsync(name, this); ;
}
public async Task Generate(IProgress<double>? progress = null) {
public async Task Generate(CancellationToken? cancelToken = null, IProgress<double>? progress = null) {
if (_pdfFile != null)
return;
progress?.Report(0.0);
@@ -114,36 +109,50 @@ namespace Elwig.Documents {
var pdf = new TempFile("pdf");
var tmpHtmls = new List<TempFile>();
var tmpFiles = new List<string>();
var n = m.Documents.Count();
int i = 0;
foreach (var doc in m.Documents) {
if (doc is PdfDocument) {
tmpFiles.Add(doc.PdfPath!);
continue;
try {
var n = m.Documents.Count();
int i = 0;
foreach (var doc in m.Documents) {
if (doc is PdfDocument) {
tmpFiles.Add(doc.PdfPath!);
continue;
}
if (cancelToken?.IsCancellationRequested ?? false)
throw new OperationCanceledException("Dokumentenerzeugung abgebrochen!");
var tmpHtml = new TempFile("html");
await File.WriteAllTextAsync(tmpHtml.FilePath, await doc.Render(), Utils.UTF8);
tmpHtmls.Add(tmpHtml);
tmpFiles.Add((doc is Letterhead ? "#" : "") + tmpHtml.FileName);
i++;
progress?.Report(GenerationProportion * 100 * i / n);
}
progress?.Report(GenerationProportion * 100);
var pages = await Pdf.Convert(tmpFiles, pdf.FileName, IsDoublePaged, cancelToken, new Progress<double>(v => progress?.Report(GenerationProportion * 100 + v * (1 - GenerationProportion))));
TotalPages = pages.Pages;
_pdfFile = pdf;
} catch {
pdf.Dispose();
throw;
} finally {
foreach (var tmp in tmpHtmls) {
tmp.Dispose();
}
var tmpHtml = new TempFile("html");
await File.WriteAllTextAsync(tmpHtml.FilePath, await doc.Render(), Utils.UTF8);
tmpHtmls.Add(tmpHtml);
tmpFiles.Add((doc is Letterhead ? "#" : "") + tmpHtml.FileName);
i++;
progress?.Report(GenerationProportion * 100 * i / n);
}
progress?.Report(GenerationProportion * 100);
var pages = await Pdf.Convert(tmpFiles, pdf.FileName, DoublePaged, new Progress<double>(v => progress?.Report(GenerationProportion * 100 + v * (1 - GenerationProportion))));
TotalPages = pages.Pages;
foreach (var tmp in tmpHtmls) {
tmp.Dispose();
}
_pdfFile = pdf;
} else {
if (cancelToken?.IsCancellationRequested ?? false)
throw new OperationCanceledException("Dokumentenerzeugung abgebrochen!");
var pdf = new TempFile("pdf");
using (var tmpHtml = new TempFile("html")) {
try {
using var tmpHtml = new TempFile("html");
await File.WriteAllTextAsync(tmpHtml.FilePath, await Render(), Utils.UTF8);
progress?.Report(50.0);
var pages = await Pdf.Convert(tmpHtml.FilePath, pdf.FilePath, DoublePaged);
var pages = await Pdf.Convert(tmpHtml.FilePath, pdf.FilePath, IsDoublePaged, cancelToken);
TotalPages = pages.Pages;
_pdfFile = pdf;
} catch {
pdf.Dispose();
throw;
}
_pdfFile = pdf;
}
progress?.Report(100.0);
}
@@ -155,7 +164,7 @@ namespace Elwig.Documents {
public async Task Print(int copies = 1) {
if (PdfPath == null) throw new InvalidOperationException("Pdf file has not been generated yet");
await Pdf.Print(PdfPath, copies, DoublePaged);
await Pdf.Print(PdfPath, copies, IsDoublePaged);
}
public void Show() {
+4 -4
View File
@@ -10,7 +10,7 @@
<link rel="stylesheet" href="file:///@Raw(Model.DocumentsPath)\Document.css" />
<link rel="stylesheet" href="file:///@Raw(Model.DocumentsPath)\Document.Page.css" />
<link rel="stylesheet" href="file:///@Raw(Model.DocumentsPath)\Document.Table.css" />
@if (Model.DoublePaged) {
@if (Model.IsDoublePaged) {
<style>
@@page :left {
margin: 25mm 25mm 35mm 20mm;
@@ -34,14 +34,14 @@
<div class="pre-footer">
<span class="date">@($"{Model.Date:dddd, d. MMMM yyyy}")</span>
<span class="doc-id">@Model.DocumentId</span>
<span class="page"></span>
<span><span class="page"></span>@Raw(Model.IsPreview ? " <b>(vorläufig)</b>" : "")</span>
</div>
<footer>@Raw(Model.Footer)</footer>
</div>
@if (Model.DoublePaged) {
@if (Model.IsDoublePaged) {
<div class="footer-wrapper left">
<div class="pre-footer">
<span class="page"></span>
<span>@Raw(Model.IsPreview ? "<b>(vorläufig)</b> " : "")<span class="page"></span></span>
<span class="doc-id">@Model.DocumentId</span>
<span class="date">@($"{Model.Date:dddd, d. MMMM yyyy}")</span>
</div>
+1 -1
View File
@@ -2,7 +2,7 @@
h1 {
text-align: center;
font-size: 24pt;
margin-top: 10mm;
margin-top: 0;
margin-bottom: 2mm;
}
+1
View File
@@ -27,6 +27,7 @@ namespace Elwig.Documents {
Data = data;
CurrencySymbol = v.Season.Currency.Symbol ?? v.Season.Currency.Code;
MemberNum = v.Credits.Count;
IsPreview = MemberNum == 0;
DeliveryNum = v.DeliveryPartPayments.DistinctBy(p => p.DeliveryPart.Delivery).Count();
DeliveryPartNum = v.DeliveryPartPayments.Count;
ModifierStat = AppDbContext.GetModifierStats(v.Year, v.AvNr).GetAwaiter().GetResult();
+2 -2
View File
@@ -164,14 +164,14 @@
<td class="number">@Utils.GetSign(considered)</td>
<td class="number"><span class="fleft">@Model.CurrencySymbol</span>@($"{Math.Abs(considered):N2}")</td>
<th class="lborder">Menge (gebunden):</th>
<td colspan="2" class="number">@($"{Model.Data.Rows.Sum(r => r.Geb.Weight):N0}") kg</td>
<td colspan="2" class="number">@($"{Model.Data.Rows.Sum(r => r.Geb.Weight + r.LowGeb.Weight):N0}") kg</td>
</tr>
<tr>
<th colspan="2">Auszahlungsbetrag:</th>
<td class="number tborder"></td>
<td class="number tborder"><span class="fleft">@Model.CurrencySymbol</span>@($"{totalSum:N2}")</td>
<th class="lborder">Gesamtmenge:</th>
<td colspan="2" class="number tborder">@($"{Model.Data.Rows.Sum(r => r.Ungeb.Weight + r.Geb.Weight):N0}") kg</td>
<td colspan="2" class="number tborder">@($"{Model.Data.Rows.Sum(r => r.Ungeb.Weight + r.LowGeb.Weight + r.Geb.Weight):N0}") kg</td>
</tr>
</tbody>
</table>
+1 -1
View File
@@ -2,7 +2,7 @@
h1 {
text-align: center;
font-size: 24pt;
margin-top: 10mm;
margin-top: 0;
margin-bottom: 2mm;
}
+1 -1
View File
@@ -2,7 +2,7 @@
h1 {
text-align: center;
font-size: 24pt;
margin-top: 10mm;
margin-top: 0;
margin-bottom: 2mm;
}
+13 -13
View File
@@ -3,11 +3,13 @@
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net10.0-windows</TargetFramework>
<PlatformTarget>x64</PlatformTarget>
<Nullable>enable</Nullable>
<UseWPF>true</UseWPF>
<UseWindowsForms>true</UseWindowsForms>
<PreserveCompilationContext>true</PreserveCompilationContext>
<ApplicationIcon>Resources\Images\Elwig.ico</ApplicationIcon>
<Version>1.0.2.0</Version>
<Version>1.0.3.4</Version>
<SatelliteResourceLanguages>de-AT</SatelliteResourceLanguages>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<ApplicationManifest>app.manifest</ApplicationManifest>
@@ -21,24 +23,22 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="bblanchon.PDFium.Win32" Version="147.0.7690" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
<PackageReference Include="LinqKit" Version="1.3.9" />
<PackageReference Include="MailKit" Version="4.14.1" />
<PackageReference Include="LinqKit" Version="1.3.11" />
<PackageReference Include="MailKit" Version="4.15.0" />
<PackageReference Include="Microsoft.AspNetCore.Razor.Language" Version="6.0.36" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="10.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Ini" Version="10.0.0" />
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.3595.46" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="10.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.3" />
<PackageReference Include="Microsoft.Extensions.Configuration.Ini" Version="10.0.3" />
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.3800.47" />
<PackageReference Include="NJsonSchema" Version="11.5.2" />
<PackageReference Include="PdfiumViewer" Version="2.13.0" />
<PackageReference Include="PdfiumViewer.Native.x86_64.no_v8-no_xfa" Version="2018.4.8.256" />
<PackageReference Include="RazorLight" Version="2.3.1" />
<PackageReference Include="ScottPlot.WPF" Version="5.1.57" />
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="3.0.2" />
<PackageReference Include="System.IO.Hashing" Version="10.0.0" />
<PackageReference Include="System.IO.Ports" Version="10.0.0" />
<PackageReference Include="System.Management" Version="10.0.0" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="10.0.0" />
<PackageReference Include="System.IO.Hashing" Version="10.0.3" />
<PackageReference Include="System.IO.Ports" Version="10.0.3" />
<PackageReference Include="System.Management" Version="10.0.3" />
</ItemGroup>
</Project>
+1 -1
View File
@@ -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 = 36;
public static readonly int RequiredSchemaVersion = 37;
private static int VersionOffset = 0;
+3 -3
View File
@@ -54,14 +54,14 @@ namespace Elwig.Helpers.Billing {
m.mgnr,
v.avnr,
ROUND(p.amount / POW(10, s.precision - 2)) AS net_amount,
IIF(lc.amount >= 0, ROUND(lp.amount / POW(10, s.precision - 2)), 0) AS prev_net_amount,
IIF(lc.amount < 0, 0, ROUND(lp.amount / POW(10, s.precision - 2))) AS prev_net_amount,
IIF(m.buchführend, s.vat_normal, s.vat_flatrate) AS vat,
ROUND(IIF({Data.ConsiderTotalPenalty}, COALESCE(b.total_penalty, 0), 0) / POW(10, s.precision - 2)) +
ROUND(IIF({Data.ConsiderContractPenalties}, COALESCE(u.total_penalty, 0), 0) / POW(10, 4 - 2)) +
ROUND(IIF({Data.ConsiderAutoBusinessShares}, -COALESCE(a.total_amount, 0), 0) / POW(10, s.precision - 2)) +
IIF({Data.ConsiderCustomModifiers}, COALESCE(x.amount, 0), 0)
AS modifiers,
IIF(lc.amount >= 0, lc.modifiers, 0) AS prev_modifiers
IIF(lc.amount < 0, 0, lc.modifiers) AS prev_modifiers
FROM season s
JOIN payment_variant v ON v.year = s.year
LEFT JOIN payment_variant l ON l.year = s.year
@@ -80,7 +80,7 @@ namespace Elwig.Helpers.Billing {
LEFT JOIN v_penalty_area_commitments u ON (u.year, u.mgnr) = (s.year, m.mgnr)
LEFT JOIN v_auto_business_shares a ON (a.year, a.mgnr) = (s.year, m.mgnr)
LEFT JOIN payment_custom x ON (x.year, x.mgnr) = (s.year, m.mgnr)
WHERE s.year = {Year} AND v.avnr = {AvNr};
WHERE s.year = {Year} AND v.avnr = {AvNr} AND p.amount > COALESCE(lp.amount, 0);
""");
await cnx.ExecuteBatch($"""
UPDATE payment_variant SET test_variant = FALSE WHERE (year, avnr) = ({Year}, {AvNr});
+4 -4
View File
@@ -206,15 +206,15 @@ namespace Elwig.Helpers {
case 1: orderingMemberList = "NAME"; break;
case 2: orderingMemberList = "KG"; break;
}
string mailSendPostal = "MGNR";
switch (MailOrdering) {
string mailSendPostal = "WISH";
switch (MailSendPostal) {
case 0: mailSendPostal = "NONE"; break;
case 1: mailSendPostal = "NO_EMAIL"; break;
case 2: mailSendPostal = "WISH"; break;
case 3: mailSendPostal = "ALL"; break;
}
string mailSendEmail = "MGNR";
switch (MailOrdering) {
string mailSendEmail = "WISH";
switch (MailSendEmail) {
case 0: mailSendEmail = "NONE"; break;
case 1: mailSendEmail = "WISH"; break;
case 2: mailSendEmail = "ALL"; break;
+4 -4
View File
@@ -783,15 +783,15 @@ namespace Elwig.Helpers.Export {
Comment = json["comment"]?.AsValue().GetValue<string>(),
ImportedAt = DateTime.Now,
}, json["parts"]!.AsArray().Select(p => p!.AsObject()).Select(p => {
var kgnr = p["kgnr"]!.AsValue().GetValue<int>();
var kgnr = p["kgnr"]?.AsValue().GetValue<int>();
var ried = p["ried"]?.AsValue().GetValue<string>();
WbRd? rd = null;
if (ried != null) {
var rde = riede.GetValueOrDefault(kgnr, []);
if (ried != null && kgnr != null) {
var rde = riede.GetValueOrDefault(kgnr.Value, []);
rd = rde.FirstOrDefault(r => r.Name == ried);
if (rd == null) {
rd = new WbRd {
KgNr = kgnr,
KgNr = kgnr.Value,
RdNr = (rde.Count == 0 ? 1 : rde.Max(r => r.RdNr)) + 1,
Name = ried,
};
+12 -3
View File
@@ -14,14 +14,23 @@ namespace Elwig.Helpers.Printing {
.UseMemoryCachingProvider()
.Build();
await Task.Delay(500);
await e.CompileTemplateAsync("Document");
await e.CompileTemplateAsync("BusinessDocument");
await e.CompileTemplateAsync("BusinessLetter");
await e.CompileTemplateAsync("DeliveryNote");
await e.CompileTemplateAsync("CreditNote");
await e.CompileTemplateAsync("DeliveryJournal");
await e.CompileTemplateAsync("Letterhead");
await e.CompileTemplateAsync("DeliveryAncmtList");
await e.CompileTemplateAsync("DeliveryConfirmation");
await e.CompileTemplateAsync("DeliveryDepreciationList");
await e.CompileTemplateAsync("DeliveryJournal");
await e.CompileTemplateAsync("DeliveryNote");
await e.CompileTemplateAsync("Letterhead");
await e.CompileTemplateAsync("MemberDataSheet");
await e.CompileTemplateAsync("MemberList");
await e.CompileTemplateAsync("PaymentVariantSummary");
await e.CompileTemplateAsync("WineQualityStatistics");
Engine = e;
evtHandler?.Invoke();
+46 -20
View File
@@ -1,28 +1,32 @@
using System.Threading.Tasks;
using Elwig.Windows;
using System.Diagnostics;
using System;
using System.IO;
using System.Collections.Generic;
using System.Windows;
using System.Text.RegularExpressions;
using System.Diagnostics;
using System.Drawing.Printing;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using PdfiumViewer;
using System.Drawing.Printing;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
namespace Elwig.Helpers.Printing {
public static class Pdf {
private static readonly string WinziPrint = new string[] { App.InstallPath }
.Union(Environment.GetEnvironmentVariable("PATH")?.Split(';') ?? [])
.Select(x => Path.Combine(x, "WinziPrint.exe"))
.Where(File.Exists)
.FirstOrDefault() ?? throw new FileNotFoundException("WiniPrint executable not found");
private static readonly string WinziPrint = (Assembly.GetEntryAssembly()?.Location.Contains(@"\bin\") ?? false) ?
Path.Combine(Assembly.GetEntryAssembly()!.Location.Split(@"\bin\")[0], "../Installer/Files/WinziPrint.exe") :
new string[] { App.InstallPath }
.Union(Environment.GetEnvironmentVariable("PATH")?.Split(';') ?? [])
.Select(x => Path.Combine(x, "WinziPrint.exe"))
.Where(File.Exists)
.FirstOrDefault() ?? throw new FileNotFoundException("WiniPrint executable not found");
private static Process? WinziPrintProc;
public static bool IsReady => WinziPrintProc != null;
public static async Task Init(Action? evtHandler = null) {
PdfiumNative.FPDF_InitLibrary();
// NOTE: If the WinziPrint daemon is already running this will succeed, but the process will fail.
// Should be no problem, as long as the daemon is not closed
var p = new Process() { StartInfo = new() {
@@ -43,27 +47,49 @@ namespace Elwig.Helpers.Printing {
public static Task Cleanup() {
WinziPrintProc?.Kill(true);
WinziPrintProc?.Close();
PdfiumNative.FPDF_DestroyLibrary();
return Task.CompletedTask;
}
public static async Task<(int Pages, IEnumerable<int> PerDoc)> Convert(string htmlPath, string pdfPath, bool doublePaged = false, IProgress<double>? progress = null) {
return await Convert([htmlPath], pdfPath, doublePaged, progress);
public static async Task<(int Pages, IEnumerable<int> PerDoc)> Convert(string htmlPath, string pdfPath, bool doublePaged = false, CancellationToken? cancelToken = null, IProgress<double>? progress = null) {
return await Convert([htmlPath], pdfPath, doublePaged, cancelToken, progress);
}
public static async Task<(int Pages, IEnumerable<int> PerDoc)> Convert(IEnumerable<string> htmlPath, string pdfPath, bool doublePaged = false, IProgress<double>? progress = null) {
public static async Task<(int Pages, IEnumerable<int> PerDoc)> Convert(IEnumerable<string> htmlPath, string pdfPath, bool doublePaged = false, CancellationToken? cancelToken = null, IProgress<double>? progress = null) {
if (WinziPrintProc == null) throw new InvalidOperationException("The WinziPrint process has not been initialized yet");
progress?.Report(0.0);
using var client = new TcpClient("127.0.0.1", 30983);
using var stream = client.GetStream();
string cnxId;
using var reader = new StreamReader(stream);
var first = await reader.ReadLineAsync() ?? throw new IOException("Invalid response from WinziPrint");
if (first.StartsWith("id:")) {
cnxId = first[3..].Trim();
} else {
throw new IOException("Invalid response from WinziPrint");
}
await stream.WriteAsync(Utils.UTF8.GetBytes(
"-e utf-8;-p;" + (doublePaged ? "-2;" : "") +
$"{string.Join(';', htmlPath)};{pdfPath}" +
"\r\n"));
using var reader = new StreamReader(stream);
bool cancelled = false;
while (true) {
if (!cancelled && (cancelToken?.IsCancellationRequested ?? false)) {
try {
using var cancelClient = new TcpClient("127.0.0.1", 30983);
using var cancelStream = cancelClient.GetStream();
using var cancelReader = new StreamReader(cancelStream);
await cancelReader.ReadLineAsync();
await cancelStream.WriteAsync(Utils.UTF8.GetBytes($"cancel;{cnxId}\r\n"));
} catch { }
cancelled = true;
}
var line = await reader.ReadLineAsync() ?? throw new IOException("Invalid response from WinziPrint");
if (line.StartsWith("error:")) {
throw new IOException($"WinziPrint: {line[6..].Trim()}");
var msg = line[6..].Trim();
if (msg == "aborted")
throw new OperationCanceledException("Dokumentenerzeugung abgebrochen!");
throw new IOException($"WinziPrint: {msg}");
} else if (line.StartsWith("progress:")) {
var parts = line[9..].Trim().Split('/').Select(int.Parse).ToArray();
progress?.Report(100.0 * parts[0] / parts[1]);
@@ -98,9 +124,9 @@ namespace Elwig.Helpers.Printing {
public static Task Print(string path, PrinterSettings settings) {
try {
using var doc = PdfDocument.Load(path);
using var printDoc = doc.CreatePrintDocument(PdfPrintMode.CutMargin);
printDoc.PrinterSettings = settings;
using var printDoc = new PdfPrintDocument(path) {
PrinterSettings = settings,
};
printDoc.Print();
} catch (Exception e) {
MessageBox.Show("Beim Drucken ist ein Fehler aufgetreten:\n\n" + e.Message, "Fehler beim Drucken", MessageBoxButton.OK, MessageBoxImage.Error);
+102
View File
@@ -0,0 +1,102 @@
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);
}
}
+14
View File
@@ -540,15 +540,29 @@ namespace Elwig.Helpers {
public static async Task ExportDocument(Document doc, ExportMode mode, string? filename = null, (Member Member, string Subject, string Text)? emailData = null) {
if (mode == ExportMode.Print && !App.Config.Debug) {
if (doc.IsPreview) {
MessageBox.Show("Dieses Dokument ist als vorläufig markiert und kann daher nicht ausgedruckt werden!",
"Vorläufiges Dokument", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
await doc.Generate();
await doc.Print();
} else if (mode == ExportMode.Email && emailData is (Member, string, string) e) {
if (doc.IsPreview) {
MessageBox.Show("Dieses Dokument ist als vorläufig markiert und kann daher nicht verschickt werden!",
"Vorläufiges Dokument", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
await doc.Generate();
var success = await SendEmail(e.Member, e.Subject, e.Text, [doc]);
if (success)
MessageBox.Show("Die E-Mail wurde erfolgreich verschickt!\n\nEs kann einige Minuten dauern, bis die E-Mail im Posteingang des Empfängers aufscheint.", "E-Mail verschickt",
MessageBoxButton.OK, MessageBoxImage.Information);
} else if (mode == ExportMode.SavePdf) {
if (doc.IsPreview) {
MessageBox.Show("Dieses Dokument ist als vorläufig markiert und sollte daher nicht langfristig gespeichert werden!",
"Vorläufiges Dokument", MessageBoxButton.OK, MessageBoxImage.Warning);
}
var d = new SaveFileDialog() {
FileName = $"{NormalizeFileName(filename ?? doc.Title)}.pdf",
DefaultExt = "pdf",
@@ -75,6 +75,7 @@ namespace Elwig.Models.Dtos {
public string? Attribute;
public string? Cultivation;
public string QualityLevel;
public bool IsDepreciated;
public (double Oe, double Kmw) Gradation;
public string[] Modifiers;
public int Weight;
@@ -89,17 +90,15 @@ namespace Elwig.Models.Dtos {
Attribute = p.Attribute?.Name;
Cultivation = p.Cultivation?.Name;
QualityLevel = p.Quality.Name;
IsDepreciated = p.QualId == "WEI";
Gradation = (p.Oe, p.Kmw);
Modifiers = p.Modifiers
.Select(m => m.Name)
.ToArray();
Modifiers = [.. p.Modifiers.Select(m => m.Name)];
Weight = p.Weight;
IsNetWeight = p.IsNetWeight;
Buckets = p.Buckets
Buckets = [.. p.Buckets
.Where(b => b.Value > 0)
.OrderByDescending(b => b.BktNr)
.Select(b => (b.Discr == "_" ? "ungeb." : $"geb. {p.SortId}{b.Discr}", b.Value))
.ToArray();
.Select(b => (b.Discr == "_" ? "ungeb." : $"geb. {p.SortId}{b.Discr}", b.Value))];
}
}
}
+2
View File
@@ -1,6 +1,8 @@
-- schema version 34 to 35
UPDATE client_parameter SET value = '0' WHERE param = 'ENABLE_TIME_TRIGGERS';
ALTER TABLE delivery_part ADD COLUMN unloading TEXT DEFAULT NULL;
UPDATE delivery_part SET unloading = 'pumped' WHERE lesewagen;
UPDATE delivery_part SET unloading = 'box' WHERE (SELECT zwstid IN ('H','S') FROM delivery d WHERE (d.year, d.did) = (delivery_part.year, delivery_part.did));
ALTER TABLE delivery_part DROP COLUMN lesewagen;
UPDATE client_parameter SET value = '1' WHERE param = 'ENABLE_TIME_TRIGGERS';
+12
View File
@@ -0,0 +1,12 @@
-- schema version 36 to 37
UPDATE client_parameter SET value = '0' WHERE param = 'ENABLE_TIME_TRIGGERS';
-- fix old deliveries
UPDATE delivery SET xtime = NULL, mtime = ctime WHERE year <= 2022 AND mtime >= 1768521600 AND mtime < 1772323200;
UPDATE delivery_part SET xtime = NULL, mtime = ctime WHERE year <= 2022 AND mtime >= 1768521600 AND mtime < 1772323200;
-- clear xtime at one laptop to force updates from this one
UPDATE delivery SET xtime = NULL WHERE year >= 2023 AND xtime >= 1771200000 AND xtime < 1771286400;
UPDATE delivery_part SET xtime = NULL WHERE year >= 2023 AND xtime >= 1771200000 AND xtime < 1771286400;
UPDATE client_parameter SET value = '1' WHERE param = 'ENABLE_TIME_TRIGGERS';
+16
View File
@@ -218,6 +218,22 @@ namespace Elwig.Services {
prd = prd.And(p => p.Unloading != DeliveryPart.Box);
filter.RemoveAt(i--);
filterNames.Add("keine Kisten");
} else if ("upload".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
prd = prd.And(p => (p.Delivery.XTime == null || p.Delivery.MTime > p.Delivery.XTime) && (p.Delivery.ITime == null || p.Delivery.MTime > p.Delivery.ITime));
filter.RemoveAt(i--);
filterNames.Add("geändert seit letztem Export");
} else if ("!upload".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
prd = prd.And(p => !((p.Delivery.XTime == null || p.Delivery.MTime > p.Delivery.XTime) && (p.Delivery.ITime == null || p.Delivery.MTime > p.Delivery.ITime)));
filter.RemoveAt(i--);
filterNames.Add("unverändert seit letztem Export");
} else if (">import".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
prd = prd.And(p => p.ITime != null && p.Delivery.MTime > p.Delivery.ITime);
filter.RemoveAt(i--);
filterNames.Add("geändert seit letztem Import");
} else if ("<import".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
prd = prd.And(p => p.Delivery.MTime <= p.Delivery.ITime);
filter.RemoveAt(i--);
filterNames.Add("unverändert seit letztem Import");
} else if (e.Length == 2 && var.ContainsKey(e.ToUpper())) {
filterVar.Add(e.ToUpper());
filter.RemoveAt(i--);
+16
View File
@@ -313,6 +313,22 @@ namespace Elwig.Services {
memberQuery = memberQuery.Where(m => !m.ContactViaPost);
filter.RemoveAt(i--);
filterNames.Add("nicht Kontaktart Post");
} else if ("upload".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
memberQuery = memberQuery.Where(p => (p.XTime == null || p.MTime > p.XTime) && (p.ITime == null || p.MTime > p.ITime));
filter.RemoveAt(i--);
filterNames.Add("geändert seit letztem Export");
} else if ("!upload".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
memberQuery = memberQuery.Where(p => !((p.XTime == null || p.MTime > p.XTime) && (p.ITime == null || p.MTime > p.ITime)));
filter.RemoveAt(i--);
filterNames.Add("unverändert seit letztem Export");
} else if (">import".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
memberQuery = memberQuery.Where(p => p.MTime > p.ITime);
filter.RemoveAt(i--);
filterNames.Add("geändert seit letztem Import");
} else if ("<import".StartsWith(e, StringComparison.CurrentCultureIgnoreCase)) {
memberQuery = memberQuery.Where(p => p.MTime <= p.ITime);
filter.RemoveAt(i--);
filterNames.Add("unverändert seit letztem Import");
} else if (e.All(char.IsAsciiDigit) && mgnr.ContainsKey(e)) {
filterMgNr.Add(int.Parse(e));
filter.RemoveAt(i--);
+5 -1
View File
@@ -271,7 +271,11 @@ namespace Elwig.Services {
}
public static async Task<bool> ChangesAvailable(AppDbContext ctx, string url, string username, string password) {
return await ctx.Members.AnyAsync(ChangedMembers) || await ctx.Deliveries.AnyAsync(ChangedDeliveries) || (Utils.HasInternetConnectivity() && (await GetFilesToImport(url, username, password)).Count > 0);
try {
return await ctx.Members.AnyAsync(ChangedMembers) || await ctx.Deliveries.AnyAsync(ChangedDeliveries) || (Utils.HasInternetConnectivity() && (await GetFilesToImport(url, username, password)).Count > 0);
} catch {
return false;
}
}
}
}
+1 -1
View File
@@ -14,7 +14,7 @@ namespace Elwig.ViewModels {
private IEnumerable<PaymentVar> _paymentVariants = [];
public BillingData? BillingData;
public bool SeasonLocked;
public bool SeasonLocked = false; // never locked
public bool WeightModifierChanged;
[ObservableProperty]
+1 -1
View File
@@ -22,7 +22,7 @@
Programmiersprache: C#<LineBreak/>
Framework: Windows Presentation Framework (WPF)<LineBreak/>
Datenbank: <Hyperlink NavigateUri="https://sqlite.org/" RequestNavigate="Hyperlink_RequestNavigate">SQLite</Hyperlink><LineBreak/>
PDF-Erstellung: <Hyperlink NavigateUri="https://weasyprint.org/" RequestNavigate="Hyperlink_RequestNavigate">WeasyPrint</Hyperlink>, <Hyperlink NavigateUri="https://github.com/toddams/RazorLight" RequestNavigate="Hyperlink_RequestNavigate">RazorLight</Hyperlink>, <Hyperlink NavigateUri="https://github.com/pvginkel/PdfiumViewer" RequestNavigate="Hyperlink_RequestNavigate">PdfiumViewer</Hyperlink><LineBreak/>
PDF-Erstellung: <Hyperlink NavigateUri="https://weasyprint.org/" RequestNavigate="Hyperlink_RequestNavigate">WeasyPrint</Hyperlink>, <Hyperlink NavigateUri="https://github.com/toddams/RazorLight" RequestNavigate="Hyperlink_RequestNavigate">RazorLight</Hyperlink>, <Hyperlink NavigateUri="https://github.com/bblanchon/pdfium-binaries" RequestNavigate="Hyperlink_RequestNavigate">Pdfium</Hyperlink><LineBreak/>
Paketierung: <Hyperlink NavigateUri="https://www.firegiant.com/wixtoolset/" RequestNavigate="Hyperlink_RequestNavigate">WiX Toolset</Hyperlink>
</TextBlock>
+1
View File
@@ -226,6 +226,7 @@
<Bold>Uhrzeit</Bold>: z.B. 06:00-08:00, 18:00-, ...<LineBreak/>
<Bold>Handwiegung</Bold>: handw[iegung], !Handw[iegung] (alle ohne Handwiegung)<LineBreak/>
<Bold>Handlese</Bold>: Handl[ese], !handl[ese] (alle ohne Handlese)<LineBreak/>
<Bold>Anlieferung</Bold>: Plane[nwagen]/Kipp[er], !plane[nwagen]/!kipp[er], Lesew[agen], !lesew[agen], kiste[n], !kiste[n]<LineBreak/>
<Bold>Gebunden</Bold>: geb[unden], ungeb[unden], !geb[unden], !ungeb[unden]<LineBreak/>
<Bold>Gerebelt</Bold>: gerebelt, !Gerebelt (nicht gerebelt gewogen)<LineBreak/>
<Bold>Freitext</Bold>: z.B. Lieferscheinnummern, Anmerkung, "quw" (sucht nach dem Text "quw")
+1 -1
View File
@@ -135,7 +135,7 @@ namespace Elwig.Windows {
NewDeliveryButton_Click(null, null);
using var ctx = new AppDbContext();
if (ctx.Seasons.Find(Utils.CurrentYear) == null) {
MessageBox.Show("Die Saison für das aktuelle Jahr wurde noch nicht erstellt. Neue Lieferungen können nicht abgespeichert werden.",
MessageBox.Show("Die Saison für das aktuelle Jahr wurde noch nicht erstellt. Neue Lieferungen können nicht abgespeichert werden.\n\n(Stammdaten -> Saisons -> Neu anlegen...)",
"Saison noch nicht erstellt", MessageBoxButton.OK, MessageBoxImage.Warning);
}
}
+26 -20
View File
@@ -69,7 +69,7 @@
Grid.Column="0" Margin="10,8,10,10"/>
<ListBox x:Name="AvaiableDocumentsList"
Grid.Column="0" Margin="10,30,10,10"
SelectionChanged="AvaiableDocumentsList_SelectionChanged"/>
SelectionChanged="AvaiableDocumentsList_SelectionChanged" MouseDoubleClick="AvaiableDocumentsList_MouseDoubleClick"/>
<Button x:Name="DocumentAddButton" Content="&#xF0AF;" FontFamily="Segoe MDL2 Assets" FontSize="14"
Grid.Column="1" Margin="0,0,0,30" VerticalAlignment="Center" Height="25" IsEnabled="False"
@@ -82,7 +82,7 @@
Grid.Column="2" Margin="10,8,10,10"/>
<ListBox x:Name="SelectedDocumentsList" DisplayMemberPath="Name"
Grid.Column="2" Margin="10,30,10,37"
SelectionChanged="SelectedDocumentsList_SelectionChanged">
SelectionChanged="SelectedDocumentsList_SelectionChanged" MouseDoubleClick="SelectedDocumentsList_MouseDoubleClick">
<ListBox.InputBindings>
<KeyBinding Key="Delete" Command="{Binding Path=DeleteCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:MailWindow}}}"/>
</ListBox.InputBindings>
@@ -138,58 +138,61 @@
<RadioButton GroupName="Recipients" x:Name="RecipientsNonDeliveryMembersInput" Content="Nicht-Lieferanten der Saison"
Margin="10,90,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Checked="RecipientsInput_Changed" Unchecked="RecipientsInput_Changed"/>
<RadioButton GroupName="Recipients" x:Name="RecipientsCustomInput" Content="Benutzerdefiniert"
<RadioButton GroupName="Recipients" x:Name="RecipientsCreditMembersInput" Content="Empfänger von Gutschriften"
Margin="10,110,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Checked="RecipientsInput_Changed" Unchecked="RecipientsInput_Changed"/>
<RadioButton GroupName="Recipients" x:Name="RecipientsCustomInput" Content="Benutzerdefiniert"
Margin="10,130,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Checked="RecipientsInput_Changed" Unchecked="RecipientsInput_Changed"/>
<Label Content="Zwst.:" x:Name="MemberBranchLabel" Margin="10,140,0,10"/>
<Label Content="Zwst.:" x:Name="MemberBranchLabel" Margin="10,160,0,10"/>
<ctrl:CheckComboBox x:Name="MemberBranchInput" AllItemsSelectedContent="Alle Stammzweigstellen" Delimiter=", " DisplayMemberPath="Name"
Margin="50,140,10,10" VerticalAlignment="Top" HorizontalAlignment="Stretch" Height="25"
Margin="50,160,10,10" VerticalAlignment="Top" HorizontalAlignment="Stretch" Height="25"
SelectionChanged="MemberInput_SelectionChanged"/>
<Label Content="Gem.:" x:Name="MemberKgLabel" Margin="10,170,0,10"/>
<Label Content="Gem.:" x:Name="MemberKgLabel" Margin="10,190,0,10"/>
<ctrl:CheckComboBox x:Name="MemberKgInput" AllItemsSelectedContent="Alle Stammgemeinden" Delimiter=", " DisplayMemberPath="Name"
IsSelectAllActive="True" SelectAllContent="Alle Stammgemeinden"
Margin="50,170,10,10" VerticalAlignment="Top" HorizontalAlignment="Stretch" Height="25"
Margin="50,190,10,10" VerticalAlignment="Top" HorizontalAlignment="Stretch" Height="25"
SelectionChanged="MemberInput_SelectionChanged"/>
<Label Content="Bio-Betrieb:" x:Name="MemberOrganicLabel" Margin="10,200,0,10"/>
<Label Content="Bio-Betrieb:" x:Name="MemberOrganicLabel" Margin="10,220,0,10"/>
<RadioButton x:Name="MemberOrganicYesInput" Content="Ja" GroupName="MemberOrganic"
Margin="80,205,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Margin="80,225,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Checked="MemberInput_Checked"/>
<RadioButton x:Name="MemberOrganicNoInput" Content="Nein" GroupName="MemberOrganic"
Margin="125,205,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Margin="125,225,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Checked="MemberInput_Checked"/>
<RadioButton x:Name="MemberOrganicIndifferentInput" Content="Egal" GroupName="MemberOrganic"
Margin="180,205,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Margin="180,225,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Checked="MemberInput_Checked"/>
<Label Content="Funktionär:" x:Name="MemberFunktionärLabel" Margin="10,230,0,10"/>
<Label Content="Funktionär:" x:Name="MemberFunktionärLabel" Margin="10,250,0,10"/>
<RadioButton x:Name="MemberFunktionärYesInput" Content="Ja" GroupName="MemberFunktionär"
Margin="80,235,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Margin="80,255,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Checked="MemberInput_Checked"/>
<RadioButton x:Name="MemberFunktionärNoInput" Content="Nein" GroupName="MemberFunktionär"
Margin="125,235,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Margin="125,255,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Checked="MemberInput_Checked"/>
<RadioButton x:Name="MemberFunktionärIndifferentInput" Content="Egal" GroupName="MemberFunktionär"
Margin="180,235,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Margin="180,255,10,10" VerticalAlignment="Top" HorizontalAlignment="Left"
Checked="MemberInput_Checked"/>
<Label Content="Vtrg.:" x:Name="MemberAreaComLabel" Margin="10,260,0,10"/>
<Label Content="Vtrg.:" x:Name="MemberAreaComLabel" Margin="10,280,0,10"/>
<ctrl:CheckComboBox x:Name="MemberAreaComInput" AllItemsSelectedContent="Alle Vertragsarten" Delimiter=", " DisplayMemberPath="VtrgId"
IsSelectAllActive="True" SelectAllContent="Alle Vertragsarten"
Margin="50,260,10,10" VerticalAlignment="Top" HorizontalAlignment="Stretch" Height="25"
Margin="50,280,10,10" VerticalAlignment="Top" HorizontalAlignment="Stretch" Height="25"
SelectionChanged="MemberInput_SelectionChanged"/>
<Label Content="Tag:" x:Name="MemberDeliveryAncmtLabel" Margin="10,260,0,10"/>
<Label Content="Tag:" x:Name="MemberDeliveryAncmtLabel" Margin="10,280,0,10"/>
<ctrl:CheckComboBox x:Name="MemberDeliveryAncmtInput" AllItemsSelectedContent="Alle Lesepläne" Delimiter=", " DisplayMemberPath="Identifier"
IsSelectAllActive="True" SelectAllContent="Alle Lesepläne"
Margin="50,260,10,10" VerticalAlignment="Top" HorizontalAlignment="Stretch" Height="25"
Margin="50,280,10,10" VerticalAlignment="Top" HorizontalAlignment="Stretch" Height="25"
SelectionChanged="MemberInput_SelectionChanged"/>
<ctrl:CheckComboBox x:Name="MemberCustomInput" AllItemsSelectedContent="Alle Mitglieder" Delimiter=", " DisplayMemberPath="AdministrativeName"
IsSelectAllActive="True" SelectAllContent="Alle Mitglieder"
Margin="10,140,10,10" VerticalAlignment="Top" HorizontalAlignment="Stretch" Height="25"
Margin="10,160,10,10" VerticalAlignment="Top" HorizontalAlignment="Stretch" Height="25"
SelectionChanged="MemberInput_SelectionChanged"/>
</Grid>
</GroupBox>
@@ -302,6 +305,9 @@
<Button x:Name="GenerateButton" Content="Generieren"
Grid.Row="0" Grid.Column="0" FontSize="14"
Click="GenerateButton_Click"/>
<Button x:Name="AbortButton" Content="Abbrechen" Visibility="Hidden" IsEnabled="False"
Grid.Row="0" Grid.Column="0" FontSize="14"
Click="AbortButton_Click"/>
<ProgressBar x:Name="ProgressBar"
Grid.Row="2" Grid.Column="0" SnapsToDevicePixels="True"/>
+88 -12
View File
@@ -13,6 +13,7 @@ using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
@@ -61,6 +62,8 @@ namespace Elwig.Windows {
protected Dictionary<Member, List<Document>>? PrintMemberDocuments;
protected Dictionary<Member, List<Document>>? EmailDocuments;
private CancellationTokenSource? CancelGeneration;
public static readonly DependencyProperty PostalAllCountProperty = DependencyProperty.Register(nameof(PostalAllCount), typeof(int), typeof(MailWindow));
public int PostalAllCount {
get => (int)GetValue(PostalAllCountProperty);
@@ -330,7 +333,35 @@ namespace Elwig.Windows {
}
}
private async void DocumentAddButton_Click(object sender, RoutedEventArgs evt) {
private void AvaiableDocumentsList_MouseDoubleClick(object sender, MouseEventArgs evt) {
if (evt.LeftButton != MouseButtonState.Pressed) return;
var src = evt.OriginalSource;
if (src is Border b) {
src = (b.Child as ContentPresenter)?.Content.ToString();
} else if (src is TextBlock t) {
src = t.Text;
} else {
return;
}
AvaiableDocumentsList.SelectedIndex = AvaiableDocumentsList.ItemsSource.Cast<object?>().ToList().IndexOf(src);
DocumentAddButton_Click(sender, null);
}
private void SelectedDocumentsList_MouseDoubleClick(object sender, MouseEventArgs evt) {
if (evt.LeftButton != MouseButtonState.Pressed) return;
var src = evt.OriginalSource;
if (src is Border b) {
src = (b.Child as ContentPresenter)?.Content.ToString();
} else if (src is TextBlock t) {
src = t.Text;
} else {
return;
}
SelectedDocumentsList.SelectedItem = SelectedDocs.FirstOrDefault(d => d.Name == (string?)src);
DocumentRemoveButton_Click(sender, null);
}
private async void DocumentAddButton_Click(object sender, RoutedEventArgs? evt) {
var idx = AvaiableDocumentsList.SelectedIndex;
using var ctx = new AppDbContext();
if (AvaiableDocumentsList.SelectedItem is not string s)
@@ -344,13 +375,13 @@ namespace Elwig.Windows {
var name = s.Split(" ")[^1];
var pv = await ctx.PaymentVariants.SingleAsync(v => v.Year == Year && v.Name == name)!;
SelectedDocs.Add(new(DocType.CreditNote, s, (pv.Year, pv.AvNr)));
RecipientsDeliveryMembersInput.IsChecked = true;
RecipientsCreditMembersInput.IsChecked = true;
}
SelectedDocumentsList.SelectedIndex = SelectedDocs.Count - 1;
await UpdateRecipients(ctx);
}
private async void DocumentRemoveButton_Click(object sender, RoutedEventArgs evt) {
private async void DocumentRemoveButton_Click(object sender, RoutedEventArgs? evt) {
DeleteCommand.Execute(null);
using var ctx = new AppDbContext();
await UpdateRecipients(ctx);
@@ -451,8 +482,11 @@ namespace Elwig.Windows {
query = query.Where(m => m.Deliveries.Any(d => d.Year == Year));
} else if (RecipientsNonDeliveryMembersInput.IsChecked == true) {
query = query.Where(m => m.IsActive && !m.Deliveries.Any(d => d.Year == Year));
} else if (RecipientsActiveMembersInput.IsChecked == true && SelectedDocs.Any(d => d.Type == DocType.DeliveryConfirmation || d.Type == DocType.CreditNote)) {
} else if (RecipientsActiveMembersInput.IsChecked == true && SelectedDocs.Any(d => d.Type == DocType.DeliveryConfirmation || d.Type == DocType.CreditNote)) {
query = query.Where(m => m.IsActive || m.Deliveries.Any(d => d.Year == Year));
} else if (RecipientsCreditMembersInput.IsChecked == true) {
var avnrs = SelectedDocs.Where(d => d.Type == DocType.CreditNote).Select(d => (((int,int)?)d.Details)?.Item2).ToList();
query = query.Where(m => m.Credits.Any(c => c.Year == Year && avnrs.Contains(c.AvNr)));
} else {
query = query.Where(m => m.IsActive);
}
@@ -594,20 +628,32 @@ namespace Elwig.Windows {
}
private void Window_Closed(object sender, EventArgs evt) {
CancelGeneration?.Dispose();
DisposeDocs();
}
private async void AbortButton_Click(object sender, RoutedEventArgs evt) {
AbortButton.IsEnabled = false;
CancelGeneration?.Cancel();
}
private async void GenerateButton_Click(object sender, RoutedEventArgs evt) {
LockInputs();
PreviewButton.IsEnabled = false;
PrintButton.IsEnabled = false;
EmailButton.IsEnabled = false;
Mouse.OverrideCursor = Cursors.Wait;
AbortButton.IsEnabled = true;
AbortButton.Visibility = Visibility.Visible;
GenerateButton.IsEnabled = false;
GenerateButton.Visibility = Visibility.Hidden;
DisposeDocs();
await UpdateClientParameters();
CancelGeneration?.Dispose();
CancelGeneration = new();
using var ctx = new AppDbContext();
var doublePaged = DoublePagedInput.IsChecked == true;
@@ -662,6 +708,9 @@ namespace Elwig.Windows {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
UnlockInputs();
GenerateButton.IsEnabled = true;
GenerateButton.Visibility = Visibility.Visible;
AbortButton.IsEnabled = false;
AbortButton.Visibility = Visibility.Hidden;
Mouse.OverrideCursor = null;
return;
}
@@ -679,6 +728,9 @@ namespace Elwig.Windows {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
UnlockInputs();
GenerateButton.IsEnabled = true;
GenerateButton.Visibility = Visibility.Visible;
AbortButton.IsEnabled = false;
AbortButton.Visibility = Visibility.Hidden;
Mouse.OverrideCursor = null;
return;
}
@@ -733,6 +785,21 @@ namespace Elwig.Windows {
}).ToList()
}).ToList();
var hasPreviewDocs = memberDocs.Any(m => m.Docs.Any(d => d.Doc.IsPreview));
if (hasPreviewDocs) {
var res = MessageBox.Show("Einige der ausgewählten Dokumente sind nur als vorläufig zu betrachten und können daher nicht verschickt/ausgedruckt werden!\n\nDies könnte an einer noch nicht festgesetzen Auszahlungsvariante liegen oder daran, dass nicht alle Adressaten/Empfänger eine Traubengutschrift erhalten\n(\"Empfänger von Gutschriften\").\n\nSoll mit dem Generieren fortgefahren werden?",
"Vorläufige Dokumente", MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
if (res != MessageBoxResult.OK) {
UnlockInputs();
GenerateButton.IsEnabled = true;
GenerateButton.Visibility = Visibility.Visible;
AbortButton.IsEnabled = false;
AbortButton.Visibility = Visibility.Hidden;
Mouse.OverrideCursor = null;
return;
}
}
var printMode = PostalAllInput.IsChecked == true ? 3 :
PostalWishInput.IsChecked == true ? 2 :
PostalNoEmailInput.IsChecked == true ? 1 : 0;
@@ -747,7 +814,7 @@ namespace Elwig.Windows {
.ToDictionary(d => d.Member, m => {
var docs = m.Docs.Select(d => d.Doc).ToList();
foreach (var doc in docs) {
doc!.DoublePaged = false;
doc!.IsDoublePaged = false;
if (doc is BusinessDocument b) {
b.IncludeSender = false;
b.Location = location;
@@ -759,7 +826,7 @@ namespace Elwig.Windows {
try {
foreach (var item1 in email.Select((e, i) => new { Index = i, e.Key, e.Value })) {
foreach (var item2 in item1.Value.Select((d, i) => new { Index = i, Doc = d })) {
await item2.Doc.Generate(new Progress<double>(v => {
await item2.Doc.Generate(CancelGeneration.Token, new Progress<double>(v => {
ProgressBar.Value = v * (item2.Index + 1) / item1.Value.Count / totalNum + 100.0 * item1.Index / totalNum;
}));
}
@@ -768,6 +835,9 @@ namespace Elwig.Windows {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
UnlockInputs();
GenerateButton.IsEnabled = true;
GenerateButton.Visibility = Visibility.Visible;
AbortButton.IsEnabled = false;
AbortButton.Visibility = Visibility.Hidden;
Mouse.OverrideCursor = null;
return;
}
@@ -788,7 +858,7 @@ namespace Elwig.Windows {
docs.Insert(0, new Letterhead(m.Member));
}
docs.ForEach(doc => {
doc.DoublePaged = doublePaged;
doc.IsDoublePaged = doublePaged;
if (doc is BusinessDocument b)
b.Location = location;
});
@@ -801,8 +871,8 @@ namespace Elwig.Windows {
if (printDocs.Count > 0) {
try {
var print = Document.Merge(printDocs);
print.DoublePaged = doublePaged;
await print.Generate(new Progress<double>(v => {
print.IsDoublePaged = doublePaged;
await print.Generate(CancelGeneration.Token, new Progress<double>(v => {
ProgressBar.Value = 100.0 * emailNum / totalNum + v * printNum / totalNum;
}));
PrintDocument = print;
@@ -811,6 +881,9 @@ namespace Elwig.Windows {
MessageBox.Show(exc.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
UnlockInputs();
GenerateButton.IsEnabled = true;
GenerateButton.Visibility = Visibility.Visible;
AbortButton.IsEnabled = false;
AbortButton.Visibility = Visibility.Hidden;
Mouse.OverrideCursor = null;
return;
}
@@ -822,10 +895,13 @@ namespace Elwig.Windows {
UnlockInputs();
GenerateButton.IsEnabled = true;
GenerateButton.Visibility = Visibility.Visible;
AbortButton.IsEnabled = false;
AbortButton.Visibility = Visibility.Hidden;
Mouse.OverrideCursor = null;
PreviewButton.IsEnabled = true;
PrintButton.IsEnabled = PrintDocument != null;
EmailButton.IsEnabled = EmailDocuments != null && App.Config.Smtp != null;
PrintButton.IsEnabled = PrintDocument != null && !hasPreviewDocs;
EmailButton.IsEnabled = EmailDocuments != null && !hasPreviewDocs && App.Config.Smtp != null;
}
private async void PreviewButton_Click(object sender, RoutedEventArgs evt) {
@@ -969,7 +1045,7 @@ namespace Elwig.Windows {
var pv = ctx.PaymentVariants.Single(v => v.Year == Year && v.Name == name)!;
SelectedDocs.Add(new(DocType.CreditNote, s, (pv.Year, pv.AvNr)));
SelectedDocumentsList.SelectedIndex = SelectedDocs.Count - 1;
RecipientsDeliveryMembersInput.IsChecked = true;
RecipientsCreditMembersInput.IsChecked = true;
}
private void DocumentInput_TextChanged(object sender, TextChangedEventArgs evt) {
+1 -1
View File
@@ -248,7 +248,7 @@
<Button x:Name="BreakdownButton"
Click="BreakdownButton_Click"
Margin="195,90,0,10" Width="190" Padding="3,5,5,5"
ToolTip="Aufschlüsselung der Menge nach Zweigstelle, Mitglied, Sorte, Attribut/Bewirt., Qualitätsstufe, gebunden/ungebunden">
ToolTip="Aufschlüsselung der Menge nach Zweigstelle, Sorte, Attribut/Bewirt., Qualitätsstufe, gebunden/ungebunden">
<Grid>
<TextBlock FontFamily="Segoe MDL2 Assets" FontSize="16" Text="&#xE9F9;"
TextAlignment="Left" HorizontalAlignment="Left" Padding="6.5,0.5,0,0"/>
@@ -16,16 +16,14 @@ namespace Elwig.Windows {
public partial class PaymentAdjustmentWindow : ContextWindow {
public readonly int Year;
public readonly bool SeasonLocked;
public readonly bool SeasonLocked = false; // never locked
public Dictionary<int, PaymentCustom>? CustomPayments;
public PaymentAdjustmentWindow(int year) {
InitializeComponent();
Year = year;
using (var ctx = new AppDbContext()) {
SeasonLocked = ctx.Seasons.Find(Year + 1) != null;
}
// using (var ctx = new AppDbContext()) { SeasonLocked = ctx.Seasons.Find(Year + 1) != null; }
Title = $"Auszahlung anpassen - Lese {Year} - Elwig";
AutoAdjustBsButton.IsEnabled = !SeasonLocked;
UnAdjustBsButton.IsEnabled = !SeasonLocked;
+9 -6
View File
@@ -1,12 +1,9 @@
using Elwig.Helpers;
using Elwig.Helpers.Billing;
using Elwig.Helpers.Export;
using Elwig.Models.Dtos;
using Elwig.Models.Entities;
using Elwig.Services;
using Elwig.ViewModels;
using Microsoft.EntityFrameworkCore;
using Microsoft.Win32;
using System;
using System.Linq;
using System.Text.Json;
@@ -35,9 +32,7 @@ namespace Elwig.Windows {
CommandBindings.Add(new CommandBinding(CtrlÜ, Menu_EbicsSave_Click));
CommandBindings.Add(new CommandBinding(CtrlShiftP, Menu_SummaryPrint_Click));
Year = year;
using (var ctx = new AppDbContext()) {
ViewModel.SeasonLocked = ctx.Seasons.Find(Year + 1) != null;
}
// using (var ctx = new AppDbContext()) { ViewModel.SeasonLocked = ctx.Seasons.Find(Year + 1) != null; }
Title = $"Auszahlungsvarianten - Lese {Year} - Elwig";
if (!App.Config.Debug) {
DataInput.Visibility = Visibility.Hidden;
@@ -55,6 +50,9 @@ namespace Elwig.Windows {
.OrderBy(v => v.AvNr)
.Include(v => v.Season.Currency)
.ToListAsync());
if (PaymentVariantList.SelectedItem == null && PaymentVariantList.Items.Count > 0) {
PaymentVariantList.SelectedIndex = PaymentVariantList.Items.Count - 1;
}
Update();
}
@@ -119,6 +117,11 @@ namespace Elwig.Windows {
private async void DeleteButton_Click(object sender, RoutedEventArgs evt) {
if (PaymentVariantList.SelectedItem is not PaymentVar v || !v.TestVariant)
return;
var res = MessageBox.Show(
$"Soll die Auszahlungsvariante \"{v.Name}\" wirklich unwiderruflich gelöscht werden?",
"Auszahlungsvariante löschen", MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
if (res != MessageBoxResult.OK)
return;
Mouse.OverrideCursor = Cursors.Wait;
try {
await PaymentVariantService.DeletePaymentVariant(v.Year, v.AvNr);
Binary file not shown.
+3 -3
View File
@@ -13,7 +13,7 @@ About
**Product:** Elwig
**Description:** Electronic Management for Vintners' Cooperatives
**Type:** ERP system
**Version:** 1.0.2.0 ([Changelog](./CHANGELOG.md))
**Version:** 1.0.3.4 ([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.0.2.0 ([Änderungsprotokoll](./CHANGELOG.md))
**Version:** 1.0.3.4 ([Änderungsprotokoll](./CHANGELOG.md))
**Lizenz:** [GNU General Public License 3.0 (GPLv3)](./LICENSE)
**Website:** https://elwig.at/
**Quellcode:** https://git.necronda.net/winzer/elwig
@@ -43,5 +43,5 @@ Packaging: [WiX Toolset](https://www.firegiant.com/wixtoolset/)
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)
PDF-Erstellung: [WeasyPrint](https://weasyprint.org/), [RazorLight](https://github.com/toddams/RazorLight), [Pdfium](https://github.com/bblanchon/pdfium-binaries)
Paketierung: [WiX Toolset](https://www.firegiant.com/wixtoolset/)
+5 -5
View File
@@ -8,18 +8,18 @@
SuppressOptionsUI="yes" ShowVersion="yes"/>
</BootstrapperApplication>
<util:RegistrySearch Id="VCredistx86" Variable="VCredistx86" Result="exists"
Root="HKLM" Key="SOFTWARE\Classes\Installer\Dependencies\VC,redist.x86,x86,14.36,bundle"/>
<util:RegistrySearch Id="VCredistx64" Variable="VCredistx64" Result="exists"
Root="HKLM" Key="SOFTWARE\Classes\Installer\Dependencies\VC,redist.x64,amd64,14.50,bundle"/>
<util:RegistrySearch Id="Webview2Machine" Variable="Webview2Machine" Result="exists"
Root="HKLM" Key="SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}"/>
<util:RegistrySearch Id="Webview2User" Variable="Webview2User" Result="exists"
Root="HKCU" Key="Software\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}"/>
<Chain>
<ExePackage Id="VCredistx86Installer" DisplayName="VC Redist x86 installer" Name="VC_redist.x86.exe"
SourceFile="$(ProjectDir)\Files\VC_redist.x86.exe"
<ExePackage Id="VCredistx64Installer" DisplayName="VC Redist x64 installer" Name="VC_redist.x64.exe"
SourceFile="$(ProjectDir)\Files\VC_redist.x64.exe"
Cache="remove" Compressed="yes" PerMachine="yes" Permanent="yes" Vital="yes"
InstallArguments="/install /passive /norestart" DetectCondition="VCredistx86"/>
InstallArguments="/install /passive /norestart" DetectCondition="VCredistx64"/>
<ExePackage Id="MicrosoftEdgeWebview2" DisplayName="Microsoft Edge Webview2 Runtime" Name="MicrosoftEdgeWebview2Setup.exe"
SourceFile="$(ProjectDir)\Files\MicrosoftEdgeWebview2Setup.exe"
Cache="remove" Compressed="yes" PerMachine="yes" Permanent ="yes" Vital="no"
+1 -1
View File
@@ -6,7 +6,7 @@
</PropertyGroup>
<Target Name="CustomBeforeBuild" BeforeTargets="BeforeBuild">
<Exec Command="curl --fail -s -L &quot;https://go.microsoft.com/fwlink/p/?LinkId=2124703&quot; -z &quot;$(ProjectDir)\Files\MicrosoftEdgeWebview2Setup.exe&quot; -o &quot;$(ProjectDir)\Files\MicrosoftEdgeWebview2Setup.exe&quot;" />
<Exec Command="curl --fail -s -L &quot;https://aka.ms/vs/17/release/vc_redist.x86.exe&quot; -z &quot;$(ProjectDir)\Files\VC_redist.x86.exe&quot; -o &quot;$(ProjectDir)\Files\VC_redist.x86.exe&quot;" />
<Exec Command="curl --fail -s -L &quot;https://aka.ms/vc14/vc_redist.x64.exe&quot; -z &quot;$(ProjectDir)\Files\VC_redist.x64.exe&quot; -o &quot;$(ProjectDir)\Files\VC_redist.x64.exe&quot;" />
<PropertyGroup>
<DefineConstants>ElwigProjectDir=..\Elwig</DefineConstants>
</PropertyGroup>
+3 -3
View File
@@ -22,13 +22,13 @@
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
<PackageReference Include="Appium.WebDriver" Version="4.4.5" />
<PackageReference Include="NReco.PdfRenderer" Version="1.6.0" />
<PackageReference Include="NUnit" Version="4.4.0" />
<PackageReference Include="NUnit3TestAdapter" Version="5.2.0" />
<PackageReference Include="NUnit" Version="4.5.0" />
<PackageReference Include="NUnit3TestAdapter" Version="6.1.0" />
<PackageReference Include="NUnit.Analyzers" Version="4.11.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="6.0.4">
<PackageReference Include="coverlet.collector" Version="8.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>