Compare commits

...
30 Commits
Author SHA1 Message Date
lorenz.stechauner 77e812f5e8 Bump version 1.1.0.3
Deploy / Build and Deploy (push) Successful in 2m1s
2026-08-17 23:53:32 +02:00
lorenz.stechauner 58bfb4f56d Tests: Update dependencies
Test / Run tests (push) Successful in 2m4s
2026-08-17 23:38:46 +02:00
lorenz.stechauner e6e140dc08 Elwig: Update dependencies 2026-08-17 23:38:43 +02:00
lorenz.stechauner eaddf0c3cb SyncService: Add distinction main/non-main device
Test / Run tests (push) Successful in 2m26s
2026-08-17 23:29:31 +02:00
lorenz.stechauner fc5ad82686 Printing: Print all copies as one single print job 2026-08-17 17:50:33 +02:00
lorenz.stechauner b76367f73a Bump version to 1.1.0.2
Test / Run tests (push) Successful in 1m56s
Deploy / Build and Deploy (push) Successful in 1m51s
2026-08-11 18:27:22 +02:00
lorenz.stechauner 76ea3513ac MainWindow: Delay email sending
Test / Run tests (push) Successful in 2m4s
2026-08-11 18:25:16 +02:00
lorenz.stechauner 07b197958d Printing: Try to duplex print with manual dialog
Test / Run tests (push) Successful in 2m12s
2026-08-11 18:09:51 +02:00
lorenz.stechauner 470c6e09e5 Printing: Change fit-to-printable-are to scale 1:1
Test / Run tests (push) Successful in 2m40s
2026-08-11 17:25:49 +02:00
lorenz.stechauner 20b19775b1 Printing: Use –FPDF_RenderPage instead of FPDF_RenderPageBitmap to allow vector graphics
Test / Run tests (push) Successful in 2m38s
2026-08-10 18:35:49 +02:00
lorenz.stechauner f13a836ebd Printing: Fix slight translocation to the bottom right
Test / Run tests (push) Successful in 3m2s
2026-08-10 13:10:10 +02:00
lorenz.stechauner 2bf926c84c Bump version to 1.1.0.1
Test / Run tests (push) Successful in 2m15s
Deploy / Build and Deploy (push) Successful in 1m59s
2026-08-05 17:17:27 +02:00
lorenz.stechauner a8cc3c9cb9 Elwig: Update dependencies
Test / Run tests (push) Successful in 1m52s
2026-08-05 10:33:47 +02:00
lorenz.stechauner 88616b2c0b MemberAdminWindow: Add icons to deliveries and area commitments buttons
Test / Run tests (push) Successful in 1m58s
2026-08-03 14:20:24 +02:00
lorenz.stechauner e6712732cd [#82] BaseDataWindow: Fixed error handling after first error to allow saving changes
Test / Run tests (push) Successful in 2m8s
2026-08-03 14:18:20 +02:00
lorenz.stechauner cfabf99c99 [#83] PaymentVariantsWindow: Automatically calculate when saving variant
Test / Run tests (push) Successful in 1m57s
2026-08-03 11:26:28 +02:00
lorenz.stechauner 668030fbff Tests: Update dependencies 2026-08-03 11:26:28 +02:00
lorenz.stechauner b445928c4d Elwig: Update dependencies 2026-08-03 11:26:28 +02:00
lorenz.stechauner 2a3999f300 Weighing: Set Date/Time of scales at startup 2026-08-03 11:26:23 +02:00
lorenz.stechauner 309f118739 Weighing: Differentiate between scale and terminal 2026-08-03 10:56:36 +02:00
lorenz.stechauner 0d8cdd5d6e Bump version to 1.1.0.0
Test / Run tests (push) Successful in 1m54s
Deploy / Build and Deploy (push) Successful in 1m42s
2026-07-09 01:43:38 +02:00
lorenz.stechauner 2350b55cea Tests: Update dependencies
Test / Run tests (push) Successful in 2m6s
2026-07-09 01:01:38 +02:00
lorenz.stechauner e8789aff37 Elwig: Update dependencies 2026-07-09 01:01:38 +02:00
lorenz.stechauner 918555f2b8 [#20] MemberAdminWindow: Add MemberBusinessSharesAdminWindow to manage member shares 2026-07-09 01:01:28 +02:00
lorenz.stechauner 1169ba5101 ChartWindow: Fix warnings and avoid null-forgiving operator
Test / Run tests (push) Successful in 2m10s
2026-07-06 19:11:39 +02:00
lorenz.stechauner 76da392f5f [#20][#80] MemberAdminWindow: Update business share status bar tool tip
Test / Run tests (push) Successful in 2m1s
2026-07-06 18:18:46 +02:00
lorenz.stechauner 000117dc67 CreditNoteData: Add AccountingNr of member
Test / Run tests (push) Successful in 3m6s
2026-07-06 11:03:38 +02:00
lorenz.stechauner 314a0d37a8 [#20] MemberDataSheet: Show members business share history 2026-07-03 12:02:44 +02:00
lorenz.stechauner 765edbdae6 [#20][#80] MemberAdminWindow: Add functionality to edit other business shares 2026-07-03 12:02:44 +02:00
lorenz.stechauner 9a0a422c8a [#20] Entities/MemberHistory: Add DeductYear to simplify billing 2026-07-03 12:02:37 +02:00
80 changed files with 2183 additions and 695 deletions
+1 -1
View File
@@ -2,7 +2,7 @@ name: Test
on: on:
push: push:
branches: ["**"] branches: ["**"]
paths: ["Elwig/**", "Tests/**", "Installer/Files/*.exe", ".gitea/workflows/test.yaml"] paths: ["Elwig/**", "Tests/**", ".gitea/workflows/test.yaml"]
jobs: jobs:
test: test:
name: Run tests name: Run tests
+83 -1
View File
@@ -2,6 +2,88 @@
Changelog Changelog
========= =========
[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}
---------------------------------------------
### Neue Funktionen {#v1.1.0.0-features}
* Per Opt-In Einstellung in den Stammdaten ist es nun möglich Mitgliederbewegungen und Verläufe von Geschäftsanteilen mit Elwig zu erfassen. ([#20][i20])
* Es wird nun unterstützt verschiedene Typen von Geschäftsanteilen pro Mitglied zu erfassen (normal, rot, weiß, ruhend). ([#80][i80])
### Behobene Fehler {#v1.1.0.0-bugfixes}
* Falls die Datenbank für die momentan verwndete Elwig-Version zu neu war kam es beim Überprüfen auf ein Update zu einem Fehler. (4ebe07f579)
* Im Stammdatenblatt (`MemberDataSheet`) wurde die Stamm-Zweigstelle nicht angeführt. (a71c41af5c)
### Sonstiges {#v1.1.0.0-misc}
* In der Buchungsliste (`CreditNoteData`) wird nun auch das Buchhaltungskonto der Mitglieder angeführt. (000117dc67)
* Viele kleine Verbesserungen der Code-Qualität. (u.a. fcd0555e4d, 69efca1cc3, beacba6bd9, 1169ba5101)
* Abhängigkeiten aktualisiert. (e8789aff37, 2350b55cea)
[v1.1.0.0]: https://git.necronda.net/winzer/elwig/releases/tag/v1.1.0.0
[i20]: https://git.necronda.net/winzer/elwig/issues/20
[i80]: https://git.necronda.net/winzer/elwig/issues/80
[v1.0.5.6][v1.0.5.6] (2026-06-25) {#v1.0.5.6} [v1.0.5.6][v1.0.5.6] (2026-06-25) {#v1.0.5.6}
--------------------------------------------- ---------------------------------------------
@@ -264,7 +346,7 @@ Changelog
[v1.0.3.0]: https://git.necronda.net/winzer/elwig/releases/tag/v1.0.3.0 [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 [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 [i71]: https://git.necronda.net/winzer/elwig/issues/71
[i73]: https://git.necronda.net/winzer/elwig/issues/73 [i73]: https://git.necronda.net/winzer/elwig/issues/73
+1 -8
View File
@@ -16,14 +16,7 @@
<dependency> <dependency>
<dependentAssembly> <dependentAssembly>
<assemblyIdentity <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*" />
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly> </dependentAssembly>
</dependency> </dependency>
</assembly> </assembly>
+11 -1
View File
@@ -145,7 +145,13 @@ namespace Elwig {
var list = new List<IScale>(); var list = new List<IScale>();
foreach (var s in Config.Scales) { foreach (var s in Config.Scales) {
try { try {
list.Add(Scale.FromConfig(s)); var scale = Scale.FromConfig(s);
if (scale is ICommandScale cmd) {
try {
await cmd.SetDateAndTime(DateTime.Now);
} catch { }
}
list.Add(scale);
} catch (Exception exc) { } catch (Exception exc) {
list.Add(new InvalidScale(s.Id)); list.Add(new InvalidScale(s.Id));
if (s.Required) if (s.Required)
@@ -344,6 +350,10 @@ namespace Elwig {
return FocusWindow<DeliveryAdminWindow>(() => new(true), w => w.ViewModel.IsReceipt); return FocusWindow<DeliveryAdminWindow>(() => new(true), w => w.ViewModel.IsReceipt);
} }
public static MemberBusinessSharesAdminWindow FocusMemberBusinessSharesWindow(int mgnr) {
return FocusWindow<MemberBusinessSharesAdminWindow>(() => new(mgnr), w => w.ViewModel.FilterMember?.MgNr == mgnr);
}
public static DeliveryAdminWindow FocusMemberDeliveries(int mgnr) { public static DeliveryAdminWindow FocusMemberDeliveries(int mgnr) {
return FocusWindow<DeliveryAdminWindow>(() => new(mgnr), w => w.ViewModel.FilterMember?.MgNr == mgnr); return FocusWindow<DeliveryAdminWindow>(() => new(mgnr), w => w.ViewModel.FilterMember?.MgNr == mgnr);
} }
+1 -1
View File
@@ -122,7 +122,7 @@ namespace Elwig.Controls {
private void OnSelectionChanged(object sender, SelectionChangedEventArgs evt) { private void OnSelectionChanged(object sender, SelectionChangedEventArgs evt) {
SelectItemsReverse(); SelectItemsReverse();
var dmp = !string.IsNullOrEmpty(ListDisplayMemberPath) ? ListDisplayMemberPath : !string.IsNullOrEmpty(DisplayMemberPath) ? DisplayMemberPath : null; var dmp = !string.IsNullOrWhiteSpace(ListDisplayMemberPath) ? ListDisplayMemberPath : !string.IsNullOrWhiteSpace(DisplayMemberPath) ? DisplayMemberPath : null;
if (SelectedItems.Count == ItemsSource.Cast<object>().Count() && AllItemsSelectedContent != null) { if (SelectedItems.Count == ItemsSource.Cast<object>().Count() && AllItemsSelectedContent != null) {
AllItemsSelected = true; AllItemsSelected = true;
} else if (SelectedItems.Count == 0) { } else if (SelectedItems.Count == 0) {
+7 -7
View File
@@ -18,7 +18,7 @@ namespace Elwig.Documents {
public class BusinessDocument : Document { public class BusinessDocument : Document {
public Member Member; public Member Member;
public MemberHistoryPoint MemberHistory; public MemberHistoryPoint MemberShares;
public string? Location; public string? Location;
public bool IncludeSender = false; public bool IncludeSender = false;
public bool UseBillingAddress = false; public bool UseBillingAddress = false;
@@ -52,7 +52,7 @@ namespace Elwig.Documents {
public BusinessDocument(string title, Member m, DateOnly? dateFrom, bool includeSender = false) : public BusinessDocument(string title, Member m, DateOnly? dateFrom, bool includeSender = false) :
base(title) { base(title) {
Member = m; Member = m;
MemberHistory = new(m.Shares, m.SharesRed, m.SharesWhite, m.SharesDormant); MemberShares = new(m.Shares, m.SharesRed, m.SharesWhite, m.SharesDormant);
Location = App.BranchLocation; Location = App.BranchLocation;
IncludeSender = includeSender; IncludeSender = includeSender;
DateFrom = dateFrom; DateFrom = dateFrom;
@@ -318,19 +318,19 @@ namespace Elwig.Documents {
.Where(b => !fbVars.Contains(b.Key)) .Where(b => !fbVars.Contains(b.Key))
.OrderBy(b => b.Value.Name); .OrderBy(b => b.Value.Name);
if (MemberHistory.Shares != 0 || (MemberHistory.SharesRed == 0 && MemberHistory.SharesWhite == 0)) { if (MemberShares.Shares != 0 || (MemberShares.SharesRed == 0 && MemberShares.SharesWhite == 0)) {
tbl.AddCell(NewBucketTh("Gesamtlieferung lt. gez. GA", isTiny: isTiny)); tbl.AddCell(NewBucketTh("Gesamtlieferung lt. gez. GA", isTiny: isTiny));
tbl.AddCells(FormatRow(MemberHistory.Shares * (season.MinKgPerShare ?? 0), MemberHistory.Shares * (season.MaxKgPerShare ?? 0), tbl.AddCells(FormatRow(MemberShares.Shares * (season.MinKgPerShare ?? 0), MemberShares.Shares * (season.MaxKgPerShare ?? 0),
deliveredWeightRed + deliveredWeightWhite, isGa: true, showPayment: includePayment, showArea: !includeDelivery, isTiny: isTiny)); deliveredWeightRed + deliveredWeightWhite, isGa: true, showPayment: includePayment, showArea: !includeDelivery, isTiny: isTiny));
} }
if (MemberHistory.SharesRed != 0 || MemberHistory.SharesWhite != 0) { if (MemberShares.SharesRed != 0 || MemberShares.SharesWhite != 0) {
tbl.AddCell(NewBucketTh("Gesamtlieferung lt. gez. GA (rot)", isTiny: isTiny)); tbl.AddCell(NewBucketTh("Gesamtlieferung lt. gez. GA (rot)", isTiny: isTiny));
tbl.AddCells(FormatRow(MemberHistory.SharesRed * (season.MinKgPerShareRed ?? season.MinKgPerShare ?? 0), MemberHistory.SharesRed * (season.MaxKgPerShareRed ?? season.MaxKgPerShare ?? 0), tbl.AddCells(FormatRow(MemberShares.SharesRed * (season.MinKgPerShareRed ?? season.MinKgPerShare ?? 0), MemberShares.SharesRed * (season.MaxKgPerShareRed ?? season.MaxKgPerShare ?? 0),
deliveredWeightRed, isGa: true, showPayment: includePayment, showArea: !includeDelivery, isTiny: isTiny)); deliveredWeightRed, isGa: true, showPayment: includePayment, showArea: !includeDelivery, isTiny: isTiny));
tbl.AddCell(NewBucketTh("Gesamtlieferung lt. gez. GA (weiß)", isTiny: isTiny)); tbl.AddCell(NewBucketTh("Gesamtlieferung lt. gez. GA (weiß)", isTiny: isTiny));
tbl.AddCells(FormatRow(MemberHistory.SharesWhite * (season.MinKgPerShareWhite ?? season.MinKgPerShare ?? 0), MemberHistory.SharesWhite * (season.MaxKgPerShareWhite ?? season.MaxKgPerShare ?? 0), tbl.AddCells(FormatRow(MemberShares.SharesWhite * (season.MinKgPerShareWhite ?? season.MinKgPerShare ?? 0), MemberShares.SharesWhite * (season.MaxKgPerShareWhite ?? season.MaxKgPerShare ?? 0),
deliveredWeightWhite, isGa: true, showPayment: includePayment, showArea: !includeDelivery, isTiny: isTiny)); deliveredWeightWhite, isGa: true, showPayment: includePayment, showArea: !includeDelivery, isTiny: isTiny));
} }
+2 -5
View File
@@ -101,11 +101,8 @@ namespace Elwig.Documents {
MemberTotalUnderDelivery -= (season.PenaltyNone ?? 0) + (season.PenaltyPerShareNone * (Member.Shares + Member.SharesRed + Member.SharesWhite) ?? 0); MemberTotalUnderDelivery -= (season.PenaltyNone ?? 0) + (season.PenaltyPerShareNone * (Member.Shares + Member.SharesRed + Member.SharesWhite) ?? 0);
} }
if (ConsiderAutoBusinessShares) { if (ConsiderAutoBusinessShares) {
var fromDate = $"{season.Year}-01-01";
var toDate = $"{season.Year}-12-31";
MemberAutoBusinessShares = await ctx.MemberHistory MemberAutoBusinessShares = await ctx.MemberHistory
.Where(h => h.ToMgNr == Member.MgNr && h.Reason == "auto") .Where(h => h.ToMgNr == Member.MgNr && h.DeductYear == season.Year)
.Where(h => h.DateString.CompareTo(fromDate) >= 0 && h.DateString.CompareTo(toDate) <= 0)
.SumAsync(h => h.Shares); .SumAsync(h => h.Shares);
MemberAutoBusinessSharesAmount = MemberAutoBusinessShares * (-season.BusinessShareValue ?? 0); MemberAutoBusinessSharesAmount = MemberAutoBusinessShares * (-season.BusinessShareValue ?? 0);
} }
@@ -205,7 +202,7 @@ namespace Elwig.Documents {
penalty += MemberTotalUnderDelivery; penalty += MemberTotalUnderDelivery;
} }
if (MemberAutoBusinessSharesAmount != 0) { if (MemberAutoBusinessSharesAmount != 0) {
tbl2.AddCells(FormatRow($"Autom. Nachz. von GA ({MemberAutoBusinessShares})", MemberAutoBusinessSharesAmount, add: true)); tbl2.AddCells(FormatRow($"Nachzeichnung von GA ({MemberAutoBusinessShares})", MemberAutoBusinessSharesAmount, add: true));
penalty += MemberAutoBusinessSharesAmount; penalty += MemberAutoBusinessSharesAmount;
} }
if (CustomPayment?.Amount != null) { if (CustomPayment?.Amount != null) {
+1 -1
View File
@@ -44,7 +44,7 @@ namespace Elwig.Documents {
.ToDictionaryAsync(g => g.Key, g => g.Sum(p => p.Weight)); .ToDictionaryAsync(g => g.Key, g => g.Sum(p => p.Weight));
MemberDeliveredWeightRed = weights.GetValueOrDefault("R", 0); MemberDeliveredWeightRed = weights.GetValueOrDefault("R", 0);
MemberDeliveredWeightWhite = weights.GetValueOrDefault("W", 0); MemberDeliveredWeightWhite = weights.GetValueOrDefault("W", 0);
MemberHistory = await ctx.GetMemberHistory(Season.Year, Member.MgNr); MemberShares = await ctx.GetMemberHistory(Season.Year, Member.MgNr);
MemberBuckets = await ctx.GetMemberBuckets(Season.Year, Member.MgNr); MemberBuckets = await ctx.GetMemberBuckets(Season.Year, Member.MgNr);
MemberStats = await AppDbContext.GetMemberStats(Season.Year, Member.MgNr); MemberStats = await AppDbContext.GetMemberStats(Season.Year, Member.MgNr);
Data ??= await DeliveryConfirmationDeliveryData.ForMember(ctx.DeliveryParts, Season.Year, Member); Data ??= await DeliveryConfirmationDeliveryData.ForMember(ctx.DeliveryParts, Season.Year, Member);
+3 -3
View File
@@ -66,7 +66,7 @@ namespace Elwig.Documents {
.ToDictionaryAsync(g => g.Key, g => g.Sum(p => p.Weight)); .ToDictionaryAsync(g => g.Key, g => g.Sum(p => p.Weight));
MemberDeliveredWeightRed = weights.GetValueOrDefault("R", 0); MemberDeliveredWeightRed = weights.GetValueOrDefault("R", 0);
MemberDeliveredWeightWhite = weights.GetValueOrDefault("W", 0); MemberDeliveredWeightWhite = weights.GetValueOrDefault("W", 0);
MemberHistory = await ctx.GetMemberHistory(Delivery.Year, Member.MgNr); MemberShares = await ctx.GetMemberHistory(Delivery.Year, Member.MgNr);
MemberBuckets = await ctx.GetMemberBuckets(Delivery.Year, Member.MgNr) ?? []; MemberBuckets = await ctx.GetMemberBuckets(Delivery.Year, Member.MgNr) ?? [];
} }
@@ -181,8 +181,8 @@ namespace Elwig.Documents {
} }
} else { } else {
var info = part.WeighingInfo; var info = part.WeighingInfo;
weighing.Add(Italic("Waage:")) weighing.Add(Italic("Waage/Terminal:"))
.Add(Normal(" " + (part.ScaleId ?? "?") + ", ")) .Add(Normal(" " + (info.ScaleId ?? "?") + "/" + (part.ScaleTerminalId ?? "?") + ", "))
.Add(Italic("ID:")) .Add(Italic("ID:"))
.Add(Normal(" " + (info.Id ?? "?"))); .Add(Normal(" " + (info.Id ?? "?")));
if (info.Date != null || info.Time != null) if (info.Date != null || info.Time != null)
+157 -5
View File
@@ -1,4 +1,5 @@
using Elwig.Helpers; using Elwig.Helpers;
using Elwig.Models;
using Elwig.Models.Entities; using Elwig.Models.Entities;
using iText.Kernel.Colors; using iText.Kernel.Colors;
using iText.Kernel.Pdf; using iText.Kernel.Pdf;
@@ -20,6 +21,7 @@ namespace Elwig.Documents {
public Season? Season; public Season? Season;
public int MemberDeliveredWeightRed; public int MemberDeliveredWeightRed;
public int MemberDeliveredWeightWhite; public int MemberDeliveredWeightWhite;
public List<MemberHistory> MemberHistory = [];
public Dictionary<string, MemberBucket> MemberBuckets = []; public Dictionary<string, MemberBucket> MemberBuckets = [];
public List<AreaCom> ActiveAreaCommitments = []; public List<AreaCom> ActiveAreaCommitments = [];
@@ -37,6 +39,10 @@ namespace Elwig.Documents {
protected override async Task LoadData(AppDbContext ctx) { protected override async Task LoadData(AppDbContext ctx) {
await base.LoadData(ctx); await base.LoadData(ctx);
Season = await ctx.FetchSeasons().FirstOrDefaultAsync() ?? throw new ArgumentException("Invalid season"); Season = await ctx.FetchSeasons().FirstOrDefaultAsync() ?? throw new ArgumentException("Invalid season");
MemberHistory = await ctx.MemberHistory
.Where(h => h.FromMgNr == Member.MgNr || h.ToMgNr == Member.MgNr)
.OrderBy(h => h.DateNoticeString).ThenBy(h => h.HistNr)
.ToListAsync();
MemberBuckets = await ctx.GetMemberBuckets(Utils.CurrentYear, Member.MgNr); MemberBuckets = await ctx.GetMemberBuckets(Utils.CurrentYear, Member.MgNr);
ActiveAreaCommitments = await Member.ActiveAreaCommitments(ctx) ActiveAreaCommitments = await Member.ActiveAreaCommitments(ctx)
.Include(c => c.Contract).ThenInclude(c => c.Revisions) .Include(c => c.Contract).ThenInclude(c => c.Revisions)
@@ -61,9 +67,18 @@ namespace Elwig.Documents {
doc.Add(new AreaBreak(AreaBreakType.NEXT_PAGE)); doc.Add(new AreaBreak(AreaBreakType.NEXT_PAGE));
firstOnPage = true; firstOnPage = true;
} }
doc.Add(new KernedParagraph(12).Add(Bold($"Flächenbindungen per {Date:dd.MM.yyyy}")).SetMargins(firstOnPage ? 0 : 24, 0, 12, 0)); doc.Add(new KernedParagraph(12).Add(Bold($"Flächenbindungen per {Date:dd.MM.yyyy}")).SetMargins(firstOnPage ? 0 : 24, 0, 6, 0));
doc.Add(NewAreaComTable(ActiveAreaCommitments)); doc.Add(NewAreaComTable(ActiveAreaCommitments));
} }
if (App.Client.EnableMemberHistory) {
bool firstOnPage = false;
if (pdf.GetNumberOfPages() == 1) {
doc.Add(new AreaBreak(AreaBreakType.NEXT_PAGE));
firstOnPage = true;
}
doc.Add(new KernedParagraph(12).Add(Bold($"Verlauf der Geschäftsanteile per {Date:dd.MM.yyyy}")).SetMargins(firstOnPage ? 0 : 24, 0, 6, 0));
doc.Add(NewMemberBusinessSharesTable(MemberHistory));
}
} }
protected Cell NewDataHdr(string title, int colspan) { protected Cell NewDataHdr(string title, int colspan) {
@@ -169,10 +184,10 @@ namespace Elwig.Documents {
}).OrderByDescending(a => a.Size).ToList(); }).OrderByDescending(a => a.Size).ToList();
var tbl = new Table(ColsMM(40, 30, 35, 15, 25, 20), true) var tbl = new Table(ColsMM(40, 30, 35, 15, 25, 20), true)
.SetWidth(UnitValue.CreatePercentValue(100)).SetFixedLayout() .SetWidth(UnitValue.CreatePercentValue(100)).SetFixedLayout()
.SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE) .SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE)
.SetBorder(Border.NO_BORDER) .SetBorder(Border.NO_BORDER)
.SetFontSize(10); .SetFontSize(10);
tbl.AddHeaderCell(NewTh("Katastralgemeinde", rowspan: 2, left: true)) tbl.AddHeaderCell(NewTh("Katastralgemeinde", rowspan: 2, left: true))
.AddHeaderCell(NewTh("Ried", rowspan: 2, left: true)) .AddHeaderCell(NewTh("Ried", rowspan: 2, left: true))
@@ -209,5 +224,142 @@ namespace Elwig.Documents {
return tbl; return tbl;
} }
protected Cell[] NewBusinessSharesCells(MemberHistoryPoint p, bool isDiff = true) {
if (App.Client.HasRedWhite) {
return [
NewTd(isDiff ? (p.SharesRed == 0 ? "" : p.SharesRed < 0 ? $"{-p.SharesRed:N0}" : $"+{p.SharesRed:N0}") : $"{p.SharesRed:N0}",
right: true, bold: !isDiff, borderTop: !isDiff),
NewTd(isDiff ? (p.SharesWhite == 0 ? "" : p.SharesWhite < 0 ? $"{-p.SharesWhite:N0}" : $"+{p.SharesWhite:N0}") : $"{p.SharesWhite:N0}",
right: true, bold: !isDiff, borderTop: !isDiff),
NewTd(isDiff ? (p.SharesDormant == 0 ? "" : p.SharesDormant < 0 ? $"{-p.SharesDormant:N0}" : $"+{p.SharesDormant:N0}") : $"{p.SharesDormant:N0}",
right: true, bold: !isDiff, borderTop: !isDiff),
];
} else {
return [
NewTd(isDiff ? (p.Shares == 0 ? "" : p.Shares < 0 ? $"{-p.Shares:N0}" : $"+{p.Shares:N0}") : $"{p.Shares:N0}",
right: true, bold: !isDiff, borderTop: !isDiff),
NewTd(isDiff ? (p.SharesDormant == 0 ? "" : p.SharesDormant < 0 ? $"{-p.SharesDormant:N0}" : $"+{p.SharesDormant:N0}") : $"{p.SharesDormant:N0}",
right : true, bold: !isDiff, borderTop: !isDiff),
];
}
}
protected Table NewMemberBusinessSharesTable(IEnumerable<MemberHistory> history) {
var tbl = new Table(ColsMM(18, 93, App.Client.HasRedWhite ? 18 : 12, App.Client.HasRedWhite ? 12 : 18, 12, 12), true)
.SetWidth(UnitValue.CreatePercentValue(100)).SetFixedLayout()
.SetBorderCollapse(BorderCollapsePropertyValue.COLLAPSE)
.SetBorder(Border.NO_BORDER)
.SetFontSize(10);
var tw = App.Client.HasRedWhite ? 1 : 2;
tbl.AddHeaderCell(NewTh("Meldung am", rowspan: 2))
.AddHeaderCell(NewTh("Text", rowspan: 2, colspan: tw, left: true))
.AddHeaderCell(NewTh("Wirksam ab", rowspan: 2))
.AddHeaderCell(NewTh("Geschäftsanteile", colspan: App.Client.HasRedWhite ? 3 : 2));
if (App.Client.HasRedWhite) {
tbl.AddHeaderCell(NewTh("rot"))
.AddHeaderCell(NewTh("weiß"))
.AddHeaderCell(NewTh("ruhend"));
} else {
tbl.AddHeaderCell(NewTh("normal"))
.AddHeaderCell(NewTh("ruhend"));
}
if (!history.Any() || Member.EntryDate <= history.First().DateNotice) {
tbl.AddCell(NewTd($"{Member.EntryDate:dd.MM.yyyy}"))
.AddCell(NewTd("Eintritt", colspan: tw, bold: true))
.AddCell(NewTd($"{Member.EntryDate:dd.MM.yyyy}"))
.AddCells(NewBusinessSharesCells(new()));
}
var recorded = history.Aggregate(new MemberHistoryPoint(), (s, h) => new(
s.Shares + (h.ToMgNr == Member.MgNr && h.ToType == BusinessShareType.Normal ? h.Shares : 0) - (h.FromMgNr == Member.MgNr && h.FromType == BusinessShareType.Normal ? h.Shares : 0),
s.SharesRed + (h.ToMgNr == Member.MgNr && h.ToType == BusinessShareType.Red ? h.Shares : 0) - (h.FromMgNr == Member.MgNr && h.FromType == BusinessShareType.Red ? h.Shares : 0),
s.SharesWhite + (h.ToMgNr == Member.MgNr && h.ToType == BusinessShareType.White ? h.Shares : 0) - (h.FromMgNr == Member.MgNr && h.FromType == BusinessShareType.White ? h.Shares : 0),
s.SharesDormant + (h.ToMgNr == Member.MgNr && h.ToType == BusinessShareType.Dormant ? h.Shares : 0) - (h.FromMgNr == Member.MgNr && h.FromType == BusinessShareType.Dormant ? h.Shares : 0)));
var cur = new MemberHistoryPoint(Member.Shares - recorded.Shares, Member.SharesRed - recorded.SharesRed, Member.SharesWhite - recorded.SharesWhite, Member.SharesDormant - recorded.SharesDormant);
if (cur.Shares != 0 || cur.SharesRed != 0 || cur.SharesWhite != 0 || cur.SharesDormant != 0) {
tbl.AddCell(NewTd())
.AddCell(NewTd("Nicht in Software erfasst", colspan: tw, italic: true))
.AddCell(NewTd())
.AddCells(NewBusinessSharesCells(cur));
if (history.Any()) {
tbl.AddCell(NewTd(borderTop: true))
.AddCell(NewTd($"Bis Lese {history.First().DateNotice.Year - 1}", borderTop: true, colspan: tw, bold: true))
.AddCell(NewTd(borderTop: true))
.AddCells(NewBusinessSharesCells(cur, isDiff: false));
}
}
DateOnly? lastDate = null;
foreach (var row in history) {
int s = 0, r = 0, w = 0, d = 0;
if (row.FromMgNr == Member.MgNr) {
switch (row.FromType) {
case BusinessShareType.Normal: s -= row.Shares; break;
case BusinessShareType.Red: r -= row.Shares; break;
case BusinessShareType.White: w -= row.Shares; break;
case BusinessShareType.Dormant: d -= row.Shares; break;
}
}
if (row.ToMgNr == Member.MgNr) {
switch (row.ToType) {
case BusinessShareType.Normal: s += row.Shares; break;
case BusinessShareType.Red: r += row.Shares; break;
case BusinessShareType.White: w += row.Shares; break;
case BusinessShareType.Dormant: d += row.Shares; break;
}
}
if (lastDate < Member.EntryDate && row.DateNotice <= Member.EntryDate) {
tbl.AddCell(NewTd($"{Member.EntryDate:dd.MM.yyyy}"))
.AddCell(NewTd("Eintritt", colspan: tw, bold: true))
.AddCell(NewTd($"{Member.EntryDate:dd.MM.yyyy}"))
.AddCells(NewBusinessSharesCells(new()));
}
if (lastDate != null && row.DateNotice.Year != lastDate?.Year) {
tbl.AddCell(NewTd(borderTop: true))
.AddCell(NewTd(lastDate?.Year == row.DateNotice.Year - 1 ? $"Lese {lastDate?.Year}" : $"Lese {lastDate?.Year}{row.DateNotice.Year - 1}", borderTop: true, colspan: tw, bold: true))
.AddCell(NewTd(borderTop: true))
.AddCells(NewBusinessSharesCells(cur, isDiff: false));
}
if (lastDate < Member.ExitDate && row.DateNotice <= Member.ExitDate) {
tbl.AddCell(NewTd($"{Member.ExitDate:dd.MM.yyyy}"))
.AddCell(NewTd("Austritt", colspan: tw, bold: true))
.AddCell(NewTd($"31.12.{Member.ExitDate.Value.Year + 1}")) // FIXME
.AddCells(NewBusinessSharesCells(new()));
}
cur = new(cur.Shares + s, cur.SharesRed + r, cur.SharesWhite + w, cur.SharesDormant + d);
tbl.AddCell(NewTd($"{row.DateNotice:dd.MM.yyyy}"))
.AddCell(NewTd(row.FormatReasonPhrase(Member.MgNr), colspan: tw))
.AddCell(NewTd($"{row.DateEffective:dd.MM.yyyy}"))
.AddCells(NewBusinessSharesCells(new(s, r, w, d)));
lastDate = row.DateNotice;
}
if (Member.EntryDate != null && history.Any() && Member.EntryDate > lastDate) {
tbl.AddCell(NewTd($"{Member.EntryDate:dd.MM.yyyy}"))
.AddCell(NewTd("Eintritt", colspan: tw, bold: true))
.AddCell(NewTd($"{Member.EntryDate:dd.MM.yyyy}"))
.AddCells(NewBusinessSharesCells(new()));
}
if (Member.ExitDate != null && (!history.Any() || Member.ExitDate > lastDate)) {
tbl.AddCell(NewTd($"{Member.ExitDate:dd.MM.yyyy}"))
.AddCell(NewTd("Austritt", colspan: tw, bold: true))
.AddCell(NewTd($"31.12.{Member.ExitDate.Value.Year + 1}")) // FIXME
.AddCells(NewBusinessSharesCells(new()));
}
tbl.AddCell(NewTd(borderTop: true))
.AddCell(NewTd(lastDate == null ? "Aktuell" : $"Ab Lese {lastDate?.Year}", borderTop: true, colspan: tw, bold: true))
.AddCell(NewTd(borderTop: true))
.AddCells(NewBusinessSharesCells(cur, isDiff: false));
return tbl;
}
} }
} }
+1 -1
View File
@@ -86,7 +86,7 @@ namespace Elwig.Documents {
.AddCell(NewTd($"{m.Plz}", 8)) .AddCell(NewTd($"{m.Plz}", 8))
.AddCell(NewTd(m.Locality, 6)) .AddCell(NewTd(m.Locality, 6))
.AddCell(NewTd(m.LfbisNr ?? "", 8)) .AddCell(NewTd(m.LfbisNr ?? "", 8))
.AddCell(NewTd($"{m.SharesTotal:N0}", 8, right: true).SetPaddingLeft(0).SetPaddingRight(0)) .AddCell(NewTd($"{m.SharesActive:N0}", 8, right: true).SetPaddingLeft(0).SetPaddingRight(0))
.AddCell(NewTd(m.DefaultKg ?? "", 6)); .AddCell(NewTd(m.DefaultKg ?? "", 6));
if (AreaComFilters.Length > 0) { if (AreaComFilters.Length > 0) {
foreach (var v in AreaComFilters) { foreach (var v in AreaComFilters) {
+1 -1
View File
@@ -139,7 +139,7 @@ namespace Elwig.Documents {
.AddCell(NewSectionTh("Datum/Überw.:", overflow: true)) .AddCell(NewSectionTh("Datum/Überw.:", overflow: true))
.AddCell(NewTd($"{Variant.Date:dd.MM.yyyy} / {Variant.TransferDate:dd.MM.yyyy}", colspan: 4, center: true)) .AddCell(NewTd($"{Variant.Date:dd.MM.yyyy} / {Variant.TransferDate:dd.MM.yyyy}", colspan: 4, center: true))
.AddCell(NewSectionTh("Automatische Nachzeichnung der GA:", colspan: 2, borderLeft: true)) .AddCell(NewSectionTh("(Automatische) Nachzeichnung von GA:", colspan: 2, borderLeft: true))
.AddCell(NewTd(BillingData.ConsiderAutoBusinessShares ? "Ja" : "Nein", center: true)) .AddCell(NewTd(BillingData.ConsiderAutoBusinessShares ? "Ja" : "Nein", center: true))
.AddCell(NewSectionTh("Berechnung:")) .AddCell(NewSectionTh("Berechnung:"))
+12 -12
View File
@@ -9,10 +9,10 @@
<UseWindowsForms>true</UseWindowsForms> <UseWindowsForms>true</UseWindowsForms>
<PreserveCompilationContext>true</PreserveCompilationContext> <PreserveCompilationContext>true</PreserveCompilationContext>
<ApplicationIcon>Resources\Images\Elwig.ico</ApplicationIcon> <ApplicationIcon>Resources\Images\Elwig.ico</ApplicationIcon>
<Version>1.0.5.6</Version> <Version>1.1.0.3</Version>
<SatelliteResourceLanguages>de-AT</SatelliteResourceLanguages> <SatelliteResourceLanguages>de-AT</SatelliteResourceLanguages>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<ApplicationManifest>app.manifest</ApplicationManifest> <ApplicationManifest>App.manifest</ApplicationManifest>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
@@ -23,21 +23,21 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="bblanchon.PDFium.Win32" Version="151.0.7906" /> <PackageReference Include="bblanchon.PDFium.Win32" Version="153.0.8009" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.2" /> <PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.2" />
<PackageReference Include="itext" Version="9.6.0" /> <PackageReference Include="itext" Version="9.7.0" />
<PackageReference Include="itext.bouncy-castle-adapter" Version="9.6.0" /> <PackageReference Include="itext.bouncy-castle-adapter" Version="9.7.0" />
<PackageReference Include="LinqKit" Version="1.3.11" /> <PackageReference Include="LinqKit" Version="1.3.11" />
<PackageReference Include="MailKit" Version="4.17.0" /> <PackageReference Include="MailKit" Version="4.17.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.9" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.11" />
<PackageReference Include="Microsoft.Extensions.Configuration.Ini" Version="10.0.9" /> <PackageReference Include="Microsoft.Extensions.Configuration.Ini" Version="10.0.11" />
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.4022.49" /> <PackageReference Include="Microsoft.Web.WebView2" Version="1.0.4129.50" />
<PackageReference Include="NJsonSchema" Version="11.6.1" /> <PackageReference Include="NJsonSchema" Version="11.6.1" />
<PackageReference Include="ScottPlot.WPF" Version="5.1.59" /> <PackageReference Include="ScottPlot.WPF" Version="5.1.59" />
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="3.0.3" /> <PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="3.0.5" />
<PackageReference Include="System.IO.Hashing" Version="10.0.9" /> <PackageReference Include="System.IO.Hashing" Version="10.0.11" />
<PackageReference Include="System.IO.Ports" Version="10.0.9" /> <PackageReference Include="System.IO.Ports" Version="10.0.11" />
<PackageReference Include="System.Management" Version="10.0.9" /> <PackageReference Include="System.Management" Version="10.0.11" />
</ItemGroup> </ItemGroup>
</Project> </Project>
+4
View File
@@ -315,6 +315,10 @@ namespace Elwig.Helpers {
return (await DeliverySchedules.Where(s => s.Year == year).Select(v => (int?)v.DsNr).MaxAsync() ?? 0) + 1; return (await DeliverySchedules.Where(s => s.Year == year).Select(v => (int?)v.DsNr).MaxAsync() ?? 0) + 1;
} }
public async Task<int> NextHistNr() {
return (await MemberHistory.Select(c => (int?)c.HistNr).MaxAsync() ?? 0) + 1;
}
public IAsyncEnumerable<Branch> FetchBranches(string? zwstid = null, bool includeWithoutMembers = true) { public IAsyncEnumerable<Branch> FetchBranches(string? zwstid = null, bool includeWithoutMembers = true) {
return _compiledQueryBranches.Invoke(this, zwstid, includeWithoutMembers); return _compiledQueryBranches.Invoke(this, zwstid, includeWithoutMembers);
} }
+5 -5
View File
@@ -54,14 +54,14 @@ namespace Elwig.Helpers.Billing {
if (addMinShares < 1) addMinShares = 1; if (addMinShares < 1) addMinShares = 1;
using var cnx = await AppDbContext.ConnectAsync(); using var cnx = await AppDbContext.ConnectAsync();
await cnx.ExecuteBatch($""" await cnx.ExecuteBatch($"""
DELETE FROM member_history WHERE source = 'elwig' AND reason = 'auto' AND SUBSTR(date, 1, 4) = '{Year}'; DELETE FROM member_history WHERE source = 'elwig' AND reason = '{MemberHistory.REASON_PRESCRIPTION}' AND deduct_year = {Year};
INSERT INTO member_history (histnr, from_mgnr, from_type, to_mgnr, to_type, date, reason, source, shares, value_per_share, currency) INSERT INTO member_history (histnr, from_mgnr, from_type, to_mgnr, to_type, date_notice, date_effective, reason, source, deduct_year, shares, value_per_share, currency, comment)
SELECT COALESCE((SELECT MAX(histnr) AS histnr FROM member_history), 0) + ROW_NUMBER() OVER(ORDER BY m.mgnr), SELECT COALESCE((SELECT MAX(histnr) AS histnr FROM member_history), 0) + ROW_NUMBER() OVER(ORDER BY m.mgnr),
NULL, NULL, u.mgnr, 1, '{date:yyyy-MM-dd}', 'auto', 'elwig', NULL, NULL, u.mgnr, 1, '{date:yyyy-MM-dd}', '{date:yyyy-MM-dd}', '{MemberHistory.REASON_PRESCRIPTION}', 'elwig', s.year,
CEIL((u.diff - {allowanceKg}.0 - {allowanceKgPerShare}.0 * u.shares) / s.max_kg_per_share CEIL((u.diff - {allowanceKg}.0 - {allowanceKgPerShare}.0 * u.shares) / s.max_kg_per_share
- {allowanceShares.ToString(CultureInfo.InvariantCulture)} - {allowanceShares.ToString(CultureInfo.InvariantCulture)}
- {allowanceRel.ToString(CultureInfo.InvariantCulture)} * u.shares) AS adjust_shares, - {allowanceRel.ToString(CultureInfo.InvariantCulture)} * u.shares) AS adjust_shares,
s.share_value / POW(10, s.precision - 2), s.currency s.share_value / POW(10, s.precision - 2), s.currency, 'durch automatische Nachzeichnung'
FROM v_total_under_delivery u FROM v_total_under_delivery u
JOIN season s ON s.year = u.year JOIN season s ON s.year = u.year
JOIN member m ON m.mgnr = u.mgnr JOIN member m ON m.mgnr = u.mgnr
@@ -72,7 +72,7 @@ namespace Elwig.Helpers.Billing {
public async Task UnAdjustBusinessShares() { public async Task UnAdjustBusinessShares() {
using var cnx = await AppDbContext.ConnectAsync(); using var cnx = await AppDbContext.ConnectAsync();
await cnx.ExecuteBatch($""" await cnx.ExecuteBatch($"""
DELETE FROM member_history WHERE source = 'elwig' AND reason = 'auto' AND SUBSTR(date, 1, 4) = '{Year}'; DELETE FROM member_history WHERE source = 'elwig' AND reason = '{MemberHistory.REASON_PRESCRIPTION}' AND deduct_year = {Year};
"""); """);
} }
+6 -2
View File
@@ -50,6 +50,7 @@ namespace Elwig.Helpers {
public string? SyncUrl = null; public string? SyncUrl = null;
public string SyncUsername = ""; public string SyncUsername = "";
public string SyncPassword = ""; public string SyncPassword = "";
public bool SyncMain = false;
public string? SmtpHost = null; public string? SmtpHost = null;
public int? SmtpPort = null; public int? SmtpPort = null;
@@ -57,9 +58,10 @@ namespace Elwig.Helpers {
public string? SmtpUsername = null; public string? SmtpUsername = null;
public string? SmtpPassword = null; public string? SmtpPassword = null;
public string? SmtpFrom = 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 ? 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; public IList<ScaleConfig> Scales;
private readonly List<ScaleConfig> ScaleList = []; private readonly List<ScaleConfig> ScaleList = [];
@@ -85,6 +87,7 @@ namespace Elwig.Helpers {
SyncUrl = config["sync:url"]; SyncUrl = config["sync:url"];
SyncUsername = config["sync:username"] ?? ""; SyncUsername = config["sync:username"] ?? "";
SyncPassword = config["sync:password"] ?? ""; SyncPassword = config["sync:password"] ?? "";
SyncMain = TrueValues.Contains(config["sync:main"]?.ToLower());
SmtpHost = config["smtp:host"]; SmtpHost = config["smtp:host"];
SmtpPort = config["smtp:port"]?.All(char.IsAsciiDigit) == true && config["smtp:port"]?.Length > 0 ? int.Parse(config["smtp:port"]!) : null; SmtpPort = config["smtp:port"]?.All(char.IsAsciiDigit) == true && config["smtp:port"]?.Length > 0 ? int.Parse(config["smtp:port"]!) : null;
@@ -92,6 +95,7 @@ namespace Elwig.Helpers {
SmtpUsername = config["smtp:username"]; SmtpUsername = config["smtp:username"];
SmtpPassword = config["smtp:password"]; SmtpPassword = config["smtp:password"];
SmtpFrom = config["smtp:from"]; 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(); var scales = config.AsEnumerable().Where(i => i.Key.StartsWith("scale.")).GroupBy(i => i.Key.Split(':')[0][6..]).Select(i => i.Key).Order();
ScaleList.Clear(); ScaleList.Clear();
+19 -9
View File
@@ -1,3 +1,4 @@
using Elwig.Models;
using Elwig.Models.Entities; using Elwig.Models.Entities;
using Elwig.Services; using Elwig.Services;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
@@ -9,6 +10,7 @@ using System.IO.Compression;
using System.Linq; using System.Linq;
using System.Text.Json.Nodes; using System.Text.Json.Nodes;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows;
namespace Elwig.Helpers.Export { namespace Elwig.Helpers.Export {
public static class ElwigData { public static class ElwigData {
@@ -239,6 +241,8 @@ namespace Elwig.Helpers.Export {
var device = meta.Device; var device = meta.Device;
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
var tx = await ctx.Database.BeginTransactionAsync();
await ctx.Database.ExecuteSqlAsync($"UPDATE client_parameter SET value = '0' WHERE param = 'ENABLE_MEMBER_HISTORY_TRIGGERS'");
var kgnrs = wbKgs.Select(k => k.KgNr).ToList(); var kgnrs = wbKgs.Select(k => k.KgNr).ToList();
var duplicateKgNrs = await ctx.WbKgs var duplicateKgNrs = await ctx.WbKgs
@@ -402,9 +406,9 @@ namespace Elwig.Helpers.Export {
importedDeliveries.Add((meta.FileName, meta.ZwstId, meta.Device, n, o, deliveries.Count - n - o, meta.DeliveryFilters)); importedDeliveries.Add((meta.FileName, meta.ZwstId, meta.Device, n, o, deliveries.Count - n - o, meta.DeliveryFilters));
} }
await ctx.Database.ExecuteSqlAsync($"UPDATE client_parameter SET value = '0' WHERE param = 'ENABLE_MEMBER_HISTORY_TRIGGERS'");
await ctx.SaveChangesAsync(); await ctx.SaveChangesAsync();
await ctx.Database.ExecuteSqlAsync($"UPDATE client_parameter SET value = '1' WHERE param = 'ENABLE_MEMBER_HISTORY_TRIGGERS'"); await ctx.Database.ExecuteSqlAsync($"UPDATE client_parameter SET value = '1' WHERE param = 'ENABLE_MEMBER_HISTORY_TRIGGERS'");
await tx.CommitAsync();
var primaryKeys = new Dictionary<string, string>() { var primaryKeys = new Dictionary<string, string>() {
["member"] = "mgnr, 0, 0", ["member"] = "mgnr, 0, 0",
@@ -748,15 +752,18 @@ namespace Elwig.Helpers.Export {
return new JsonObject { return new JsonObject {
["histnr"] = h.HistNr, ["histnr"] = h.HistNr,
["from_mgnr"] = h.FromMgNr, ["from_mgnr"] = h.FromMgNr,
["from_type"] = h.FromType, ["from_type"] = h.FromType?.ToString().ToLower(),
["to_mgnr"] = h.ToMgNr, ["to_mgnr"] = h.ToMgNr,
["to_type"] = h.ToType, ["to_type"] = h.ToType?.ToString().ToLower(),
["date"] = h.DateString, ["date_notice"] = h.DateNoticeString,
["date_effective"] = h.DateEffectiveString,
["reason"] = h.Reason, ["reason"] = h.Reason,
["source"] = h.Source, ["source"] = h.Source,
["shares"] = h.Shares, ["shares"] = h.Shares,
["signed"] = h.MemberHasSigned,
["value_per_share"] = h.ValuePerShare, ["value_per_share"] = h.ValuePerShare,
["currency"] = h.CurrencyCode, ["currency"] = h.CurrencyCode,
["deduct_year"] = h.DeductYear,
["comment"] = h.Comment, ["comment"] = h.Comment,
}; };
} }
@@ -765,15 +772,18 @@ namespace Elwig.Helpers.Export {
return new MemberHistory { return new MemberHistory {
HistNr = json["histnr"]!.AsValue().GetValue<int>(), HistNr = json["histnr"]!.AsValue().GetValue<int>(),
FromMgNr = json["from_mgnr"]?.AsValue().GetValue<int>(), FromMgNr = json["from_mgnr"]?.AsValue().GetValue<int>(),
FromType = json["from_type"]?.AsValue().GetValue<int>(), FromType = Enum.TryParse<BusinessShareType>(json["from_type"]?.AsValue().GetValue<string>(), true, out var from) ? from : null,
ToMgNr = json["to_mgnr"]?.AsValue().GetValue<int>(), ToMgNr = json["to_mgnr"]?.AsValue().GetValue<int>(),
ToType = json["to_type"]?.AsValue().GetValue<int>(), ToType = Enum.TryParse<BusinessShareType>(json["to_type"]?.AsValue().GetValue<string>(), true, out var to) ? to : null,
DateString = json["date"]!.AsValue().GetValue<string>(), DateNoticeString = json["date_notice"]!.AsValue().GetValue<string>(),
DateEffectiveString = json["date_effective"]!.AsValue().GetValue<string>(),
Reason = json["reason"]!.AsValue().GetValue<string>(), Reason = json["reason"]!.AsValue().GetValue<string>(),
Source = json["source"]!.AsValue().GetValue<string>(), Source = json["source"]!.AsValue().GetValue<string>(),
Shares = json["shares"]!.AsValue().GetValue<int>(), Shares = json["shares"]!.AsValue().GetValue<int>(),
MemberHasSigned = json["signed"]?.AsValue().GetValue<bool>() ?? false,
ValuePerShare = json["value_per_share"]?.AsValue().GetValue<decimal>(), ValuePerShare = json["value_per_share"]?.AsValue().GetValue<decimal>(),
CurrencyCode = json["currency"]?.AsValue().GetValue<string>(), CurrencyCode = json["currency"]?.AsValue().GetValue<string>(),
DeductYear = json["deduct_year"]?.AsValue().GetValue<int>(),
Comment = json["comment"]?.AsValue().GetValue<string>(), Comment = json["comment"]?.AsValue().GetValue<string>(),
}; };
} }
@@ -941,7 +951,7 @@ namespace Elwig.Helpers.Export {
if (p.Unloading != null) obj["unloading"] = p.Unloading; if (p.Unloading != null) obj["unloading"] = p.Unloading;
if (p.Temperature != null) obj["temperature"] = p.Temperature; if (p.Temperature != null) obj["temperature"] = p.Temperature;
if (p.Acid != null) obj["acid"] = p.Acid; if (p.Acid != null) obj["acid"] = p.Acid;
if (p.ScaleId != null) obj["scale_id"] = p.ScaleId; if (p.ScaleTerminalId != null) obj["scale_terminal"] = p.ScaleTerminalId;
if (p.WeighingData != null) obj["weighing_data"] = JsonNode.Parse(p.WeighingData); if (p.WeighingData != null) obj["weighing_data"] = JsonNode.Parse(p.WeighingData);
if (p.WeighingReason != null) obj["weighing_reason"] = p.WeighingReason; if (p.WeighingReason != null) obj["weighing_reason"] = p.WeighingReason;
return obj; return obj;
@@ -1012,7 +1022,7 @@ namespace Elwig.Helpers.Export {
Unloading = p["unloading"]?.AsValue().GetValue<string>() ?? ((p["lesewagen"]?.AsValue().GetValue<bool>() ?? false) ? DeliveryPart.Pumped : null), Unloading = p["unloading"]?.AsValue().GetValue<string>() ?? ((p["lesewagen"]?.AsValue().GetValue<bool>() ?? false) ? DeliveryPart.Pumped : null),
Temperature = p["temperature"]?.AsValue().GetValue<double>(), Temperature = p["temperature"]?.AsValue().GetValue<double>(),
Acid = p["acid"]?.AsValue().GetValue<double>(), Acid = p["acid"]?.AsValue().GetValue<double>(),
ScaleId = p["scale_id"]?.AsValue().GetValue<string>(), ScaleTerminalId = p["scale_terminal"]?.AsValue().GetValue<string>() ?? p["scale_id"]?.AsValue().GetValue<string>(),
WeighingData = p["weighing_data"]?.AsObject().ToJsonString(Utils.JsonOpts), WeighingData = p["weighing_data"]?.AsObject().ToJsonString(Utils.JsonOpts),
WeighingReason = p["weighing_reason"]?.AsValue().GetValue<string>(), WeighingReason = p["weighing_reason"]?.AsValue().GetValue<string>(),
}, createdAt == null || modifiedAt == null ? null : }, createdAt == null || modifiedAt == null ? null :
+26
View File
@@ -4,11 +4,14 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.IO.Compression; using System.IO.Compression;
using System.IO.Hashing; using System.IO.Hashing;
using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Reflection; using System.Reflection;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
namespace Elwig.Helpers { namespace Elwig.Helpers {
public static partial class Extensions { public static partial class Extensions {
@@ -145,5 +148,28 @@ namespace Elwig.Helpers {
} }
return [.. list]; return [.. list];
} }
public static IEnumerable<T> Join<T>(this IEnumerable<T> src, Func<T> separatorFactory) {
var srcArr = src.ToArray();
for (int i = 0; i < srcArr.Length; i++) {
yield return srcArr[i];
if (i < srcArr.Length - 1) {
yield return separatorFactory();
}
}
}
public static void AddToolTipCell(this Grid grid, string text, int row, int col, int colSpan = 1, bool bold = false, bool alignRight = false, bool alignCenter = false) {
var tb = new TextBlock() {
Text = text,
TextAlignment = alignRight ? TextAlignment.Right : alignCenter ? TextAlignment.Center : TextAlignment.Left,
Margin = new(0, 12 * row, 0, 0),
FontWeight = bold ? FontWeights.Bold : FontWeights.Normal,
};
tb.SetValue(Grid.ColumnProperty, col);
tb.SetValue(Grid.ColumnSpanProperty, colSpan);
grid.Children.Add(tb);
}
} }
} }
+3 -14
View File
@@ -1,7 +1,6 @@
using Elwig.Services; using Elwig.Services;
using Elwig.Windows; using Elwig.Windows;
using System; using System;
using System.Drawing.Printing;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Elwig.Helpers.Printing { 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) { public static 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) {
try { try {
using var printDoc = new PdfPrintDocument(path) { var printer = new PdfPrinter();
PrinterSettings = settings, printer.Print(path, copies, doublePaged);
};
printDoc.Print();
} catch (Exception exc) { } catch (Exception exc) {
InteractionService.ShowException("Fehler beim Drucken", "Beim Drucken ist ein Fehler aufgetreten", exc); InteractionService.ShowException("Fehler beim Drucken", "Beim Drucken ist ein Fehler aufgetreten", exc);
} }
-102
View File
@@ -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);
}
}
+83
View File
@@ -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;
}
}
}
+38
View File
@@ -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);
}
}
+239
View File
@@ -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);
}
}
}
}
+1 -1
View File
@@ -516,7 +516,7 @@ namespace Elwig.Helpers {
public static async Task<SmtpClient?> GetSmtpClient() { public static async Task<SmtpClient?> GetSmtpClient() {
if (App.Config.Smtp == null) if (App.Config.Smtp == null)
return 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(); var client = new SmtpClient();
await client.ConnectAsync(host, port, mode == "starttls" ? SecureSocketOptions.StartTls : SecureSocketOptions.None); await client.ConnectAsync(host, port, mode == "starttls" ? SecureSocketOptions.StartTls : SecureSocketOptions.None);
await client.AuthenticateAsync(username, password); await client.AuthenticateAsync(username, password);
+8 -14
View File
@@ -136,8 +136,7 @@ namespace Elwig.Helpers {
return new(false, "PLZ zu kurz"); return new(false, "PLZ zu kurz");
} }
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
int plz = int.Parse(input.Text); if (!int.TryParse(input.Text, out var plz) || ctx.Postleitzahlen.Find(plz) == null) {
if (ctx.Postleitzahlen.Find(plz) == null) {
return new(false, "Ungültige PLZ"); return new(false, "Ungültige PLZ");
} }
return new(true, null); return new(true, null);
@@ -423,8 +422,7 @@ namespace Elwig.Helpers {
} }
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
int nr = int.Parse(input.Text); if (!int.TryParse(input.Text, out var nr) || !ctx.MgNrExists(nr).GetAwaiter().GetResult()) {
if (!ctx.MgNrExists(nr).GetAwaiter().GetResult()) {
return new(false, "Ungültige Mitgliedsnummer"); return new(false, "Ungültige Mitgliedsnummer");
} }
@@ -440,8 +438,7 @@ namespace Elwig.Helpers {
} }
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
int nr = int.Parse(input.Text); if (!int.TryParse(input.Text, out var nr) || nr != m?.MgNr && ctx.MgNrExists(nr).GetAwaiter().GetResult()) {
if (nr != m?.MgNr && ctx.MgNrExists(nr).GetAwaiter().GetResult()) {
return new(false, "Mitgliedsnummer wird bereits verwendet"); return new(false, "Mitgliedsnummer wird bereits verwendet");
} }
@@ -476,7 +473,7 @@ namespace Elwig.Helpers {
return res; return res;
} else if (!required && input.Text.Length == 0) { } else if (!required && input.Text.Length == 0) {
return new(true, null); return new(true, null);
} else if (!ctx.MgNrExists(int.Parse(input.Text)).GetAwaiter().GetResult()) { } else if (!int.TryParse(input.Text, out var nr) ||!ctx.MgNrExists(nr).GetAwaiter().GetResult()) {
return new(false, "Ein Mitglied mit dieser Mitgliedsnummer existiert nicht"); return new(false, "Ein Mitglied mit dieser Mitgliedsnummer existiert nicht");
} }
@@ -537,7 +534,7 @@ namespace Elwig.Helpers {
return (parts[0]?.Length == 4) ? new(true, null) : new(false, "Datum ist ungültig"); return (parts[0]?.Length == 4) ? new(true, null) : new(false, "Datum ist ungültig");
} else if (p == 1) { } else if (p == 1) {
// only month and year provided // only month and year provided
int m = parts[0] != null && parts[0] != "" ? int.Parse(parts[0] ?? "0") : 0; int m = parts[0] != null && parts[0] != "" && int.TryParse(parts[0], out var v) ? v : 0;
if (parts[1]?.Length != 4 || parts[0]?.Length != 2 || m < 1 || m > 12) if (parts[1]?.Length != 4 || parts[0]?.Length != 2 || m < 1 || m > 12)
return new(false, "Datum ist ungültig"); return new(false, "Datum ist ungültig");
return new(true, null); return new(true, null);
@@ -589,8 +586,7 @@ namespace Elwig.Helpers {
} }
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
int nr = int.Parse(input.Text); if (!int.TryParse(input.Text, out var nr) || (nr != c?.FbNr && ctx.FbNrExists(nr).GetAwaiter().GetResult())) {
if (nr != c?.FbNr && ctx.FbNrExists(nr).GetAwaiter().GetResult()) {
return new(false, "Flächenbindungsnummer wird bereits verwendet"); return new(false, "Flächenbindungsnummer wird bereits verwendet");
} }
@@ -605,8 +601,7 @@ namespace Elwig.Helpers {
return new(true, null); return new(true, null);
} }
var oe = double.Parse(input.Text); if (!double.TryParse(input.Text, out var oe) || oe < 10 || oe >= 300) {
if (oe < 10 || oe >= 300) {
return new(false, "Ungültiger Oechsle-Wert"); return new(false, "Ungültiger Oechsle-Wert");
} }
@@ -621,8 +616,7 @@ namespace Elwig.Helpers {
return new(true, null); return new(true, null);
} }
var kmw = double.Parse(input.Text); if (!double.TryParse(input.Text, out var kmw) || kmw < 5 || kmw >= 50) {
if (kmw < 5 || kmw >= 50) {
return new(false, "Ungültiger KMW-Wert"); return new(false, "Ungültiger KMW-Wert");
} }
+2 -5
View File
@@ -9,9 +9,8 @@ namespace Elwig.Helpers.Weighing {
public class AveryEventScale : Scale, IEventScale, IDisposable { public class AveryEventScale : Scale, IEventScale, IDisposable {
public string Manufacturer => "Avery"; public string Manufacturer => "Avery";
public int InternalScaleNr => 1;
public string Model { get; private set; } public string Model { get; private set; }
public string ScaleId { get; private set; } public string ScaleTerminalId { get; private set; }
public bool IsReady { get; private set; } public bool IsReady { get; private set; }
public bool HasFillingClearance { get; private set; } public bool HasFillingClearance { get; private set; }
@@ -19,13 +18,11 @@ namespace Elwig.Helpers.Weighing {
private bool IsRunning = true; private bool IsRunning = true;
private readonly Thread BackgroundThread; private readonly Thread BackgroundThread;
private readonly string Connection;
public AveryEventScale(string id, string model, string cnx, string? log = null, bool required = true) : public AveryEventScale(string id, string model, string cnx, string? log = null, bool required = true) :
base(cnx, null, null, null, log, true, !required) { base(cnx, null, null, null, log, true, !required) {
ScaleId = id; ScaleTerminalId = id;
Model = model; Model = model;
Connection = cnx;
IsReady = true; IsReady = true;
HasFillingClearance = false; HasFillingClearance = false;
Stream.WriteTimeout = -1; Stream.WriteTimeout = -1;
@@ -5,18 +5,17 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Elwig.Helpers.Weighing { namespace Elwig.Helpers.Weighing {
public class GassnerScale : Scale, ICommandScale { public class GassnerEnqScale : Scale, ICommandScale {
public string Manufacturer => "Gassner"; public string Manufacturer => "Gassner";
public int InternalScaleNr => 1;
public string Model { get; private set; } public string Model { get; private set; }
public string ScaleId { get; private set; } public string ScaleTerminalId { get; private set; }
public bool IsReady { get; private set; } public bool IsReady { get; private set; }
public bool HasFillingClearance { get; private set; } public bool HasFillingClearance { get; private set; }
public GassnerScale(string id, string model, string cnx, string? empty = null, string? filling = null, int? limit = null, string? log = null) : public GassnerEnqScale(string id, string model, string cnx, string? empty = null, string? filling = null, int? limit = null, string? log = null) :
base(cnx, empty, filling, limit, log) { base(cnx, empty, filling, limit, log) {
ScaleId = id; ScaleTerminalId = id;
Model = model; Model = model;
IsReady = true; IsReady = true;
HasFillingClearance = false; HasFillingClearance = false;
@@ -24,10 +23,9 @@ namespace Elwig.Helpers.Weighing {
Stream.ReadTimeout = 11000; Stream.ReadTimeout = 11000;
} }
protected Task SendCommand(char command) => SendCommand(Convert.ToByte(command)); protected Task SendCommand(string command) => SendCommand(Encoding.ASCII.GetBytes(command));
protected async Task SendCommand(byte command) { protected async Task SendCommand(byte[] cmd) {
byte[] cmd = [command];
await Stream.WriteAsync(cmd); await Stream.WriteAsync(cmd);
if (LogPath != null) await File.AppendAllTextAsync(LogPath, Encoding.ASCII.GetString(cmd)); if (LogPath != null) await File.AppendAllTextAsync(LogPath, Encoding.ASCII.GetString(cmd));
} }
@@ -53,15 +51,15 @@ namespace Elwig.Helpers.Weighing {
return line[1..^1]; return line[1..^1];
} }
protected async Task<WeighingResult> Weigh(bool incIdentNr, bool retry = true) { protected async Task<WeighingResult> Weigh(int? internalScaleNr, bool incIdentNr, bool retry = true) {
string record; string record;
try { try {
await SendCommand(incIdentNr ? '\x05' : '?'); await SendCommand(incIdentNr ? "\x05" : "?");
record = await ReceiveResponse(); record = await ReceiveResponse();
} catch (IOException) { } catch (IOException) {
if (!retry || Tcp == null) throw; if (!retry || Tcp == null) throw;
ReconnectTcp(); ReconnectTcp();
return await Weigh(incIdentNr, false); return await Weigh(internalScaleNr, incIdentNr, false);
} }
if (record.Length != 45) if (record.Length != 45)
throw new FormatException("Invalid response from scale: Received record has invalid size"); throw new FormatException("Invalid response from scale: Received record has invalid size");
@@ -80,6 +78,7 @@ namespace Elwig.Helpers.Weighing {
GrossWeight = int.Parse(brutto), GrossWeight = int.Parse(brutto),
TareWeight = int.Parse(tara), TareWeight = int.Parse(tara),
NetWeight = int.Parse(netto), NetWeight = int.Parse(netto),
ScaleId = scaleNr,
WeighingId = identNr, WeighingId = identNr,
FullWeighingId = identNr, FullWeighingId = identNr,
Date = DateOnly.TryParseExact(date, "yyyyMMdd", out var d) ? d : null, Date = DateOnly.TryParseExact(date, "yyyyMMdd", out var d) ? d : null,
@@ -87,12 +86,12 @@ namespace Elwig.Helpers.Weighing {
}; };
} }
public async Task<WeighingResult> Weigh() { public async Task<WeighingResult> Weigh(int? scaleNr = null) {
return await Weigh(true); return await Weigh(scaleNr, true);
} }
public async Task<WeighingResult> GetCurrentWeight() { public async Task<WeighingResult> GetCurrentWeight(int? scaleNr = null) {
return await Weigh(false); return await Weigh(scaleNr, false);
} }
public async Task Empty() { public async Task Empty() {
@@ -126,8 +125,9 @@ namespace Elwig.Helpers.Weighing {
await SetFillingClearance(false); await SetFillingClearance(false);
} }
public Task SetDateAndTime(DateTime dateTime) { public async Task SetDateAndTime(DateTime dateTime) {
throw new NotImplementedException("Für Waagen vom Typ 'Gassner' ist diese Funktion noch nicht implementiert"); await SendCommand($"C{dateTime:yyyyMMddHHmmss}\r");
await ReceiveResponse();
} }
} }
} }
+2 -2
View File
@@ -10,13 +10,13 @@ namespace Elwig.Helpers.Weighing {
/// Get the current weight on the scale without performing a weighing process /// Get the current weight on the scale without performing a weighing process
/// </summary> /// </summary>
/// <returns>Result of the weighing process (probably without a weighing id)</returns> /// <returns>Result of the weighing process (probably without a weighing id)</returns>
Task<WeighingResult> GetCurrentWeight(); Task<WeighingResult> GetCurrentWeight(int? scaleNr = null);
/// <summary> /// <summary>
/// Perform a weighing process /// Perform a weighing process
/// </summary> /// </summary>
/// <returns>Result of the weighing process (including a weighing id)</returns> /// <returns>Result of the weighing process (including a weighing id)</returns>
Task<WeighingResult> Weigh(); Task<WeighingResult> Weigh(int? scaleNr = null);
/// <summary> /// <summary>
/// Empty the scale container or grant clearance to do so /// Empty the scale container or grant clearance to do so
+1 -6
View File
@@ -18,12 +18,7 @@ namespace Elwig.Helpers.Weighing {
/// <summary> /// <summary>
/// Unique identificator of the scale /// Unique identificator of the scale
/// </summary> /// </summary>
string ScaleId { get; } string ScaleTerminalId { get; }
/// <summary>
/// Internal identifying number of the scale in its system
/// </summary>
int InternalScaleNr { get; }
/// <summary> /// <summary>
/// Indicates if the scale is currently processing a request or not /// Indicates if the scale is currently processing a request or not
+1 -2
View File
@@ -5,8 +5,7 @@ namespace Elwig.Helpers.Weighing {
public string Manufacturer => "NONE"; public string Manufacturer => "NONE";
public string Model => "NONE"; public string Model => "NONE";
public string ScaleId => id; public string ScaleTerminalId => id;
public int InternalScaleNr => 0;
public bool IsReady => false; public bool IsReady => false;
public bool HasFillingClearance => false; public bool HasFillingClearance => false;
public int? WeightLimit => null; public int? WeightLimit => null;
+3 -3
View File
@@ -28,10 +28,10 @@ namespace Elwig.Helpers.Weighing {
int? limit = config.Limit != null ? int.Parse(config.Limit) : null; int? limit = config.Limit != null ? int.Parse(config.Limit) : null;
if (config.Type == "SysTec-IT") { if (config.Type == "SysTec-IT") {
return new SysTecITScale(config.Id, config.Model!, config.Connection!, config.Empty, config.Filling, limit, config.Log); return new SysTecITScale(config.Id, config.Model!, config.Connection!, config.Empty, config.Filling, limit, config.Log);
} else if (config.Type == "Avery-Async") { } else if (config.Type == "Gassner-Enq" || config.Type == "Gassner") {
return new GassnerEnqScale(config.Id, config.Model!, config.Connection!, config.Empty, config.Filling, limit, config.Log);
} else if (config.Type == "Avery-Event" || config.Type == "Avery-Async") {
return new AveryEventScale(config.Id, config.Model!, config.Connection!, config.Log, config.Required); return new AveryEventScale(config.Id, config.Model!, config.Connection!, config.Log, config.Required);
} else if (config.Type == "Gassner") {
return new GassnerScale(config.Id, config.Model!, config.Connection!, config.Empty, config.Filling, limit, config.Log);
} else { } else {
throw new ArgumentException($"Invalid scale type: \"{config.Type}\""); throw new ArgumentException($"Invalid scale type: \"{config.Type}\"");
} }
+10 -10
View File
@@ -8,15 +8,14 @@ namespace Elwig.Helpers.Weighing {
public class SysTecITScale : Scale, ICommandScale { public class SysTecITScale : Scale, ICommandScale {
public string Manufacturer => "SysTec"; public string Manufacturer => "SysTec";
public int InternalScaleNr => 1;
public string Model { get; private set; } public string Model { get; private set; }
public string ScaleId { get; private set; } public string ScaleTerminalId { get; private set; }
public bool IsReady { get; private set; } public bool IsReady { get; private set; }
public bool HasFillingClearance { get; private set; } public bool HasFillingClearance { get; private set; }
public SysTecITScale(string id, string model, string cnx, string? empty = null, string? filling = null, int? limit = null, string? log = null) : public SysTecITScale(string id, string model, string cnx, string? empty = null, string? filling = null, int? limit = null, string? log = null) :
base(cnx, empty, filling, limit, log) { base(cnx, empty, filling, limit, log) {
ScaleId = id; ScaleTerminalId = id;
Model = model; Model = model;
IsReady = true; IsReady = true;
HasFillingClearance = false; HasFillingClearance = false;
@@ -74,15 +73,15 @@ namespace Elwig.Helpers.Weighing {
return line[1..^3]; return line[1..^3];
} }
protected async Task<WeighingResult> Weigh(bool incIdentNr, bool retry = true) { protected async Task<WeighingResult> Weigh(int internalScalNr, bool incIdentNr, bool retry = true) {
string record; string record;
try { try {
await SendCommand(incIdentNr ? $"RN{InternalScaleNr}" : $"RM{InternalScaleNr}"); await SendCommand(incIdentNr ? $"RN{internalScalNr}" : $"RM{internalScalNr}");
record = await ReceiveResponse(); record = await ReceiveResponse();
} catch (IOException) { } catch (IOException) {
if (!retry || Tcp == null) throw; if (!retry || Tcp == null) throw;
ReconnectTcp(); ReconnectTcp();
return await Weigh(incIdentNr, false); return await Weigh(internalScalNr, incIdentNr, false);
} }
if (record.Length != 62) if (record.Length != 62)
throw new FormatException("Invalid response from scale: Received record has invalid size"); throw new FormatException("Invalid response from scale: Received record has invalid size");
@@ -114,6 +113,7 @@ namespace Elwig.Helpers.Weighing {
GrossWeight = int.Parse(brutto), GrossWeight = int.Parse(brutto),
TareWeight = int.Parse(tara), TareWeight = int.Parse(tara),
NetWeight = int.Parse(netto), NetWeight = int.Parse(netto),
ScaleId = scaleNr,
WeighingId = identNr, WeighingId = identNr,
FullWeighingId = identNr != null ? $"{parsedDate:yyyy-MM-dd}/{identNr}" : null, FullWeighingId = identNr != null ? $"{parsedDate:yyyy-MM-dd}/{identNr}" : null,
Date = parsedDate, Date = parsedDate,
@@ -121,12 +121,12 @@ namespace Elwig.Helpers.Weighing {
}; };
} }
public async Task<WeighingResult> Weigh() { public async Task<WeighingResult> Weigh(int? scaleNr = 1) {
return await Weigh(true); return await Weigh(scaleNr ?? 1, true);
} }
public async Task<WeighingResult> GetCurrentWeight() { public async Task<WeighingResult> GetCurrentWeight(int? scaleNr = 1) {
return await Weigh(false); return await Weigh(scaleNr ?? 1, false);
} }
public async Task Empty() { public async Task Empty() {
+7 -1
View File
@@ -21,6 +21,11 @@ namespace Elwig.Helpers.Weighing {
/// </summary> /// </summary>
public int? NetWeight; public int? NetWeight;
/// <summary>
/// Reported id of the scale
/// </summary>
public string? ScaleId;
/// <summary> /// <summary>
/// Weighing id (or IdentNr) provided by the scale /// Weighing id (or IdentNr) provided by the scale
/// </summary> /// </summary>
@@ -44,11 +49,12 @@ namespace Elwig.Helpers.Weighing {
/// <returns>&lt;[GrossWeight-TaraWeight=]NetWeight/WeighingId/Date/Time&gt;</returns> /// <returns>&lt;[GrossWeight-TaraWeight=]NetWeight/WeighingId/Date/Time&gt;</returns>
public override readonly string ToString() { public override readonly string ToString() {
var w = NetWeight != null ? (GrossWeight != null && TareWeight != null ? $"{GrossWeight}-{TareWeight}=" : "") + $"{NetWeight}kg" : ""; var w = NetWeight != null ? (GrossWeight != null && TareWeight != null ? $"{GrossWeight}-{TareWeight}=" : "") + $"{NetWeight}kg" : "";
return $"<{w}/{WeighingId}/{Date:yyyy-MM-dd}/{Time:HH:mm}>"; return $"<{w}/{WeighingId}/{Date:yyyy-MM-dd}/{Time:HH:mm:ss}>";
} }
public readonly JsonObject ToJson() { public readonly JsonObject ToJson() {
var obj = new JsonObject(); var obj = new JsonObject();
if (ScaleId != null) obj["scale"] = ScaleId;
if (FullWeighingId != null) obj["id"] = FullWeighingId; if (FullWeighingId != null) obj["id"] = FullWeighingId;
if (WeighingId != null) obj["nr"] = int.Parse(WeighingId); if (WeighingId != null) obj["nr"] = int.Parse(WeighingId);
if (Date != null) obj["date"] = $"{Date:yyyy-MM-dd}"; if (Date != null) obj["date"] = $"{Date:yyyy-MM-dd}";
+5
View File
@@ -0,0 +1,5 @@
namespace Elwig.Models {
public enum BusinessShareType {
Normal = 1, Red = 2, White = 3, Dormant = 9,
}
}
+6 -1
View File
@@ -17,6 +17,7 @@ namespace Elwig.Models.Dtos {
("Address", "Adresse", null, 60), ("Address", "Adresse", null, 60),
("Plz", "PLZ", null, 10), ("Plz", "PLZ", null, 10),
("Locality", "Ort", null, 60), ("Locality", "Ort", null, 60),
("AccountingNr", "BH-Konto", null, 20),
("Iban", "IBAN", null, 45), ("Iban", "IBAN", null, 45),
("TgNr", "TG-Nr.", null, 20), ("TgNr", "TG-Nr.", null, 20),
("Sum", "Zwischens.", "€", 20), ("Sum", "Zwischens.", "€", 20),
@@ -53,7 +54,7 @@ namespace Elwig.Models.Dtos {
SELECT m.mgnr, m.name AS name_1, SELECT m.mgnr, m.name AS name_1,
COALESCE(m.prefix || ' ', '') || m.given_name || COALESCE(m.prefix || ' ', '') || m.given_name ||
COALESCE(' ' || m.middle_names, '') || COALESCE(' ' || m.suffix, '') AS name_2, COALESCE(' ' || m.middle_names, '') || COALESCE(' ' || m.suffix, '') AS name_2,
p.plz, o.name AS ort, m.address, m.iban, c.tgnr, s.year, s.precision, p.plz, o.name AS ort, m.address, m.accounting_nr, m.iban, c.tgnr, s.year, s.precision,
p.amount - p.net_amount AS surcharge, p.amount - p.net_amount AS surcharge,
c.net_amount, c.prev_net_amount, c.vat, c.vat_amount, c.gross_amount, c.modifiers, c.prev_modifiers, c.amount, c.net_amount, c.prev_net_amount, c.vat, c.vat_amount, c.gross_amount, c.modifiers, c.prev_modifiers, c.amount,
ROUND(b.total_penalty / POW(10, s.precision - 2)) AS shares_penalty, ROUND(b.total_penalty / POW(10, s.precision - 2)) AS shares_penalty,
@@ -83,6 +84,7 @@ namespace Elwig.Models.Dtos {
public string Address; public string Address;
public int Plz; public int Plz;
public string Locality; public string Locality;
public string? AccountingNr;
public string? Iban; public string? Iban;
public string TgNr; public string TgNr;
public decimal Sum; public decimal Sum;
@@ -108,6 +110,7 @@ namespace Elwig.Models.Dtos {
Address = row.Address; Address = row.Address;
Plz = row.Plz; Plz = row.Plz;
Locality = row.Locality; Locality = row.Locality;
AccountingNr = row.AccountingNr;
Iban = row.Iban != null ? Utils.FormatIban(row.Iban) : null; Iban = row.Iban != null ? Utils.FormatIban(row.Iban) : null;
TgNr = $"{row.Year}/{row.TgNr}"; TgNr = $"{row.Year}/{row.TgNr}";
Total = Utils.DecFromDb(row.NetAmount, prec1); Total = Utils.DecFromDb(row.NetAmount, prec1);
@@ -153,6 +156,8 @@ namespace Elwig.Models.Dtos {
public required string LocalityFull { get; set; } public required string LocalityFull { get; set; }
[NotMapped] [NotMapped]
public string Locality => LocalityFull.Split(",")[0]; public string Locality => LocalityFull.Split(",")[0];
[Column("accounting_nr")]
public string? AccountingNr { get; set; }
[Column("iban")] [Column("iban")]
public string? Iban { get; set; } public string? Iban { get; set; }
[Column("year")] [Column("year")]
+3 -5
View File
@@ -19,7 +19,7 @@ namespace Elwig.Models.Dtos {
("Locality", "Ort", null, 60), ("Locality", "Ort", null, 60),
("DefaultKg", "Stammgemeinde", null, 60), ("DefaultKg", "Stammgemeinde", null, 60),
("Branch", "Zweigstelle", null, 40), ("Branch", "Zweigstelle", null, 40),
("SharesTotal", "GA", null, 10), ("SharesActive", "GA", null, 10),
("BillingName", "Rechnungsname", null, 60), ("BillingName", "Rechnungsname", null, 60),
("BillingAddress", "Rechnungsadresse", null, 60), ("BillingAddress", "Rechnungsadresse", null, 60),
("BillingPlz", "PLZ", null, 10), ("BillingPlz", "PLZ", null, 10),
@@ -69,8 +69,7 @@ namespace Elwig.Models.Dtos {
public int Shares; public int Shares;
public int SharesRed; public int SharesRed;
public int SharesWhite; public int SharesWhite;
public int SharesDormant; public int SharesActive;
public int SharesTotal;
public string Address; public string Address;
public int Plz; public int Plz;
public string Locality; public string Locality;
@@ -105,8 +104,7 @@ namespace Elwig.Models.Dtos {
Shares = m.Shares; Shares = m.Shares;
SharesRed = m.SharesRed; SharesRed = m.SharesRed;
SharesWhite = m.SharesWhite; SharesWhite = m.SharesWhite;
SharesDormant = m.SharesDormant; SharesActive = Shares + SharesRed + SharesWhite;
SharesTotal = Shares + SharesRed + SharesWhite + SharesDormant;
Address = m.Address; Address = m.Address;
Plz = m.PostalDest.AtPlz!.Plz; Plz = m.PostalDest.AtPlz!.Plz;
Locality = m.PostalDest.AtPlz!.Ort.Name; Locality = m.PostalDest.AtPlz!.Ort.Name;
+4 -3
View File
@@ -119,16 +119,17 @@ namespace Elwig.Models.Entities {
public double? Acid { get; set; } public double? Acid { get; set; }
[Column("scale_id")] [Column("scale_id")]
public string? ScaleId { get; set; } public string? ScaleTerminalId { get; set; }
[Column("weighing_data")] [Column("weighing_data")]
public string? WeighingData { get; set; } public string? WeighingData { get; set; }
[NotMapped] [NotMapped]
public (string? Id, int? Gross, int? Tare, int? Net, DateOnly? Date, TimeOnly? Time) WeighingInfo { public (string? ScaleId, string? Id, int? Gross, int? Tare, int? Net, DateOnly? Date, TimeOnly? Time) WeighingInfo {
get { get {
try { try {
var obj = JsonNode.Parse(WeighingData!)!.AsObject(); var obj = JsonNode.Parse(WeighingData!)!.AsObject();
return ( return (
obj["scale"]?.AsValue().GetValue<string>(),
obj["id"]?.AsValue().GetValue<string>(), obj["id"]?.AsValue().GetValue<string>(),
obj["gross_weight"]?.AsValue().GetValue<int>(), obj["gross_weight"]?.AsValue().GetValue<int>(),
obj["tare_weight"]?.AsValue().GetValue<int>(), obj["tare_weight"]?.AsValue().GetValue<int>(),
@@ -137,7 +138,7 @@ namespace Elwig.Models.Entities {
TimeOnly.TryParseExact(obj["time"]?.AsValue().GetValue<string>(), ["HH:mm:ss", "HH:mm"], out var t) ? t : null TimeOnly.TryParseExact(obj["time"]?.AsValue().GetValue<string>(), ["HH:mm:ss", "HH:mm"], out var t) ? t : null
); );
} catch { } catch {
return (null, null, null, null, null, null); return (null, null, null, null, null, null, null);
} }
} }
} }
+2 -2
View File
@@ -42,6 +42,8 @@ namespace Elwig.Models.Entities {
[NotMapped] [NotMapped]
public string ShortName => (!string.IsNullOrWhiteSpace(GivenName) ? $"{GivenName} " : "") + Name; public string ShortName => (!string.IsNullOrWhiteSpace(GivenName) ? $"{GivenName} " : "") + Name;
[NotMapped] [NotMapped]
public string FullAdministrativeName => $"{AdministrativeName} ({MgNr})";
[NotMapped]
public string AdministrativeName => AdministrativeName1 + (!string.IsNullOrWhiteSpace(AdministrativeName2) ? $" {AdministrativeName2}" : ""); public string AdministrativeName => AdministrativeName1 + (!string.IsNullOrWhiteSpace(AdministrativeName2) ? $" {AdministrativeName2}" : "");
[NotMapped] [NotMapped]
public string AdministrativeName1 => IsJuridicalPerson ? Name : Name.Replace('ß', 'ẞ').ToUpper(); public string AdministrativeName1 => IsJuridicalPerson ? Name : Name.Replace('ß', 'ẞ').ToUpper();
@@ -79,8 +81,6 @@ namespace Elwig.Models.Entities {
[Column("shares_dormant")] [Column("shares_dormant")]
public int SharesDormant { get; set; } public int SharesDormant { get; set; }
[NotMapped]
public int SharesTotal => Shares + SharesRed + SharesWhite + SharesDormant;
[NotMapped] [NotMapped]
public int SharesActive => Shares + SharesRed + SharesWhite; public int SharesActive => Shares + SharesRed + SharesWhite;
+71 -9
View File
@@ -6,29 +6,69 @@ using System.ComponentModel.DataAnnotations.Schema;
namespace Elwig.Models.Entities { namespace Elwig.Models.Entities {
[Table("member_history"), PrimaryKey("HistNr")] [Table("member_history"), PrimaryKey("HistNr")]
public class MemberHistory { public class MemberHistory {
public const string REASON_PURCHASE = "purchase"; // Kauf
public const string REASON_CONVERT = "convert"; // Änderung
public const string REASON_TRANSFER = "transfer"; // Übertragung
public const string REASON_PRESCRIPTION = "prescription"; // Vorschreibung
public const string REASON_EXCLUSION = "exclusion"; // Ausschluss
public const string REASON_DECEASED = "deceased"; // Tod
public const string REASON_RETIREMENT = "retirement"; // Kündigung/stilllegen
public const string REASON_PAYOUT = "payout"; // Auszahlung
[Column("histnr")] [Column("histnr")]
public int HistNr { get; set; } public int HistNr { get; set; }
[Column("from_mgnr")] [Column("from_mgnr")]
public int? FromMgNr { get; set; } public int? FromMgNr { get; set; }
[Column("from_type")] [Column("from_type")]
public int? FromType { get; set; } public int? FromTypeValue { get; set; }
[NotMapped]
public BusinessShareType? FromType {
get => (BusinessShareType?)FromTypeValue;
set => FromTypeValue = (int?)value;
}
[Column("to_mgnr")] [Column("to_mgnr")]
public int? ToMgNr { get; set; } public int? ToMgNr { get; set; }
[Column("to_type")] [Column("to_type")]
public int? ToType { get; set; } public int? ToTypeValue { get; set; }
[Column("date")]
public required string DateString { get; set; }
[NotMapped] [NotMapped]
public DateOnly Date { public BusinessShareType? ToType {
get => DateOnly.ParseExact(DateString, "yyyy-MM-dd"); get => (BusinessShareType?)ToTypeValue;
set => ToTypeValue = (int?)value;
}
[Column("date_notice")]
public required string DateNoticeString { get; set; }
[NotMapped]
public DateOnly DateNotice {
get => DateOnly.ParseExact(DateNoticeString, "yyyy-MM-dd");
set => value.ToString("yyyy-MM-dd");
}
[Column("date_effective")]
public required string DateEffectiveString { get; set; }
[NotMapped]
public DateOnly DateEffective {
get => DateOnly.ParseExact(DateEffectiveString, "yyyy-MM-dd");
set => value.ToString("yyyy-MM-dd"); set => value.ToString("yyyy-MM-dd");
} }
[Column("reason")] [Column("reason")]
public required string Reason { get; set; } public required string Reason { get; set; }
[NotMapped]
public string ReasonPretty => Reason switch {
REASON_PURCHASE => "Kauf",
REASON_CONVERT => "Änderung",
REASON_TRANSFER => "Übertragung",
REASON_PRESCRIPTION => "Vorschreibung",
REASON_EXCLUSION => "Ausschluss",
REASON_DECEASED => "Tod",
REASON_RETIREMENT => "Kündigung",
REASON_PAYOUT => "Auszahlung",
_ => Reason,
};
[Column("source")] [Column("source")]
public required string Source { get; set; } public required string Source { get; set; }
@@ -36,6 +76,9 @@ namespace Elwig.Models.Entities {
[Column("shares")] [Column("shares")]
public int Shares { get; set; } public int Shares { get; set; }
[Column("signed")]
public bool MemberHasSigned { get; set; }
[Column("value_per_share")] [Column("value_per_share")]
public long? ValuePerShareValue { get; set; } public long? ValuePerShareValue { get; set; }
[NotMapped] [NotMapped]
@@ -50,14 +93,33 @@ namespace Elwig.Models.Entities {
[Column("currency")] [Column("currency")]
public string? CurrencyCode { get; set; } public string? CurrencyCode { get; set; }
[Column("deduct_year")]
public int? DeductYear { get; set; }
[Column("comment")] [Column("comment")]
public string? Comment { get; set; } public string? Comment { get; set; }
public string FormatReasonPhrase(int mgnr) {
if (Reason == REASON_TRANSFER) {
if (FromMgNr == mgnr) {
return $"{ReasonPretty} an {ToMember?.FullAdministrativeName ?? "Nachfolger"}" + (Comment != null ? $", {Comment}" : "");
} else if (ToMgNr == mgnr) {
return $"{ReasonPretty} von {FromMember?.FullAdministrativeName ?? "Vorgänger"}" + (Comment != null ? $", {Comment}" : "");
}
}
return ReasonPretty + (Comment != null ? $", {Comment}" : "");
}
[NotMapped]
public int? PoVMgNr { get; set; }
[NotMapped]
public string PoVReasonPhrase => FormatReasonPhrase(PoVMgNr ?? 0);
[ForeignKey("FromMgNr")] [ForeignKey("FromMgNr")]
public virtual Member FromMember { get; private set; } = null!; public virtual Member? FromMember { get; private set; } = null!;
[ForeignKey("ToMgNr")] [ForeignKey("ToMgNr")]
public virtual Member ToMember { get; private set; } = null!; public virtual Member? ToMember { get; private set; } = null!;
[ForeignKey("CurrencyCode")] [ForeignKey("CurrencyCode")]
public virtual Currency Currency { get; private set; } = null!; public virtual Currency Currency { get; private set; } = null!;
+22 -14
View File
@@ -3,9 +3,12 @@
PRAGMA writable_schema = ON; PRAGMA writable_schema = ON;
ALTER TABLE member RENAME COLUMN business_shares TO shares; ALTER TABLE member RENAME COLUMN business_shares TO shares;
ALTER TABLE member ADD COLUMN shares_red INTEGER NOT NULL DEFAULT 0; ALTER TABLE member ADD COLUMN shares_red INTEGER NOT NULL DEFAULT 0 CHECK (shares_red >= 0);
ALTER TABLE member ADD COLUMN shares_white INTEGER NOT NULL DEFAULT 0; ALTER TABLE member ADD COLUMN shares_white INTEGER NOT NULL DEFAULT 0 CHECK (shares_white >= 0);
ALTER TABLE member ADD COLUMN shares_dormant INTEGER NOT NULL DEFAULT 0; ALTER TABLE member ADD COLUMN shares_dormant INTEGER NOT NULL DEFAULT 0 CHECK (shares_dormant >= 0);
UPDATE sqlite_schema SET sql = REPLACE(sql, 'shares INTEGER NOT NULL DEFAULT 0', 'shares INTEGER NOT NULL DEFAULT 0 CHECK (shares >= 0)')
WHERE type = 'table' AND name = 'member';
UPDATE client_parameter SET value = '0' WHERE param = 'ENABLE_TIME_TRIGGERS'; UPDATE client_parameter SET value = '0' WHERE param = 'ENABLE_TIME_TRIGGERS';
UPDATE member UPDATE member
@@ -20,13 +23,16 @@ CREATE TABLE member_history_new (
from_type INTEGER, from_type INTEGER,
to_mgnr INTEGER, to_mgnr INTEGER,
to_type INTEGER, to_type INTEGER,
date TEXT NOT NULL CHECK (date REGEXP '^[1-9][0-9]{3}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])$') DEFAULT CURRENT_DATE, date_notice TEXT NOT NULL CHECK (date_notice REGEXP '^[1-9][0-9]{3}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])$') DEFAULT CURRENT_DATE,
reason TEXT NOT NULL CHECK (reason REGEXP '^[a-z_]+$'), date_effective TEXT NOT NULL CHECK (date_effective REGEXP '^[1-9][0-9]{3}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])$') DEFAULT CURRENT_DATE,
source TEXT NOT NULL CHECK (source REGEXP '^[a-z_]+$'), reason TEXT NOT NULL CHECK (reason REGEXP '^[a-z_]+$'),
source TEXT NOT NULL CHECK (source REGEXP '^[a-z_]+$'),
shares INTEGER NOT NULL, shares INTEGER NOT NULL CHECK (shares > 0),
signed INTEGER NOT NULL CHECK (signed IN (TRUE, FALSE)) DEFAULT FALSE,
value_per_share INTEGER DEFAULT NULL, value_per_share INTEGER DEFAULT NULL,
currency TEXT DEFAULT NULL, currency TEXT DEFAULT NULL,
deduct_year INTEGER DEFAULT NULL,
comment TEXT DEFAULT NULL, comment TEXT DEFAULT NULL,
CONSTRAINT pk_member_history PRIMARY KEY (histnr), CONSTRAINT pk_member_history PRIMARY KEY (histnr),
@@ -44,8 +50,10 @@ CREATE TABLE member_history_new (
((to_mgnr IS NULL AND to_type IS NULL) OR (to_mgnr IS NOT NULL AND to_type IS NOT NULL))) ((to_mgnr IS NULL AND to_type IS NULL) OR (to_mgnr IS NOT NULL AND to_type IS NOT NULL)))
) STRICT; ) STRICT;
INSERT INTO member_history_new (histnr, from_mgnr, from_type, to_mgnr, to_type, date, reason, source, shares, value_per_share, currency, comment) INSERT INTO member_history_new (histnr, from_mgnr, from_type, to_mgnr, to_type, date_notice, date_effective, reason, source, shares, value_per_share, currency, deduct_year, comment)
SELECT ROW_NUMBER() OVER(ORDER BY h.date, h.mgnr), NULL, NULL, h.mgnr, 1, h.date, h.type, 'elwig', h.business_shares, s.bs_value / POW(10, s.precision - 2), s.currency, comment SELECT ROW_NUMBER() OVER(ORDER BY h.date, h.mgnr), NULL, NULL, h.mgnr, 1, h.date, h.date,
IIF(h.type = 'auto', 'prescription', h.type), 'elwig', h.business_shares, s.bs_value / POW(10, s.precision - 2), s.currency,
IIF(h.type = 'auto', s.year, NULL), 'automatische Nachzeichnung'
FROM member_history h FROM member_history h
JOIN season s ON s.year = SUBSTR(h.date, 1, 4); JOIN season s ON s.year = SUBSTR(h.date, 1, 4);
@@ -69,7 +77,7 @@ BEGIN
END; END;
CREATE TRIGGER t_member_history_u_member CREATE TRIGGER t_member_history_u_member
AFTER UPDATE ON member_history FOR EACH ROW AFTER UPDATE OF from_mgnr, from_type, to_mgnr, to_type, shares ON member_history FOR EACH ROW
WHEN (SELECT value FROM client_parameter WHERE param = 'ENABLE_MEMBER_HISTORY_TRIGGERS') = 1 WHEN (SELECT value FROM client_parameter WHERE param = 'ENABLE_MEMBER_HISTORY_TRIGGERS') = 1
BEGIN BEGIN
UPDATE member SET shares = shares + OLD.shares WHERE mgnr = OLD.from_mgnr AND OLD.from_type = 1; UPDATE member SET shares = shares + OLD.shares WHERE mgnr = OLD.from_mgnr AND OLD.from_type = 1;
@@ -246,8 +254,8 @@ SELECT m.mgnr, s.year,
m.shares_white + SUM(IIF(h1.from_type = 3, h1.shares, 0)) - SUM(IIF(h2.to_type = 3, h2.shares, 0)) AS shares_white, m.shares_white + SUM(IIF(h1.from_type = 3, h1.shares, 0)) - SUM(IIF(h2.to_type = 3, h2.shares, 0)) AS shares_white,
m.shares_dormant + SUM(IIF(h1.from_type = 9, h1.shares, 0)) - SUM(IIF(h2.to_type = 9, h2.shares, 0)) AS shares_dormant m.shares_dormant + SUM(IIF(h1.from_type = 9, h1.shares, 0)) - SUM(IIF(h2.to_type = 9, h2.shares, 0)) AS shares_dormant
FROM member m, v_virtual_season s FROM member m, v_virtual_season s
LEFT JOIN member_history h1 ON (SUBSTR(h1.date, 1, 4) + 0) > s.year AND h1.from_mgnr = m.mgnr LEFT JOIN member_history h1 ON (SUBSTR(h1.date_notice, 1, 4) + 0) > s.year AND h1.from_mgnr = m.mgnr
LEFT JOIN member_history h2 ON (SUBSTR(h2.date, 1, 4) + 0) > s.year AND h2.to_mgnr = m.mgnr LEFT JOIN member_history h2 ON (SUBSTR(h2.date_notice, 1, 4) + 0) > s.year AND h2.to_mgnr = m.mgnr
GROUP BY m.mgnr, s.year GROUP BY m.mgnr, s.year
ORDER BY m.mgnr, s.year; ORDER BY m.mgnr, s.year;
@@ -306,12 +314,12 @@ ORDER BY u.year, u.mgnr;
DROP VIEW v_auto_business_shares; DROP VIEW v_auto_business_shares;
CREATE VIEW v_auto_business_shares AS CREATE VIEW v_auto_business_shares AS
SELECT (SUBSTR(h.date, 1, 4) + 0) AS year, SELECT (SUBSTR(h.date_notice, 1, 4) + 0) AS year,
h.to_mgnr AS mgnr, h.to_mgnr AS mgnr,
SUM(h.shares) AS shares, SUM(h.shares) AS shares,
SUM(h.shares * COALESCE(h.value_per_share, 0)) AS total_amount SUM(h.shares * COALESCE(h.value_per_share, 0)) AS total_amount
FROM member_history h FROM member_history h
WHERE h.reason = 'auto' AND h.source = 'elwig' WHERE h.reason = 'prescription' AND h.source = 'elwig'
GROUP BY year, h.to_mgnr GROUP BY year, h.to_mgnr
ORDER BY year, h.to_mgnr; ORDER BY year, h.to_mgnr;
+8 -21
View File
@@ -6,7 +6,6 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows;
namespace Elwig.Services { namespace Elwig.Services {
public static class AreaComService { public static class AreaComService {
@@ -115,7 +114,7 @@ namespace Elwig.Services {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
var c = new AreaComContract { var c = new AreaComContract {
FbNr = oldFbNr ?? newFbNr, FbNr = oldFbNr ?? newFbNr,
Comment = string.IsNullOrEmpty(vm.Comment) ? null : vm.Comment, Comment = string.IsNullOrWhiteSpace(vm.Comment) ? null : vm.Comment,
KgNr = vm.Kg!.KgNr, KgNr = vm.Kg!.KgNr,
RdNr = vm.Rd?.RdNr, RdNr = vm.Rd?.RdNr,
}; };
@@ -158,25 +157,13 @@ namespace Elwig.Services {
}); });
} }
private static void AddToolTipCell(Grid grid, string text, int row, int col, int colSpan = 1, bool bold = false, bool alignRight = false, bool alignCenter = false) {
var tb = new TextBlock() {
Text = text,
TextAlignment = alignRight ? TextAlignment.Right : alignCenter ? TextAlignment.Center : TextAlignment.Left,
Margin = new(0, 12 * row, 0, 0),
FontWeight = bold ? FontWeights.Bold : FontWeights.Normal,
};
tb.SetValue(Grid.ColumnProperty, col);
tb.SetValue(Grid.ColumnSpanProperty, colSpan);
grid.Children.Add(tb);
}
private static void AddToolTipRow(Grid grid, int row, string? h1, string? h2, int area, int? min, int? max) { private static void AddToolTipRow(Grid grid, int row, string? h1, string? h2, int area, int? min, int? max) {
var bold = h2 == null; var bold = h2 == null;
if (h1 != null) AddToolTipCell(grid, h1 + ":", row, 0, (h2 == null) ? 2 : 1, bold); if (h1 != null) grid.AddToolTipCell(h1 + ":", row, 0, (h2 == null) ? 2 : 1, bold);
if (h2 != null) AddToolTipCell(grid, h2 + ":", row, 1, 1, bold); if (h2 != null) grid.AddToolTipCell(h2 + ":", row, 1, bold: bold);
AddToolTipCell(grid, $"{area:N0} m²", row, 2, 1, bold, true); grid.AddToolTipCell($"{area:N0} m²", row, 2, bold: bold, alignRight: true);
AddToolTipCell(grid, min == null ? "" : $"{min:N0} kg", row, 3, 1, bold, true); grid.AddToolTipCell(min == null ? "" : $"{min:N0} kg", row, 3, bold: bold, alignRight: true);
AddToolTipCell(grid, max == null ? "" : $"{max:N0} kg", row, 4, 1, bold, true); grid.AddToolTipCell(max == null ? "" : $"{max:N0} kg", row, 4, bold: bold, alignRight: true);
} }
public static async Task<(string, (string?, string?, int, int?, int?)[])> GenerateToolTipData(IQueryable<AreaCom> areaComs, int maxKgPerHa) { public static async Task<(string, (string?, string?, int, int?, int?)[])> GenerateToolTipData(IQueryable<AreaCom> areaComs, int maxKgPerHa) {
@@ -255,8 +242,8 @@ namespace Elwig.Services {
grid.ColumnDefinitions.Add(new() { Width = new(80) }); grid.ColumnDefinitions.Add(new() { Width = new(80) });
grid.ColumnDefinitions.Add(new() { Width = new(80) }); grid.ColumnDefinitions.Add(new() { Width = new(80) });
grid.ColumnDefinitions.Add(new() { Width = new(80) }); grid.ColumnDefinitions.Add(new() { Width = new(80) });
AddToolTipCell(grid, "Lieferpflicht", 0, 3, 1, false, false, true); grid.AddToolTipCell("Lieferpflicht", 0, 3, alignCenter: true);
AddToolTipCell(grid, "Lieferrecht", 0, 4, 1, false, false, true); grid.AddToolTipCell("Lieferrecht", 0, 4, 1, alignCenter: true);
int rowNum = 1; int rowNum = 1;
foreach (var row in data) { foreach (var row in data) {
if (rowNum == 2 || (rowNum != 1 && row.Item1 != null)) rowNum++; if (rowNum == 2 || (rowNum != 1 && row.Item1 != null)) rowNum++;
+5 -18
View File
@@ -8,7 +8,6 @@ using Microsoft.EntityFrameworkCore;
using Elwig.Documents; using Elwig.Documents;
using Elwig.Helpers.Export; using Elwig.Helpers.Export;
using Elwig.Models.Dtos; using Elwig.Models.Dtos;
using System.Windows;
using System; using System;
using LinqKit; using LinqKit;
using System.Windows.Controls; using System.Windows.Controls;
@@ -276,27 +275,15 @@ namespace Elwig.Services {
} }
} }
private static void AddToolTipCell(Grid grid, string text, int row, int col, int colSpan = 1, bool bold = false, bool alignRight = false, bool alignCenter = false) {
var tb = new TextBlock() {
Text = text,
TextAlignment = alignRight ? TextAlignment.Right : alignCenter ? TextAlignment.Center : TextAlignment.Left,
Margin = new(0, 12 * row, 0, 0),
FontWeight = bold ? FontWeights.Bold : FontWeights.Normal,
};
tb.SetValue(Grid.ColumnProperty, col);
tb.SetValue(Grid.ColumnSpanProperty, colSpan);
grid.Children.Add(tb);
}
private static void AddToolTipRow(Grid grid, int row, string? h1, string? h2, int weight, int? total1, int total2) { private static void AddToolTipRow(Grid grid, int row, string? h1, string? h2, int weight, int? total1, int total2) {
var bold = h2 == null; var bold = h2 == null;
if (h1 != null) AddToolTipCell(grid, h1 + ":", row, 0, (h2 == null) ? 2 : 1, bold); if (h1 != null) grid.AddToolTipCell(h1 + ":", row, 0, (h2 == null) ? 2 : 1, bold);
if (h2 != null) AddToolTipCell(grid, h2 + ":", row, 1, 1, bold); if (h2 != null) grid.AddToolTipCell(h2 + ":", row, 1, 1, bold);
AddToolTipCell(grid, $"{weight:N0} kg", row, 2, 1, bold, true); grid.AddToolTipCell($"{weight:N0} kg", row, 2, bold: bold, alignRight: true);
if (total1 != null && total1 != 0) if (total1 != null && total1 != 0)
AddToolTipCell(grid, $"{weight * 100.0 / total1:N1} %", row, 3, 1, bold, true); grid.AddToolTipCell($"{weight * 100.0 / total1:N1} %", row, 3, bold: bold, alignRight: true);
if (total2 != 0) if (total2 != 0)
AddToolTipCell(grid, $"{weight * 100.0 / total2:N1} %", row, 4, 1, bold, true); grid.AddToolTipCell($"{weight * 100.0 / total2:N1} %", row, 4, bold: bold, alignRight: true);
} }
public static async Task<(string Text, (string?, string?, int, int?, int)[] Grid)> GenerateToolTipData(IQueryable<DeliveryAncmt> deliveryAncmts) { public static async Task<(string Text, (string?, string?, int, int?, int)[] Grid)> GenerateToolTipData(IQueryable<DeliveryAncmt> deliveryAncmts) {
+18 -40
View File
@@ -6,7 +6,6 @@ using Elwig.Models.Entities;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows;
using System; using System;
using Elwig.ViewModels; using Elwig.ViewModels;
using LinqKit; using LinqKit;
@@ -23,15 +22,6 @@ namespace Elwig.Services {
FromFilters, FromToday, FromSeason, FromSeasonAndBranch, Selected, FromFilters, FromToday, FromSeason, FromSeasonAndBranch, Selected,
}; };
public static async Task<Member?> GetMemberAsync(int mgnr) {
using var ctx = new AppDbContext();
return await ctx.FetchMembers(mgnr).SingleOrDefaultAsync();
}
public static Member? GetMember(int mgnr) {
return GetMemberAsync(mgnr).GetAwaiter().GetResult();
}
public static void ClearInputs(this DeliveryAdminViewModel vm) { public static void ClearInputs(this DeliveryAdminViewModel vm) {
} }
@@ -77,7 +67,7 @@ namespace Elwig.Services {
vm.IsGebunden = p.IsGebunden; vm.IsGebunden = p.IsGebunden;
vm.Unloading = p.Unloading; vm.Unloading = p.Unloading;
vm.ScaleId = p.ScaleId; vm.ScaleTerminalId = p.ScaleTerminalId;
vm.WeighingData = p.WeighingData; vm.WeighingData = p.WeighingData;
vm.ManualWeighingReason = p.WeighingReason; vm.ManualWeighingReason = p.WeighingReason;
} }
@@ -486,7 +476,7 @@ namespace Elwig.Services {
if (partNew && timeIsDefault) { if (partNew && timeIsDefault) {
newTimeString = DateTime.Now.ToString("HH:mm:ss"); newTimeString = DateTime.Now.ToString("HH:mm:ss");
} else if (partNew || timeHasChanged) { } else if (partNew || timeHasChanged) {
newTimeString = string.IsNullOrEmpty(vm.Time) ? null : vm.Time + ":00"; newTimeString = string.IsNullOrWhiteSpace(vm.Time) ? null : vm.Time + ":00";
} }
var d = new Delivery { var d = new Delivery {
@@ -498,7 +488,7 @@ namespace Elwig.Services {
ZwstId = vm.Branch!.ZwstId, ZwstId = vm.Branch!.ZwstId,
LsNr = newLsNr ?? vm.LsNr!, LsNr = newLsNr ?? vm.LsNr!,
MgNr = vm.MgNr!.Value, MgNr = vm.MgNr!.Value,
Comment = string.IsNullOrEmpty(vm.Comment) ? null : vm.Comment, Comment = string.IsNullOrWhiteSpace(vm.Comment) ? null : vm.Comment,
}; };
p = new DeliveryPart { p = new DeliveryPart {
@@ -521,11 +511,11 @@ namespace Elwig.Services {
Unloading = vm.Unloading, Unloading = vm.Unloading,
Temperature = vm.Temperature, Temperature = vm.Temperature,
Acid = vm.Acid, Acid = vm.Acid,
Comment = string.IsNullOrEmpty(vm.PartComment) ? null : vm.PartComment, Comment = string.IsNullOrWhiteSpace(vm.PartComment) ? null : vm.PartComment,
Weight = vm.Weight!.Value, Weight = vm.Weight!.Value,
IsManualWeighing = vm.IsManualWeighing, IsManualWeighing = vm.IsManualWeighing,
ScaleId = vm.ScaleId, ScaleTerminalId = vm.ScaleTerminalId,
WeighingData = vm.WeighingData, WeighingData = vm.WeighingData,
WeighingReason = vm.ManualWeighingReason, WeighingReason = vm.ManualWeighingReason,
}; };
@@ -940,36 +930,24 @@ namespace Elwig.Services {
} }
} }
private static void AddToolTipCell(Grid grid, string text, int row, int col, int colSpan = 1, bool bold = false, bool alignRight = false, bool alignCenter = false) {
var tb = new TextBlock() {
Text = text,
TextAlignment = alignRight ? TextAlignment.Right : alignCenter ? TextAlignment.Center : TextAlignment.Left,
Margin = new(0, 12 * row, 0, 0),
FontWeight = bold ? FontWeights.Bold : FontWeights.Normal,
};
tb.SetValue(Grid.ColumnProperty, col);
tb.SetValue(Grid.ColumnSpanProperty, colSpan);
grid.Children.Add(tb);
}
private static void AddWeightToolTipRow(Grid grid, int row, string? h1, string? h2, int weight, int? total1, int total2) { private static void AddWeightToolTipRow(Grid grid, int row, string? h1, string? h2, int weight, int? total1, int total2) {
var bold = h2 == null; var bold = h2 == null;
if (h1 != null) AddToolTipCell(grid, h1 + ":", row, 0, (h2 == null) ? 2 : 1, bold); if (h1 != null) grid.AddToolTipCell(h1 + ":", row, 0, (h2 == null) ? 2 : 1, bold);
if (h2 != null) AddToolTipCell(grid, h2 + ":", row, 1, 1, bold); if (h2 != null) grid.AddToolTipCell(h2 + ":", row, 1, 1, bold);
AddToolTipCell(grid, $"{weight:N0} kg", row, 2, 1, bold, true); grid.AddToolTipCell($"{weight:N0} kg", row, 2, bold: bold, alignRight: true);
if (total1 != null && total1 != 0) if (total1 != null && total1 != 0)
AddToolTipCell(grid, $"{weight * 100.0 / total1:N1} %", row, 3, 1, bold, true); grid.AddToolTipCell($"{weight * 100.0 / total1:N1} %", row, 3, bold: bold, alignRight: true);
if (total2 != 0) if (total2 != 0)
AddToolTipCell(grid, $"{weight * 100.0 / total2:N1} %", row, 4, 1, bold, true); grid.AddToolTipCell($"{weight * 100.0 / total2:N1} %", row, 4, bold: bold, alignRight: true);
} }
private static void AddGradationToolTipRow(Grid grid, int row, string? h1, string? h2, double min, double avg, double max) { private static void AddGradationToolTipRow(Grid grid, int row, string? h1, string? h2, double min, double avg, double max) {
var bold = h2 == null; var bold = h2 == null;
if (h1 != null) AddToolTipCell(grid, h1 + ":", row, 0, (h2 == null) ? 2 : 1, bold); if (h1 != null) grid.AddToolTipCell(h1 + ":", row, 0, (h2 == null) ? 2 : 1, bold);
if (h2 != null) AddToolTipCell(grid, h2 + ":", row, 1, 1, bold); if (h2 != null) grid.AddToolTipCell(h2 + ":", row, 1, bold: bold);
AddToolTipCell(grid, $"{min:N1}°", row, 2, 1, bold, true); grid.AddToolTipCell($"{min:N1}°", row, 2, bold: bold, alignRight: true);
AddToolTipCell(grid, $"{avg:N1}°", row, 3, 1, bold, true); grid.AddToolTipCell($"{avg:N1}°", row, 3, bold: bold, alignRight: true);
AddToolTipCell(grid, $"{max:N1}°", row, 4, 1, bold, true); grid.AddToolTipCell($"{max:N1}°", row, 4, bold: bold, alignRight: true);
} }
public static async Task<(string WeightText, (string?, string?, int, int?, int)[] WeightGrid, string GradationText, (string?, string?, double, double, double)[] GradationGrid)> GenerateToolTipData(IQueryable<DeliveryPart> deliveryParts) { public static async Task<(string WeightText, (string?, string?, int, int?, int)[] WeightGrid, string GradationText, (string?, string?, double, double, double)[] GradationGrid)> GenerateToolTipData(IQueryable<DeliveryPart> deliveryParts) {
@@ -1098,9 +1076,9 @@ namespace Elwig.Services {
gGrid.ColumnDefinitions.Add(new() { Width = new(35) }); gGrid.ColumnDefinitions.Add(new() { Width = new(35) });
gGrid.ColumnDefinitions.Add(new() { Width = new(35) }); gGrid.ColumnDefinitions.Add(new() { Width = new(35) });
gGrid.ColumnDefinitions.Add(new() { Width = new(35) }); gGrid.ColumnDefinitions.Add(new() { Width = new(35) });
AddToolTipCell(gGrid, "Min.", 0, 2, 1, false, false, true); gGrid.AddToolTipCell("Min.", 0, 2, alignCenter: true);
AddToolTipCell(gGrid, "⌀", 0, 3, 1, false, false, true); gGrid.AddToolTipCell("⌀", 0, 3, alignCenter: true);
AddToolTipCell(gGrid, "Max.", 0, 4, 1, false, false, true); gGrid.AddToolTipCell("Max.", 0, 4, alignCenter: true);
rowNum = 1; rowNum = 1;
foreach (var row in gradationData) { foreach (var row in gradationData) {
if (rowNum != 1 && row.Item2 == null) rowNum++; if (rowNum != 1 && row.Item2 == null) rowNum++;
+13
View File
@@ -48,6 +48,19 @@ namespace Elwig.Services {
} }
} }
public static bool? AskContinueYesNo(string title, string text) {
if (NextContinue != null) {
var r = NextContinue(title, text);
NextContinue = null;
return r;
} else if (Override != null) {
return Override("continue", title, text) != null;
} else {
var r = MessageBox.Show(text, title, MessageBoxButton.YesNoCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
return r == MessageBoxResult.Yes ? true : r == MessageBoxResult.No ? false : null;
}
}
public static bool AskConfirmation(string title, string text) { public static bool AskConfirmation(string title, string text) {
if (NextConfirmation != null) { if (NextConfirmation != null) {
var r = NextConfirmation(title, text); var r = NextConfirmation(title, text);
@@ -0,0 +1,98 @@
using Elwig.Helpers;
using Elwig.Models;
using Elwig.Models.Entities;
using Elwig.ViewModels;
using Microsoft.EntityFrameworkCore;
using System.Linq;
using System.Threading.Tasks;
namespace Elwig.Services {
public static class MemberBusinessSharesService {
public static async Task InitInputs(this MemberBusinessSharesViewModel vm) {
using var ctx = new AppDbContext();
vm.DateNoticeString = $"{Utils.Today:dd.MM.yyyy}";
vm.ValuePerShare = (await ctx.Seasons.OrderBy(s => s.Year).LastOrDefaultAsync())?.BusinessShareValue;
}
public static void ClearInputs(this MemberBusinessSharesViewModel vm) {
}
public static void FillInputs(this MemberBusinessSharesViewModel vm, MemberHistory h) {
var mgnr = vm.FilterMember.MgNr;
vm.DateNotice = h.DateNotice;
vm.DateEffective = h.DateEffective;
vm.Reason = h.Reason + (h.Reason == MemberHistory.REASON_TRANSFER ? $"_{(h.ToMgNr == mgnr ? "from" : "to")}" : "");
vm.Shares = h.Shares;
vm.MemberHasSigned = h.MemberHasSigned;
vm.ValuePerShare = h.ValuePerShare;
vm.OtherMgNr = h.FromMgNr != null && h.FromMgNr != mgnr ? h.FromMgNr : h.ToMgNr != null && h.ToMgNr != mgnr ? h.ToMgNr : null;
vm.DeductYear = h.DeductYear ?? h.DateNotice.Year;
vm.Deduct = h.DeductYear != null;
vm.Comment = h.Comment;
}
public static async Task<int> UpdateMemberHistory(this MemberBusinessSharesViewModel vm, int? oldHistNr, bool enableTriggers) {
return await Task.Run(async () => {
using var ctx = new AppDbContext();
var tx = await ctx.Database.BeginTransactionAsync();
await ctx.Database.ExecuteSqlAsync($"UPDATE client_parameter SET value = {(enableTriggers ? "1" : "0")} WHERE param = 'ENABLE_MEMBER_HISTORY_TRIGGERS'");
var h = new MemberHistory {
HistNr = oldHistNr ?? await ctx.NextHistNr(),
FromMgNr =
vm.Reason == $"{MemberHistory.REASON_TRANSFER}_from" ? vm.OtherMgNr :
vm.Reason == MemberHistory.REASON_PURCHASE || vm.Reason == MemberHistory.REASON_PRESCRIPTION ? null :
vm.FilterMember.MgNr,
FromType =
vm.Reason == MemberHistory.REASON_PAYOUT ? BusinessShareType.Dormant :
vm.Reason == MemberHistory.REASON_PURCHASE || vm.Reason == MemberHistory.REASON_PRESCRIPTION ? null :
BusinessShareType.Normal,
ToMgNr =
vm.Reason == MemberHistory.REASON_PAYOUT || vm.Reason == MemberHistory.REASON_EXCLUSION ? null :
vm.Reason == $"{MemberHistory.REASON_TRANSFER}_to" ? vm.OtherMgNr :
vm.FilterMember.MgNr,
ToType =
vm.Reason == MemberHistory.REASON_PAYOUT || vm.Reason == MemberHistory.REASON_EXCLUSION ? null :
vm.Reason == MemberHistory.REASON_RETIREMENT || vm.Reason == MemberHistory.REASON_DECEASED ? BusinessShareType.Dormant :
BusinessShareType.Normal,
DateNoticeString = $"{vm.DateNotice:yyyy-MM-dd}",
DateEffectiveString = $"{vm.DateEffective:yyyy-MM-dd}",
Reason = vm.Reason?.Split("_")[0] ?? MemberHistory.REASON_CONVERT,
Source = "manual",
Shares = vm.Shares ?? 0,
MemberHasSigned = vm.MemberHasSigned,
ValuePerShare = vm.ValuePerShare,
CurrencyCode = vm.ValuePerShare != null ? "EUR" : null,
DeductYear = vm.Deduct ? vm.DeductYear : null,
Comment = string.IsNullOrWhiteSpace(vm.Comment) ? null : vm.Comment.Trim(),
};
if (oldHistNr != null) {
ctx.Update(h);
} else {
ctx.Add(h);
}
await ctx.SaveChangesAsync();
await ctx.Database.ExecuteSqlAsync($"UPDATE client_parameter SET value = '1' WHERE param = 'ENABLE_MEMBER_HISTORY_TRIGGERS'");
await tx.CommitAsync();
return h.HistNr;
});
}
public static async Task DeleteMemberHistory(int histnr, bool enableTriggers) {
await Task.Run(async () => {
using var ctx = new AppDbContext();
var tx = await ctx.Database.BeginTransactionAsync();
await ctx.Database.ExecuteSqlAsync($"UPDATE client_parameter SET value = {(enableTriggers ? "1" : "0")} WHERE param = 'ENABLE_MEMBER_HISTORY_TRIGGERS'");
await ctx.MemberHistory.Where(h => h.HistNr == histnr).ExecuteDeleteAsync();
await ctx.Database.ExecuteSqlAsync($"UPDATE client_parameter SET value = '1' WHERE param = 'ENABLE_MEMBER_HISTORY_TRIGGERS'");
await tx.CommitAsync();
});
}
}
}
+13 -10
View File
@@ -501,7 +501,10 @@ namespace Elwig.Services {
var history2 = await query.IgnoreAutoIncludes() var history2 = await query.IgnoreAutoIncludes()
.SelectMany(m => m.HistoryTo) .SelectMany(m => m.HistoryTo)
.ToListAsync(); .ToListAsync();
var history = history1.Union(history2).DistinctBy(h => h.HistNr).OrderBy(h => h.HistNr).ToList(); var history = history1.Union(history2)
.DistinctBy(h => h.HistNr)
.OrderBy(h => h.DateNotice).ThenBy(h => h.HistNr)
.ToList();
var areaComs = await query var areaComs = await query
.SelectMany(m => m.AreaCommitments) .SelectMany(m => m.AreaCommitments)
.Select(c => c.Contract).Distinct() .Select(c => c.Contract).Distinct()
@@ -541,33 +544,33 @@ namespace Elwig.Services {
Name = vm.Name!, Name = vm.Name!,
Suffix = vm.IsJuridicalPerson || string.IsNullOrWhiteSpace(vm.Suffix) ? null : vm.Suffix, Suffix = vm.IsJuridicalPerson || string.IsNullOrWhiteSpace(vm.Suffix) ? null : vm.Suffix,
ForTheAttentionOf = !vm.IsJuridicalPerson || string.IsNullOrWhiteSpace(vm.ForTheAttentionOf) ? null : vm.ForTheAttentionOf, ForTheAttentionOf = !vm.IsJuridicalPerson || string.IsNullOrWhiteSpace(vm.ForTheAttentionOf) ? null : vm.ForTheAttentionOf,
Birthday = string.IsNullOrEmpty(vm.Birthday) ? null : string.Join("-", vm.Birthday!.Split(".").Reverse()), Birthday = string.IsNullOrWhiteSpace(vm.Birthday) ? null : string.Join("-", vm.Birthday!.Split(".").Reverse()),
IsDeceased = vm.IsDeceased, IsDeceased = vm.IsDeceased,
CountryNum = 40, // Austria AT AUT CountryNum = 40, // Austria AT AUT
PostalDestId = vm.Ort!.Id, PostalDestId = vm.Ort!.Id,
Address = vm.Address!, Address = vm.Address!,
Iban = string.IsNullOrEmpty(vm.Iban) ? null : vm.Iban?.Replace(" ", ""), Iban = string.IsNullOrWhiteSpace(vm.Iban) ? null : vm.Iban?.Replace(" ", ""),
Bic = string.IsNullOrEmpty(vm.Bic) ? null : vm.Bic, Bic = string.IsNullOrWhiteSpace(vm.Bic) ? null : vm.Bic,
UstIdNr = string.IsNullOrEmpty(vm.UstIdNr) ? null : vm.UstIdNr, UstIdNr = string.IsNullOrWhiteSpace(vm.UstIdNr) ? null : vm.UstIdNr,
LfbisNr = string.IsNullOrEmpty(vm.LfbisNr) ? null : vm.LfbisNr, LfbisNr = string.IsNullOrWhiteSpace(vm.LfbisNr) ? null : vm.LfbisNr,
IsBuchführend = vm.IsBuchführend, IsBuchführend = vm.IsBuchführend,
IsOrganic = vm.IsOrganic, IsOrganic = vm.IsOrganic,
EntryDateString = string.IsNullOrEmpty(vm.EntryDate) ? null : string.Join("-", vm.EntryDate.Split(".").Reverse()), EntryDateString = string.IsNullOrWhiteSpace(vm.EntryDate) ? null : string.Join("-", vm.EntryDate.Split(".").Reverse()),
ExitDateString = string.IsNullOrEmpty(vm.ExitDate) ? null : string.Join("-", vm.ExitDate.Split(".").Reverse()), ExitDateString = string.IsNullOrWhiteSpace(vm.ExitDate) ? null : string.Join("-", vm.ExitDate.Split(".").Reverse()),
Shares = App.Client.HasRedWhite ? 0 : vm.BusinessShares1 ?? 0, Shares = App.Client.HasRedWhite ? 0 : vm.BusinessShares1 ?? 0,
SharesRed = App.Client.HasRedWhite ? vm.BusinessShares1 ?? 0 : 0, SharesRed = App.Client.HasRedWhite ? vm.BusinessShares1 ?? 0 : 0,
SharesWhite = App.Client.HasRedWhite ? vm.BusinessShares2 ?? 0 : 0, SharesWhite = App.Client.HasRedWhite ? vm.BusinessShares2 ?? 0 : 0,
SharesDormant = App.Client.HasRedWhite ? vm.BusinessShares3 ?? 0 : vm.BusinessShares2 ?? 0, SharesDormant = App.Client.HasRedWhite ? vm.BusinessShares3 ?? 0 : vm.BusinessShares2 ?? 0,
AccountingNr = string.IsNullOrEmpty(vm.AccountingNr) ? null : vm.AccountingNr, AccountingNr = string.IsNullOrWhiteSpace(vm.AccountingNr) ? null : vm.AccountingNr,
IsActive = vm.IsActive, IsActive = vm.IsActive,
IsVollLieferant = vm.IsVollLieferant, IsVollLieferant = vm.IsVollLieferant,
IsFunktionär = vm.IsFunktionär, IsFunktionär = vm.IsFunktionär,
ZwstId = vm.Branch?.ZwstId, ZwstId = vm.Branch?.ZwstId,
DefaultKgNr = vm.DefaultKg?.KgNr, DefaultKgNr = vm.DefaultKg?.KgNr,
Comment = string.IsNullOrEmpty(vm.Comment) ? null : vm.Comment, Comment = string.IsNullOrWhiteSpace(vm.Comment) ? null : vm.Comment,
ContactViaPost = vm.ContactViaPost, ContactViaPost = vm.ContactViaPost,
ContactViaEmail = vm.ContactViaEmail, ContactViaEmail = vm.ContactViaEmail,
}; };
+1 -1
View File
@@ -300,7 +300,7 @@ namespace Elwig.Services {
TransferDate = vm.TransferDate, TransferDate = vm.TransferDate,
TestVariant = vm.SelectedPaymentVariant?.TestVariant ?? true, TestVariant = vm.SelectedPaymentVariant?.TestVariant ?? true,
CalcTimeUnix = vm.SelectedPaymentVariant?.CalcTimeUnix, CalcTimeUnix = vm.SelectedPaymentVariant?.CalcTimeUnix,
Comment = string.IsNullOrEmpty(vm.Comment) ? null : vm.Comment, Comment = string.IsNullOrWhiteSpace(vm.Comment) ? null : vm.Comment,
Data = JsonSerializer.Serialize(d.Data), Data = JsonSerializer.Serialize(d.Data),
}; };
avnr = v.AvNr; avnr = v.AvNr;
+15 -3
View File
@@ -33,7 +33,10 @@ namespace Elwig.Services {
var history2 = await query.IgnoreAutoIncludes() var history2 = await query.IgnoreAutoIncludes()
.SelectMany(m => m.HistoryTo) .SelectMany(m => m.HistoryTo)
.ToListAsync(); .ToListAsync();
var history = history1.Union(history2).DistinctBy(h => h.HistNr).OrderBy(h => h.HistNr).ToList(); var history = history1.Union(history2)
.DistinctBy(h => h.HistNr)
.OrderBy(h => h.DateNotice).ThenBy(h => h.HistNr)
.ToList();
var areaComs = await query var areaComs = await query
.SelectMany(m => m.AreaCommitments) .SelectMany(m => m.AreaCommitments)
.Select(c => c.Contract).Distinct() .Select(c => c.Contract).Distinct()
@@ -211,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 { try {
var import = await GetFilesToImport(url, username, password); var import = await GetFilesToImport(url, username, password);
var paths = new List<string>(); var paths = new List<string>();
@@ -223,7 +226,7 @@ namespace Elwig.Services {
paths.Add(filename); paths.Add(filename);
} }
} }
await ElwigData.Import(paths, ElwigData.ImportMode.FromBranches); await ElwigData.Import(paths, confirmImports ? ElwigData.ImportMode.Interactively : ElwigData.ImportMode.FromBranches);
} catch (HttpRequestException exc) { } catch (HttpRequestException exc) {
InteractionService.ShowException("Daten herunterladen", "Eventuell Internetverbindung prüfen!", exc); InteractionService.ShowException("Daten herunterladen", "Eventuell Internetverbindung prüfen!", exc);
} catch (TaskCanceledException exc) { } catch (TaskCanceledException exc) {
@@ -261,5 +264,14 @@ namespace Elwig.Services {
return false; 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;
}
}
} }
} }
+1 -1
View File
@@ -25,7 +25,7 @@ namespace Elwig.ViewModels {
[ObservableProperty] [ObservableProperty]
private string? _manualWeighingReason; private string? _manualWeighingReason;
[ObservableProperty] [ObservableProperty]
private string? _scaleId; private string? _scaleTerminalId;
[ObservableProperty] [ObservableProperty]
private string? _weighingData; private string? _weighingData;
+2 -3
View File
@@ -6,6 +6,7 @@ using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Documents;
namespace Elwig.ViewModels { namespace Elwig.ViewModels {
public partial class MemberAdminViewModel : ObservableObject { public partial class MemberAdminViewModel : ObservableObject {
@@ -200,9 +201,7 @@ namespace Elwig.ViewModels {
[ObservableProperty] [ObservableProperty]
private string? _statusMembersToolTip; private string? _statusMembersToolTip;
[ObservableProperty] [ObservableProperty]
private string _statusBusinessShares = "-"; private TextBlock? _statusBusinessShares;
[ObservableProperty]
private string? _statusBusinessSharesToolTip;
[ObservableProperty] [ObservableProperty]
private string _statusDeliveriesLastSeason = "-"; private string _statusDeliveriesLastSeason = "-";
[ObservableProperty] [ObservableProperty]
@@ -0,0 +1,76 @@
using CommunityToolkit.Mvvm.ComponentModel;
using Elwig.Models.Entities;
using System;
using System.Collections.Generic;
using System.Windows;
namespace Elwig.ViewModels {
public partial class MemberBusinessSharesViewModel : ObservableObject {
[ObservableProperty]
private string _title = "Geschäftsanteilbewegungen - Elwig";
public required Member FilterMember { get; set; }
[ObservableProperty]
private MemberHistory? _selectedHistoryEntry;
[ObservableProperty]
private IEnumerable<MemberHistory> _history = [];
[ObservableProperty]
private string? _dateNoticeString;
public DateOnly? DateNotice {
get => DateOnly.TryParseExact(DateNoticeString, "dd.MM.yyyy", out var d) ? d : null;
set => DateNoticeString = $"{value:dd.MM.yyyy}";
}
[ObservableProperty]
private string? _dateEffectiveString;
public DateOnly? DateEffective {
get => DateOnly.TryParseExact(DateEffectiveString, "dd.MM.yyyy", out var d) ? d : null;
set => DateEffectiveString = $"{value:dd.MM.yyyy}";
}
[ObservableProperty]
private string? _reason;
[ObservableProperty]
private string? _sharesString;
public int? Shares {
get => int.TryParse(SharesString, out var shares) ? shares : null;
set => SharesString = $"{value}";
}
[ObservableProperty]
private string? _otherMgNrString;
public int? OtherMgNr {
get => int.TryParse(OtherMgNrString, out var mgnr) ? mgnr : null;
set => OtherMgNrString = $"{value}";
}
[ObservableProperty]
private string? _deductYearString;
public int? DeductYear {
get => int.TryParse(DeductYearString, out var year) ? year : null;
set => DeductYearString = $"{value}";
}
[ObservableProperty]
private bool _deduct;
[ObservableProperty]
private bool _memberHasSigned;
[ObservableProperty]
private string? _valuePerShareString;
public decimal? ValuePerShare {
get => decimal.TryParse(ValuePerShareString, out var v) ? v : null;
set => ValuePerShareString = $"{value:0.00}";
}
[ObservableProperty]
private string? _totalAmount;
[ObservableProperty]
private string? _comment;
[ObservableProperty]
private Visibility _controlButtonsVisibility = Visibility.Visible;
[ObservableProperty]
private Visibility _editingButtonsVisibility = Visibility.Hidden;
[ObservableProperty]
private Visibility _personalNameVisibility = Visibility.Visible;
[ObservableProperty]
private Visibility _juridicalNameVisibility = Visibility.Hidden;
}
}
+9 -4
View File
@@ -164,10 +164,10 @@ namespace Elwig.Windows {
} else if (input is TextBox tb && tb.Text.Length == 0) { } else if (input is TextBox tb && tb.Text.Length == 0) {
ControlUtils.SetInputInvalid(input); ControlUtils.SetInputInvalid(input);
Valid[input] = false; Valid[input] = false;
} else if (input is ComboBox cb && cb.SelectedItem == null && cb.ItemsSource != null && cb.ItemsSource.Cast<object>().Any()) { } else if (input is ComboBox cb && cb.SelectedItem == null && cb.HasItems) {
ControlUtils.SetInputInvalid(input); ControlUtils.SetInputInvalid(input);
Valid[input] = false; Valid[input] = false;
} else if (input is ListBox lb && lb.SelectedItem == null && lb.ItemsSource != null && lb.ItemsSource.Cast<object>().Any()) { } else if (input is ListBox lb && lb.SelectedItem == null && lb.HasItems) {
ControlUtils.SetInputInvalid(input); ControlUtils.SetInputInvalid(input);
Valid[input] = false; Valid[input] = false;
} else if (input is CheckBox ckb && ((ckb.IsThreeState && ckb.IsChecked == null) || (!ckb.IsThreeState && ckb.IsChecked != true))) { } else if (input is CheckBox ckb && ((ckb.IsThreeState && ckb.IsChecked == null) || (!ckb.IsThreeState && ckb.IsChecked != true))) {
@@ -285,8 +285,13 @@ namespace Elwig.Windows {
var binding = cb.GetBindingExpression(ComboBox.SelectedItemProperty); var binding = cb.GetBindingExpression(ComboBox.SelectedItemProperty);
binding?.UpdateSource(); binding?.UpdateSource();
} }
foreach (var lb in ListBoxInputs) foreach (var lb in ListBoxInputs) {
lb.SelectedItems.Clear(); if (lb.SelectionMode == SelectionMode.Single) {
lb.SelectedItem = null;
} else {
lb.SelectedItems.Clear();
}
}
foreach (var cb in CheckBoxInputs) { foreach (var cb in CheckBoxInputs) {
cb.IsChecked = cb.IsThreeState ? null : false; cb.IsChecked = cb.IsThreeState ? null : false;
var binding = cb.GetBindingExpression(CheckBox.IsCheckedProperty); var binding = cb.GetBindingExpression(CheckBox.IsCheckedProperty);
+2 -1
View File
@@ -552,7 +552,8 @@
<Label Content="Mitgliederbewegungen:" Margin="10,40,10,10"/> <Label Content="Mitgliederbewegungen:" Margin="10,40,10,10"/>
<CheckBox x:Name="ParameterBusinessShareHistoryInput" Content="Mit Elwig erfassen" Margin="160,45,10,15" <CheckBox x:Name="ParameterBusinessShareHistoryInput" Content="Mit Elwig erfassen" Margin="160,45,10,15"
HorizontalAlignment="Left"/> HorizontalAlignment="Left"
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"/>
</Grid> </Grid>
</GroupBox> </GroupBox>
<GroupBox x:Name="ParameterAreaComGroup" Header="Berechnung Flächenbindungen (aktuelle Saison)" Margin="10,10,10,0" VerticalAlignment="Top"> <GroupBox x:Name="ParameterAreaComGroup" Header="Berechnung Flächenbindungen (aktuelle Saison)" Margin="10,10,10,0" VerticalAlignment="Top">
+17 -17
View File
@@ -47,26 +47,26 @@ namespace Elwig.Windows {
if (!_actChanged || _actList == null || _acts == null || _actIds == null) if (!_actChanged || _actList == null || _acts == null || _actIds == null)
return; return;
foreach (var (vtrgid, _) in _acts.Where(a => a.Value == null)) { // delete
ctx.Remove(ctx.AreaCommitmentTypes.Find(vtrgid)!); var delete = _acts.Where(a => a.Value == null).Select(a => a.Key).ToList();
} await ctx.AreaCommitmentTypes.Where(v => delete.Contains(v.VtrgId)).ExecuteDeleteAsync();
foreach (var (attr, old) in _actIds) {
attr.VtrgId = old;
}
foreach (var (old, vtrgid) in _acts.Where(a => a.Value != null)) {
ctx.Update(ctx.AreaCommitmentTypes.Find(old)!);
}
await ctx.SaveChangesAsync();
foreach (var (old, vtrgid) in _acts.Where(a => a.Value != null)) { // update
ctx.UpdateRange(_actList
.Where(_actIds.ContainsKey)
.Select(t => {
t.VtrgId = _actIds[t];
ctx.Entry(t).State = EntityState.Added;
return t;
}));
await ctx.SaveChangesAsync();
foreach (var (old, vtrgid) in _acts.Where(a => a.Value != null && a.Key != a.Value)) {
await ctx.Database.ExecuteSqlAsync($"UPDATE area_commitment_type SET vtrgid = {vtrgid} WHERE vtrgid = {old}"); await ctx.Database.ExecuteSqlAsync($"UPDATE area_commitment_type SET vtrgid = {vtrgid} WHERE vtrgid = {old}");
} }
await ctx.SaveChangesAsync();
foreach (var type in _actList.Where(a => !_actIds.ContainsKey(a))) { // insert
if (type.VtrgId == null) continue; ctx.AddRange(_actList
ctx.Add(type); .Where(t => !_actIds.ContainsKey(t) && t.VtrgId != null));
}
await ctx.SaveChangesAsync(); await ctx.SaveChangesAsync();
} }
@@ -125,7 +125,7 @@ namespace Elwig.Windows {
var id = AreaCommitmentTypeIdInput.Text; var id = AreaCommitmentTypeIdInput.Text;
if (old != null) _acts[old] = id; if (old != null) _acts[old] = id;
attr.VtrgId = id; attr.VtrgId = id;
attr.SortId = v?.SortId; attr.SortId = v?.SortId ?? "";
attr.AttrId = a?.AttrId; attr.AttrId = a?.AttrId;
attr.MinKgPerHa = AreaCommitmentTypeMinKgPerHaInput.Text.Length > 0 ? int.Parse(AreaCommitmentTypeMinKgPerHaInput.Text) : null; attr.MinKgPerHa = AreaCommitmentTypeMinKgPerHaInput.Text.Length > 0 ? int.Parse(AreaCommitmentTypeMinKgPerHaInput.Text) : null;
attr.PenaltyPerKg = AreaCommitmentTypePenaltyPerKgInput.Text.Length > 0 ? decimal.Parse(AreaCommitmentTypePenaltyPerKgInput.Text) : null; attr.PenaltyPerKg = AreaCommitmentTypePenaltyPerKgInput.Text.Length > 0 ? decimal.Parse(AreaCommitmentTypePenaltyPerKgInput.Text) : null;
+13 -12
View File
@@ -41,25 +41,26 @@ namespace Elwig.Windows {
if (!_branchChanged || _branchList == null || _branches == null || _branchIds == null) if (!_branchChanged || _branchList == null || _branches == null || _branchIds == null)
return; return;
// delete
var deleteZwstIds = _branches.Where(b => b.Value == null).Select(b => b.Key).ToList(); var deleteZwstIds = _branches.Where(b => b.Value == null).Select(b => b.Key).ToList();
await ctx.Branches.Where(b => deleteZwstIds.Contains(b.ZwstId)).ExecuteDeleteAsync(); await ctx.Branches.Where(b => deleteZwstIds.Contains(b.ZwstId)).ExecuteDeleteAsync();
foreach (var (branch, old) in _branchIds) { // update
branch.ZwstId = old; ctx.UpdateRange(_branchList
} .Where(_branchIds.ContainsKey)
foreach (var (old, zwstid) in _branches.Where(b => b.Value != null)) { .Select(b => {
ctx.Update(ctx.Branches.Find(old)!); b.ZwstId = _branchIds[b];
} ctx.Entry(b).State = EntityState.Added;
return b;
}));
await ctx.SaveChangesAsync(); await ctx.SaveChangesAsync();
foreach (var (old, zwstid) in _branches.Where(b => b.Value != null && b.Key != b.Value)) {
foreach (var (old, zwstid) in _branches.Where(b => b.Value != null)) {
await ctx.Database.ExecuteSqlAsync($"UPDATE branch SET zwstid = {zwstid} WHERE zwstid = {old}"); await ctx.Database.ExecuteSqlAsync($"UPDATE branch SET zwstid = {zwstid} WHERE zwstid = {old}");
} }
foreach (var branch in _branchList.Where(b => !_branchIds.ContainsKey(b))) { // insert
if (branch.ZwstId == null) continue; ctx.AddRange(_branchList
ctx.Add(branch); .Where(b => !_branchIds.ContainsKey(b) && b.ZwstId != null));
}
await ctx.SaveChangesAsync(); await ctx.SaveChangesAsync();
} }
+16 -16
View File
@@ -48,30 +48,30 @@ namespace Elwig.Windows {
if (!_modChanged || _modList == null || _mods == null || _modIds == null) if (!_modChanged || _modList == null || _mods == null || _modIds == null)
return; return;
var year = (SeasonList.SelectedItem as Season)?.Year;
int i = 0; int i = 0;
foreach (var mod in _modList) mod.Ordering = ++i; foreach (var mod in _modList) mod.Ordering = ++i;
var year = (SeasonList.SelectedItem as Season)?.Year; // delete
foreach (var (modid, _) in _mods.Where(m => m.Value == null)) { var deleteModIds = _mods.Where(b => b.Value == null).Select(b => b.Key).ToList();
ctx.Remove(ctx.Modifiers.Find(year, modid)!); await ctx.Modifiers.Where(b => b.Year == year && deleteModIds.Contains(b.ModId)).ExecuteDeleteAsync();
}
foreach (var (mod, old) in _modIds) {
mod.ModId = old;
}
foreach (var (old, modid) in _mods.Where(m => m.Value != null)) {
ctx.Update(ctx.Modifiers.Find(year, old)!);
}
await ctx.SaveChangesAsync();
// update
ctx.UpdateRange(_modList
.Where(_modIds.ContainsKey)
.Select(m => {
m.ModId = _modIds[m];
ctx.Entry(m).State = EntityState.Added;
return m;
}));
await ctx.SaveChangesAsync();
foreach (var (old, modid) in _mods.Where(m => m.Value != null)) { foreach (var (old, modid) in _mods.Where(m => m.Value != null)) {
await ctx.Database.ExecuteSqlAsync($"UPDATE modifier SET modid = {modid} WHERE (year, modid) = ({year}, {old})"); await ctx.Database.ExecuteSqlAsync($"UPDATE modifier SET modid = {modid} WHERE (year, modid) = ({year}, {old})");
} }
await ctx.SaveChangesAsync();
foreach (var mod in _modList.Where(m => !_modIds.ContainsKey(m))) { // insert
if (mod.ModId == null) continue; ctx.AddRange(_modList
await ctx.AddAsync(mod); .Where(m => !_modIds.ContainsKey(m) && m.ModId != null));
}
await ctx.SaveChangesAsync(); await ctx.SaveChangesAsync();
} }
+14 -12
View File
@@ -41,26 +41,28 @@ namespace Elwig.Windows {
if (!_attrChanged || _attrList == null || _attrs == null || _attrIds == null) if (!_attrChanged || _attrList == null || _attrs == null || _attrIds == null)
return; return;
// delete
var deleteAttrIds = _attrs.Where(a => a.Value == null).Select(a => a.Key).ToList(); var deleteAttrIds = _attrs.Where(a => a.Value == null).Select(a => a.Key).ToList();
await ctx.WineAttributes.Where(a => deleteAttrIds.Contains(a.AttrId)).ExecuteDeleteAsync(); await ctx.WineAttributes.Where(a => deleteAttrIds.Contains(a.AttrId)).ExecuteDeleteAsync();
foreach (var (attr, old) in _attrIds) {
attr.AttrId = old;
}
foreach (var (old, attrid) in _attrs.Where(a => a.Value != null)) {
ctx.Update(ctx.WineAttributes.Find(old)!);
}
await ctx.SaveChangesAsync();
// update
ctx.UpdateRange(_attrList
.Where(_attrIds.ContainsKey)
.Select(a => {
a.AttrId = _attrIds[a];
ctx.Entry(a).State = EntityState.Added;
return a;
}));
await ctx.SaveChangesAsync();
foreach (var (old, attrid) in _attrs.Where(a => a.Value != null)) { foreach (var (old, attrid) in _attrs.Where(a => a.Value != null)) {
await ctx.Database.ExecuteSqlAsync($"UPDATE wine_attribute SET attrid = {attrid} WHERE attrid = {old}"); await ctx.Database.ExecuteSqlAsync($"UPDATE wine_attribute SET attrid = {attrid} WHERE attrid = {old}");
await ctx.Database.ExecuteSqlAsync($"UPDATE area_commitment_type SET vtrgid = (sortid || COALESCE(attrid, '') || COALESCE(disc, '')) WHERE attrid = {attrid}"); await ctx.Database.ExecuteSqlAsync($"UPDATE area_commitment_type SET vtrgid = (sortid || COALESCE(attrid, '') || COALESCE(disc, '')) WHERE attrid = {attrid}");
await ctx.Database.ExecuteSqlRawAsync($"UPDATE payment_variant SET data = REPLACE(REPLACE(data, '/{old}\"', '/{attrid}\"'), '/{old}-', '/{attrid}-')"); await ctx.Database.ExecuteSqlAsync($"UPDATE payment_variant SET data = REPLACE(REPLACE(data, {$"/{old}\""}, {$"/{attrid}\""}), {$"/{old}-"}, {$"/{attrid}-"})");
} }
foreach (var attr in _attrList.Where(a => !_attrIds.ContainsKey(a))) { // insert
if (attr.AttrId == null) continue; ctx.AddRange(_attrList
ctx.Add(attr); .Where(a => !_attrIds.ContainsKey(a) && a.AttrId != null));
}
await ctx.SaveChangesAsync(); await ctx.SaveChangesAsync();
} }
+14 -12
View File
@@ -41,25 +41,27 @@ namespace Elwig.Windows {
if (!_cultChanged || _cultList == null || _cults == null || _cultIds == null) if (!_cultChanged || _cultList == null || _cults == null || _cultIds == null)
return; return;
// delete
var deleteCultIds = _cults.Where(c => c.Value == null).Select(c => c.Key).ToList(); var deleteCultIds = _cults.Where(c => c.Value == null).Select(c => c.Key).ToList();
await ctx.WineCultivations.Where(c => deleteCultIds.Contains(c.CultId)).ExecuteDeleteAsync(); await ctx.WineCultivations.Where(c => deleteCultIds.Contains(c.CultId)).ExecuteDeleteAsync();
foreach (var (cult, old) in _cultIds) {
cult.CultId = old;
}
foreach (var (old, cultid) in _cults.Where(c => c.Value != null)) {
ctx.Update(ctx.WineCultivations.Find(old)!);
}
await ctx.SaveChangesAsync();
// update
ctx.UpdateRange(_cultList
.Where(_cultIds.ContainsKey)
.Select(c => {
c.CultId = _cultIds[c];
ctx.Entry(c).State = EntityState.Added;
return c;
}));
await ctx.SaveChangesAsync();
foreach (var (old, cultid) in _cults.Where(c => c.Value != null)) { foreach (var (old, cultid) in _cults.Where(c => c.Value != null)) {
await ctx.Database.ExecuteSqlAsync($"UPDATE wine_cultivation SET cultid = {cultid} WHERE cultid = {old}"); await ctx.Database.ExecuteSqlAsync($"UPDATE wine_cultivation SET cultid = {cultid} WHERE cultid = {old}");
await ctx.Database.ExecuteSqlRawAsync($"UPDATE payment_variant SET data = REPLACE(data, '-{old}\"', '-{cultid}\"')"); await ctx.Database.ExecuteSqlAsync($"UPDATE payment_variant SET data = REPLACE(data, {$"-{old}\""}, {$"-{cultid}\""})");
} }
foreach (var cult in _cultList.Where(c => !_cultIds.ContainsKey(c))) { // insert
if (cult.CultId == null) continue; ctx.AddRange(_cultList
ctx.Add(cult); .Where(c => !_cultIds.ContainsKey(c) && c.CultId != null));
}
await ctx.SaveChangesAsync(); await ctx.SaveChangesAsync();
} }
+28 -31
View File
@@ -12,8 +12,6 @@ using System.Windows.Input;
namespace Elwig.Windows { namespace Elwig.Windows {
public partial class BaseDataWindow : AdministrationWindow { public partial class BaseDataWindow : AdministrationWindow {
protected AppDbContext? EditContext;
public BaseDataWindow() { public BaseDataWindow() {
InitializeComponent(); InitializeComponent();
RequiredInputs = [ RequiredInputs = [
@@ -189,31 +187,30 @@ namespace Elwig.Windows {
} }
private async Task InitEditing() { private async Task InitEditing() {
EditContext = new AppDbContext(); using var ctx = new AppDbContext();
await BranchesInitEditing(EditContext); await BranchesInitEditing(ctx);
await WineAttributesInitEditing(EditContext); await WineAttributesInitEditing(ctx);
await WineCultivationsInitEditing(EditContext); await WineCultivationsInitEditing(ctx);
await AreaCommitmentTypesInitEditing(EditContext); await AreaCommitmentTypesInitEditing(ctx);
await SeasonsInitEditing(EditContext); await SeasonsInitEditing(ctx);
await ModifiersInitEditing(EditContext); await ModifiersInitEditing(ctx);
} }
private async Task Save() { private async Task Save() {
await UpdateClientParameters(App.Client); await UpdateClientParameters(App.Client);
await UpdateParameters(Utils.CurrentLastSeason); await UpdateParameters(Utils.CurrentLastSeason);
using var tx = await EditContext!.Database.BeginTransactionAsync(); using var ctx = new AppDbContext();
await BranchesSave(EditContext!); using var tx = await ctx.Database.BeginTransactionAsync();
await WineAttributesSave(EditContext!); await BranchesSave(ctx);
await WineCultivationsSave(EditContext!); await WineAttributesSave(ctx);
await AreaCommitmentTypesSave(EditContext!); await WineCultivationsSave(ctx);
await SeasonsSave(EditContext!); await AreaCommitmentTypesSave(ctx);
await ModifiersSave(EditContext!); await SeasonsSave(ctx);
await ModifiersSave(ctx);
await tx.CommitAsync(); await tx.CommitAsync();
} }
private async Task FinishEditing() { private async Task FinishEditing() {
EditContext?.Dispose();
EditContext = null;
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
await BranchesFinishEditing(ctx); await BranchesFinishEditing(ctx);
await WineAttributesFinishEditing(ctx); await WineAttributesFinishEditing(ctx);
@@ -361,29 +358,29 @@ namespace Elwig.Windows {
private async Task UpdateClientParameters(ClientParameters p) { private async Task UpdateClientParameters(ClientParameters p) {
p.Name = ClientNameInput.Text; p.Name = ClientNameInput.Text;
p.NameSuffix = string.IsNullOrEmpty(ClientNameSuffixInput.Text) ? null : ClientNameSuffixInput.Text; p.NameSuffix = string.IsNullOrWhiteSpace(ClientNameSuffixInput.Text) ? null : ClientNameSuffixInput.Text;
p.NameType = ClientNameTypeInput.Text; p.NameType = ClientNameTypeInput.Text;
p.NameToken = ClientNameTokenInput.Text; p.NameToken = ClientNameTokenInput.Text;
p.NameShort = ClientNameShortInput.Text; p.NameShort = ClientNameShortInput.Text;
p.Address = ClientAddressInput.Text; p.Address = ClientAddressInput.Text;
p.Plz = int.Parse(ClientPlzInput.Text); p.Plz = int.Parse(ClientPlzInput.Text);
p.Ort = ClientOrtInput.Text; p.Ort = ClientOrtInput.Text;
p.Iban = string.IsNullOrEmpty(ClientIbanInput.Text) ? null : ClientIbanInput.Text; p.Iban = string.IsNullOrWhiteSpace(ClientIbanInput.Text) ? null : ClientIbanInput.Text;
p.Bic = string.IsNullOrEmpty(ClientBicInput.Text) ? null : ClientBicInput.Text; p.Bic = string.IsNullOrWhiteSpace(ClientBicInput.Text) ? null : ClientBicInput.Text;
p.UstIdNr = string.IsNullOrEmpty(ClientUstIdNrInput.Text) ? null : ClientUstIdNrInput.Text; p.UstIdNr = string.IsNullOrWhiteSpace(ClientUstIdNrInput.Text) ? null : ClientUstIdNrInput.Text;
p.LfbisNr = string.IsNullOrEmpty(ClientLfbisNrInput.Text) ? null : ClientLfbisNrInput.Text; p.LfbisNr = string.IsNullOrWhiteSpace(ClientLfbisNrInput.Text) ? null : ClientLfbisNrInput.Text;
p.OrganicAuthority = string.IsNullOrEmpty(ClientOrganicAuthorityInput.Text) ? null : ClientOrganicAuthorityInput.Text; p.OrganicAuthority = string.IsNullOrWhiteSpace(ClientOrganicAuthorityInput.Text) ? null : ClientOrganicAuthorityInput.Text;
p.PhoneNr = string.IsNullOrEmpty(ClientPhoneNrInput.Text) ? null : ClientPhoneNrInput.Text; p.PhoneNr = string.IsNullOrWhiteSpace(ClientPhoneNrInput.Text) ? null : ClientPhoneNrInput.Text;
p.FaxNr = string.IsNullOrEmpty(ClientFaxNrInput.Text) ? null : ClientFaxNrInput.Text; p.FaxNr = string.IsNullOrWhiteSpace(ClientFaxNrInput.Text) ? null : ClientFaxNrInput.Text;
p.EmailAddress = string.IsNullOrEmpty(ClientEmailAddressInput.Text) ? null : ClientEmailAddressInput.Text; p.EmailAddress = string.IsNullOrWhiteSpace(ClientEmailAddressInput.Text) ? null : ClientEmailAddressInput.Text;
p.Website = string.IsNullOrEmpty(ClientWebsiteInput.Text) ? null : ClientWebsiteInput.Text; p.Website = string.IsNullOrWhiteSpace(ClientWebsiteInput.Text) ? null : ClientWebsiteInput.Text;
p.ModeBusinessShares = ParameterBusinessShareModeInput.SelectedIndex; p.ModeBusinessShares = ParameterBusinessShareModeInput.SelectedIndex;
p.EnableMemberHistory = ParameterBusinessShareHistoryInput.IsChecked ?? false; p.EnableMemberHistory = ParameterBusinessShareHistoryInput.IsChecked ?? false;
p.TextDeliveryNote = string.IsNullOrEmpty(TextElementDeliveryNote.Text) ? null : TextElementDeliveryNote.Text; p.TextDeliveryNote = string.IsNullOrWhiteSpace(TextElementDeliveryNote.Text) ? null : TextElementDeliveryNote.Text;
p.ModeDeliveryNoteStats = (ModeDeliveryNoteNone.IsChecked == true) ? 0 : (ModeDeliveryNoteGaOnly.IsChecked == true) ? 1 : (ModeDeliveryNoteShort.IsChecked == true) ? 2 : (ModeDeliveryNoteFull.IsChecked == true) ? 3 : 2; p.ModeDeliveryNoteStats = (ModeDeliveryNoteNone.IsChecked == true) ? 0 : (ModeDeliveryNoteGaOnly.IsChecked == true) ? 1 : (ModeDeliveryNoteShort.IsChecked == true) ? 2 : (ModeDeliveryNoteFull.IsChecked == true) ? 3 : 2;
p.TextDeliveryConfirmation = string.IsNullOrEmpty(TextElementDeliveryConfirmation.Text) ? null : TextElementDeliveryConfirmation.Text; p.TextDeliveryConfirmation = string.IsNullOrWhiteSpace(TextElementDeliveryConfirmation.Text) ? null : TextElementDeliveryConfirmation.Text;
p.TextCreditNote = string.IsNullOrEmpty(TextElementCreditNote.Text) ? null : TextElementCreditNote.Text; p.TextCreditNote = string.IsNullOrWhiteSpace(TextElementCreditNote.Text) ? null : TextElementCreditNote.Text;
p.ExportEbicsVersion = ParameterExportEbicsVersion.SelectedIndex + 3; p.ExportEbicsVersion = ParameterExportEbicsVersion.SelectedIndex + 3;
p.ExportEbicsAddress = ParameterExportEbicsAddress.SelectedIndex; p.ExportEbicsAddress = ParameterExportEbicsAddress.SelectedIndex;
+46 -33
View File
@@ -26,12 +26,12 @@ namespace Elwig.Windows {
private bool HasChanged = false; private bool HasChanged = false;
private bool Updating = false; private bool Updating = false;
private Scatter DataPlot; private Scatter? DataPlot;
private Scatter? GebundenPlot; private Scatter? GebundenPlot;
private Marker HighlightedPointPlot; private Marker? HighlightedPointPlot;
private Marker PrimaryMarkedPointPlot; private Marker? PrimaryMarkedPointPlot;
private Marker SecondaryMarkedPointPlot; private Marker? SecondaryMarkedPointPlot;
private Text TooltipPlot; private Text? TooltipPlot;
private static readonly LegendItem private static readonly LegendItem
UngebundenLegend = new() { UngebundenLegend = new() {
@@ -77,7 +77,7 @@ namespace Elwig.Windows {
PriceInput.Unit = $"{CurrencySymbol}/kg"; PriceInput.Unit = $"{CurrencySymbol}/kg";
GebundenFlatBonus.Unit = $"{CurrencySymbol}/kg"; GebundenFlatBonus.Unit = $"{CurrencySymbol}/kg";
PaymentVar = ctx.PaymentVariants.Find(year, avnr) ?? throw new ArgumentException("PaymentVar not found"); PaymentVar = ctx.PaymentVariants.Find(year, avnr) ?? throw new ArgumentException("PaymentVar not found");
Title = $"{PaymentVar?.Name} - Lese {year} - Elwig"; Title = $"{PaymentVar.Name} - Lese {year} - Elwig";
LockContext = true; LockContext = true;
} }
@@ -215,10 +215,12 @@ namespace Elwig.Windows {
GebundenPlot.MarkerStyle = new MarkerStyle(MarkerShape.FilledCircle, 9, ColorGebunden); GebundenPlot.MarkerStyle = new MarkerStyle(MarkerShape.FilledCircle, 9, ColorGebunden);
} }
DataPlot = OechslePricePlot.Plot.Add.Scatter(SelectedGraphEntry!.DataGraph.DataX, SelectedGraphEntry!.DataGraph.DataY); if (SelectedGraphEntry != null) {
DataPlot.LineStyle.Color = ColorUngebunden; DataPlot = OechslePricePlot.Plot.Add.Scatter(SelectedGraphEntry.DataGraph.DataX, SelectedGraphEntry.DataGraph.DataY);
DataPlot.Color = ColorUngebunden; DataPlot.LineStyle.Color = ColorUngebunden;
DataPlot.MarkerStyle = new MarkerStyle(MarkerShape.FilledCircle, 9, ColorUngebunden); DataPlot.Color = ColorUngebunden;
DataPlot.MarkerStyle = new MarkerStyle(MarkerShape.FilledCircle, 9, ColorUngebunden);
}
OechslePricePlot.Plot.Axes.SetLimits(Math.Min(GraphEntry.MinX, GraphEntry.MinXGeb) - 1, GraphEntry.MaxX + 1, -0.1, 1.5); OechslePricePlot.Plot.Axes.SetLimits(Math.Min(GraphEntry.MinX, GraphEntry.MinXGeb) - 1, GraphEntry.MaxX + 1, -0.1, 1.5);
@@ -244,7 +246,10 @@ namespace Elwig.Windows {
SecondaryMarkedPoint = -1; SecondaryMarkedPoint = -1;
ChangeActiveGraph(null); ChangeActiveGraph(null);
HideGradationLines(); HideGradationLines();
OechslePricePlot.Plot.Remove(DataPlot); if (DataPlot != null) {
OechslePricePlot.Plot.Remove(DataPlot);
DataPlot = null;
}
if (GebundenPlot != null) { if (GebundenPlot != null) {
OechslePricePlot.Plot.Remove(GebundenPlot); OechslePricePlot.Plot.Remove(GebundenPlot);
GebundenPlot = null; GebundenPlot = null;
@@ -254,9 +259,9 @@ namespace Elwig.Windows {
OechslePricePlot.Refresh(); OechslePricePlot.Refresh();
} }
private void ChangeMarker(Marker point, bool visible, double x = 0, double y = 0) { private static void ChangeMarker(Marker? point, bool visible, double x = 0, double y = 0) {
point.Location = new Coordinates(x, y); point?.Location = new Coordinates(x, y);
point.IsVisible = visible; point?.IsVisible = visible;
} }
private void EnableActionButtons() { private void EnableActionButtons() {
@@ -416,7 +421,7 @@ namespace Elwig.Windows {
var res = Validator.CheckDecimal(PriceInput, true, 2, Season.Precision); var res = Validator.CheckDecimal(PriceInput, true, 2, Season.Precision);
if (res.IsValid && double.TryParse(PriceInput.Text, out double price)) { if (res.IsValid && double.TryParse(PriceInput.Text, out double price)) {
ActiveGraph.SetPriceAt(PrimaryMarkedPoint, price); ActiveGraph.SetPriceAt(PrimaryMarkedPoint, price);
PrimaryMarkedPointPlot.Location = new Coordinates(PrimaryMarkedPointPlot.Location.X, price); PrimaryMarkedPointPlot?.Location = new Coordinates(PrimaryMarkedPointPlot.Location.X, price);
SetHasChanged(); SetHasChanged();
OechslePricePlot.Refresh(); OechslePricePlot.Refresh();
CheckGebundenTypeFixed(); CheckGebundenTypeFixed();
@@ -492,17 +497,19 @@ namespace Elwig.Windows {
ChangeMarker(PrimaryMarkedPointPlot, true, ActiveGraph.GetOechsleAt(PrimaryMarkedPoint), ActiveGraph.GetPriceAt(PrimaryMarkedPoint)); ChangeMarker(PrimaryMarkedPointPlot, true, ActiveGraph.GetOechsleAt(PrimaryMarkedPoint), ActiveGraph.GetPriceAt(PrimaryMarkedPoint));
Updating = true; if (Highlighted.Graph != null) {
OechsleInput.Text = Highlighted.Graph!.GetOechsleAt(Highlighted.Index).ToString(); Updating = true;
GebInput.IsChecked = Highlighted.Graph == SelectedGraphEntry?.GebundenGraph; OechsleInput.Text = Highlighted.Graph.GetOechsleAt(Highlighted.Index).ToString();
PriceInput.Text = Math.Round(Highlighted.Graph.GetPriceAt(Highlighted.Index), Season.Precision).ToString(); GebInput.IsChecked = Highlighted.Graph == SelectedGraphEntry?.GebundenGraph;
Updating = false; PriceInput.Text = Math.Round(Highlighted.Graph.GetPriceAt(Highlighted.Index), Season.Precision).ToString();
Updating = false;
}
EnableActionButtons(); EnableActionButtons();
} else { } else {
PrimaryMarkedPoint = -1; PrimaryMarkedPoint = -1;
SecondaryMarkedPoint = -1; SecondaryMarkedPoint = -1;
if (SelectedGraphEntry!.GebundenGraph != null) { if (SelectedGraphEntry?.GebundenGraph != null) {
ChangeActiveGraph(null); ChangeActiveGraph(null);
} }
ChangeMarker(PrimaryMarkedPointPlot, false); ChangeMarker(PrimaryMarkedPointPlot, false);
@@ -548,21 +555,26 @@ namespace Elwig.Windows {
if (mouseOnData != null) { if (mouseOnData != null) {
ChangeMarker(HighlightedPointPlot, true, mouseOnData.Value.X, mouseOnData.Value.Y); ChangeMarker(HighlightedPointPlot, true, mouseOnData.Value.X, mouseOnData.Value.Y);
HighlightedPointPlot.IsVisible = true; HighlightedPointPlot?.IsVisible = true;
HoverChanged = true ^ HoverActive; HoverChanged = true ^ HoverActive;
HoverActive = true; HoverActive = true;
HandleTooltip(mouseOnData.Value.X, mouseOnData.Value.Y, mouseOnData.Value.Index, SelectedGraphEntry!.DataGraph, e.GetPosition(OechslePricePlot), e is MouseWheelEventArgs); if (SelectedGraphEntry?.DataGraph is Graph g)
HandleTooltip(mouseOnData.Value.X, mouseOnData.Value.Y, mouseOnData.Value.Index, g, e.GetPosition(OechslePricePlot), e is MouseWheelEventArgs);
} else if (mouseOnGebunden != null) { } else if (mouseOnGebunden != null) {
ChangeMarker(HighlightedPointPlot, true, mouseOnGebunden.Value.X, mouseOnGebunden.Value.Y); ChangeMarker(HighlightedPointPlot, true, mouseOnGebunden.Value.X, mouseOnGebunden.Value.Y);
HighlightedPointPlot.IsVisible = true; HighlightedPointPlot?.IsVisible = true;
HoverChanged = true ^ HoverActive; HoverChanged = true ^ HoverActive;
HoverActive = true; HoverActive = true;
HandleTooltip(mouseOnGebunden.Value.X, mouseOnGebunden.Value.Y, mouseOnGebunden.Value.Index, SelectedGraphEntry!.GebundenGraph!, e.GetPosition(OechslePricePlot), e is MouseWheelEventArgs); if (SelectedGraphEntry?.GebundenGraph is Graph g)
HandleTooltip(mouseOnGebunden.Value.X, mouseOnGebunden.Value.Y, mouseOnGebunden.Value.Index, g, e.GetPosition(OechslePricePlot), e is MouseWheelEventArgs);
} else { } else {
ChangeMarker(HighlightedPointPlot, false); ChangeMarker(HighlightedPointPlot, false);
HoverChanged = false ^ HoverActive; HoverChanged = false ^ HoverActive;
HoverActive = false; HoverActive = false;
OechslePricePlot.Plot.PlottableList.Remove(TooltipPlot); if (TooltipPlot != null) {
OechslePricePlot.Plot.PlottableList.Remove(TooltipPlot);
TooltipPlot = null;
}
OechslePricePlot.Refresh(); OechslePricePlot.Refresh();
} }
} }
@@ -577,7 +589,10 @@ namespace Elwig.Windows {
private void HandleTooltip(double pointX, double pointY, int pointIndex, Graph g, Point p, bool force) { private void HandleTooltip(double pointX, double pointY, int pointIndex, Graph g, Point p, bool force) {
if (force || LastHighlighted != Highlighted || HoverChanged) { if (force || LastHighlighted != Highlighted || HoverChanged) {
OechslePricePlot.Plot.PlottableList.Remove(TooltipPlot); if (TooltipPlot != null) {
OechslePricePlot.Plot.PlottableList.Remove(TooltipPlot);
TooltipPlot = null;
}
if (TooltipInput.IsChecked == true) { if (TooltipInput.IsChecked == true) {
Coordinates mouseLocation = GetMouseCoordinates(new(p.X, p.Y - 30)); Coordinates mouseLocation = GetMouseCoordinates(new(p.X, p.Y - 30));
TooltipPlot = OechslePricePlot.Plot.Add.Text($"Oechsle: {pointX:N2}, Preis: {Math.Round(pointY, Season.Precision)} {CurrencySymbol}/kg", mouseLocation.X, mouseLocation.Y); TooltipPlot = OechslePricePlot.Plot.Add.Text($"Oechsle: {pointX:N2}, Preis: {Math.Round(pointY, Season.Precision)} {CurrencySymbol}/kg", mouseLocation.X, mouseLocation.Y);
@@ -676,7 +691,7 @@ namespace Elwig.Windows {
} }
} }
private void DisableTextBox(TextBox u) { private static void DisableTextBox(TextBox u) {
u.IsEnabled = false; u.IsEnabled = false;
u.IsReadOnly = true; u.IsReadOnly = true;
} }
@@ -707,10 +722,8 @@ namespace Elwig.Windows {
ActiveGraph = g; ActiveGraph = g;
} }
private void ChangeLineWidth(Scatter? p, double lineWidth) { private static void ChangeLineWidth(Scatter? p, double lineWidth) {
if (p != null) { p?.LineWidth = (float)lineWidth;
p.LineWidth = (float)lineWidth;
}
} }
private void GraphList_SelectionChanged(object sender, SelectionChangedEventArgs e) { private void GraphList_SelectionChanged(object sender, SelectionChangedEventArgs e) {
@@ -752,7 +765,7 @@ namespace Elwig.Windows {
} }
} }
SelectedGraphEntry!.Vaributes = VaributeInput.SelectedItems.Cast<Varibute>().ToList(); SelectedGraphEntry?.Vaributes = [.. VaributeInput.SelectedItems.Cast<Varibute>()];
SetHasChanged(); SetHasChanged();
GraphList.Items.Refresh(); GraphList.Items.Refresh();
VaributeInput.Items.Refresh(); VaributeInput.Items.Refresh();
+13 -12
View File
@@ -85,10 +85,10 @@ namespace Elwig.Windows {
if (n < 3) WeighingCButton.Visibility = Visibility.Hidden; if (n < 3) WeighingCButton.Visibility = Visibility.Hidden;
if (n < 4) WeighingDButton.Visibility = Visibility.Hidden; if (n < 4) WeighingDButton.Visibility = Visibility.Hidden;
if (n == 1) WeighingAButton.Content = "Wiegen"; if (n == 1) WeighingAButton.Content = "Wiegen";
if (n > 1) WeighingAButton.Content = $"Wiegen {App.CommandScales[0].ScaleId}"; if (n > 1) WeighingAButton.Content = $"Wiegen {App.CommandScales[0].ScaleTerminalId}";
if (n >= 2) WeighingBButton.Content = $"Wiegen {App.CommandScales[1].ScaleId}"; if (n >= 2) WeighingBButton.Content = $"Wiegen {App.CommandScales[1].ScaleTerminalId}";
if (n >= 3) WeighingCButton.Content = $"Wiegen {App.CommandScales[2].ScaleId}"; if (n >= 3) WeighingCButton.Content = $"Wiegen {App.CommandScales[2].ScaleTerminalId}";
if (n >= 4) WeighingDButton.Content = $"Wiegen {App.CommandScales[3].ScaleId}"; if (n >= 4) WeighingDButton.Content = $"Wiegen {App.CommandScales[3].ScaleTerminalId}";
WeighingManualButton.Margin = new Thickness(10, 10 + n * 32, 10, 10); WeighingManualButton.Margin = new Thickness(10, 10 + n * 32, 10, 10);
foreach (var s in App.EventScales) { foreach (var s in App.EventScales) {
s.WeighingEvent += Scale_Weighing; s.WeighingEvent += Scale_Weighing;
@@ -124,7 +124,8 @@ namespace Elwig.Windows {
public DeliveryAdminWindow(int mgnr) : public DeliveryAdminWindow(int mgnr) :
this() { this() {
ViewModel.FilterMember = DeliveryService.GetMember(mgnr) ?? throw new ArgumentException("MgNr argument has invalid value"); using var ctx = new AppDbContext();
ViewModel.FilterMember = ctx.Members.Find(mgnr) ?? throw new ArgumentException("MgNr argument has invalid value");
ViewModel.Title = $"Lieferungen - {ViewModel.FilterMember.AdministrativeName} - Elwig"; ViewModel.Title = $"Lieferungen - {ViewModel.FilterMember.AdministrativeName} - Elwig";
ViewModel.EnableAllSeasons = true; ViewModel.EnableAllSeasons = true;
} }
@@ -365,7 +366,7 @@ namespace Elwig.Windows {
private void InitialInputs() { private void InitialInputs() {
ViewModel.LastScaleError = null; ViewModel.LastScaleError = null;
ViewModel.WeighingData = null; ViewModel.WeighingData = null;
ViewModel.ScaleId = null; ViewModel.ScaleTerminalId = null;
ViewModel.ManualWeighingReason = null; ViewModel.ManualWeighingReason = null;
ClearOriginalValues(); ClearOriginalValues();
@@ -482,7 +483,7 @@ namespace Elwig.Windows {
await base.OnRenewContext(ctx); await base.OnRenewContext(ctx);
if (ViewModel.FilterMember != null) { if (ViewModel.FilterMember != null) {
if (await DeliveryService.GetMemberAsync(ViewModel.FilterMember.MgNr) is not Member m) { if (await ctx.FetchMembers(ViewModel.FilterMember.MgNr).SingleOrDefaultAsync() is not Member m) {
Close(); Close();
return; return;
} }
@@ -650,13 +651,13 @@ namespace Elwig.Windows {
private void OnWeighingResult(IScale scale, WeighingResult res) { private void OnWeighingResult(IScale scale, WeighingResult res) {
if ((res.NetWeight ?? 0) > 0 && res.FullWeighingId != null) { if ((res.NetWeight ?? 0) > 0 && res.FullWeighingId != null) {
ViewModel.Weight = res.NetWeight; ViewModel.Weight = res.NetWeight;
ViewModel.ScaleId = scale.ScaleId; ViewModel.ScaleTerminalId = scale.ScaleTerminalId;
ViewModel.WeighingData = res.ToJson().ToJsonString(); ViewModel.WeighingData = res.ToJson().ToJsonString();
ViewModel.ManualWeighingReason = null; ViewModel.ManualWeighingReason = null;
ManualWeighingInput.IsChecked = false; ManualWeighingInput.IsChecked = false;
} else { } else {
ViewModel.Weight = null; ViewModel.Weight = null;
ViewModel.ScaleId = null; ViewModel.ScaleTerminalId = null;
ViewModel.WeighingData = null; ViewModel.WeighingData = null;
} }
ViewModel.LastScaleError = null; ViewModel.LastScaleError = null;
@@ -770,7 +771,7 @@ namespace Elwig.Windows {
} }
private void EmptyScale() { private void EmptyScale() {
var scale = App.Scales.Where(s => s.ScaleId == ViewModel.ScaleId).FirstOrDefault(); var scale = App.Scales.Where(s => s.ScaleTerminalId == ViewModel.ScaleTerminalId).FirstOrDefault();
if (scale is not ICommandScale cs) return; if (scale is not ICommandScale cs) return;
cs.Empty(); cs.Empty();
} }
@@ -952,7 +953,7 @@ namespace Elwig.Windows {
ViewModel.Weight = res?.Item1; ViewModel.Weight = res?.Item1;
ManualWeighingInput.IsChecked = true; ManualWeighingInput.IsChecked = true;
ViewModel.ManualWeighingReason = res?.Item2; ViewModel.ManualWeighingReason = res?.Item2;
ViewModel.ScaleId = null; ViewModel.ScaleTerminalId = null;
ViewModel.WeighingData = null; ViewModel.WeighingData = null;
} }
@@ -1200,7 +1201,7 @@ namespace Elwig.Windows {
} }
private async Task UpdateLsNr() { private async Task UpdateLsNr() {
if (string.IsNullOrEmpty(ViewModel.Date) || ViewModel.Branch == null) { if (string.IsNullOrWhiteSpace(ViewModel.Date) || ViewModel.Branch == null) {
ViewModel.LsNr = ""; ViewModel.LsNr = "";
} else { } else {
try { try {
+1
View File
@@ -958,6 +958,7 @@ namespace Elwig.Windows {
m.EmailAddresses.OrderBy(a => a.Nr).Select(a => a.Address).ToArray(), m.EmailAddresses.OrderBy(a => a.Nr).Select(a => a.Address).ToArray(),
subject, docs.Select(d => d.Title).ToArray() subject, docs.Select(d => d.Title).ToArray()
)]); )]);
await Task.Delay((int)(App.Config.SmtpWait * 1000));
} }
}); });
+22 -4
View File
@@ -200,8 +200,13 @@ namespace Elwig.Windows {
return; return;
Mouse.OverrideCursor = Cursors.Wait; Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => { await Task.Run(async () => {
await SyncService.Download(App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword); if (App.Config.SyncMain) {
await SyncService.UploadModified(App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword); 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; Mouse.OverrideCursor = null;
} }
@@ -211,7 +216,7 @@ namespace Elwig.Windows {
return; return;
Mouse.OverrideCursor = Cursors.Wait; Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => { 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; Mouse.OverrideCursor = null;
} }
@@ -229,6 +234,10 @@ namespace Elwig.Windows {
private async void Menu_Sync_UploadModified_Click(object sender, RoutedEventArgs evt) { private async void Menu_Sync_UploadModified_Click(object sender, RoutedEventArgs evt) {
if (App.Config.SyncUrl == null) if (App.Config.SyncUrl == null)
return; 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; Mouse.OverrideCursor = Cursors.Wait;
await Task.Run(async () => { await Task.Run(async () => {
await SyncService.UploadModified(App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword); await SyncService.UploadModified(App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword);
@@ -296,6 +305,11 @@ namespace Elwig.Windows {
if (App.Config.SyncUrl == null) if (App.Config.SyncUrl == null)
return; 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!")) 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; return;
@@ -367,7 +381,11 @@ namespace Elwig.Windows {
await Task.Delay(delay); await Task.Delay(delay);
var ch = false; var ch = false;
using (var ctx = new AppDbContext()) { using (var ctx = new AppDbContext()) {
ch = await SyncService.ChangesAvailable(ctx, App.Config.SyncUrl, App.Config.SyncUsername, App.Config.SyncPassword); 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(() => { await App.MainDispatcher.BeginInvoke(() => {
if (ch) { if (ch) {
+34 -22
View File
@@ -233,7 +233,7 @@
</DataGridTextColumn> </DataGridTextColumn>
<DataGridTextColumn Header="Nachname" Binding="{Binding Name}" Width="140"/> <DataGridTextColumn Header="Nachname" Binding="{Binding Name}" Width="140"/>
<DataGridTextColumn Header="Vorname" Binding="{Binding GivenName}" Width="140"/> <DataGridTextColumn Header="Vorname" Binding="{Binding GivenName}" Width="140"/>
<DataGridTextColumn Header="GA" Binding="{Binding SharesTotal, StringFormat='{}{0} '}" Width="40"> <DataGridTextColumn Header="GA" Binding="{Binding SharesActive, StringFormat='{}{0} '}" Width="40">
<DataGridTextColumn.CellStyle> <DataGridTextColumn.CellStyle>
<Style> <Style>
<Setter Property="TextBlock.TextAlignment" Value="Right"/> <Setter Property="TextBlock.TextAlignment" Value="Right"/>
@@ -619,22 +619,26 @@
Margin="0,40,10,0" Width="78" Grid.Column="1" HorizontalAlignment="Left" TextAlignment="Right" Margin="0,40,10,0" Width="78" Grid.Column="1" HorizontalAlignment="Left" TextAlignment="Right"
TextChanged="DateInput_TextChanged" LostFocus="DateInput_LostFocus"/> TextChanged="DateInput_TextChanged" LostFocus="DateInput_LostFocus"/>
<Label Content="Geschäftsanteile:" Margin="10,65,0,0" Grid.Column="0"/> <Label Content="BH-Konto:" Margin="10,70,0,0" Grid.Column="0"/>
<Label x:Name="BusinessSharesLabel" Content="(rot/weiß/ruhend)" Margin="10,78,0,0" Grid.Column="0" FontSize="10"/> <TextBox x:Name="AccountingNrInput" Text="{Binding AccountingNr, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,70,10,0" Width="63" Grid.Column="1" HorizontalAlignment="Left"
TextChanged="TextBox_TextChanged"/>
<Label Content="Geschäftsanteile:" Margin="10,95,0,0" Grid.Column="0"/>
<Label x:Name="BusinessSharesLabel" Content="(rot/weiß/ruhend)" Margin="10,108,0,0" Grid.Column="0" FontSize="10"/>
<TextBox x:Name="BusinessShares1Input" Text="{Binding BusinessShares1String, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" <TextBox x:Name="BusinessShares1Input" Text="{Binding BusinessShares1String, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,70,10,0" Width="32" Grid.Column="1" HorizontalAlignment="Left" TextAlignment="Right" Margin="0,100,10,0" Width="32" Grid.Column="1" Grid.ColumnSpan="2" HorizontalAlignment="Left" TextAlignment="Right"
TextChanged="IntegerInput_TextChanged"/> TextChanged="IntegerInput_TextChanged"/>
<TextBox x:Name="BusinessShares2Input" Text="{Binding BusinessShares2String, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" <TextBox x:Name="BusinessShares2Input" Text="{Binding BusinessShares2String, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="37,70,10,0" Width="32" Grid.Column="1" HorizontalAlignment="Left" TextAlignment="Right" Margin="37,100,10,0" Width="32" Grid.Column="1" Grid.ColumnSpan="2" HorizontalAlignment="Left" TextAlignment="Right"
TextChanged="IntegerInput_TextChanged"/> TextChanged="IntegerInput_TextChanged"/>
<TextBox x:Name="BusinessShares3Input" Text="{Binding BusinessShares3String, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" <TextBox x:Name="BusinessShares3Input" Text="{Binding BusinessShares3String, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="74,70,10,0" Width="32" Grid.Column="1" HorizontalAlignment="Left" TextAlignment="Right" Margin="74,100,10,0" Width="32" Grid.Column="1" Grid.ColumnSpan="2" HorizontalAlignment="Left" TextAlignment="Right"
TextChanged="IntegerInput_TextChanged"/> TextChanged="IntegerInput_TextChanged"/>
<Button x:Name="BusinessSharesButton" FontFamily="Segoe MDL2 Assets" Content="&#xEB05;" FontSize="16" Padding="0.5,0,0,0" IsEnabled="{Binding IsMemberSelected}"
<Label Content="BH-Konto:" Margin="10,100,0,0" Grid.Column="0"/> Margin="111,100,10,0" Width="25" Height="25" Grid.Column="1" Grid.ColumnSpan="2" HorizontalAlignment="Left" VerticalAlignment="Top"
<TextBox x:Name="AccountingNrInput" Text="{Binding AccountingNr, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" ToolTip="Geschäftsanteile bearbeiten"
Margin="0,100,10,0" Grid.Column="1" Click="BusinessSharesButton_Click"/>
TextChanged="TextBox_TextChanged"/>
<CheckBox x:Name="ActiveInput" Content="Aktiv" IsChecked="{Binding IsActive, Mode=TwoWay}" IsEnabled="False" <CheckBox x:Name="ActiveInput" Content="Aktiv" IsChecked="{Binding IsActive, Mode=TwoWay}" IsEnabled="False"
Checked="ActiveInput_Changed" Unchecked="ActiveInput_Changed" Checked="ActiveInput_Changed" Unchecked="ActiveInput_Changed"
@@ -663,7 +667,7 @@
<Label Content="Anmerkung:" Margin="10,190,0,0" Grid.Column="0"/> <Label Content="Anmerkung:" Margin="10,190,0,0" Grid.Column="0"/>
<TextBox x:Name="CommentInput" Text="{Binding Comment, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" <TextBox x:Name="CommentInput" Text="{Binding Comment, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,190,10,70" Grid.Column="1" Grid.ColumnSpan="2" Margin="0,190,10,70" Grid.Column="1" Grid.ColumnSpan="2" FontSize="12"
TextChanged="TextBox_TextChanged" TextChanged="TextBox_TextChanged"
VerticalAlignment="Stretch" Height="auto" AcceptsReturn="True" TextWrapping="Wrap" VerticalScrollBarVisibility="Visible"/> VerticalAlignment="Stretch" Height="auto" AcceptsReturn="True" TextWrapping="Wrap" VerticalScrollBarVisibility="Visible"/>
@@ -702,12 +706,24 @@
</TextBlock.ToolTip> </TextBlock.ToolTip>
</TextBlock> </TextBlock>
<Button x:Name="DeliveryButton" Content="Lieferungen" IsEnabled="{Binding IsMemberSelected}" <Button x:Name="DeliveryButton" IsEnabled="{Binding IsMemberSelected}"
Click="DeliveryButton_Click" Click="DeliveryButton_Click"
HorizontalAlignment="Right" Margin="10,00,10,37" Width="150" VerticalAlignment="Bottom" Grid.ColumnSpan="3"/> HorizontalAlignment="Right" Margin="10,00,10,37" Width="160" VerticalAlignment="Bottom" Grid.ColumnSpan="3" HorizontalContentAlignment="Stretch">
<Button x:Name="AreaCommitmentButton" Content="Flächenbindungen" IsEnabled="{Binding IsMemberSelected}" <Grid>
<TextBlock Margin="0,0,10,0" TextAlignment="Center">Lieferungen</TextBlock>
<TextBlock FontFamily="Segoe MDL2 Assets" FontSize="16" Text="&#xE8A7;"
TextAlignment="Left" HorizontalAlignment="Right" Padding="0,1.5,0,0" Margin="0,0,0,0"/>
</Grid>
</Button>
<Button x:Name="AreaCommitmentButton" IsEnabled="{Binding IsMemberSelected}"
Click="AreaCommitmentButton_Click" Click="AreaCommitmentButton_Click"
HorizontalAlignment="Right" Margin="10,10,10,5" Width="150" VerticalAlignment="Bottom" Grid.ColumnSpan="3"/> HorizontalAlignment="Right" Margin="10,10,10,5" Width="160" VerticalAlignment="Bottom" Grid.ColumnSpan="3" HorizontalContentAlignment="Stretch">
<Grid>
<TextBlock Margin="0,0,15,0" TextAlignment="Center">Flächenbindungen</TextBlock>
<TextBlock FontFamily="Segoe MDL2 Assets" FontSize="16" Text="&#xE8A7;"
TextAlignment="Left" HorizontalAlignment="Right" Padding="0,1.5,0,0" Margin="0,0,0,0"/>
</Grid>
</Button>
</Grid> </Grid>
</GroupBox> </GroupBox>
</Grid> </Grid>
@@ -719,7 +735,7 @@
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="150"/> <ColumnDefinition Width="150"/>
<ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="200"/> <ColumnDefinition Width="1*"/>
<ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="1*"/> <ColumnDefinition Width="1*"/>
<ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/>
@@ -736,11 +752,7 @@
</TextBlock> </TextBlock>
</StatusBarItem> </StatusBarItem>
<Separator Grid.Column="1"/> <Separator Grid.Column="1"/>
<StatusBarItem Grid.Column="2"> <StatusBarItem Grid.Column="2" Content="{Binding StatusBusinessShares}"/>
<TextBlock ToolTip="{Binding StatusBusinessSharesToolTip}">
Geschäftsanteile: <Run Text="{Binding StatusBusinessShares}"/>
</TextBlock>
</StatusBarItem>
<Separator Grid.Column="3"/> <Separator Grid.Column="3"/>
<StatusBarItem Grid.Column="4"> <StatusBarItem Grid.Column="4">
<TextBlock ToolTip="{Binding StatusAreaCommitmentToolTip}"> <TextBlock ToolTip="{Binding StatusAreaCommitmentToolTip}">
+157 -36
View File
@@ -1,18 +1,20 @@
using Microsoft.EntityFrameworkCore; using Elwig.Dialogs;
using System; using Elwig.Documents;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Elwig.Helpers; using Elwig.Helpers;
using Elwig.Models.Entities; using Elwig.Models.Entities;
using System.Threading.Tasks;
using Elwig.Documents;
using System.Diagnostics;
using Elwig.Dialogs;
using Elwig.Services; using Elwig.Services;
using Elwig.ViewModels; using Elwig.ViewModels;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data; using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media; using System.Windows.Media;
namespace Elwig.Windows { namespace Elwig.Windows {
@@ -38,9 +40,16 @@ namespace Elwig.Windows {
CommandBindings.Add(new CommandBinding(CtrlO, Menu_List_ShowActive_Click)); CommandBindings.Add(new CommandBinding(CtrlO, Menu_List_ShowActive_Click));
CommandBindings.Add(new CommandBinding(CtrlShiftP, Menu_MemberDataSheet_Print_Click)); CommandBindings.Add(new CommandBinding(CtrlShiftP, Menu_MemberDataSheet_Print_Click));
CommandBindings.Add(new CommandBinding(CtrlShiftO, Menu_List_PrintActive_Click)); CommandBindings.Add(new CommandBinding(CtrlShiftO, Menu_List_PrintActive_Click));
ExemptInputs = [ List<Control> exempt = [
SearchInput, ActiveMemberInput, MemberList, SearchInput, ActiveMemberInput, MemberList,
]; ];
if (App.Client.EnableMemberHistory) {
exempt.AddRange([BusinessShares1Input, BusinessShares2Input, BusinessShares3Input]);
BusinessShares1Input.IsReadOnly = true;
BusinessShares2Input.IsReadOnly = true;
BusinessShares3Input.IsReadOnly = true;
}
ExemptInputs = [.. exempt];
RequiredInputs = [ RequiredInputs = [
MgNrInput, GivenNameInput, NameInput, MgNrInput, GivenNameInput, NameInput,
AddressInput, PlzInput, OrtInput, BillingOrtInput, AddressInput, PlzInput, OrtInput, BillingOrtInput,
@@ -101,6 +110,11 @@ namespace Elwig.Windows {
BusinessShares2Input.Background = Brushes.WhiteSmoke; BusinessShares2Input.Background = Brushes.WhiteSmoke;
BusinessShares2Input.ToolTip = "Geschäftsanteile (ruhend)"; BusinessShares2Input.ToolTip = "Geschäftsanteile (ruhend)";
BusinessShares3Input.Visibility = Visibility.Hidden; BusinessShares3Input.Visibility = Visibility.Hidden;
BusinessSharesButton.Margin = new(74, 100, 10, 0);
}
if (!App.Client.EnableMemberHistory) {
BusinessSharesButton.Visibility = Visibility.Hidden;
} }
UpdateContactInfoVisibility(); UpdateContactInfoVisibility();
@@ -133,7 +147,7 @@ namespace Elwig.Windows {
var cursor = Mouse.OverrideCursor != null; var cursor = Mouse.OverrideCursor != null;
if (!cursor) Mouse.OverrideCursor = Cursors.Wait; if (!cursor) Mouse.OverrideCursor = Cursors.Wait;
var query = (vm.SearchQuery, vm.ShowOnlyActiveMembers); var query = (vm.SearchQuery, vm.ShowOnlyActiveMembers);
var (members, totalMemberCount, totalBusinessShares) = await Task.Run(async () => { var (members, stat) = await Task.Run(async () => {
using var ctx = new AppDbContext(); using var ctx = new AppDbContext();
var (_, memberQuery, filter) = await vm.GetFilters(ctx); var (_, memberQuery, filter) = await vm.GetFilters(ctx);
var members = await memberQuery var members = await memberQuery
@@ -160,10 +174,17 @@ namespace Elwig.Windows {
.ThenBy(m => m.MgNr)]; .ThenBy(m => m.MgNr)];
} }
var totalMemberCount = await ctx.Members.CountAsync(); var stat = (await ctx.Members.GroupBy(m => 1).Select(g => new {
var totalBusinessShares = await ctx.Members.SumAsync(m => m.Shares + m.SharesRed + m.SharesWhite + m.SharesDormant); Count = g.Count(),
Shares = g.Sum(m => m.Shares),
SharesRed = g.Sum(m => m.SharesRed),
SharesWhite = g.Sum(m => m.SharesWhite),
SharesDormant = g.Sum(m => m.SharesDormant),
SharesTotal = g.Sum(m => m.Shares + m.SharesRed + m.SharesWhite + m.SharesDormant),
SharesActive = g.Sum(m => m.Shares + m.SharesRed + m.SharesWhite),
}).ToListAsync()).Select(g => (g.Count, g.Shares, g.SharesRed, g.SharesWhite, g.SharesDormant, g.SharesTotal, g.SharesActive)).ToList();
return (members, totalMemberCount, totalBusinessShares); return (members, stat[0]);
}); });
if (!cursor) Mouse.OverrideCursor = null; if (!cursor) Mouse.OverrideCursor = null;
if (query != (ViewModel.SearchQuery, ViewModel.ShowOnlyActiveMembers)) return; if (query != (ViewModel.SearchQuery, ViewModel.ShowOnlyActiveMembers)) return;
@@ -173,8 +194,37 @@ namespace Elwig.Windows {
if (updateSort && MemberList.SelectedItem != null) if (updateSort && MemberList.SelectedItem != null)
MemberList.ScrollIntoView(MemberList.SelectedItem); MemberList.ScrollIntoView(MemberList.SelectedItem);
ViewModel.StatusMembers = $"{members.Count:N0} ({totalMemberCount:N0})"; ViewModel.StatusMembers = $"{members.Count:N0} ({stat.Count:N0})";
ViewModel.StatusBusinessShares = $"{members.Sum(m => m.Shares + m.SharesRed + m.SharesWhite + m.SharesDormant):N0} ({totalBusinessShares:N0})";
var sA = members.Sum(m => m.Shares);
var rA = members.Sum(m => m.SharesRed);
var wA = members.Sum(m => m.SharesWhite);
var dA = members.Sum(m => m.SharesDormant);
List<(int Count, Brush? Color)> a = [];
if (sA > 0) a.Add((sA, null));
if (rA > 0) a.Add((rA, Brushes.DarkRed));
if (wA > 0) a.Add((wA, Brushes.DarkGreen));
if (a.Count == 0) a.Add((0, null));
List<(int Count, Brush? Color)> b = [];
if (stat.Shares > 0) b.Add((stat.Shares, null));
if (stat.SharesRed > 0) b.Add((stat.SharesRed, Brushes.DarkRed));
if (stat.SharesWhite > 0) b.Add((stat.SharesWhite, Brushes.DarkGreen));
if (a.Count == 0) b.Add((0, null));
Run[] inlines = [
new("Geschäftsanteile: "),
.. a.Select(i => new Run($"{i.Count:N0}") { Foreground = i.Color ?? Brushes.Black }).Join(() => new("+")),
new(" ("),
.. b.Select(i => new Run($"{i.Count:N0}") { Foreground = i.Color ?? Brushes.Black }).Join(() => new("+")),
new(")")
];
if (ViewModel.StatusBusinessShares == null) {
ViewModel.StatusBusinessShares = new();
} else {
ViewModel.StatusBusinessShares.Inlines.Clear();
}
ViewModel.StatusBusinessShares.Inlines.AddRange(inlines);
} }
private void RefreshInputs(bool validate = false) { private void RefreshInputs(bool validate = false) {
@@ -198,6 +248,17 @@ namespace Elwig.Windows {
ClearOriginalValues(); ClearOriginalValues();
ClearDefaultValues(); ClearDefaultValues();
await ViewModel.InitInputs(); await ViewModel.InitInputs();
if (App.Client.EnableMemberHistory) {
BusinessShares1Input.Text = "0";
BusinessShares2Input.Text = "0";
BusinessShares3Input.Text = "0";
} else if (App.Client.HasRedWhite) {
BusinessShares3Input.Text = "0";
SetDefaultValue(BusinessShares3Input);
} else {
BusinessShares2Input.Text = "0";
SetDefaultValue(BusinessShares2Input);
}
SetDefaultValue(MgNrInput); SetDefaultValue(MgNrInput);
SetDefaultValue(EntryDateInput); SetDefaultValue(EntryDateInput);
SetDefaultValue(ActiveInput); SetDefaultValue(ActiveInput);
@@ -209,7 +270,7 @@ namespace Elwig.Windows {
ControlUtils.RenewItemsSource(BranchInput, await ctx.FetchBranches().ToListAsync()); ControlUtils.RenewItemsSource(BranchInput, await ctx.FetchBranches().ToListAsync());
ControlUtils.RenewItemsSource(DefaultKgInput, await ctx.WbKgs.Select(k => k.AtKg).OrderBy(k => k.Name).ToListAsync()); ControlUtils.RenewItemsSource(DefaultKgInput, await ctx.WbKgs.Select(k => k.AtKg).OrderBy(k => k.Name).ToListAsync());
var font = new System.Windows.Media.FontFamily("Segoe MDL2 Assets"); var font = new FontFamily("Segoe MDL2 Assets");
MenuItem? temp = null; MenuItem? temp = null;
var seasons = await ctx.Seasons.Include(s => s.PaymentVariants).OrderByDescending(s => s.Year).ToListAsync(); var seasons = await ctx.Seasons.Include(s => s.PaymentVariants).OrderByDescending(s => s.Year).ToListAsync();
Menu_DeliveryConfirmation.Items.Clear(); Menu_DeliveryConfirmation.Items.Clear();
@@ -286,10 +347,21 @@ namespace Elwig.Windows {
await RefreshList(); await RefreshList();
var stat = await ctx.Members.GroupBy(m => m.IsActive).Select(g => new {
IsActive = g.Key,
Count = g.Count(),
Shares = g.Sum(m => m.Shares),
SharesRed = g.Sum(m => m.SharesRed),
SharesWhite = g.Sum(m => m.SharesWhite),
SharesDormant = g.Sum(m => m.SharesDormant),
SharesTotal = g.Sum(m => m.Shares + m.SharesRed + m.SharesWhite + m.SharesDormant),
SharesActive = g.Sum(m => m.Shares + m.SharesRed + m.SharesWhite),
}).ToDictionaryAsync(g => g.IsActive);
var (s1, s2) = ('\u2007', '\u202f'); var (s1, s2) = ('\u2007', '\u202f');
var mA = $"{await ctx.Members.CountAsync(m => m.IsActive):N0}"; var mA = $"{stat.GetValueOrDefault(true)?.Count ?? 0:N0}";
var mI = $"{await ctx.Members.CountAsync(m => !m.IsActive):N0}"; var mI = $"{stat.GetValueOrDefault(false)?.Count ?? 0:N0}";
var mT = $"{await ctx.Members.CountAsync():N0}"; var mT = $"{stat.Sum(g => g.Value.Count):N0}";
var mM = Math.Max(mA.Length, Math.Max(mI.Length, mT.Length)); var mM = Math.Max(mA.Length, Math.Max(mI.Length, mT.Length));
var mS = mM > 3; var mS = mM > 3;
if (mS) mM--; if (mS) mM--;
@@ -298,16 +370,53 @@ namespace Elwig.Windows {
$"{new string(s1, Math.Max(0, mM - mI.Length))}{(mS && mI.Length < 4 ? s2 : "")}{mI} nicht aktive Mitglieder\n" + $"{new string(s1, Math.Max(0, mM - mI.Length))}{(mS && mI.Length < 4 ? s2 : "")}{mI} nicht aktive Mitglieder\n" +
$"{new string(s1, Math.Max(0, mM - mT.Length))}{(mS && mT.Length < 4 ? s2 : "")}{mT} Mitglieder gesamt"; $"{new string(s1, Math.Max(0, mM - mT.Length))}{(mS && mT.Length < 4 ? s2 : "")}{mT} Mitglieder gesamt";
var bA = $"{await ctx.Members.Where(m => m.IsActive).SumAsync(m => m.Shares + m.SharesRed + m.SharesWhite + m.SharesDormant):N0}"; var grid = new Grid();
var bI = $"{await ctx.Members.Where(m => !m.IsActive).SumAsync(m => m.Shares + m.SharesRed + m.SharesWhite + m.SharesDormant):N0}"; grid.ColumnDefinitions.Add(new() { Width = new(100) });
var bT = $"{await ctx.Members.SumAsync(m => m.Shares + m.SharesRed + m.SharesWhite + m.SharesDormant):N0}"; grid.AddToolTipCell("Geschäftsanteile:", 0, 0, bold: true);
var bM = Math.Max(bA.Length, Math.Max(bI.Length, bT.Length)); grid.AddToolTipCell("Aktive Mitglieder", 1, 0);
var bS = bM > 3; grid.AddToolTipCell("Nicht aktive Mg.", 2, 0);
if (bS) bM--; grid.AddToolTipCell("Alle Mitglieder", 3, 0, bold: true);
ViewModel.StatusBusinessSharesToolTip = if (App.Client.HasRedWhite) {
$"{new string(s1, Math.Max(0, bM - bA.Length))}{(bS && bA.Length < 4 ? s2 : "")}{bA} Geschäftsanteile von aktiven Mitgliedern\n" + grid.ColumnDefinitions.Add(new() { Width = new(50) });
$"{new string(s1, Math.Max(0, bM - bI.Length))}{(bS && bI.Length < 4 ? s2 : "")}{bI} Geschäftsanteile von nicht aktiven Mitgliedern\n" + grid.ColumnDefinitions.Add(new() { Width = new(50) });
$"{new string(s1, Math.Max(0, bM - bT.Length))}{(bS && bT.Length < 4 ? s2 : "")}{bT} Geschäftsanteile gesamt"; grid.ColumnDefinitions.Add(new() { Width = new(50) });
grid.ColumnDefinitions.Add(new() { Width = new(50) });
grid.AddToolTipCell("rot", 0, 1, alignRight: true);
grid.AddToolTipCell("weiß", 0, 2, alignRight: true);
grid.AddToolTipCell("ruhend", 0, 3, alignRight: true);
grid.AddToolTipCell("gesamt", 0, 4, alignRight: true);
grid.AddToolTipCell($"{stat.GetValueOrDefault(true)?.SharesRed ?? 0:N0}", 1, 1, alignRight: true);
grid.AddToolTipCell($"{stat.GetValueOrDefault(true)?.SharesWhite ?? 0:N0}", 1, 2, alignRight: true);
grid.AddToolTipCell($"{stat.GetValueOrDefault(true)?.SharesDormant ?? 0:N0}", 1, 3, alignRight: true);
grid.AddToolTipCell($"{stat.GetValueOrDefault(true)?.SharesTotal ?? 0:N0}", 1, 4, alignRight: true);
grid.AddToolTipCell($"{stat.GetValueOrDefault(false)?.SharesRed ?? 0:N0}", 2, 1, alignRight: true);
grid.AddToolTipCell($"{stat.GetValueOrDefault(false)?.SharesWhite ?? 0:N0}", 2, 2, alignRight: true);
grid.AddToolTipCell($"{stat.GetValueOrDefault(false)?.SharesDormant ?? 0:N0}", 2, 3, alignRight: true);
grid.AddToolTipCell($"{stat.GetValueOrDefault(false)?.SharesTotal ?? 0:N0}", 2, 4, alignRight: true);
grid.AddToolTipCell($"{stat.Sum(g => g.Value.SharesRed):N0}", 3, 1, alignRight: true, bold: true);
grid.AddToolTipCell($"{stat.Sum(g => g.Value.SharesWhite):N0}", 3, 2, alignRight: true, bold: true);
grid.AddToolTipCell($"{stat.Sum(g => g.Value.SharesDormant):N0}", 3, 3, alignRight: true, bold: true);
grid.AddToolTipCell($"{stat.Sum(g => g.Value.SharesTotal):N0}", 3, 4, alignRight: true, bold: true);
} else {
grid.ColumnDefinitions.Add(new() { Width = new(50) });
grid.ColumnDefinitions.Add(new() { Width = new(50) });
grid.ColumnDefinitions.Add(new() { Width = new(50) });
grid.AddToolTipCell("normal", 0, 1, alignRight: true);
grid.AddToolTipCell("ruhend", 0, 2, alignRight: true);
grid.AddToolTipCell("gesamt", 0, 3, alignRight: true);
grid.AddToolTipCell($"{stat.GetValueOrDefault(true)?.Shares ?? 0:N0}", 1, 1, alignRight: true);
grid.AddToolTipCell($"{stat.GetValueOrDefault(true)?.SharesDormant ?? 0:N0}", 1, 2, alignRight: true);
grid.AddToolTipCell($"{stat.GetValueOrDefault(true)?.SharesTotal ?? 0:N0}", 1, 3, alignRight: true);
grid.AddToolTipCell($"{stat.GetValueOrDefault(false)?.Shares ?? 0:N0}", 2, 1, alignRight: true);
grid.AddToolTipCell($"{stat.GetValueOrDefault(false)?.SharesDormant ?? 0:N0}", 2, 2, alignRight: true);
grid.AddToolTipCell($"{stat.GetValueOrDefault(false)?.SharesTotal ?? 0:N0}", 2, 3, alignRight: true);
grid.AddToolTipCell($"{stat.Sum(g => g.Value.Shares):N0}", 3, 1, alignRight: true, bold: true);
grid.AddToolTipCell($"{stat.Sum(g => g.Value.SharesDormant):N0}", 3, 2, alignRight: true, bold: true);
grid.AddToolTipCell($"{stat.Sum(g => g.Value.SharesTotal):N0}", 3, 3, alignRight: true, bold: true);
}
ViewModel.StatusBusinessShares?.ToolTip = grid;
} }
private void SetPhoneNrInputVisible(int nr, bool visible, int? position = null) { private void SetPhoneNrInputVisible(int nr, bool visible, int? position = null) {
@@ -493,6 +602,10 @@ namespace Elwig.Windows {
ViewModel.EnableSearchInputs = true; ViewModel.EnableSearchInputs = true;
} }
private void BusinessSharesButton_Click(object sender, RoutedEventArgs evt) {
App.FocusMemberBusinessSharesWindow(ViewModel.SelectedMember!.MgNr);
}
private void AreaCommitmentButton_Click(object sender, RoutedEventArgs evt) { private void AreaCommitmentButton_Click(object sender, RoutedEventArgs evt) {
App.FocusMemberAreaComs(ViewModel.SelectedMember!.MgNr); App.FocusMemberAreaComs(ViewModel.SelectedMember!.MgNr);
} }
@@ -735,7 +848,7 @@ namespace Elwig.Windows {
lastVisible = true; lastVisible = true;
for (int i = 0; i < EmailAddressInputs.Length; i++) { for (int i = 0; i < EmailAddressInputs.Length; i++) {
var input = EmailAddressInputs[i]; var input = EmailAddressInputs[i];
var vis = !string.IsNullOrEmpty(input.Address.Text) || (m?.EmailAddresses.Any(a => a.Nr - 1 == i) ?? false); var vis = !string.IsNullOrWhiteSpace(input.Address.Text) || (m?.EmailAddresses.Any(a => a.Nr - 1 == i) ?? false);
var cVis = vis || (extra && lastVisible); var cVis = vis || (extra && lastVisible);
SetEmailAddressInputVisible(i, cVis, cVis ? num++ : null); SetEmailAddressInputVisible(i, cVis, cVis ? num++ : null);
lastVisible = vis; lastVisible = vis;
@@ -743,7 +856,7 @@ namespace Elwig.Windows {
lastVisible = true; lastVisible = true;
for (int i = 0; i < PhoneNrInputs.Length; i++) { for (int i = 0; i < PhoneNrInputs.Length; i++) {
var input = PhoneNrInputs[i]; var input = PhoneNrInputs[i];
var vis = !string.IsNullOrEmpty(input.Number.Text) || (m?.TelephoneNumbers.Any(n => n.Nr - 1 == i) ?? false); var vis = !string.IsNullOrWhiteSpace(input.Number.Text) || (m?.TelephoneNumbers.Any(n => n.Nr - 1 == i) ?? false);
var cVis = vis || (extra && lastVisible); var cVis = vis || (extra && lastVisible);
SetPhoneNrInputVisible(i, cVis, cVis ? num++ : null); SetPhoneNrInputVisible(i, cVis, cVis ? num++ : null);
lastVisible = vis; lastVisible = vis;
@@ -760,6 +873,14 @@ namespace Elwig.Windows {
new protected void ClearInputs(bool validate = false) { new protected void ClearInputs(bool validate = false) {
ViewModel.ClearInputs(); ViewModel.ClearInputs();
if (App.Client.EnableMemberHistory) {
BusinessShares1Input.Text = "";
BusinessShares2Input.Text = "";
BusinessShares3Input.Text = "";
ControlUtils.ClearInputState(BusinessShares1Input);
ControlUtils.ClearInputState(BusinessShares2Input);
ControlUtils.ClearInputState(BusinessShares3Input);
}
base.ClearInputs(validate); base.ClearInputs(validate);
} }
@@ -804,9 +925,9 @@ namespace Elwig.Windows {
var oldMember = await ctx.FetchMembers(mgnr).SingleAsync(); var oldMember = await ctx.FetchMembers(mgnr).SingleAsync();
var newName = $"{ViewModel.Name?.Replace('ß', 'ẞ').ToUpper()} " + var newName = $"{ViewModel.Name?.Replace('ß', 'ẞ').ToUpper()} " +
$"{ViewModel.Prefix}{(!string.IsNullOrEmpty(ViewModel.Prefix) ? " " : "")}" + $"{ViewModel.Prefix}{(!string.IsNullOrWhiteSpace(ViewModel.Prefix) ? " " : "")}" +
$"{ViewModel.GivenName}{(!string.IsNullOrEmpty(ViewModel.GivenName) ? " " : "")}" + $"{ViewModel.GivenName}{(!string.IsNullOrWhiteSpace(ViewModel.GivenName) ? " " : "")}" +
$"{ViewModel.Suffix}{(!string.IsNullOrEmpty(ViewModel.Suffix) ? " " : "")}"; $"{ViewModel.Suffix}{(!string.IsNullOrWhiteSpace(ViewModel.Suffix) ? " " : "")}";
var d = new AreaComTransferDialog(oldMember.AdministrativeName, newName, areaComs.Count, areaComs.Sum(c => c.Area)); var d = new AreaComTransferDialog(oldMember.AdministrativeName, newName, areaComs.Count, areaComs.Sum(c => c.Area));
if (d.ShowDialog() != true) if (d.ShowDialog() != true)
return; return;
@@ -0,0 +1,214 @@
<local:AdministrationWindow
x:Class="Elwig.Windows.MemberBusinessSharesAdminWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Elwig.Windows"
xmlns:ctrl="clr-namespace:Elwig.Controls"
xmlns:vm="clr-namespace:Elwig.ViewModels"
Title="{Binding Title}" Height="450" Width="800" MinHeight="400" MinWidth="700">
<Window.DataContext>
<vm:MemberBusinessSharesViewModel/>
</Window.DataContext>
<Window.Resources>
<Style TargetType="Label">
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="VerticalAlignment" Value="Top"/>
<Setter Property="Padding" Value="2,4,2,4"/>
<Setter Property="Height" Value="25"/>
</Style>
<Style TargetType="TextBox">
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalAlignment" Value="Top"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="Padding" Value="2"/>
<Setter Property="Height" Value="25"/>
<Setter Property="TextWrapping" Value="NoWrap"/>
</Style>
<Style TargetType="ctrl:UnitTextBox">
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalAlignment" Value="Top"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="Padding" Value="2"/>
<Setter Property="Height" Value="25"/>
<Setter Property="TextWrapping" Value="NoWrap"/>
</Style>
<Style TargetType="ComboBox">
<Setter Property="Height" Value="25"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalAlignment" Value="Top"/>
</Style>
<Style TargetType="Button">
<Setter Property="FontSize" Value="14"/>
<Setter Property="Padding" Value="9,3"/>
<Setter Property="Height" Value="27"/>
</Style>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" MinWidth="300"/>
<ColumnDefinition Width="5"/>
<ColumnDefinition Width="1*" MinWidth="350"/>
</Grid.ColumnDefinitions>
<Grid Margin="5,0,0,0">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="42"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ListBox x:Name="MemberHistoryList" Margin="5,10,5,0" Grid.ColumnSpan="3"
ItemsSource="{Binding History, Mode=TwoWay}" SelectedItem="{Binding SelectedHistoryEntry, Mode=TwoWay}"
SelectionChanged="MemberHistoryList_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding DateNotice, StringFormat='{}{0:dd.MM.yy}'}" Width="55" TextAlignment="Left" Margin="0,0,0,0"/>
<TextBlock Text="{Binding DateEffective, StringFormat='{}{0:dd.MM.yy}'}" Width="55" TextAlignment="Left" Margin="0,0,0,0"/>
<TextBlock Text="{Binding Shares, StringFormat='{}{0:N0}'}" Width="15" TextAlignment="Right" Margin="0,0,10,0"/>
<TextBlock Text="{Binding PoVReasonPhrase}" TextAlignment="Left" Margin="0,0,0,0"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button x:Name="NewHistoryButton" Content="Neu" Visibility="{Binding ControlButtonsVisibility}"
HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="5,5,2.5,10" Grid.Column="0" Grid.Row="2"
Click="NewHistoryButton_Click">
<Button.ToolTip>
<TextBlock FontWeight="Bold">Alt+Einfg</TextBlock>
</Button.ToolTip>
</Button>
<Button x:Name="EditHistoryButton" Content="Bearbeiten" IsEnabled="False" Visibility="{Binding ControlButtonsVisibility}"
HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="2.5,5,2.5,10" Grid.Column="1" Grid.Row="2"
Click="EditHistoryButton_Click">
<Button.ToolTip>
<TextBlock FontWeight="Bold">Strg+B</TextBlock>
</Button.ToolTip>
</Button>
<Button x:Name="DeleteHistoryButton" Content="Löschen" IsEnabled="False" Visibility="{Binding ControlButtonsVisibility}"
HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="2.5,5,5,10" Grid.Column="2" Grid.Row="2"
Click="DeleteHistoryButton_Click">
<Button.ToolTip>
<TextBlock FontWeight="Bold">Alt+Entf</TextBlock>
</Button.ToolTip>
</Button>
<Button x:Name="SaveButton" Content="Speichern" IsEnabled="False" Visibility="{Binding EditingButtonsVisibility}"
HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="5,5,2.5,10" Grid.Column="0" Grid.Row="2"
Click="SaveButton_Click">
<Button.ToolTip>
<TextBlock FontWeight="Bold">Strg+S</TextBlock>
</Button.ToolTip>
</Button>
<Button x:Name="ResetButton" Content="Zurücksetzen" IsEnabled="False" Visibility="{Binding EditingButtonsVisibility}"
HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="2.5,5,2.5,10" Grid.Column="1" Grid.Row="2"
Click="ResetButton_Click">
<Button.ToolTip>
<TextBlock FontWeight="Bold">Strg+Z</TextBlock>
</Button.ToolTip>
</Button>
<Button x:Name="CancelButton" Content="Abbrechen" IsEnabled="False" Visibility="{Binding EditingButtonsVisibility}" IsCancel="True"
HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="2.5,5,5,10" Grid.Column="2" Grid.Row="2"
Click="CancelButton_Click">
<Button.ToolTip>
<TextBlock FontWeight="Bold">Esc</TextBlock>
</Button.ToolTip>
</Button>
</Grid>
<GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
<Grid Grid.Column="2">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="95"/>
</Grid.RowDefinitions>
<GroupBox Header="Geschäftsanteilbewegung" Margin="5,10,5,5">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="110"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="Grund:" Margin="10,10,0,0" Grid.Column="0"/>
<ComboBox x:Name="ReasonInput" SelectedValue="{Binding Reason, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,10,10,0" Grid.Column="1"
SelectedValuePath="Tag"
SelectionChanged="ReasonInput_SelectionChanged">
<ComboBoxItem Tag="purchase">Kauf</ComboBoxItem>
<ComboBoxItem Tag="transfer_to">Übertragung an...</ComboBoxItem>
<ComboBoxItem Tag="transfer_from">Übertragung von...</ComboBoxItem>
<ComboBoxItem Tag="prescription">Vorschreibung</ComboBoxItem>
<ComboBoxItem Tag="exclusion">Ausschluss</ComboBoxItem>
<ComboBoxItem Tag="deceased">Tod</ComboBoxItem>
<ComboBoxItem Tag="retirement">Kündigung</ComboBoxItem>
<ComboBoxItem Tag="payout">Auszahlung</ComboBoxItem>
</ComboBox>
<Label Content="Anderes Mitgl.:" Margin="10,40,0,0" Grid.Column="0"/>
<TextBox x:Name="OtherMgNrInput" Text="{Binding OtherMgNrString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Width="48" Grid.Column="1" Margin="0,40,0,0" HorizontalAlignment="Left" TextAlignment="Right"
TextChanged="OtherMgNrInput_TextChanged" LostFocus="OtherMgNrInput_LostFocus"/>
<ComboBox x:Name="OtherMemberInput"
Grid.Column="1" Margin="53,40,40,10" IsEditable="True"
ItemTemplate="{StaticResource MemberAdminNameTemplate}" TextSearch.TextPath="AdministrativeName"
SelectionChanged="OtherMemberInput_SelectionChanged"/>
<Button x:Name="OtherMemberReferenceButton" Grid.Column="1" Height="25" Width="25" FontFamily="Segoe MDL2 Assets" Content="&#xEE35;" Padding="0,0,0,0"
Margin="10,40,10,10" VerticalAlignment="Top" HorizontalAlignment="Right" ToolTip="Zu Mitglied springen"
Click="OtherMemberReferenceButton_Click"/>
<Label Content="Anmerkung:" Margin="10,70,0,0" Grid.Column="0"/>
<TextBox x:Name="CommentInput" Text="{Binding Comment, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,70,10,0" Grid.Column="1"/>
<Label Content="Meldung:" Margin="10,100,0,0" Grid.Column="0"/>
<TextBox x:Name="DateNoticeInput" Text="{Binding DateNoticeString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,100,10,0" Width="78" Grid.Column="1" HorizontalAlignment="Left" TextAlignment="Right"
TextChanged="DateNoticeInput_TextChanged" LostFocus="DateInput_LostFocus"/>
<CheckBox x:Name="HasMemberSignedInput" IsChecked="{Binding MemberHasSigned, Mode=TwoWay}" Content="Von Mg. unterfertigt"
Margin="88,105,10,0" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="TOp"
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"/>
<Label Content="Wirksam:" Margin="10,130,0,0" Grid.Column="0"/>
<TextBox x:Name="DateEffeciveInput" Text="{Binding DateEffectiveString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,130,10,0" Width="78" Grid.Column="1" HorizontalAlignment="Left" TextAlignment="Right"
TextChanged="DateInput_TextChanged" LostFocus="DateInput_LostFocus"/>
<Label Content="Geschäftsanteile:" Margin="10,160,0,0" Grid.Column="0"/>
<TextBox x:Name="SharesInput" Text="{Binding SharesString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="0,160,10,0" Width="32" Grid.Column="1" HorizontalAlignment="Left" TextAlignment="Right"
TextChanged="SharesInput_TextChanged"/>
<CheckBox x:Name="DeductInput" IsChecked="{Binding Deduct, Mode=TwoWay}"
Margin="42,165,10,0" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="TOp"
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed">
<TextBlock>
bei Auszahlung <Run Text="{Binding DeductYearString}"/> abziehen
</TextBlock>
</CheckBox>
<Label Content="Betrag:" Margin="10,190,0,10"/>
<ctrl:UnitTextBox x:Name="ValuePerShareInput" Text="{Binding ValuePerShareString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Unit="€/GA" TextChanged="AmountPerShareInput_TextChanged"
Grid.Column="1" Width="76" Margin="0,190,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<ctrl:UnitTextBox x:Name="TotalAmountInput" Text="{Binding TotalAmount}" Unit="€" IsEnabled="False"
Grid.Column="1" Width="77" Margin="81,190,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"/>
</Grid>
</GroupBox>
<GroupBox Header="Mitglied" Grid.Row="1" Margin="5,5,5,10">
<Grid>
<TextBlock x:Name="MemberInfo" Text="Name (1234)"
FontSize="14" Margin="10,10,10,10"/>
</Grid>
</GroupBox>
</Grid>
</Grid>
</local:AdministrationWindow>
@@ -0,0 +1,347 @@
using Elwig.Helpers;
using Elwig.Models.Entities;
using Elwig.Services;
using Elwig.ViewModels;
using Microsoft.EntityFrameworkCore;
using System;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace Elwig.Windows {
public partial class MemberBusinessSharesAdminWindow : AdministrationWindow {
public MemberBusinessSharesViewModel ViewModel => (MemberBusinessSharesViewModel)DataContext;
public MemberBusinessSharesAdminWindow(int mgnr) {
InitializeComponent();
using var ctx = new AppDbContext();
ViewModel.FilterMember = ctx.Members.Find(mgnr) ?? throw new ArgumentException("MgNr argument has invalid value");
ViewModel.Title = $"Geschäftsanteilbewegungen - {ViewModel.FilterMember.AdministrativeName} - Elwig";
ExemptInputs = [
MemberHistoryList, TotalAmountInput
];
RequiredInputs = [
ReasonInput, DateNoticeInput, DateEffeciveInput, SharesInput
];
}
public void FocusMemberHistory(int histnr) {
if (IsEditing || IsCreating) return;
var item = ViewModel.History.FirstOrDefault(h => h.HistNr == histnr);
if (item != null) {
ControlUtils.SelectItem(MemberHistoryList, item);
}
}
private async Task RefreshList() {
var vm = ViewModel;
var cursor = Mouse.OverrideCursor != null;
if (!cursor) Mouse.OverrideCursor = Cursors.Wait;
var history = await Task.Run(async () => {
using var ctx = new AppDbContext();
return await ctx.MemberHistory
.Where(h => h.FromMgNr == vm.FilterMember.MgNr || h.ToMgNr == vm.FilterMember.MgNr)
.OrderBy(h => h.DateNoticeString).ThenBy(h => h.HistNr)
.ToListAsync();
});
if (!cursor) Mouse.OverrideCursor = null;
history.ForEach(h => h.PoVMgNr = vm.FilterMember.MgNr);
ControlUtils.RenewItemsSource(MemberHistoryList, history,
MemberHistoryList_SelectionChanged, ControlUtils.RenewSourceDefault.None);
RefreshInputs();
}
private void RefreshInputs(bool validate = false) {
ClearInputStates();
if (ViewModel.SelectedHistoryEntry is MemberHistory h) {
EditHistoryButton.IsEnabled = true;
DeleteHistoryButton.IsEnabled = true;
FillInputs(h);
} else {
EditHistoryButton.IsEnabled = false;
DeleteHistoryButton.IsEnabled = false;
ClearOriginalValues();
ClearDefaultValues();
ClearInputs(validate);
ClearInputStates();
}
GC.Collect();
}
private void FillInputs(MemberHistory h) {
ClearOriginalValues();
ClearDefaultValues();
ViewModel.FillInputs(h);
ReasonInput.SelectedValue = h.Reason + (h.Reason == MemberHistory.REASON_TRANSFER ? $"_{(h.FromMgNr == ViewModel.FilterMember.MgNr ? "to" : "from")}" : "");
FinishInputFilling();
}
private async Task InitInputs() {
ClearOriginalValues();
ClearDefaultValues();
await ViewModel.InitInputs();
SetDefaultValue(DateNoticeInput);
if (ViewModel.ValuePerShare != null)
SetDefaultValue(ValuePerShareInput);
ValidateRequiredInputs();
}
new protected void ClearInputs(bool validate = false) {
ViewModel.ClearInputs();
base.ClearInputs(validate);
}
override protected void UpdateButtons() {
if (!IsEditing && !IsCreating) return;
bool ch = HasChanged, v = IsValid;
ResetButton.IsEnabled = ch;
SaveButton.IsEnabled = v && ch;
}
protected override async Task OnRenewContext(AppDbContext ctx) {
await base.OnRenewContext(ctx);
if (await ctx.FetchMembers(ViewModel.FilterMember.MgNr).SingleOrDefaultAsync() is not Member m) {
Close();
return;
}
ViewModel.FilterMember = m;
ViewModel.Title = $"Geschäftsanteilbewegungen - {ViewModel.FilterMember.AdministrativeName} - Elwig";
ControlUtils.RenewItemsSource(OtherMemberInput, await ctx.FetchMembers(includeNotActive: true).ToListAsync());
MemberInfo.Text = $"{m.FullAdministrativeName}\nGA: {m.Shares:N0} (normal) / {m.SharesRed:N0} (rot) / {m.SharesWhite:N0} (weiß) / {m.SharesDormant:N0} (ruhend)";
await RefreshList();
}
private void MemberHistoryList_SelectionChanged(object? sender, SelectionChangedEventArgs? evt) {
RefreshInputs();
}
protected override void ShortcutNew() {
if (!NewHistoryButton.IsEnabled || NewHistoryButton.Visibility != Visibility.Visible)
return;
NewHistoryButton_Click(null, null);
}
private async void NewHistoryButton_Click(object? sender, RoutedEventArgs? evt) {
IsCreating = true;
MemberHistoryList.IsEnabled = false;
ViewModel.SelectedHistoryEntry = null;
HideNewEditDeleteButtons();
ShowSaveResetCancelButtons();
UnlockInputs();
await InitInputs();
DeductInput.IsEnabled = false;
OtherMgNrInput.IsEnabled = false;
OtherMemberInput.IsEnabled = false;
}
protected override void ShortcutEdit() {
if (!EditHistoryButton.IsEnabled || EditHistoryButton.Visibility != Visibility.Visible)
return;
EditHistoryButton_Click(null, null);
}
private void EditHistoryButton_Click(object? sender, RoutedEventArgs? evt) {
if (ViewModel.SelectedHistoryEntry == null) return;
IsEditing = true;
MemberHistoryList.IsEnabled = false;
HideNewEditDeleteButtons();
ShowSaveResetCancelButtons();
UnlockInputs();
DeductInput.IsEnabled = ViewModel.Reason == MemberHistory.REASON_PURCHASE || ViewModel.Reason == MemberHistory.REASON_PRESCRIPTION;
OtherMgNrInput.IsEnabled = ViewModel.Reason?.StartsWith(MemberHistory.REASON_TRANSFER) ?? false;
OtherMemberInput.IsEnabled = OtherMgNrInput.IsEnabled;
}
protected override void ShortcutDelete() {
if (!DeleteHistoryButton.IsEnabled || DeleteHistoryButton.Visibility != Visibility.Visible)
return;
DeleteHistoryButton_Click(null, null);
}
private async void DeleteHistoryButton_Click(object? sender, RoutedEventArgs? evt) {
if (ViewModel.SelectedHistoryEntry is not MemberHistory h)
return;
if (InteractionService.AskContinueYesNo("Geschäftsanteilbewegung löschen", $"Soll die Geschäftsanteilbewegung wirklich unwiderruflich\ngelöscht werden?\n\nFalls ja:\nSoll die Änderung der aktuellen GA wieder rückgängig gemacht werden?") is bool enableTriggers) {
Mouse.OverrideCursor = Cursors.Wait;
try {
await MemberBusinessSharesService.DeleteMemberHistory(h.HistNr, enableTriggers);
App.HintContextChange();
} catch (Exception exc) {
InteractionService.ShowDbException("Geschäftsanteilbewegung löschen", exc);
}
Mouse.OverrideCursor = null;
}
}
protected override void ShortcutSave() {
if (!SaveButton.IsEnabled || SaveButton.Visibility != Visibility.Visible)
return;
SaveButton_Click(null, null);
}
private async void SaveButton_Click(object? sender, RoutedEventArgs? evt) {
Mouse.OverrideCursor = Cursors.Wait;
SaveButton.IsEnabled = false;
int mgnr;
try {
mgnr = await ViewModel.UpdateMemberHistory(ViewModel.SelectedHistoryEntry?.HistNr, IsEditing || ViewModel.DateNotice >= DateOnly.FromDateTime(Utils.Today).AddDays(-14));
App.HintContextChange();
} catch (Exception exc) {
InteractionService.ShowDbException("Geschäftsanteilbewegung aktualisieren", exc);
SaveButton.IsEnabled = true;
Mouse.OverrideCursor = null;
return;
}
IsEditing = false;
IsCreating = false;
MemberHistoryList.IsEnabled = true;
OtherMgNrInput.IsEnabled = true;
HideSaveResetCancelButtons();
ShowNewEditDeleteButtons();
LockInputs();
FinishInputFilling();
await EnsureContextRenewed();
Mouse.OverrideCursor = null;
if (mgnr is int m)
FocusMemberHistory(m);
}
protected override void ShortcutReset() {
if (!ResetButton.IsEnabled || ResetButton.Visibility != Visibility.Visible)
return;
ResetButton_Click(null, null);
}
private async void ResetButton_Click(object? sender, RoutedEventArgs? evt) {
if (IsEditing) {
RefreshInputs();
} else if (IsCreating) {
ClearInputs();
await InitInputs();
}
UpdateButtons();
}
private void CancelButton_Click(object sender, RoutedEventArgs evt) {
IsEditing = false;
IsCreating = false;
MemberHistoryList.IsEnabled = true;
OtherMgNrInput.IsEnabled = true;
HideSaveResetCancelButtons();
ShowNewEditDeleteButtons();
RefreshInputs();
LockInputs();
}
private void ShowSaveResetCancelButtons() {
SaveButton.IsEnabled = false;
ResetButton.IsEnabled = false;
CancelButton.IsEnabled = true;
ViewModel.EditingButtonsVisibility = Visibility.Visible;
}
private void HideSaveResetCancelButtons() {
SaveButton.IsEnabled = false;
ResetButton.IsEnabled = false;
CancelButton.IsEnabled = false;
ViewModel.EditingButtonsVisibility = Visibility.Hidden;
}
private void ShowNewEditDeleteButtons() {
NewHistoryButton.IsEnabled = true;
EditHistoryButton.IsEnabled = ViewModel.SelectedHistoryEntry != null;
DeleteHistoryButton.IsEnabled = ViewModel.SelectedHistoryEntry != null;
ViewModel.ControlButtonsVisibility = Visibility.Visible;
}
private void HideNewEditDeleteButtons() {
NewHistoryButton.IsEnabled = false;
EditHistoryButton.IsEnabled = false;
DeleteHistoryButton.IsEnabled = false;
ViewModel.ControlButtonsVisibility = Visibility.Hidden;
}
private void OtherMgNrInput_TextChanged(object sender, TextChangedEventArgs evt) {
var valid = InputTextChanged((TextBox)sender, Validator.CheckMgNr);
var text = OtherMgNrInput.Text;
var caret = OtherMgNrInput.CaretIndex;
ControlUtils.SelectItemWithPk(OtherMemberInput, valid ? ViewModel.OtherMgNr : null);
OtherMgNrInput.Text = text;
OtherMgNrInput.CaretIndex = caret;
}
private void OtherMgNrInput_LostFocus(object sender, RoutedEventArgs evt) {
var valid = InputLostFocus((TextBox)sender, Validator.CheckMgNr);
ControlUtils.SelectItemWithPk(OtherMemberInput, valid ? ViewModel.OtherMgNr : null);
}
private void OtherMemberInput_SelectionChanged(object? sender, SelectionChangedEventArgs? evt) {
var m = OtherMemberInput.SelectedItem as Member;
ViewModel.OtherMgNr = m?.MgNr;
}
private void OtherMemberReferenceButton_Click(object sender, RoutedEventArgs evt) {
if (OtherMemberInput.SelectedItem is not Member m) return;
App.FocusMember(m.MgNr);
}
private void ReasonInput_SelectionChanged(object sender, RoutedEventArgs evt) {
ComboBox_SelectionChanged(sender, evt);
if (!IsEditing && !IsCreating) return;
if (ViewModel.DateNotice is not DateOnly d) return;
if (ViewModel.Reason == MemberHistory.REASON_EXCLUSION || ViewModel.Reason == MemberHistory.REASON_DECEASED || ViewModel.Reason == MemberHistory.REASON_RETIREMENT) {
ViewModel.DateEffectiveString = $"31.12.{d.Year + 1}";
} else {
ViewModel.DateEffectiveString = ViewModel.DateNoticeString;
}
DeductInput.IsEnabled = ViewModel.Reason == MemberHistory.REASON_PURCHASE || ViewModel.Reason == MemberHistory.REASON_PRESCRIPTION;
if (!DeductInput.IsEnabled) DeductInput.IsChecked = false;
OtherMgNrInput.IsEnabled = ViewModel.Reason?.StartsWith(MemberHistory.REASON_TRANSFER) ?? false;
OtherMemberInput.IsEnabled = OtherMgNrInput.IsEnabled;
if (!OtherMgNrInput.IsEnabled) OtherMgNrInput.Text = "";
}
private void DateNoticeInput_TextChanged(object sender, TextChangedEventArgs evt) {
DateInput_TextChanged(sender, evt);
if (!IsEditing && !IsCreating) return;
if (ViewModel.DateNotice is not DateOnly d) return;
ViewModel.DeductYear = d.Year;
if (ViewModel.DateEffective == null && ViewModel.Reason != null) {
if (ViewModel.Reason == MemberHistory.REASON_EXCLUSION || ViewModel.Reason == MemberHistory.REASON_DECEASED || ViewModel.Reason == MemberHistory.REASON_RETIREMENT) {
ViewModel.DateEffectiveString = $"31.12.{d.Year + 1}";
} else {
ViewModel.DateEffectiveString = ViewModel.DateNoticeString;
}
}
}
private void UpdateAmount() {
ViewModel.TotalAmount = $"{ViewModel.Shares * ViewModel.ValuePerShare:N2}";
}
private void SharesInput_TextChanged(object sender, TextChangedEventArgs evt) {
IntegerInput_TextChanged(sender, evt);
UpdateAmount();
}
private void AmountPerShareInput_TextChanged(object sender, TextChangedEventArgs evt) {
InputTextChanged((TextBox)sender, Validator.CheckDecimal((TextBox)sender, false, 3, 2));
UpdateAmount();
}
}
}
+1 -1
View File
@@ -194,7 +194,7 @@
</Grid> </Grid>
</GroupBox> </GroupBox>
<GroupBox Header="Automatische Nachzeichnung der Geschäftsanteile" Margin="5,10,10,10" Height="180" Width="365" <GroupBox Header="Automatische Nachzeichnung von Geschäftsanteilen" Margin="5,10,10,10" Height="180" Width="365"
VerticalAlignment="Bottom" HorizontalAlignment="Left"> VerticalAlignment="Bottom" HorizontalAlignment="Left">
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
@@ -60,7 +60,7 @@ namespace Elwig.Windows {
CustomPayments = await ctx.CustomPayments.Where(p => p.Year == Year).ToDictionaryAsync(p => p.MgNr, p => p); CustomPayments = await ctx.CustomPayments.Where(p => p.Year == Year).ToDictionaryAsync(p => p.MgNr, p => p);
var history = await ctx.MemberHistory var history = await ctx.MemberHistory
.Where(h => h.DateString.CompareTo($"{Year}-01-01") >= 0 && h.DateString.CompareTo($"{Year}-12-31") <= 0 && h.Reason == "auto" && h.Shares > 0) .Where(h => h.DeductYear == Year)
.GroupBy(h => h.ToMember) .GroupBy(h => h.ToMember)
.ToDictionaryAsync(h => h.Key.MgNr, h => h.Sum(g => g.Shares)); .ToDictionaryAsync(h => h.Key.MgNr, h => h.Sum(g => g.Shares));
+29 -12
View File
@@ -7,7 +7,7 @@
xmlns:local="clr-namespace:Elwig.Windows" xmlns:local="clr-namespace:Elwig.Windows"
xmlns:vm="clr-namespace:Elwig.ViewModels" xmlns:vm="clr-namespace:Elwig.ViewModels"
xmlns:ctrl="clr-namespace:Elwig.Controls" xmlns:ctrl="clr-namespace:Elwig.Controls"
Title="Auszahlungsvarianten - Elwig" Height="480" Width="850" MinHeight="400" MinWidth="850"> Title="Auszahlungsvarianten - Elwig" Height="480" Width="850" MinHeight="430" MinWidth="850">
<Window.DataContext> <Window.DataContext>
<vm:PaymentVariantsViewModel/> <vm:PaymentVariantsViewModel/>
</Window.DataContext> </Window.DataContext>
@@ -188,18 +188,17 @@
Margin="110,135,10,10" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="110,135,10,10" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Top"
Checked="ConsiderPenaltyInput_Changed" Unchecked="ConsiderPenaltyInput_Changed"/> Checked="ConsiderPenaltyInput_Changed" Unchecked="ConsiderPenaltyInput_Changed"/>
<CheckBox x:Name="ConsiderAutoInput" IsChecked="{Binding ConsiderAuto, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsEnabled="{Binding IsEnabled}" <CheckBox x:Name="ConsiderAutoInput" IsChecked="{Binding ConsiderAuto, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsEnabled="{Binding IsEnabled}"
Content="Automatische Nachzeichnungen der GA" Content="(Automatische) Nachzeichnungen von GA"
Margin="110,155,10,10" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="110,155,10,10" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Top"
Checked="ConsiderAutoInput_Changed" Unchecked="ConsiderAutoInput_Changed"/> Checked="ConsiderAutoInput_Changed" Unchecked="ConsiderAutoInput_Changed"/>
<CheckBox x:Name="ConsiderCustomInput" IsChecked="{Binding ConsiderCustom, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsEnabled="{Binding IsEnabled}" <CheckBox x:Name="ConsiderCustomInput" IsChecked="{Binding ConsiderCustom, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsEnabled="{Binding IsEnabled}"
Content="Benutzerdefinierte Zu-/Abschläge pro Mitglied" Content="Benutzerdefinierte Zu-/Abschläge pro Mitglied"
Margin="110,175,10,10" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="110,175,10,10" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Top"
Checked="ConsiderCustomInput_Changed" Unchecked="ConsiderCustomInput_Changed"/> Checked="ConsiderCustomInput_Changed" Unchecked="ConsiderCustomInput_Changed"/>
<Label Content="&#xF0AE;" FontFamily="Segoe MDL2 Assets" FontSize="16" Grid.Row="0" Grid.Column="1" Margin="108,195,10,10"/>
<Grid Grid.Column="0" Grid.ColumnSpan="2" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="50,200,10,10"> <Grid Grid.Column="0" Grid.ColumnSpan="2" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="50,200,10,10">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="110"/> <ColumnDefinition Width="130"/>
<ColumnDefinition Width="27"/> <ColumnDefinition Width="27"/>
<ColumnDefinition Width="110"/> <ColumnDefinition Width="110"/>
<ColumnDefinition Width="27"/> <ColumnDefinition Width="27"/>
@@ -207,7 +206,7 @@
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="27"/> <RowDefinition Height="27"/>
<RowDefinition Height="5"/> <RowDefinition Height="37"/>
<RowDefinition Height="27"/> <RowDefinition Height="27"/>
<RowDefinition Height="5"/> <RowDefinition Height="5"/>
<RowDefinition Height="27"/> <RowDefinition Height="27"/>
@@ -227,11 +226,23 @@
</Grid.Resources> </Grid.Resources>
<Button x:Name="EditButton" IsEnabled="{Binding IsPaymentVariantSelected}" <Button x:Name="EditButton" IsEnabled="{Binding IsPaymentVariantSelected}"
Content="{Binding EditText}" Grid.Column="0" Grid.Row="2" Grid.Column="0" Grid.Row="2" HorizontalContentAlignment="Stretch"
Click="EditButton_Click"/> Click="EditButton_Click">
<Grid>
<TextBlock Margin="0,0,13,0" TextAlignment="Center" Text="{Binding EditText}"/>
<TextBlock FontFamily="Segoe MDL2 Assets" FontSize="16" Text="&#xE8A7;"
TextAlignment="Left" HorizontalAlignment="Right" Padding="0,1.5,0,0" Margin="0,0,5,0"/>
</Grid>
</Button>
<Label Content="&#xF0AF;" FontFamily="Segoe MDL2 Assets" FontSize="16" Grid.Row="2" Grid.Column="1"/> <Label Content="&#xF0AF;" FontFamily="Segoe MDL2 Assets" FontSize="16" Grid.Row="2" Grid.Column="1"/>
<Button x:Name="ModifierButton" Content="Zu-/Abschläge" Grid.Column="0" Grid.Row="4" <Button x:Name="ModifierButton" Grid.Column="0" Grid.Row="4" HorizontalContentAlignment="Stretch"
Click="ModifierButton_Click"/> Click="ModifierButton_Click">
<Grid>
<TextBlock Margin="0,0,15,0" TextAlignment="Center">Zu-/Abschläge</TextBlock>
<TextBlock FontFamily="Segoe MDL2 Assets" FontSize="16" Text="&#xE8A7;"
TextAlignment="Left" HorizontalAlignment="Right" Padding="0,1.5,0,0" Margin="0,0,5,0"/>
</Grid>
</Button>
<Label Content="&#xF0AF;" FontFamily="Segoe MDL2 Assets" FontSize="16" Grid.Row="4" Grid.Column="1" RenderTransformOrigin="0.5,0.5" > <Label Content="&#xF0AF;" FontFamily="Segoe MDL2 Assets" FontSize="16" Grid.Row="4" Grid.Column="1" RenderTransformOrigin="0.5,0.5" >
<Label.RenderTransform> <Label.RenderTransform>
<TransformGroup> <TransformGroup>
@@ -244,8 +255,14 @@
Content="Berechnen" Grid.Column="2" Grid.Row="2" Content="Berechnen" Grid.Column="2" Grid.Row="2"
Click="CalculateButton_Click"/> Click="CalculateButton_Click"/>
<Label Content="{Binding Arrow}" FontFamily="Segoe MDL2 Assets" FontSize="16" Grid.Row="2" Grid.Column="3"/> <Label Content="{Binding Arrow}" FontFamily="Segoe MDL2 Assets" FontSize="16" Grid.Row="2" Grid.Column="3"/>
<Button x:Name="PaymentAdjustmentButton" Content="Anpassen" Grid.Column="2" Grid.Row="4" <Button x:Name="PaymentAdjustmentButton" Grid.Column="2" Grid.Row="4" HorizontalContentAlignment="Stretch"
Click="PaymentAdjustmentButton_Click"/> Click="PaymentAdjustmentButton_Click">
<Grid>
<TextBlock Margin="0,0,13,0" TextAlignment="Center">Anpassen</TextBlock>
<TextBlock FontFamily="Segoe MDL2 Assets" FontSize="16" Text="&#xE8A7;"
TextAlignment="Left" HorizontalAlignment="Right" Padding="0,1.5,0,0" Margin="0,0,5,0"/>
</Grid>
</Button>
<Label Content="{Binding Arrow}" FontFamily="Segoe MDL2 Assets" FontSize="16" Grid.Row="4" Grid.Column="3" RenderTransformOrigin="0.5,0.5" > <Label Content="{Binding Arrow}" FontFamily="Segoe MDL2 Assets" FontSize="16" Grid.Row="4" Grid.Column="3" RenderTransformOrigin="0.5,0.5" >
<Label.RenderTransform> <Label.RenderTransform>
<TransformGroup> <TransformGroup>
@@ -261,7 +278,7 @@
Content="Freigeben" Grid.Column="4" Grid.Row="2" Content="Freigeben" Grid.Column="4" Grid.Row="2"
Click="RevertButton_Click"/> Click="RevertButton_Click"/>
<Button x:Name="SaveButton" IsEnabled="{Binding SaveIsEnabled}" <Button x:Name="SaveButton" IsEnabled="{Binding SaveIsEnabled}"
Content="Speichern" Grid.Column="4" Grid.Row="0" Content="Speichern" Grid.Column="2" Grid.Row="0"
Click="SaveButton_Click"/> Click="SaveButton_Click"/>
</Grid> </Grid>
+14 -1
View File
@@ -5,6 +5,7 @@ using Elwig.Services;
using Elwig.ViewModels; using Elwig.ViewModels;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text.Json; using System.Text.Json;
using System.Threading.Tasks; using System.Threading.Tasks;
@@ -239,15 +240,27 @@ namespace Elwig.Windows {
private async void SaveButton_Click(object sender, RoutedEventArgs evt) { private async void SaveButton_Click(object sender, RoutedEventArgs evt) {
if (PaymentVariantList.SelectedItem is not PaymentVar v || ViewModel.BillingData == null) if (PaymentVariantList.SelectedItem is not PaymentVar v || ViewModel.BillingData == null)
return; return;
Mouse.OverrideCursor = Cursors.Wait; Mouse.OverrideCursor = Cursors.Wait;
try { try {
await ViewModel.UpdatePaymentVariant(v.Year, v.AvNr); await ViewModel.UpdatePaymentVariant(v.Year, v.AvNr);
App.HintContextChange();
} catch (Exception exc) { } catch (Exception exc) {
await ForceContextReload(); await ForceContextReload();
InteractionService.ShowDbException("Auszahlungsvariante aktualisieren", exc); InteractionService.ShowDbException("Auszahlungsvariante aktualisieren", exc);
} }
try {
await Task.Run(async () => {
var b = await BillingVariant.Create(v.Year, v.AvNr);
await b.Calculate(false);
});
} catch (KeyNotFoundException exc) {
InteractionService.ShowInformation("Noch nicht alle Preise festgelegt", exc.Message);
} catch (Exception exc) {
InteractionService.ShowException("Berechnungsfehler", exc);
}
App.HintContextChange();
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
await EnsureContextRenewed(); await EnsureContextRenewed();
CommentInput_TextChanged(null, null); CommentInput_TextChanged(null, null);
DateInput_TextChanged(null, null); DateInput_TextChanged(null, null);
+1
View File
@@ -26,6 +26,7 @@ auto = true
;username = "" ;username = ""
;password = "" ;password = ""
;from = mail@wg.at ;from = mail@wg.at
;wait = 0.5
;[scale.1] ;[scale.1]
;type = SysTec-IT ;type = SysTec-IT
+2 -2
View File
@@ -13,7 +13,7 @@ About
**Product:** Elwig **Product:** Elwig
**Description:** Electronic Management for Vintners' Cooperatives **Description:** Electronic Management for Vintners' Cooperatives
**Type:** ERP system **Type:** ERP system
**Version:** 1.0.5.6 ([Changelog](./CHANGELOG.md)) **Version:** 1.1.0.3 ([Changelog](./CHANGELOG.md))
**License:** [GNU General Public License 3.0 (GPLv3)](./LICENSE) **License:** [GNU General Public License 3.0 (GPLv3)](./LICENSE)
**Website:** https://elwig.at/ **Website:** https://elwig.at/
**Source code:** https://git.necronda.net/winzer/elwig **Source code:** https://git.necronda.net/winzer/elwig
@@ -33,7 +33,7 @@ Packaging: [WiX Toolset](https://www.firegiant.com/wixtoolset/)
**Produkt:** Elwig **Produkt:** Elwig
**Beschreibung:** Elektronische Winzergenossenschaftsverwaltung **Beschreibung:** Elektronische Winzergenossenschaftsverwaltung
**Typ:** Warenwirtschaftssystem (ERP-System) **Typ:** Warenwirtschaftssystem (ERP-System)
**Version:** 1.0.5.6 ([Änderungsprotokoll](./CHANGELOG.md)) **Version:** 1.1.0.3 ([Änderungsprotokoll](./CHANGELOG.md))
**Lizenz:** [GNU General Public License 3.0 (GPLv3)](./LICENSE) **Lizenz:** [GNU General Public License 3.0 (GPLv3)](./LICENSE)
**Website:** https://elwig.at/ **Website:** https://elwig.at/
**Quellcode:** https://git.necronda.net/winzer/elwig **Quellcode:** https://git.necronda.net/winzer/elwig
+1 -1
View File
@@ -19,7 +19,7 @@
</Target> </Target>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.6.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.9.0" />
<PackageReference Include="Appium.WebDriver" Version="4.4.5" /> <PackageReference Include="Appium.WebDriver" Version="4.4.5" />
<PackageReference Include="NReco.PdfRenderer" Version="1.6.0" /> <PackageReference Include="NReco.PdfRenderer" Version="1.6.0" />
<PackageReference Include="NUnit" Version="4.6.1" /> <PackageReference Include="NUnit" Version="4.6.1" />
@@ -23,7 +23,7 @@ namespace Tests.UnitTests.DocumentTests {
1 Grüner Veltliner Qualitätswein 73 15,0 3 219 1 Grüner Veltliner Qualitätswein 73 15,0 3 219
Herkunft: Österreich / Weinland / Niederösterreich Herkunft: Österreich / Weinland / Niederösterreich
/ Matzner Hügel / Hohenruppersdorf / KG Hohenruppersdorf / Matzner Hügel / Hohenruppersdorf / KG Hohenruppersdorf
Waage: 1, ID: 321 09:02, 01.10.2020 Waage/Terminal: ?/1, ID: 321 09:02, 01.10.2020
Brutto: 3 219 kg Tara: 0 kg Netto: 3 219 kg gerebelt gewogen Brutto: 3 219 kg Tara: 0 kg Netto: 3 219 kg gerebelt gewogen
""")); """));
}); });
@@ -49,13 +49,13 @@ namespace Tests.UnitTests.DocumentTests {
1 Grüner Veltliner Qualitätswein 82 16,7 4 002 1 Grüner Veltliner Qualitätswein 82 16,7 4 002
Herkunft: Österreich / Weinland / Niederösterreich Herkunft: Österreich / Weinland / Niederösterreich
/ Matzner Hügel / Hohenruppersdorf / KG Hohenruppersdorf / Matzner Hügel / Hohenruppersdorf / KG Hohenruppersdorf
Waage: ?, ID: ? (gerebelt gewogen) Waage/Terminal: ?/?, ID: ? (gerebelt gewogen)
""")); """));
Assert.That(text, Contains.Substring(""" Assert.That(text, Contains.Substring("""
2 Grüner Veltliner Qualitätswein 75 15,3 481 2 Grüner Veltliner Qualitätswein 75 15,3 481
Herkunft: Österreich / Weinland / Niederösterreich Herkunft: Österreich / Weinland / Niederösterreich
/ Matzner Hügel / Hohenruppersdorf / KG Hohenruppersdorf / Matzner Hügel / Hohenruppersdorf / KG Hohenruppersdorf
Waage: ?, ID: ? (gerebelt gewogen) Waage/Terminal: ?/?, ID: ? (gerebelt gewogen)
""")); """));
Assert.That(text, Contains.Substring("Gesamt: 81 16,5 4 483")); Assert.That(text, Contains.Substring("Gesamt: 81 16,5 4 483"));
}); });
@@ -80,19 +80,19 @@ namespace Tests.UnitTests.DocumentTests {
1 Grüner Veltliner Wein 75 15,4 2 561 1 Grüner Veltliner Wein 75 15,4 2 561
Herkunft: Österreich Herkunft: Österreich
/ Matzner Hügel / Hohenruppersdorf / KG Hohenruppersdorf / Matzner Hügel / Hohenruppersdorf / KG Hohenruppersdorf
Waage: ?, ID: ? (gerebelt gewogen) Waage/Terminal: ?/?, ID: ? (gerebelt gewogen)
""")); """));
Assert.That(text, Contains.Substring(""" Assert.That(text, Contains.Substring("""
2 Grüner Veltliner Kabinett Wein 87 17,6 3 129 2 Grüner Veltliner Kabinett Wein 87 17,6 3 129
Herkunft: Österreich Herkunft: Österreich
/ Matzner Hügel / Hohenruppersdorf / KG Hohenruppersdorf / Matzner Hügel / Hohenruppersdorf / KG Hohenruppersdorf
Waage: ?, ID: ? (gerebelt gewogen) Waage/Terminal: ?/?, ID: ? (gerebelt gewogen)
""")); """));
Assert.That(text, Contains.Substring(""" Assert.That(text, Contains.Substring("""
3 Grüner Veltliner Wein 79 16,1 1 280 3 Grüner Veltliner Wein 79 16,1 1 280
Herkunft: Österreich Herkunft: Österreich
/ Matzner Hügel / Hohenruppersdorf / KG Hohenruppersdorf / Matzner Hügel / Hohenruppersdorf / KG Hohenruppersdorf
Waage: ?, ID: ? (gerebelt gewogen) Waage/Terminal: ?/?, ID: ? (gerebelt gewogen)
""")); """));
Assert.That(text, Contains.Substring("Gesamt: 81 16,5 6 970")); Assert.That(text, Contains.Substring("Gesamt: 81 16,5 6 970"));
}); });
@@ -118,14 +118,14 @@ namespace Tests.UnitTests.DocumentTests {
Bewirtschaftung: Bio (AT-BIO-302) Bewirtschaftung: Bio (AT-BIO-302)
Herkunft: Österreich Herkunft: Österreich
/ Wolkersdorfer Hochleithen / Wolkersdorf im Weinviertel / KG Wolkersdorf / Wolkersdorfer Hochleithen / Wolkersdorf im Weinviertel / KG Wolkersdorf
Waage: ?, ID: ? (gerebelt gewogen) Waage/Terminal: ?/?, ID: ? (gerebelt gewogen)
""")); """));
Assert.That(text, Contains.Substring(""" Assert.That(text, Contains.Substring("""
2 Grüner Veltliner Qualitätswein 75 15,4 2 134 2 Grüner Veltliner Qualitätswein 75 15,4 2 134
Bewirtschaftung: Bio (AT-BIO-302) Bewirtschaftung: Bio (AT-BIO-302)
Herkunft: Österreich / Weinland / Niederösterreich Herkunft: Österreich / Weinland / Niederösterreich
/ Wolkersdorfer Hochleithen / Wolkersdorf im Weinviertel / KG Wolkersdorf / Wolkersdorfer Hochleithen / Wolkersdorf im Weinviertel / KG Wolkersdorf
Waage: ?, ID: ? (gerebelt gewogen) Waage/Terminal: ?/?, ID: ? (gerebelt gewogen)
""")); """));
Assert.That(text, Contains.Substring("Gesamt: 78 15,9 5 332")); Assert.That(text, Contains.Substring("Gesamt: 78 15,9 5 332"));
}); });
@@ -152,12 +152,12 @@ namespace Tests.UnitTests.DocumentTests {
Herkunft: Österreich / Weinland / Niederösterreich Herkunft: Österreich / Weinland / Niederösterreich
/ Matzner Hügel / Hohenruppersdorf / KG Hohenruppersdorf / Matzner Hügel / Hohenruppersdorf / KG Hohenruppersdorf
Zu-/Abschläge: Geschädigte Trauben 10,00 % Zu-/Abschläge: Geschädigte Trauben 10,00 %
Waage: ?, ID: ? (gerebelt gewogen) Waage/Terminal: ?/?, ID: ? (gerebelt gewogen)
2 Grüner Veltliner Kabinett Kabinett 87 17,7 1 873 2 Grüner Veltliner Kabinett Kabinett 87 17,7 1 873
Herkunft: Österreich / Weinland / Niederösterreich Herkunft: Österreich / Weinland / Niederösterreich
/ Matzner Hügel / Hohenruppersdorf / KG Hohenruppersdorf / Matzner Hügel / Hohenruppersdorf / KG Hohenruppersdorf
Zu-/Abschläge: Keine Voranmeldung 0,1000 /kg Zu-/Abschläge: Keine Voranmeldung 0,1000 /kg
Waage: ?, ID: ? (gerebelt gewogen) Waage/Terminal: ?/?, ID: ? (gerebelt gewogen)
Gesamt: 87 17,6 4 860 Gesamt: 87 17,6 4 860
""")); """));
} }
@@ -31,16 +31,19 @@ namespace Tests.UnitTests.WeighingTests {
Mock.Weight = 1235; Mock.Weight = 1235;
Assert.That(await Scale!.GetCurrentWeight(), Is.EqualTo(new WeighingResult { Assert.That(await Scale!.GetCurrentWeight(), Is.EqualTo(new WeighingResult {
GrossWeight = 1235, TareWeight = 0, NetWeight = 1235, GrossWeight = 1235, TareWeight = 0, NetWeight = 1235,
ScaleId = "1",
Date = new DateOnly(2020, 10, 17), Time = new TimeOnly(14, 23), Date = new DateOnly(2020, 10, 17), Time = new TimeOnly(14, 23),
})); }));
Mock.Weight = 1240; Mock.Weight = 1240;
Assert.That(await Scale!.GetCurrentWeight(), Is.EqualTo(new WeighingResult { Assert.That(await Scale!.GetCurrentWeight(), Is.EqualTo(new WeighingResult {
GrossWeight = 1240, TareWeight = 0, NetWeight = 1240, GrossWeight = 1240, TareWeight = 0, NetWeight = 1240,
ScaleId = "1",
Date = new DateOnly(2020, 10, 17), Time = new TimeOnly(14, 23), Date = new DateOnly(2020, 10, 17), Time = new TimeOnly(14, 23),
})); }));
Mock.Weight = 1245; Mock.Weight = 1245;
Assert.That(await Scale!.GetCurrentWeight(), Is.EqualTo(new WeighingResult { Assert.That(await Scale!.GetCurrentWeight(), Is.EqualTo(new WeighingResult {
GrossWeight = 1245, TareWeight = 0, NetWeight = 1245, GrossWeight = 1245, TareWeight = 0, NetWeight = 1245,
ScaleId = "1",
Date = new DateOnly(2020, 10, 17), Time = new TimeOnly(14, 23), Date = new DateOnly(2020, 10, 17), Time = new TimeOnly(14, 23),
})); }));
} }
@@ -50,19 +53,19 @@ namespace Tests.UnitTests.WeighingTests {
Mock.Weight = 1235; Mock.Weight = 1235;
Assert.That(await Scale!.Weigh(), Is.EqualTo(new WeighingResult { Assert.That(await Scale!.Weigh(), Is.EqualTo(new WeighingResult {
GrossWeight = 1235, TareWeight = 0, NetWeight = 1235, GrossWeight = 1235, TareWeight = 0, NetWeight = 1235,
WeighingId = "1", FullWeighingId = $"2020-10-17/1", ScaleId = "1", WeighingId = "1", FullWeighingId = $"2020-10-17/1",
Date = new DateOnly(2020, 10, 17), Time = new TimeOnly(14, 23), Date = new DateOnly(2020, 10, 17), Time = new TimeOnly(14, 23),
})); }));
Mock.Weight = 3335; Mock.Weight = 3335;
Assert.That(await Scale!.Weigh(), Is.EqualTo(new WeighingResult { Assert.That(await Scale!.Weigh(), Is.EqualTo(new WeighingResult {
GrossWeight = 3335, TareWeight = 0, NetWeight = 3335, GrossWeight = 3335, TareWeight = 0, NetWeight = 3335,
WeighingId = "2", FullWeighingId = $"2020-10-17/2", ScaleId = "1", WeighingId = "2", FullWeighingId = $"2020-10-17/2",
Date = new DateOnly(2020, 10, 17), Time = new TimeOnly(14, 23), Date = new DateOnly(2020, 10, 17), Time = new TimeOnly(14, 23),
})); }));
Mock.Weight = 6420; Mock.Weight = 6420;
Assert.That(await Scale!.Weigh(), Is.EqualTo(new WeighingResult { Assert.That(await Scale!.Weigh(), Is.EqualTo(new WeighingResult {
GrossWeight = 6420, TareWeight = 0, NetWeight = 6420, GrossWeight = 6420, TareWeight = 0, NetWeight = 6420,
WeighingId = "3", FullWeighingId = $"2020-10-17/3", ScaleId = "1", WeighingId = "3", FullWeighingId = $"2020-10-17/3",
Date = new DateOnly(2020, 10, 17), Time = new TimeOnly(14, 23), Date = new DateOnly(2020, 10, 17), Time = new TimeOnly(14, 23),
})); }));
} }
@@ -5,7 +5,7 @@ namespace Tests.UnitTests.WeighingTests {
public class ScaleTestHaugsdorfDMA02 { public class ScaleTestHaugsdorfDMA02 {
private MockScale Mock; private MockScale Mock;
private GassnerScale Scale; private GassnerEnqScale Scale;
[OneTimeSetUp] [OneTimeSetUp]
public void SetupScale() { public void SetupScale() {
@@ -32,29 +32,23 @@ namespace Tests.UnitTests.WeighingTests {
Mock.Weight = 1234; Mock.Weight = 1234;
Mock.Tare = 0; Mock.Tare = 0;
Assert.That(await Scale!.GetCurrentWeight(), Is.EqualTo(new WeighingResult { Assert.That(await Scale!.GetCurrentWeight(), Is.EqualTo(new WeighingResult {
GrossWeight = 1234, GrossWeight = 1234, TareWeight = 0, NetWeight = 1234,
TareWeight = 0, ScaleId = "1",
NetWeight = 1234, Date = new DateOnly(2020, 10, 15), Time = new TimeOnly(12, 34),
Date = new DateOnly(2020, 10, 15),
Time = new TimeOnly(12, 34),
})); }));
Mock.Weight = 1235; Mock.Weight = 1235;
Mock.Tare = 46; Mock.Tare = 46;
Assert.That(await Scale!.GetCurrentWeight(), Is.EqualTo(new WeighingResult { Assert.That(await Scale!.GetCurrentWeight(), Is.EqualTo(new WeighingResult {
GrossWeight = 1281, GrossWeight = 1281, TareWeight = 46, NetWeight = 1235,
TareWeight = 46, ScaleId = "1",
NetWeight = 1235, Date = new DateOnly(2020, 10, 15), Time = new TimeOnly(12, 34),
Date = new DateOnly(2020, 10, 15),
Time = new TimeOnly(12, 34),
})); }));
Mock.Weight = 1236; Mock.Weight = 1236;
Mock.Tare = 92; Mock.Tare = 92;
Assert.That(await Scale!.GetCurrentWeight(), Is.EqualTo(new WeighingResult { Assert.That(await Scale!.GetCurrentWeight(), Is.EqualTo(new WeighingResult {
GrossWeight = 1328, GrossWeight = 1328, TareWeight = 92, NetWeight = 1236,
TareWeight = 92, ScaleId = "1",
NetWeight = 1236, Date = new DateOnly(2020, 10, 15), Time = new TimeOnly(12, 34),
Date = new DateOnly(2020, 10, 15),
Time = new TimeOnly(12, 34),
})); }));
} }
@@ -63,35 +57,23 @@ namespace Tests.UnitTests.WeighingTests {
Mock.Weight = 1234; Mock.Weight = 1234;
Mock.Tare = 92; Mock.Tare = 92;
Assert.That(await Scale!.Weigh(), Is.EqualTo(new WeighingResult { Assert.That(await Scale!.Weigh(), Is.EqualTo(new WeighingResult {
GrossWeight = 1326, GrossWeight = 1326, TareWeight = 92, NetWeight = 1234,
TareWeight = 92, ScaleId = "1", WeighingId = "1", FullWeighingId = "1",
NetWeight = 1234, Date = new DateOnly(2020, 10, 15), Time = new TimeOnly(12, 34),
WeighingId = "1",
FullWeighingId = "1",
Date = new DateOnly(2020, 10, 15),
Time = new TimeOnly(12, 34),
})); }));
Mock.Weight = 3333; Mock.Weight = 3333;
Mock.Tare = 41; Mock.Tare = 41;
Assert.That(await Scale!.Weigh(), Is.EqualTo(new WeighingResult { Assert.That(await Scale!.Weigh(), Is.EqualTo(new WeighingResult {
GrossWeight = 3374, GrossWeight = 3374, TareWeight = 41, NetWeight = 3333,
TareWeight = 41, ScaleId = "1", WeighingId = "2", FullWeighingId = "2",
NetWeight = 3333, Date = new DateOnly(2020, 10, 15), Time = new TimeOnly(12, 34),
WeighingId = "2",
FullWeighingId = "2",
Date = new DateOnly(2020, 10, 15),
Time = new TimeOnly(12, 34),
})); }));
Mock.Weight = 4321; Mock.Weight = 4321;
Mock.Tare = 0; Mock.Tare = 0;
Assert.That(await Scale!.Weigh(), Is.EqualTo(new WeighingResult { Assert.That(await Scale!.Weigh(), Is.EqualTo(new WeighingResult {
GrossWeight = 4321, GrossWeight = 4321, TareWeight = 0, NetWeight = 4321,
TareWeight = 0, ScaleId = "1", WeighingId = "3", FullWeighingId = "3",
NetWeight = 4321, Date = new DateOnly(2020, 10, 15), Time = new TimeOnly(12, 34),
WeighingId = "3",
FullWeighingId = "3",
Date = new DateOnly(2020, 10, 15),
Time = new TimeOnly(12, 34),
})); }));
} }
@@ -31,16 +31,19 @@ namespace Tests.UnitTests.WeighingTests {
Mock.Weight = 1234; Mock.Weight = 1234;
Assert.That(await Scale!.GetCurrentWeight(), Is.EqualTo(new WeighingResult { Assert.That(await Scale!.GetCurrentWeight(), Is.EqualTo(new WeighingResult {
GrossWeight = 1234, TareWeight = 0, NetWeight = 1234, GrossWeight = 1234, TareWeight = 0, NetWeight = 1234,
ScaleId = "1",
Date = new DateOnly(2020, 10, 15), Time = new TimeOnly(12, 34), Date = new DateOnly(2020, 10, 15), Time = new TimeOnly(12, 34),
})); }));
Mock.Weight = 1235; Mock.Weight = 1235;
Assert.That(await Scale!.GetCurrentWeight(), Is.EqualTo(new WeighingResult { Assert.That(await Scale!.GetCurrentWeight(), Is.EqualTo(new WeighingResult {
GrossWeight = 1235, TareWeight = 0, NetWeight = 1235, GrossWeight = 1235, TareWeight = 0, NetWeight = 1235,
ScaleId = "1",
Date = new DateOnly(2020, 10, 15), Time = new TimeOnly(12, 34), Date = new DateOnly(2020, 10, 15), Time = new TimeOnly(12, 34),
})); }));
Mock.Weight = 1236; Mock.Weight = 1236;
Assert.That(await Scale!.GetCurrentWeight(), Is.EqualTo(new WeighingResult { Assert.That(await Scale!.GetCurrentWeight(), Is.EqualTo(new WeighingResult {
GrossWeight = 1236, TareWeight = 0, NetWeight = 1236, GrossWeight = 1236, TareWeight = 0, NetWeight = 1236,
ScaleId = "1",
Date = new DateOnly(2020, 10, 15), Time = new TimeOnly(12, 34), Date = new DateOnly(2020, 10, 15), Time = new TimeOnly(12, 34),
})); }));
} }
@@ -50,19 +53,19 @@ namespace Tests.UnitTests.WeighingTests {
Mock.Weight = 1234; Mock.Weight = 1234;
Assert.That(await Scale!.Weigh(), Is.EqualTo(new WeighingResult { Assert.That(await Scale!.Weigh(), Is.EqualTo(new WeighingResult {
GrossWeight = 1234, TareWeight = 0, NetWeight = 1234, GrossWeight = 1234, TareWeight = 0, NetWeight = 1234,
WeighingId = "1", FullWeighingId = $"2020-10-15/1", ScaleId = "1", WeighingId = "1", FullWeighingId = $"2020-10-15/1",
Date = new DateOnly(2020, 10, 15), Time = new TimeOnly(12, 34), Date = new DateOnly(2020, 10, 15), Time = new TimeOnly(12, 34),
})); }));
Mock.Weight = 3333; Mock.Weight = 3333;
Assert.That(await Scale!.Weigh(), Is.EqualTo(new WeighingResult { Assert.That(await Scale!.Weigh(), Is.EqualTo(new WeighingResult {
GrossWeight = 3333, TareWeight = 0, NetWeight = 3333, GrossWeight = 3333, TareWeight = 0, NetWeight = 3333,
WeighingId = "2", FullWeighingId = $"2020-10-15/2", ScaleId = "1", WeighingId = "2", FullWeighingId = $"2020-10-15/2",
Date = new DateOnly(2020, 10, 15), Time = new TimeOnly(12, 34), Date = new DateOnly(2020, 10, 15), Time = new TimeOnly(12, 34),
})); }));
Mock.Weight = 4321; Mock.Weight = 4321;
Assert.That(await Scale!.Weigh(), Is.EqualTo(new WeighingResult { Assert.That(await Scale!.Weigh(), Is.EqualTo(new WeighingResult {
GrossWeight = 4321, TareWeight = 0, NetWeight = 4321, GrossWeight = 4321, TareWeight = 0, NetWeight = 4321,
WeighingId = "3", FullWeighingId = $"2020-10-15/3", ScaleId = "1", WeighingId = "3", FullWeighingId = $"2020-10-15/3",
Date = new DateOnly(2020, 10, 15), Time = new TimeOnly(12, 34), Date = new DateOnly(2020, 10, 15), Time = new TimeOnly(12, 34),
})); }));
} }
@@ -5,7 +5,7 @@ namespace Tests.UnitTests.WeighingTests {
public class ScaleTestSitzendorfDMA03Baby { public class ScaleTestSitzendorfDMA03Baby {
private MockScale Mock; private MockScale Mock;
private GassnerScale Scale; private GassnerEnqScale Scale;
[OneTimeSetUp] [OneTimeSetUp]
public void SetupScale() { public void SetupScale() {
@@ -32,29 +32,23 @@ namespace Tests.UnitTests.WeighingTests {
Mock.Weight = 1234; Mock.Weight = 1234;
Mock.Tare = 0; Mock.Tare = 0;
Assert.That(await Scale!.GetCurrentWeight(), Is.EqualTo(new WeighingResult { Assert.That(await Scale!.GetCurrentWeight(), Is.EqualTo(new WeighingResult {
GrossWeight = 1234, GrossWeight = 1234, TareWeight = 0, NetWeight = 1234,
TareWeight = 0, ScaleId = "1",
NetWeight = 1234, Date = new DateOnly(2020, 10, 15), Time = new TimeOnly(12, 34),
Date = new DateOnly(2020, 10, 15),
Time = new TimeOnly(12, 34),
})); }));
Mock.Weight = 1235; Mock.Weight = 1235;
Mock.Tare = 46; Mock.Tare = 46;
Assert.That(await Scale!.GetCurrentWeight(), Is.EqualTo(new WeighingResult { Assert.That(await Scale!.GetCurrentWeight(), Is.EqualTo(new WeighingResult {
GrossWeight = 1281, GrossWeight = 1281, TareWeight = 46, NetWeight = 1235,
TareWeight = 46, ScaleId = "1",
NetWeight = 1235, Date = new DateOnly(2020, 10, 15), Time = new TimeOnly(12, 34),
Date = new DateOnly(2020, 10, 15),
Time = new TimeOnly(12, 34),
})); }));
Mock.Weight = 1236; Mock.Weight = 1236;
Mock.Tare = 92; Mock.Tare = 92;
Assert.That(await Scale!.GetCurrentWeight(), Is.EqualTo(new WeighingResult { Assert.That(await Scale!.GetCurrentWeight(), Is.EqualTo(new WeighingResult {
GrossWeight = 1328, GrossWeight = 1328, TareWeight = 92, NetWeight = 1236,
TareWeight = 92, ScaleId = "1",
NetWeight = 1236, Date = new DateOnly(2020, 10, 15), Time = new TimeOnly(12, 34),
Date = new DateOnly(2020, 10, 15),
Time = new TimeOnly(12, 34),
})); }));
} }
@@ -63,35 +57,23 @@ namespace Tests.UnitTests.WeighingTests {
Mock.Weight = 1234; Mock.Weight = 1234;
Mock.Tare = 92; Mock.Tare = 92;
Assert.That(await Scale!.Weigh(), Is.EqualTo(new WeighingResult { Assert.That(await Scale!.Weigh(), Is.EqualTo(new WeighingResult {
GrossWeight = 1326, GrossWeight = 1326, TareWeight = 92, NetWeight = 1234,
TareWeight = 92, ScaleId = "1", WeighingId = "1", FullWeighingId = "1",
NetWeight = 1234, Date = new DateOnly(2020, 10, 15), Time = new TimeOnly(12, 34),
WeighingId = "1",
FullWeighingId = "1",
Date = new DateOnly(2020, 10, 15),
Time = new TimeOnly(12, 34),
})); }));
Mock.Weight = 3333; Mock.Weight = 3333;
Mock.Tare = 41; Mock.Tare = 41;
Assert.That(await Scale!.Weigh(), Is.EqualTo(new WeighingResult { Assert.That(await Scale!.Weigh(), Is.EqualTo(new WeighingResult {
GrossWeight = 3374, GrossWeight = 3374, TareWeight = 41, NetWeight = 3333,
TareWeight = 41, ScaleId = "1", WeighingId = "2", FullWeighingId = "2",
NetWeight = 3333, Date = new DateOnly(2020, 10, 15), Time = new TimeOnly(12, 34),
WeighingId = "2",
FullWeighingId = "2",
Date = new DateOnly(2020, 10, 15),
Time = new TimeOnly(12, 34),
})); }));
Mock.Weight = 4321; Mock.Weight = 4321;
Mock.Tare = 0; Mock.Tare = 0;
Assert.That(await Scale!.Weigh(), Is.EqualTo(new WeighingResult { Assert.That(await Scale!.Weigh(), Is.EqualTo(new WeighingResult {
GrossWeight = 4321, GrossWeight = 4321, TareWeight = 0, NetWeight = 4321,
TareWeight = 0, ScaleId = "1", WeighingId = "3", FullWeighingId = "3",
NetWeight = 4321, Date = new DateOnly(2020, 10, 15), Time = new TimeOnly(12, 34),
WeighingId = "3",
FullWeighingId = "3",
Date = new DateOnly(2020, 10, 15),
Time = new TimeOnly(12, 34),
})); }));
} }
@@ -40,21 +40,25 @@ namespace Tests.UnitTests.WeighingTests {
MockA.Weight = 1234; MockA.Weight = 1234;
Assert.That(await ScaleA!.GetCurrentWeight(), Is.EqualTo(new WeighingResult { Assert.That(await ScaleA!.GetCurrentWeight(), Is.EqualTo(new WeighingResult {
GrossWeight = 1234, TareWeight = 0, NetWeight = 1234, GrossWeight = 1234, TareWeight = 0, NetWeight = 1234,
ScaleId = "1",
Date = new DateOnly(2020, 10, 8), Time = new TimeOnly(8, 47), Date = new DateOnly(2020, 10, 8), Time = new TimeOnly(8, 47),
})); }));
MockB.Weight = 3456; MockB.Weight = 3456;
Assert.That(await ScaleB!.GetCurrentWeight(), Is.EqualTo(new WeighingResult { Assert.That(await ScaleB!.GetCurrentWeight(), Is.EqualTo(new WeighingResult {
GrossWeight = 3456, TareWeight = 0, NetWeight = 3456, GrossWeight = 3456, TareWeight = 0, NetWeight = 3456,
ScaleId = "1",
Date = new DateOnly(2020, 10, 8), Time = new TimeOnly(8, 47), Date = new DateOnly(2020, 10, 8), Time = new TimeOnly(8, 47),
})); }));
MockA.Weight = 1236; MockA.Weight = 1236;
Assert.That(await ScaleA!.GetCurrentWeight(), Is.EqualTo(new WeighingResult { Assert.That(await ScaleA!.GetCurrentWeight(), Is.EqualTo(new WeighingResult {
GrossWeight = 1236, TareWeight = 0, NetWeight = 1236, GrossWeight = 1236, TareWeight = 0, NetWeight = 1236,
ScaleId = "1",
Date = new DateOnly(2020, 10, 8), Time = new TimeOnly(8, 47), Date = new DateOnly(2020, 10, 8), Time = new TimeOnly(8, 47),
})); }));
MockB.Weight = 3457; MockB.Weight = 3457;
Assert.That(await ScaleB!.GetCurrentWeight(), Is.EqualTo(new WeighingResult { Assert.That(await ScaleB!.GetCurrentWeight(), Is.EqualTo(new WeighingResult {
GrossWeight = 3457, TareWeight = 0, NetWeight = 3457, GrossWeight = 3457, TareWeight = 0, NetWeight = 3457,
ScaleId = "1",
Date = new DateOnly(2020, 10, 8), Time = new TimeOnly(8, 47), Date = new DateOnly(2020, 10, 8), Time = new TimeOnly(8, 47),
})); }));
} }
@@ -64,25 +68,25 @@ namespace Tests.UnitTests.WeighingTests {
MockA.Weight = 1234; MockA.Weight = 1234;
Assert.That(await ScaleA!.Weigh(), Is.EqualTo(new WeighingResult { Assert.That(await ScaleA!.Weigh(), Is.EqualTo(new WeighingResult {
GrossWeight = 1234, TareWeight = 0, NetWeight = 1234, GrossWeight = 1234, TareWeight = 0, NetWeight = 1234,
WeighingId = "1", FullWeighingId = $"2020-10-08/1", ScaleId = "1", WeighingId = "1", FullWeighingId = $"2020-10-08/1",
Date = new DateOnly(2020, 10, 8), Time = new TimeOnly(8, 47), Date = new DateOnly(2020, 10, 8), Time = new TimeOnly(8, 47),
})); }));
MockB.Weight = 3456; MockB.Weight = 3456;
Assert.That(await ScaleB!.Weigh(), Is.EqualTo(new WeighingResult { Assert.That(await ScaleB!.Weigh(), Is.EqualTo(new WeighingResult {
GrossWeight = 3456, TareWeight = 0, NetWeight = 3456, GrossWeight = 3456, TareWeight = 0, NetWeight = 3456,
WeighingId = "1", FullWeighingId = $"2020-10-08/1", ScaleId = "1", WeighingId = "1", FullWeighingId = $"2020-10-08/1",
Date = new DateOnly(2020, 10, 8), Time = new TimeOnly(8, 47), Date = new DateOnly(2020, 10, 8), Time = new TimeOnly(8, 47),
})); }));
MockA.Weight = 4321; MockA.Weight = 4321;
Assert.That(await ScaleA!.Weigh(), Is.EqualTo(new WeighingResult { Assert.That(await ScaleA!.Weigh(), Is.EqualTo(new WeighingResult {
GrossWeight = 4321, TareWeight = 0, NetWeight = 4321, GrossWeight = 4321, TareWeight = 0, NetWeight = 4321,
WeighingId = "2", FullWeighingId = $"2020-10-08/2", ScaleId = "1", WeighingId = "2", FullWeighingId = $"2020-10-08/2",
Date = new DateOnly(2020, 10, 8), Time = new TimeOnly(8, 47), Date = new DateOnly(2020, 10, 8), Time = new TimeOnly(8, 47),
})); }));
MockB.Weight = 3333; MockB.Weight = 3333;
Assert.That(await ScaleB!.Weigh(), Is.EqualTo(new WeighingResult { Assert.That(await ScaleB!.Weigh(), Is.EqualTo(new WeighingResult {
GrossWeight = 3333, TareWeight = 0, NetWeight = 3333, GrossWeight = 3333, TareWeight = 0, NetWeight = 3333,
WeighingId = "2", FullWeighingId = $"2020-10-08/2", ScaleId = "1", WeighingId = "2", FullWeighingId = $"2020-10-08/2",
Date = new DateOnly(2020, 10, 8), Time = new TimeOnly(8, 47), Date = new DateOnly(2020, 10, 8), Time = new TimeOnly(8, 47),
})); }));
} }