Compare commits

...

32 Commits

Author SHA1 Message Date
39279a5dda Bump version to 0.3.2 2023-09-19 16:29:34 +02:00
5271f357f5 DeliveryAdminWindow: Add DeliveryJournal 2023-09-19 02:11:30 +02:00
13ba3f90f6 DeliveryAdminWindow: Add Filter to BKI export 2023-09-19 00:57:59 +02:00
43be8bf391 DeliveryAdminWindow: Empty scale only after saving to database 2023-09-19 00:47:10 +02:00
826a76c56c AppDbUpdater: Add schema_version 2 2023-09-19 00:37:46 +02:00
efaae5f490 DeliveryAdminWindow: 'Activate()' window after awaiting doc.Print(2) 2023-09-18 21:48:03 +02:00
3a73265a75 ContextWindow: Change renew context event handling 2023-09-18 21:46:14 +02:00
a6fef7fd9b Utils: Fix GetSearchScore for multiple occurances of keyword in haystack 2023-09-18 21:17:37 +02:00
a08df4c3ed DeliveryAdminWindow: Add auto focus for weighing buttons on enter 2023-09-18 20:59:59 +02:00
9701af9e36 AppDbUpdater: Fix version comparison 2023-09-18 10:03:48 +02:00
b4f1eeee84 Bump version to 0.3.1 2023-09-18 02:05:16 +02:00
2922fe0138 BaseDataWindow: Remove DecimalInput check 2023-09-18 01:40:59 +02:00
704facbc6b App: Use Ort insteas of Destination for Branch Location 2023-09-18 01:32:54 +02:00
404e8a0c27 BaseDataWindow: Fix Modifier creation 2023-09-18 01:30:45 +02:00
ef621fab2d Validator: Fix usage of maxLen and maxDecimal in CheckDecimal 2023-09-18 01:27:15 +02:00
0938e33fe1 DeliveryAdminWindow: Fix LNr calculation for new deliveries 2023-09-18 01:04:09 +02:00
6b5c283e10 Update dependencies 2023-09-17 22:12:15 +02:00
b6400c41c4 Bump version to 0.3.0 2023-09-17 21:31:06 +02:00
24b7078a05 Add AppDbUpdater 2023-09-17 20:48:07 +02:00
dc215d3350 BusinessDocument: Make aside table a bit more compact 2023-09-15 14:35:25 +02:00
b80cbc037c AreaComAdminWindow: Add comment input 2023-09-14 23:43:38 +02:00
4891501f62 DeliveryAdminWindow: Fix filter count check 2023-09-14 23:27:43 +02:00
6d3adc48f6 DeliveryNote: Add manual weighing reason 2023-09-14 23:25:37 +02:00
f5eea1e906 Models: Add MemberEmailAddr 2023-09-14 22:32:28 +02:00
ba691f4d17 Documents: Make business documents more compact 2023-09-14 20:44:48 +02:00
470f092482 DeliveryAdminWindow: Move manual weighing button to last position 2023-09-14 17:51:48 +02:00
e9e4c75edd Bump version to 0.2.1 2023-09-13 23:37:26 +02:00
ff1a4e7182 Documents: Add ShowFoldMarks flag 2023-09-13 23:22:35 +02:00
1e9cad6de7 DeliveryAdminWindow: Use last scale error as default manual weighing reason 2023-09-13 23:19:04 +02:00
62fe087598 DeliveryAdminWindow: Hopefully fix 'Erste Übernahme' bug 2023-09-13 22:57:21 +02:00
7f01b85878 HelpersUtilsTest: fix file encoding 2023-09-13 22:04:01 +02:00
a659d07db2 Config: add debug flag 2023-09-13 22:02:50 +02:00
38 changed files with 601 additions and 193 deletions

View File

@ -11,6 +11,7 @@ using System.Windows.Threading;
using System.Globalization; using System.Globalization;
using System.Threading; using System.Threading;
using System.Windows.Markup; using System.Windows.Markup;
using System.Reflection;
namespace Elwig { namespace Elwig {
public partial class App : Application { public partial class App : Application {
@ -20,10 +21,23 @@ namespace Elwig {
public static readonly string TempPath = Path.Combine(Path.GetTempPath(), "Elwig"); public static readonly string TempPath = Path.Combine(Path.GetTempPath(), "Elwig");
public static readonly Config Config = new(DataPath + "config.ini"); public static readonly Config Config = new(DataPath + "config.ini");
public static int VersionMajor { get; private set; }
public static int VersionMinor { get; private set; }
public static int VersionPatch { get; private set; }
public static string Version {
get => $"{VersionMajor}.{VersionMinor}.{VersionPatch}";
private set {
var p = value.Split(".").Select(p => int.Parse(p.Trim())).ToArray();
VersionMajor = p.ElementAtOrDefault(0);
VersionMinor = p.ElementAtOrDefault(1);
VersionPatch = p.ElementAtOrDefault(2);
}
}
public static string ZwstId { get; private set; } public static string ZwstId { get; private set; }
public static string BranchName { get; private set; } public static string BranchName { get; private set; }
public static int? BranchPlz { get; private set; } public static int? BranchPlz { get; private set; }
public static string? BranchOrt { get; private set; } public static string? BranchLocation { get; private set; }
public static string? BranchAddress { get; private set; } public static string? BranchAddress { get; private set; }
public static string? BranchPhoneNr { get; private set; } public static string? BranchPhoneNr { get; private set; }
public static string? BranchFaxNr { get; private set; } public static string? BranchFaxNr { get; private set; }
@ -36,7 +50,7 @@ namespace Elwig {
public App() : base() { public App() : base() {
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance); System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
Directory.CreateDirectory(App.TempPath); Directory.CreateDirectory(TempPath);
Directory.CreateDirectory(DataPath); Directory.CreateDirectory(DataPath);
MainDispatcher = Dispatcher; MainDispatcher = Dispatcher;
Scales = Array.Empty<IScale>(); Scales = Array.Empty<IScale>();
@ -56,15 +70,19 @@ namespace Elwig {
new FrameworkPropertyMetadata(XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)) new FrameworkPropertyMetadata(XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag))
); );
Dictionary<string, (string, string, int?, string?, string?, string?, string?, string?)> branches = new(); Version = typeof(App).GetTypeInfo().Assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion ?? "";
using (var ctx = new AppDbContext()) {
try { try {
if (!ctx.Database.CanConnect()) { AppDbUpdater.CheckDb();
MessageBox.Show($"Invalid Database:\n\n{Config.DatabaseFile}", "Invalid Database", MessageBoxButton.OK, MessageBoxImage.Error); } catch (Exception e) {
MessageBox.Show($"Invalid Database:\n\n{e.Message}", "Invalid Database", MessageBoxButton.OK, MessageBoxImage.Error);
Shutdown(); Shutdown();
return; return;
} else { }
branches = ctx.Branches.ToDictionary(b => b.Name.ToLower(), b => (b.ZwstId, b.Name, b.PostalDest?.AtPlz?.Plz, b.PostalDest?.AtPlz?.Dest, b.Address, b.PhoneNr, b.FaxNr, b.MobileNr));
Dictionary<string, (string, string, int?, string?, string?, string?, string?, string?)> branches = new();
using (var ctx = new AppDbContext()) {
branches = ctx.Branches.ToDictionary(b => b.Name.ToLower(), b => (b.ZwstId, b.Name, b.PostalDest?.AtPlz?.Plz, b.PostalDest?.AtPlz?.Ort.Name, b.Address, b.PhoneNr, b.FaxNr, b.MobileNr));
try { try {
Client = new(ctx); Client = new(ctx);
} catch (Exception e) { } catch (Exception e) {
@ -73,12 +91,7 @@ namespace Elwig {
return; return;
} }
} }
} catch (Exception e) {
MessageBox.Show($"Invalid Database:\n\n{e.Message}", "Invalid Database", MessageBoxButton.OK, MessageBoxImage.Error);
Shutdown();
return;
}
}
Utils.RunBackground("HTML Initialization", () => Documents.Html.Init(PrintingReadyChanged)); Utils.RunBackground("HTML Initialization", () => Documents.Html.Init(PrintingReadyChanged));
Utils.RunBackground("PDF Initialization", () => Documents.Pdf.Init(PrintingReadyChanged)); Utils.RunBackground("PDF Initialization", () => Documents.Pdf.Init(PrintingReadyChanged));
@ -114,7 +127,7 @@ namespace Elwig {
ZwstId = entry.Item1; ZwstId = entry.Item1;
BranchName = entry.Item2; BranchName = entry.Item2;
BranchPlz = entry.Item3; BranchPlz = entry.Item3;
BranchOrt = entry.Item4; BranchLocation = entry.Item4;
BranchAddress = entry.Item5; BranchAddress = entry.Item5;
BranchPhoneNr = entry.Item6; BranchPhoneNr = entry.Item6;
BranchFaxNr = entry.Item7; BranchFaxNr = entry.Item7;
@ -125,7 +138,7 @@ namespace Elwig {
ZwstId = entry.Item1; ZwstId = entry.Item1;
BranchName = entry.Item2; BranchName = entry.Item2;
BranchPlz = entry.Item3; BranchPlz = entry.Item3;
BranchOrt = entry.Item4; BranchLocation = entry.Item4;
BranchAddress = entry.Item5; BranchAddress = entry.Item5;
BranchPhoneNr = entry.Item6; BranchPhoneNr = entry.Item6;
BranchFaxNr = entry.Item7; BranchFaxNr = entry.Item7;

View File

@ -9,19 +9,16 @@ namespace Elwig.Dialogs {
public int Weight = 0; public int Weight = 0;
public string? Reason = null; public string? Reason = null;
public ManualWeighingDialog() { public ManualWeighingDialog(string? reason = null) {
InitializeComponent(); InitializeComponent();
ReasonInput.Text = reason;
} }
private void ConfirmButton_Click(object sender, RoutedEventArgs evt) { private void ConfirmButton_Click(object sender, RoutedEventArgs evt) {
DialogResult = true; DialogResult = true;
Weight = int.Parse(WeightInput.Text); Weight = int.Parse(WeightInput.Text);
Reason = Regex.Replace(ReasonInput.Text, @"\s+", "").Trim(); Reason = Regex.Replace(ReasonInput.Text, @"\s+", " ").Trim();
if (Reason == "") { if (Reason == "") Reason = null;
Reason = null;
} else if (!Reason.EndsWith(".") || !Reason.EndsWith("!") || !Reason.EndsWith("?")) {
Reason += ".";
}
Close(); Close();
} }

View File

@ -14,5 +14,8 @@
<address>@Model.Address</address> <address>@Model.Address</address>
</div> </div>
<aside>@Raw(Model.Aside)</aside> <aside>@Raw(Model.Aside)</aside>
@if (Model.ShowDateAndLocation) {
<div class="date">@Model.Location, am @($"{Model.Date:dd.MM.yyyy}")</div>
}
</div> </div>
@RenderBody() @RenderBody()

View File

@ -3,6 +3,8 @@ using Elwig.Models;
namespace Elwig.Documents { namespace Elwig.Documents {
public abstract class BusinessDocument : Document { public abstract class BusinessDocument : Document {
public bool ShowDateAndLocation = false;
public Member Member; public Member Member;
public bool IncludeSender = false; public bool IncludeSender = false;
public bool UseBillingAddress = false; public bool UseBillingAddress = false;
@ -11,7 +13,7 @@ namespace Elwig.Documents {
public BusinessDocument(string title, Member m, bool includeSender = false) : base(title) { public BusinessDocument(string title, Member m, bool includeSender = false) : base(title) {
Member = m; Member = m;
Location = App.BranchName; Location = App.BranchLocation;
IncludeSender = includeSender; IncludeSender = includeSender;
var uid = (m.UstIdNr ?? "-") + (m.IsBuchführend ? "" : " <i>(pauschaliert)</i>"); var uid = (m.UstIdNr ?? "-") + (m.IsBuchführend ? "" : " <i>(pauschaliert)</i>");
Aside = $"<table><colgroup><col span='1' style='width: 22.5mm;'/><col span='1' style='width: 42.5mm;'/></colgroup>" + Aside = $"<table><colgroup><col span='1' style='width: 22.5mm;'/><col span='1' style='width: 42.5mm;'/></colgroup>" +

View File

@ -7,7 +7,6 @@
var bucketNum = Model.BucketNames.Length; var bucketNum = Model.BucketNames.Length;
} }
<main> <main>
<div class="date">@Model.Location, am @($"{Model.Date:dd.MM.yyyy}")</div>
<h1>@Model.Title</h1> <h1>@Model.Title</h1>
<table class="credit"> <table class="credit">
<colgroup> <colgroup>

View File

@ -16,6 +16,7 @@ namespace Elwig.Documents {
public CreditNote(Credit c, AppDbContext ctx) : base($"Traubengutschrift Nr. {c.TgId} {c.Payment.Variant.Name}", c.Member) { public CreditNote(Credit c, AppDbContext ctx) : base($"Traubengutschrift Nr. {c.TgId} {c.Payment.Variant.Name}", c.Member) {
UseBillingAddress = true; UseBillingAddress = true;
ShowDateAndLocation = true;
Credit = c; Credit = c;
Aside = Aside.Replace("</table>", "") + Aside = Aside.Replace("</table>", "") +
$"<thead><tr><th colspan='2'>Gutschrift</th></tr></thead><tbody>" + $"<thead><tr><th colspan='2'>Gutschrift</th></tr></thead><tbody>" +

View File

@ -0,0 +1,67 @@
@using RazorLight
@inherits TemplatePage<Elwig.Documents.DeliveryJournal>
@model Elwig.Documents.DeliveryJournal
@{ Layout = "Document"; }
<link rel="stylesheet" href="file:///@Raw(Model.DataPath)\resources\style-deliveryjournal.css"/>
<main>
<h1>Lieferjournal</h1>
<h2>@Model.Filter</h2>
<table class="journal">
<colgroup>
<col style="width: 25mm;"/>
<col style="width: 5mm;"/>
<col style="width: 17mm;"/>
<col style="width: 10mm;"/>
<col style="width: 8mm;"/>
<col style="width: 38mm;"/>
<col style="width: 28mm;"/>
<col style="width: 10mm;"/>
<col style="width: 10mm;"/>
<col style="width: 14mm;"/>
</colgroup>
<thead>
<tr>
<th rowspan="2" style="text-align: left;">Lieferschein-Nr.</th>
<th rowspan="2">Pos.</th>
<th rowspan="2">Datum</th>
<th rowspan="2">Zeit</th>
<th colspan="2" rowspan="2" style="text-align: left;">Mitglied</th>
<th rowspan="2" style="text-align: left;">Sorte</th>
<th colspan="2">Gradation</th>
<th>Gewicht</th>
</tr>
<tr>
<th>[°Oe]</th>
<th>[°KMW]</th>
<th>[kg]</th>
</tr>
</thead>
<tbody>
@foreach (var p in Model.Deliveries) {
<tr>
<td>@p.Delivery.LsNr</td>
<td>@p.DPNr</td>
<td>@($"{p.Delivery.Date:dd.MM.yyyy}")</td>
<td>@($"{p.Delivery.Time:HH:mm}")</td>
<td class="mgnr">@p.Delivery.Member.MgNr</td>
<td>@p.Delivery.Member.AdministrativeName</td>
<td>@p.Variant.Name</td>
<td class="grad">@($"{p.Oe:N0}")</td>
<td class="grad">@($"{p.Kmw:N1}")</td>
<td class="weight">@($"{p.Weight:N0}")</td>
</tr>
}
<tr class="sum">
@{
var kmw = Elwig.Helpers.Utils.AggregateDeliveryPartsKmw(Model.Deliveries);
var oe = Elwig.Helpers.Utils.KmwToOe(kmw);
}
<td colspan="2">Gesamt:</td>
<td colspan="5">(Teil-)Lieferungen: @($"{Model.Deliveries.DistinctBy(p => p.Delivery).Count():N0}") (@($"{Model.Deliveries.Count():N0}"))</td>
<td class="grad">@($"{oe:N0}")</td>
<td class="grad">@($"{kmw:N1}")</td>
<td class="weight">@($"{Model.Deliveries.Sum(p => p.Weight):N0}")</td>
</tr>
</tbody>
</table>
</main>

View File

@ -0,0 +1,25 @@
using Elwig.Helpers;
using Elwig.Models;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Elwig.Documents {
public class DeliveryJournal : Document {
public string Filter;
public IEnumerable<DeliveryPart> Deliveries;
public DeliveryJournal(string filter, IEnumerable<DeliveryPart> deliveries) : base($"Lieferjournal {filter}") {
Filter = filter;
Deliveries = deliveries;
}
public DeliveryJournal(AppDbContext ctx, DateOnly date) :
this(date.ToString("dd.MM.yyyy"), ctx.DeliveryParts
.Where(p => p.Delivery.DateString == date.ToString("yyy-MM-dd"))
.OrderBy(p => p.Delivery.LsNr)
.ThenBy(p => p.DPNr)
.ToList()) { }
}
}

View File

@ -4,7 +4,6 @@
@{ Layout = "BusinessDocument"; } @{ Layout = "BusinessDocument"; }
<link rel="stylesheet" href="file:///@Raw(Model.DataPath)\resources\style-deliverynote.css" /> <link rel="stylesheet" href="file:///@Raw(Model.DataPath)\resources\style-deliverynote.css" />
<main> <main>
<div class="date">@Model.Location, am @($"{Model.Date:dd.MM.yyyy}")</div>
<h1>@Model.Title</h1> <h1>@Model.Title</h1>
@{ @{
bool displayStats = true; // Model.Delivery.Year == Model.CurrentNextSeason bool displayStats = true; // Model.Delivery.Year == Model.CurrentNextSeason
@ -91,7 +90,8 @@
} }
} }
<tr><td></td><td colspan="5"> <tr><td></td><td colspan="5">
@Raw(part.ManualWeighing ? "<i>Handwiegung</i>" : $"<i>Waage:</i> {part.ScaleId ?? "?"}, <i>ID:</i> {part.WeighingId ?? "?"}") (@(part.IsGerebelt ? "gerebelt gewogen" : "nicht gerebelt gewogen")) @Raw(part.ManualWeighing ? "<i>Handwiegung</i>" : $"<i>Waage:</i> {part.ScaleId ?? "?"}, <i>ID:</i> {part.WeighingId ?? "?"}")
(@(part.IsGerebelt ? "gerebelt gewogen" : "nicht gerebelt gewogen"))@Raw(part.WeighingReason != null ? $", <i>Begründung:</i>" : "") @part.WeighingReason
</td></tr> </td></tr>
@if (part.Comment != null) { @if (part.Comment != null) {
<tr><td></td><td colspan="5"><i>Anmerkung:</i> @part.Comment</td></tr> <tr><td></td><td colspan="5"><i>Anmerkung:</i> @part.Comment</td></tr>
@ -127,7 +127,7 @@
</colgroup> </colgroup>
<thead> <thead>
<tr> <tr>
<th><b>Gesamtlieferung</b> [kg]</th> <th><b>Lese @Model.Delivery.Year</b> per @($"{Model.Date:dd.MM.yyyy}") [kg]</th>
<th>Lieferpflicht</th> <th>Lieferpflicht</th>
<th>Lieferrecht</th> <th>Lieferrecht</th>
<th>Unterliefert</th> <th>Unterliefert</th>
@ -147,13 +147,14 @@
$"<td>{sum:N0}</td>"; $"<td>{sum:N0}</td>";
} }
var sortids = Model.Delivery.Parts.Select(p => p.SortId).ToList(); var sortids = Model.Delivery.Parts.Select(p => p.SortId).ToList();
var buckets = Model.MemberBuckets.GroupBy(b => b.Item1[..2]).ToDictionary(g => g.Key, g => g.Count());
} }
<tr> <tr>
<th>Geschäftsanteile</th> <th>Gesamtlieferung</th>
@Raw(FormatRow(Model.Member.DeliveryObligation, Model.Member.DeliveryRight, Model.Member.Deliveries.Where(d => d.Year == Model.Delivery.Year).Sum(d => d.Weight))) @Raw(FormatRow(Model.Member.DeliveryObligation, Model.Member.DeliveryRight, Model.Member.Deliveries.Where(d => d.Year == Model.Delivery.Year).Sum(d => d.Weight)))
</tr> </tr>
@foreach (var (id, name, right, obligation, sum) in Model.MemberBuckets.OrderBy(b => b.Item1)) { @foreach (var (id, name, right, obligation, sum) in Model.MemberBuckets.OrderBy(b => b.Item1)) {
if (right > 0 && obligation > 0) { if (right > 0 || obligation > 0 || (sum > 0 && buckets[id[..2]] > 1 && !id.EndsWith('_'))) {
<tr class="@(sortids.Contains(id[..2]) ? "" : "optional")"> <tr class="@(sortids.Contains(id[..2]) ? "" : "optional")">
<th>@name</th> <th>@name</th>
@Raw(FormatRow(obligation, right, sum)) @Raw(FormatRow(obligation, right, sum))

View File

@ -11,6 +11,7 @@ namespace Elwig.Documents {
public DeliveryNote(Delivery d, AppDbContext ctx) : base($"Traubenübernahmeschein Nr. {d.LsNr}", d.Member) { public DeliveryNote(Delivery d, AppDbContext ctx) : base($"Traubenübernahmeschein Nr. {d.LsNr}", d.Member) {
UseBillingAddress = true; UseBillingAddress = true;
ShowDateAndLocation = true;
Delivery = d; Delivery = d;
Aside = Aside.Replace("</table>", "") + Aside = Aside.Replace("</table>", "") +
$"<thead><tr><th colspan='2'>Lieferung</th></tr></thead><tbody>" + $"<thead><tr><th colspan='2'>Lieferung</th></tr></thead><tbody>" +

View File

@ -18,12 +18,14 @@
<link rel="stylesheet" href="file:///@Raw(Model.DataPath)\resources\style-page.css"/> <link rel="stylesheet" href="file:///@Raw(Model.DataPath)\resources\style-page.css"/>
</head> </head>
<body> <body>
@if (Model.ShowFoldMarks) {
<div class="m1"></div> <div class="m1"></div>
<div class="m2"></div> <div class="m2"></div>
<div class="m3"></div> <div class="m3"></div>
<div class="m1 r"></div> <div class="m1 r"></div>
<div class="m2 r"></div> <div class="m2 r"></div>
<div class="m3 r"></div> <div class="m3 r"></div>
}
<div class="footer-wrapper"> <div class="footer-wrapper">
<div class="pre-footer"> <div class="pre-footer">
<span class="date">@($"{Model.Date:dddd, d. MMMM yyyy}")</span> <span class="date">@($"{Model.Date:dddd, d. MMMM yyyy}")</span>

View File

@ -8,6 +8,8 @@ namespace Elwig.Documents {
private TempFile? PdfFile = null; private TempFile? PdfFile = null;
public bool ShowFoldMarks = App.Config.Debug;
public string DataPath; public string DataPath;
public int CurrentNextSeason; public int CurrentNextSeason;
public string? DocumentId; public string? DocumentId;
@ -22,8 +24,8 @@ namespace Elwig.Documents {
DataPath = App.DataPath; DataPath = App.DataPath;
CurrentNextSeason = Utils.CurrentNextSeason; CurrentNextSeason = Utils.CurrentNextSeason;
Title = title; Title = title;
Author = App.Client.NameFull; Author = c.NameFull;
Header = $"<h1>{c.Name}</h1>"; Header = $"<div class='name'>{c.Name}</div><div class='suffix'>{c.NameSuffix}</div>";
Footer = Utils.GenerateFooter("<br/>", " \u00b7 ") Footer = Utils.GenerateFooter("<br/>", " \u00b7 ")
.Item(c.NameFull).NextLine() .Item(c.NameFull).NextLine()
.Item(c.Address).Item($"{c.Plz} {c.Ort}").Item("Österreich").Item("Tel.", c.PhoneNr).Item("Fax", c.FaxNr).NextLine() .Item(c.Address).Item($"{c.Plz} {c.Ort}").Item("Österreich").Item("Tel.", c.PhoneNr).Item("Fax", c.FaxNr).NextLine()
@ -51,6 +53,8 @@ namespace Elwig.Documents {
name = "DeliveryNote"; name = "DeliveryNote";
} else if (this is CreditNote) { } else if (this is CreditNote) {
name = "CreditNote"; name = "CreditNote";
} else if (this is DeliveryJournal) {
name = "DeliveryJournal";
} else { } else {
throw new InvalidOperationException("Invalid document object"); throw new InvalidOperationException("Invalid document object");
} }

View File

@ -19,6 +19,7 @@ namespace Elwig.Documents {
await e.CompileTemplateAsync("BusinessLetter"); await e.CompileTemplateAsync("BusinessLetter");
await e.CompileTemplateAsync("DeliveryNote"); await e.CompileTemplateAsync("DeliveryNote");
await e.CompileTemplateAsync("CreditNote"); await e.CompileTemplateAsync("CreditNote");
await e.CompileTemplateAsync("DeliveryJournal");
Engine = e; Engine = e;
evtHandler(); evtHandler();

View File

@ -14,6 +14,13 @@
position: relative; position: relative;
} }
.info-wrapper .date {
text-align: right;
position: absolute;
right: 0;
bottom: -1.5em;
}
.address-wrapper { .address-wrapper {
height: 45mm; height: 45mm;
width: 85mm; width: 85mm;
@ -68,6 +75,14 @@ aside table tbody td {
font-size: 10pt; font-size: 10pt;
} }
aside table tbody th {
padding: 0.25mm 0.5mm 0.25mm 1mm;
}
aside table tbody td {
padding: 0.25mm 0;
}
aside table tbody th { aside table tbody th {
font-weight: normal; font-weight: normal;
} }
@ -80,7 +95,7 @@ main > *:first-child {
margin-top: 0; margin-top: 0;
} }
.main-wrapper h1, .main-wrapper p { main h1, .main-wrapper p {
font-size: 12pt; font-size: 12pt;
margin: 1em 0; margin: 1em 0;
text-align: justify; text-align: justify;
@ -92,12 +107,8 @@ main > *:first-child {
hyphens: manual; hyphens: manual;
} }
.main-wrapper .date { main h1 {
margin-bottom: 2em; margin-top: 0;
text-align: right;
}
.main-wrapper h1 {
margin-bottom: 2em; margin-bottom: 2em;
} }

View File

@ -0,0 +1,47 @@
h1 {
text-align: center;
font-size: 24pt;
margin-bottom: 2mm;
}
h2 {
text-align: center;
font-size: 14pt;
margin-top: 2mm;
}
table.journal {
font-size: 10pt;
}
table.journal thead {
font-size: 8pt;
}
table.journal th {
font-weight: normal;
font-style: italic;
}
table.journal td {
overflow: hidden;
white-space: nowrap;
}
table.journal .mgnr,
table.journal .weight {
text-align: right;
}
table.journal .grad {
text-align: center;
}
table.journal tr.sum {
font-weight: bold;
}
table.journal tr.sum td {
border-top: 0.5pt solid black;
}

View File

@ -1,4 +1,8 @@
main h1 {
margin-bottom: 1.5em !important;
}
table.delivery { table.delivery {
margin-bottom: 5mm; margin-bottom: 5mm;
} }

View File

@ -29,7 +29,7 @@ table th {
header { header {
height: 45mm; height: 45mm;
padding: 5mm; padding: 10mm 0 0 0;
position: absolute; position: absolute;
top: -25mm; top: -25mm;
left: 0; left: 0;
@ -38,9 +38,15 @@ header {
overflow: hidden; overflow: hidden;
} }
header h1 { header .name {
font-size: 18pt; font-size: 18pt;
margin-top: 10mm; margin-top: 10mm;
font-weight: bold;
}
header .suffix {
font-size: 12pt;
font-weight: bold;
} }
.footer-wrapper { .footer-wrapper {

View File

@ -7,7 +7,7 @@
<UseWPF>true</UseWPF> <UseWPF>true</UseWPF>
<PreserveCompilationContext>true</PreserveCompilationContext> <PreserveCompilationContext>true</PreserveCompilationContext>
<ApplicationIcon>elwig.ico</ApplicationIcon> <ApplicationIcon>elwig.ico</ApplicationIcon>
<Version>0.2.0</Version> <Version>0.3.2</Version>
<SatelliteResourceLanguages>de-AT</SatelliteResourceLanguages> <SatelliteResourceLanguages>de-AT</SatelliteResourceLanguages>
</PropertyGroup> </PropertyGroup>
@ -19,9 +19,9 @@
<PackageReference Include="Balbarak.WeasyPrint" Version="2.0.2" /> <PackageReference Include="Balbarak.WeasyPrint" Version="2.0.2" />
<PackageReference Include="Extended.Wpf.Toolkit" Version="4.5.1" /> <PackageReference Include="Extended.Wpf.Toolkit" Version="4.5.1" />
<PackageReference Include="ini-parser" Version="2.5.2" /> <PackageReference Include="ini-parser" Version="2.5.2" />
<PackageReference Include="Microsoft.AspNetCore.Razor.Language" Version="6.0.21" /> <PackageReference Include="Microsoft.AspNetCore.Razor.Language" Version="6.0.22" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="7.0.10" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="7.0.11" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.10" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.11" />
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.1938.49" /> <PackageReference Include="Microsoft.Web.WebView2" Version="1.0.1938.49" />
<PackageReference Include="RazorLight" Version="2.3.1" /> <PackageReference Include="RazorLight" Version="2.3.1" />
<PackageReference Include="ScottPlot.WPF" Version="4.1.67" /> <PackageReference Include="ScottPlot.WPF" Version="4.1.67" />

View File

@ -0,0 +1,85 @@
using Microsoft.Data.Sqlite;
using System;
namespace Elwig.Helpers {
public static class AppDbUpdater {
public static readonly int RequiredSchemaVersion = 2;
private static int _versionOffset = 0;
private static readonly Action<SqliteConnection>[] _updaters = new[] {
UpdateDbSchema_1_To_2, UpdateDbSchema_2_To_3
};
private static void ExecuteNonQuery(SqliteConnection cnx, string sql) {
using var cmd = cnx.CreateCommand();
cmd.CommandText = sql;
cmd.ExecuteNonQuery();
}
private static object? ExecuteScalar(SqliteConnection cnx, string sql) {
using var cmd = cnx.CreateCommand();
cmd.CommandText = sql;
return cmd.ExecuteScalar();
}
public static string CheckDb() {
using var cnx = AppDbContext.Connect();
var applId = (long?)ExecuteScalar(cnx, "PRAGMA application_id") ?? 0;
if (applId != 0x454C5747) throw new Exception("Invalid application_id of database");
var schemaVers = (long?)ExecuteScalar(cnx, "PRAGMA schema_version") ?? 0;
_versionOffset = (int)(schemaVers % 100);
if (_versionOffset != 0) {
// schema was modified manually/externally
// TODO issue warning
}
UpdateDbSchema(cnx, (int)(schemaVers / 100), RequiredSchemaVersion);
var userVers = (long?)ExecuteScalar(cnx, "PRAGMA user_version") ?? 0;
var major = userVers >> 24;
var minor = (userVers >> 16) & 0xFF;
var patch = userVers & 0xFFFF;
if (App.VersionMajor > major ||
(App.VersionMajor == major && App.VersionMinor > minor) ||
(App.VersionMajor == major && App.VersionMinor == minor && App.VersionPatch > patch))
{
long vers = (App.VersionMajor << 24) | (App.VersionMinor << 16) | App.VersionPatch;
ExecuteNonQuery(cnx, $"PRAGMA user_version = {vers}");
}
return $"{major}.{minor}.{patch}";
}
private static void UpdateDbSchema(SqliteConnection cnx, int fromVersion, int toVersion) {
if (fromVersion == toVersion) {
return;
} else if (fromVersion > toVersion) {
throw new Exception("schema_version of database is too new");
} else if (toVersion - 1 > _updaters.Length) {
throw new Exception("Unable to update database schema: Updater not implemented");
} else if (fromVersion <= 0) {
throw new Exception("schema_version of database is invalid");
}
ExecuteNonQuery(cnx, "PRAGMA locking_mode = EXCLUSIVE");
ExecuteNonQuery(cnx, "BEGIN EXCLUSIVE");
for (int i = fromVersion; i < toVersion; i++) {
_updaters[i - 1](cnx);
}
ExecuteNonQuery(cnx, "COMMIT");
ExecuteNonQuery(cnx, "VACUUM");
ExecuteNonQuery(cnx, $"PRAGMA schema_version = {toVersion * 100 + _versionOffset}");
}
private static void UpdateDbSchema_1_To_2(SqliteConnection cnx) {
ExecuteNonQuery(cnx, "DROP VIEW v_area_commitment");
ExecuteNonQuery(cnx, "ALTER TABLE delivery_part DROP COLUMN weighing_reason");
ExecuteNonQuery(cnx, "ALTER TABLE delivery_part ADD COLUMN weighing_reason TEXT CHECK(NOT (manual_weighing = FALSE AND weighing_reason IS NOT NULL))");
}
private static void UpdateDbSchema_2_To_3(SqliteConnection cnx) { }
}
}

View File

@ -8,6 +8,7 @@ namespace Elwig.Helpers {
public class Config { public class Config {
private readonly string FileName; private readonly string FileName;
public bool Debug;
public string DatabaseFile = App.DataPath + "database.sqlite3"; public string DatabaseFile = App.DataPath + "database.sqlite3";
public string? DatabaseLog = null; public string? DatabaseLog = null;
public string? Branch = null; public string? Branch = null;
@ -49,6 +50,13 @@ namespace Elwig.Helpers {
Branch = branch; Branch = branch;
} }
if (ini == null || !ini.TryGetKey("general.debug", out string debug)) {
Debug = false;
} else {
debug = debug.ToLower();
Debug = debug == "1" || debug == "true" || debug == "yes" || debug == "on";
}
ScaleList.Clear(); ScaleList.Clear();
Scales = ScaleList; Scales = ScaleList;
if (ini != null) { if (ini != null) {
@ -72,6 +80,7 @@ namespace Elwig.Helpers {
using var file = new StreamWriter(FileName, false, Utils.UTF8); using var file = new StreamWriter(FileName, false, Utils.UTF8);
file.Write($"\r\n[general]\r\n"); file.Write($"\r\n[general]\r\n");
if (Branch != null) file.Write($"branch = {Branch}\r\n"); if (Branch != null) file.Write($"branch = {Branch}\r\n");
if (Debug) file.Write("debug = true\r\n");
file.Write($"\r\n[database]\r\nfile = {DatabaseFile}\r\n"); file.Write($"\r\n[database]\r\nfile = {DatabaseFile}\r\n");
if (DatabaseLog != null) file.Write($"log = {DatabaseLog}\r\n"); if (DatabaseLog != null) file.Write($"log = {DatabaseLog}\r\n");
foreach (var s in ScaleList) { foreach (var s in ScaleList) {

View File

@ -193,34 +193,33 @@ namespace Elwig.Helpers {
if (!searchKeywords.Any()) if (!searchKeywords.Any())
return 0; return 0;
return words return searchKeywords
.Select(w => { .Select(k => {
k = k.ToLower();
var scores = words.Select(w => {
w = w?.ToLower(); w = w?.ToLower();
var p = w?.ToLower()?.Split(" "); var p = w?.ToLower()?.Split(" ");
if (w == null || p == null) if (w == null || p == null) {
return 0; return 0;
} else if (k == w) {
var t1 = searchKeywords.Where(f => w == f).Select(f => f.Length).OrderDescending().FirstOrDefault(0); return 4 + k.Length;
var t2 = searchKeywords.Where(f => p.Any(a => a == f)).Select(f => f.Length).OrderDescending().FirstOrDefault(0); } else if (p.Any(a => a == k)) {
var t3 = searchKeywords.Where(f => p.Any(a => a.StartsWith(f))).Select(f => f.Length).OrderDescending().FirstOrDefault(0); return 3 + k.Length;
var t4 = searchKeywords.Where(f => w.Contains(f)).Select(f => f.Length).OrderDescending().FirstOrDefault(0); } else if (p.Any(a => a.StartsWith(k))) {
if (t1 > 0) { return 2 + k.Length;
return 4 + t1; } else if (w.Contains(k)) {
} else if (t2 > 0) { return 1 + k.Length;
return 3 + t2;
} else if (t3 > 0) {
return 2 + t3;
} else if (t4 > 0) {
return 1 + t4;
} else { } else {
return 0; return 0;
} }
});
return scores.Max() + scores.Count(s => s > 0);
}) })
.Sum(); .Sum();
} }
public static (int, string?)? ShowManualWeighingDialog() { public static (int, string?)? ShowManualWeighingDialog(string? reason = null) {
var d = new ManualWeighingDialog(); var d = new ManualWeighingDialog(reason);
return d.ShowDialog() == true ? (d.Weight, d.Reason) : null; return d.ShowDialog() == true ? (d.Weight, d.Reason) : null;
} }

View File

@ -70,9 +70,9 @@ namespace Elwig.Helpers {
for (int i = 0; i < input.Text.Length; i++) { for (int i = 0; i < input.Text.Length; i++) {
char ch = input.Text[i]; char ch = input.Text[i];
if (char.IsAsciiDigit(ch)) { if (char.IsAsciiDigit(ch)) {
if (v2 == -1 && v1 < maxLen) { if (v2 == -1 && (maxLen == -1 || v1 < maxLen)) {
text += ch; v1++; text += ch; v1++;
} else if (v2 != -1 && v2 < maxDecimal) { } else if (v2 != -1 && (maxDecimal == -1 || v2 < maxDecimal)) {
text += ch; v2++; text += ch; v2++;
} }
} else if (v2 == 0-1 && ch == ',' || ch == '.') { } else if (v2 == 0-1 && ch == ',' || ch == '.') {

View File

@ -87,6 +87,9 @@ namespace Elwig.Models {
[Column("weighing_id")] [Column("weighing_id")]
public string? WeighingId { get; set; } public string? WeighingId { get; set; }
[Column("weighing_reason")]
public string? WeighingReason { get; set; }
[Column("comment")] [Column("comment")]
public string? Comment { get; set; } public string? Comment { get; set; }

View File

@ -128,9 +128,6 @@ namespace Elwig.Models {
[Column("address")] [Column("address")]
public string Address { get; set; } public string Address { get; set; }
[Column("email")]
public string? Email { get; set; }
[Column("default_kgnr")] [Column("default_kgnr")]
public int? DefaultKgNr { get; set; } public int? DefaultKgNr { get; set; }
@ -174,6 +171,9 @@ namespace Elwig.Models {
[InverseProperty("Member")] [InverseProperty("Member")]
public virtual ISet<MemberTelNr> TelephoneNumbers { get; private set; } public virtual ISet<MemberTelNr> TelephoneNumbers { get; private set; }
[InverseProperty("member")]
public virtual ISet<MemberEmailAddr> EmailAddresses { get; private set; }
public string FullAddress => $"{Address}, {PostalDest.AtPlz.Plz} {PostalDest.AtPlz.Ort.Name}"; public string FullAddress => $"{Address}, {PostalDest.AtPlz.Plz} {PostalDest.AtPlz.Ort.Name}";
public int DeliveryRight => BusinessShares * App.Client.DeliveryRight; public int DeliveryRight => BusinessShares * App.Client.DeliveryRight;

View File

@ -0,0 +1,22 @@
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations.Schema;
namespace Elwig.Models {
[Table("member_email_address"), PrimaryKey("MgNr", "Nr")]
public class MemberEmailAddr {
[Column("mgnr")]
public int MgNr { get; set; }
[Column("nr")]
public int Nr { get; set; }
[Column("address")]
public string Address { get; set; }
[Column("comment")]
public string? Comment { get; set; }
[ForeignKey("MgNr")]
public virtual Member Member { get; private set; }
}
}

View File

@ -16,20 +16,20 @@ namespace Elwig.Windows {
protected Control[] ExemptInputs { private get; set; } protected Control[] ExemptInputs { private get; set; }
protected Control[] RequiredInputs { private get; set; } protected Control[] RequiredInputs { private get; set; }
private bool _IsEditing; private bool _isEditing;
private bool _IsCreating; private bool _isCreating;
protected bool IsEditing { protected bool IsEditing {
get { return _IsEditing; } get { return _isEditing; }
set { set {
_IsEditing = value; _isEditing = value;
LockContext = IsEditing; LockContext = IsEditing || IsCreating;
} }
} }
protected bool IsCreating { protected bool IsCreating {
get { return _IsCreating; } get { return _isCreating; }
set { set {
_IsCreating = value; _isCreating = value;
LockContext = IsEditing; LockContext = IsEditing || IsCreating;
} }
} }
protected bool DoShowWarningWindows = true; protected bool DoShowWarningWindows = true;
@ -99,7 +99,7 @@ namespace Elwig.Windows {
abstract protected void UpdateButtons(); abstract protected void UpdateButtons();
protected override async Task RenewContext() { protected override async Task OnRenewContext() {
for (int i = 0; i < PlzInputs.Length; i++) for (int i = 0; i < PlzInputs.Length; i++)
UpdatePlz(PlzInputs[i], PlzOrtInputs[i]); UpdatePlz(PlzInputs[i], PlzOrtInputs[i]);
} }
@ -413,7 +413,7 @@ namespace Elwig.Windows {
UpdateButtons(); UpdateButtons();
} }
protected void TextBox_TextChanged(object sender, RoutedEventArgs evt) { protected void TextBox_TextChanged(object sender, RoutedEventArgs? evt) {
var input = (TextBox)sender; var input = (TextBox)sender;
if (SenderIsRequired(input) && input.Text.Length == 0) { if (SenderIsRequired(input) && input.Text.Length == 0) {
ValidateInput(input, false); ValidateInput(input, false);
@ -462,6 +462,10 @@ namespace Elwig.Windows {
InputTextChanged((TextBox)sender, Validator.CheckInteger); InputTextChanged((TextBox)sender, Validator.CheckInteger);
} }
protected void DecimalInput_TextChanged(object sender, RoutedEventArgs evt) {
InputTextChanged((TextBox)sender, Validator.CheckDecimal);
}
protected void PartialDateInput_TextChanged(object sender, RoutedEventArgs evt) { protected void PartialDateInput_TextChanged(object sender, RoutedEventArgs evt) {
InputTextChanged((TextBox)sender, Validator.CheckPartialDate); InputTextChanged((TextBox)sender, Validator.CheckPartialDate);
} }

View File

@ -131,6 +131,10 @@
<Label Content="Bewirt.-Art:" Margin="10,100,0,0" Grid.Column="0" Grid.ColumnSpan="2"/> <Label Content="Bewirt.-Art:" Margin="10,100,0,0" Grid.Column="0" Grid.ColumnSpan="2"/>
<ComboBox x:Name="WineCultivationInput" DisplayMemberPath="Name" TextSearch.TextPath="Name" <ComboBox x:Name="WineCultivationInput" DisplayMemberPath="Name" TextSearch.TextPath="Name"
HorizontalAlignment="Stretch" Margin="0,100,10,0" Grid.Column="1" Grid.ColumnSpan="3"/> HorizontalAlignment="Stretch" Margin="0,100,10,0" Grid.Column="1" Grid.ColumnSpan="3"/>
<Label Content="Anmerkung:" Margin="10,130,0,0" Grid.Column="0" Grid.ColumnSpan="2"/>
<TextBox x:Name="CommentInput" TextChanged="TextBox_TextChanged"
HorizontalAlignment="Stretch" Margin="0,130,10,0" Grid.Column="1" Grid.ColumnSpan="3"/>
</Grid> </Grid>
</GroupBox> </GroupBox>

View File

@ -40,11 +40,8 @@ namespace Elwig.Windows {
private async Task RefreshAreaCommitmentListQuery() { private async Task RefreshAreaCommitmentListQuery() {
List<AreaCom> areaComs = await Context.AreaCommitments.Where(a => a.MgNr == Member.MgNr).OrderBy(a => a.FbNr).ToListAsync(); List<AreaCom> areaComs = await Context.AreaCommitments.Where(a => a.MgNr == Member.MgNr).OrderBy(a => a.FbNr).ToListAsync();
ControlUtils.RenewItemsSource(AreaCommitmentList, areaComs, i => (i as AreaCom)?.FbNr,
ControlUtils.RenewItemsSource(AreaCommitmentList, areaComs, i => (i as AreaCom)?.FbNr); AreaCommitmentList_SelectionChanged, ControlUtils.RenewSourceDefault.None);
if (areaComs.Count == 1)
AreaCommitmentList.SelectedIndex = 0;
RefreshInputs(); RefreshInputs();
} }
@ -82,6 +79,8 @@ namespace Elwig.Windows {
AreaComTypeInput.SelectedItem = a.AreaComType; AreaComTypeInput.SelectedItem = a.AreaComType;
WineCultivationInput.SelectedItem = a.WineCult; WineCultivationInput.SelectedItem = a.WineCult;
CommentInput.Text = a.Comment;
FinishInputFilling(); FinishInputFilling();
} }
@ -96,8 +95,8 @@ namespace Elwig.Windows {
ValidateRequiredInputs(); ValidateRequiredInputs();
} }
protected override async Task RenewContext() { protected override async Task OnRenewContext() {
await base.RenewContext(); await base.OnRenewContext();
ControlUtils.RenewItemsSource(KgInput, await Context.WbKgs.Select(k => k.AtKg).OrderBy(k => k.Name).ToListAsync(), i => (i as AT_Kg)?.KgNr); ControlUtils.RenewItemsSource(KgInput, await Context.WbKgs.Select(k => k.AtKg).OrderBy(k => k.Name).ToListAsync(), i => (i as AT_Kg)?.KgNr);
ControlUtils.RenewItemsSource(AreaComTypeInput, await Context.AreaCommitmentTypes.OrderBy(v => v.VtrgId).ToListAsync(), i => (i as AreaComType)?.VtrgId); ControlUtils.RenewItemsSource(AreaComTypeInput, await Context.AreaCommitmentTypes.OrderBy(v => v.VtrgId).ToListAsync(), i => (i as AreaComType)?.VtrgId);
ControlUtils.RenewItemsSource(WineCultivationInput, await Context.WineCultivations.OrderBy(c => c.Name).ToListAsync(), i => (i as WineCult)?.CultId); ControlUtils.RenewItemsSource(WineCultivationInput, await Context.WineCultivations.OrderBy(c => c.Name).ToListAsync(), i => (i as WineCult)?.CultId);
@ -151,6 +150,7 @@ namespace Elwig.Windows {
a.Area = int.Parse(AreaInput.Text); a.Area = int.Parse(AreaInput.Text);
a.VtrgId = (AreaComTypeInput.SelectedItem as AreaComType)?.VtrgId; a.VtrgId = (AreaComTypeInput.SelectedItem as AreaComType)?.VtrgId;
a.CultId = (WineCultivationInput.SelectedItem as WineCult)?.CultId; a.CultId = (WineCultivationInput.SelectedItem as WineCult)?.CultId;
a.Comment = (CommentInput.Text == "") ? null : CommentInput.Text;
EntityEntry<AreaCom>? tr = null; EntityEntry<AreaCom>? tr = null;
try { try {

View File

@ -52,8 +52,8 @@ namespace Elwig.Windows {
FillInputs(App.Client); FillInputs(App.Client);
} }
protected override async Task RenewContext() { protected override async Task OnRenewContext() {
await base.RenewContext(); await base.OnRenewContext();
ControlUtils.RenewItemsSource(SeasonList, await Context.Seasons.OrderByDescending(s => s.Year).ToListAsync(), s => (s as Season)?.Year, null, ControlUtils.RenewSourceDefault.First); ControlUtils.RenewItemsSource(SeasonList, await Context.Seasons.OrderByDescending(s => s.Year).ToListAsync(), s => (s as Season)?.Year, null, ControlUtils.RenewSourceDefault.First);
var year = (SeasonList.SelectedItem as Season)?.Year; var year = (SeasonList.SelectedItem as Season)?.Year;
ControlUtils.RenewItemsSource(SeasonModifierList, await Context.Modifiers.Where(m => m.Year == year).OrderBy(m => m.Ordering).ToListAsync(), m => (m as Modifier)?.ModId); ControlUtils.RenewItemsSource(SeasonModifierList, await Context.Modifiers.Where(m => m.Year == year).OrderBy(m => m.Ordering).ToListAsync(), m => (m as Modifier)?.ModId);
@ -117,6 +117,7 @@ namespace Elwig.Windows {
await Context.SaveChangesAsync(); await Context.SaveChangesAsync();
foreach (var mod in ModifierList.Where(m => !ModifierIds.ContainsKey(m))) { foreach (var mod in ModifierList.Where(m => !ModifierIds.ContainsKey(m))) {
if (mod.ModId == null) continue;
await Context.AddAsync(mod); await Context.AddAsync(mod);
} }
await Context.SaveChangesAsync(); await Context.SaveChangesAsync();
@ -321,6 +322,7 @@ namespace Elwig.Windows {
} }
private void SeasonModifierRelInput_TextChanged(object sender, TextChangedEventArgs evt) { private void SeasonModifierRelInput_TextChanged(object sender, TextChangedEventArgs evt) {
// DecimalInput_TextChanged(sender, evt); FIXME '-' is ignored
if ((!IsEditing && !IsCreating) || SeasonModifierList.SelectedItem is not Modifier mod) return; if ((!IsEditing && !IsCreating) || SeasonModifierList.SelectedItem is not Modifier mod) return;
ModifiersChanged = ModifiersChanged || (SeasonModifierRelInput.Text ?? "") != ((SeasonModifierList.SelectedItem as Modifier)?.Rel?.ToString() ?? ""); ModifiersChanged = ModifiersChanged || (SeasonModifierRelInput.Text ?? "") != ((SeasonModifierList.SelectedItem as Modifier)?.Rel?.ToString() ?? "");
if (ModifierUpdate) return; if (ModifierUpdate) return;
@ -331,11 +333,13 @@ namespace Elwig.Windows {
} }
private void SeasonModifierAbsInput_TextChanged(object sender, TextChangedEventArgs evt) { private void SeasonModifierAbsInput_TextChanged(object sender, TextChangedEventArgs evt) {
if ((!IsEditing && !IsCreating) || SeasonModifierList.SelectedItem is not Modifier mod) return; // DecimalInput_TextChanged(sender, evt); FIXME '-' is ignored
if ((!IsEditing && !IsCreating) || SeasonModifierList.SelectedItem is not Modifier mod || SeasonList.SelectedItem is not Season s) return;
ModifiersChanged = ModifiersChanged || (SeasonModifierAbsInput.Text ?? "") != ((SeasonModifierList.SelectedItem as Modifier)?.Abs?.ToString() ?? ""); ModifiersChanged = ModifiersChanged || (SeasonModifierAbsInput.Text ?? "") != ((SeasonModifierList.SelectedItem as Modifier)?.Abs?.ToString() ?? "");
if (ModifierUpdate) return; if (ModifierUpdate) return;
mod.Abs = decimal.TryParse(SeasonModifierAbsInput.Text, out var v) ? v : null; // FIXME ValueStr does not work in ModifierList when modifier is newly created
if (mod.Abs != null) SeasonModifierRelInput.Text = ""; mod.AbsValue = decimal.TryParse(SeasonModifierAbsInput.Text, out var v) ? Utils.DecToDb(v, s.Precision) : null;
if (mod.AbsValue != null) SeasonModifierRelInput.Text = "";
CollectionViewSource.GetDefaultView(ModifierList).Refresh(); CollectionViewSource.GetDefaultView(ModifierList).Refresh();
UpdateButtons(); UpdateButtons();
} }

View File

@ -214,8 +214,8 @@ namespace Elwig.Windows {
FinishInputFilling(); FinishInputFilling();
} }
protected override async Task RenewContext() { protected override async Task OnRenewContext() {
await base.RenewContext(); await base.OnRenewContext();
await RefreshGraphList(); await RefreshGraphList();
} }

View File

@ -7,30 +7,32 @@ using System.Windows.Threading;
namespace Elwig.Windows { namespace Elwig.Windows {
public abstract class ContextWindow : Window { public abstract class ContextWindow : Window {
public static readonly int RenewSec = 10;
protected AppDbContext Context { get; private set; } protected AppDbContext Context { get; private set; }
protected bool LockContext { get; set; } = false; protected bool LockContext { get; set; } = false;
private readonly DispatcherTimer ContextRenewTimer; private readonly DispatcherTimer _timer;
private static readonly int ContextRenewSec = 10; private bool _renewPending = false;
public ContextWindow() : base() { public ContextWindow() : base() {
ContextRenewTimer = new DispatcherTimer(); _timer = new DispatcherTimer();
ContextRenewTimer.Tick += new EventHandler(OnRenewContext); _timer.Tick += new EventHandler(OnShouldRenewContext);
ContextRenewTimer.Interval = new TimeSpan(0, 0, ContextRenewSec); _timer.Interval = new TimeSpan(0, 0, RenewSec);
ContextRenewTimer.Start(); _timer.Start();
Context = new(); Context = new();
Loaded += OnLoaded; Loaded += OnLoaded;
} }
private void OnRenewContext(object? sender, EventArgs evt) { private async void OnShouldRenewContext(object? sender, EventArgs evt) {
if (LockContext || !Context.HasBackendChanged) return; if (!Context.HasBackendChanged) return;
Context.Dispose(); _renewPending = true;
Context = new(); if (LockContext) return;
RenewContext().GetAwaiter().GetResult(); await RenewContext();
} }
private void OnLoaded(object sender, RoutedEventArgs evt) { private void OnLoaded(object sender, RoutedEventArgs evt) {
RenewContext().GetAwaiter().GetResult(); OnRenewContext().GetAwaiter().GetResult();
} }
protected override void OnClosed(EventArgs evt) { protected override void OnClosed(EventArgs evt) {
@ -38,6 +40,14 @@ namespace Elwig.Windows {
Context.Dispose(); Context.Dispose();
} }
abstract protected Task RenewContext(); protected async Task RenewContext() {
if (!_renewPending) return;
Context.Dispose();
Context = new();
await OnRenewContext();
_renewPending = false;
}
abstract protected Task OnRenewContext();
} }
} }

View File

@ -63,6 +63,10 @@
Click="Menu_Print_ShowDeliveryNote_Click"/> Click="Menu_Print_ShowDeliveryNote_Click"/>
<MenuItem x:Name="Menu_Print_PrintDeliveryNote" Header="Lieferschein drucken" IsEnabled="False" <MenuItem x:Name="Menu_Print_PrintDeliveryNote" Header="Lieferschein drucken" IsEnabled="False"
Click="Menu_Print_PrintDeliveryNote_Click"/> Click="Menu_Print_PrintDeliveryNote_Click"/>
<MenuItem x:Name="Menu_Print_ShowDeliveryJournalToday" Header="Lieferjournal anzeigen (heute)"
Click="Menu_Print_ShowDeliveryJournalToday_Click"/>
<MenuItem x:Name="Menu_Print_ShowDeliveryJournalYesterday" Header="Lieferjournal anzeigen (gestern)"
Click="Menu_Print_ShowDeliveryJournalYesterday_Click"/>
</MenuItem> </MenuItem>
<MenuItem Header="Exportieren"> <MenuItem Header="Exportieren">
<MenuItem x:Name="Menu_Export_Bki" Header="Traubentransportscheinliste (BKI)"/> <MenuItem x:Name="Menu_Export_Bki" Header="Traubentransportscheinliste (BKI)"/>
@ -230,20 +234,20 @@
<Label Content="Gradation:" Margin="10,10,10,10"/> <Label Content="Gradation:" Margin="10,10,10,10"/>
<Grid Grid.Column="1" Width="54" Height="25" Margin="0,10,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"> <Grid Grid.Column="1" Width="54" Height="25" Margin="0,10,10,10" HorizontalAlignment="Left" VerticalAlignment="Top">
<TextBox x:Name="GradationOeInput" TextAlignment="Right" Padding="2,2,23,2" <TextBox x:Name="GradationOeInput" TextAlignment="Right" Padding="2,2,23,2"
TextChanged="GradationOeInput_TextChanged" LostFocus="GradationOeInput_LostFocus"/> TextChanged="GradationOeInput_TextChanged" LostFocus="GradationOeInput_LostFocus" KeyUp="Input_KeyUp"/>
<Label Content="°Oe" Margin="0,4,3,0" HorizontalAlignment="Right" FontSize="10"/> <Label Content="°Oe" Margin="0,4,3,0" HorizontalAlignment="Right" FontSize="10"/>
</Grid> </Grid>
<Label Content="=" Margin="60,10,10,10" Grid.Column="1"/> <Label Content="=" Margin="60,10,10,10" Grid.Column="1"/>
<Grid Grid.Column="1" Width="68" Height="25" Margin="78,10,10,10" HorizontalAlignment="Left" VerticalAlignment="Top"> <Grid Grid.Column="1" Width="68" Height="25" Margin="78,10,10,10" HorizontalAlignment="Left" VerticalAlignment="Top">
<TextBox x:Name="GradationKmwInput" TextAlignment="Right" Padding="2,2,34,2" SnapsToDevicePixels="True" <TextBox x:Name="GradationKmwInput" TextAlignment="Right" Padding="2,2,34,2" SnapsToDevicePixels="True"
TextChanged="GradationKmwInput_TextChanged" LostFocus="GradationKmwInput_LostFocus"/> TextChanged="GradationKmwInput_TextChanged" LostFocus="GradationKmwInput_LostFocus" KeyUp="Input_KeyUp"/>
<Label Content="°KMW" Margin="0,4,3,0" HorizontalAlignment="Right" FontSize="10"/> <Label Content="°KMW" Margin="0,4,3,0" HorizontalAlignment="Right" FontSize="10"/>
</Grid> </Grid>
<Label Content="Qualitätsstufe:" Margin="10,40,10,10"/> <Label Content="Qualitätsstufe:" Margin="10,40,10,10"/>
<ComboBox x:Name="WineQualityLevelInput" Width="146" Margin="0,40,10,10" Grid.Column="1" HorizontalAlignment="Left" <ComboBox x:Name="WineQualityLevelInput" Width="146" Margin="0,40,10,10" Grid.Column="1" HorizontalAlignment="Left"
ItemTemplate="{StaticResource WineQualityLevelTemplate}" ItemTemplate="{StaticResource WineQualityLevelTemplate}"
SelectionChanged="WineQualityLevelInput_SelectionChanged"/> SelectionChanged="WineQualityLevelInput_SelectionChanged" KeyUp="Input_KeyUp"/>
<CheckBox x:Name="AbgewertetInput" Content="Abgewertet" IsEnabled="False" <CheckBox x:Name="AbgewertetInput" Content="Abgewertet" IsEnabled="False"
VerticalAlignment="Top" HorizontalAlignment="Left" Margin="10,75,10,10" Grid.Column="0" Grid.ColumnSpan="2"/> VerticalAlignment="Top" HorizontalAlignment="Left" Margin="10,75,10,10" Grid.Column="0" Grid.ColumnSpan="2"/>
@ -272,22 +276,21 @@
VerticalAlignment="Top" HorizontalAlignment="Left" Margin="10,75,10,10" Grid.Column="0" Grid.ColumnSpan="2" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="10,75,10,10" Grid.Column="0" Grid.ColumnSpan="2"
Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"/> Checked="CheckBox_Changed" Unchecked="CheckBox_Changed"/>
<Button x:Name="WeighingManualButton" Content="Handwiegung" Width="120"
Click="WeighingManualButton_Click"
VerticalAlignment="Top" HorizontalAlignment="Right" Margin="10,10,10,10" Grid.Column="2"/>
<Button x:Name="WeighingAButton" Content="Wiegen A" Width="120" <Button x:Name="WeighingAButton" Content="Wiegen A" Width="120"
Click="WeighingButton_Click" Click="WeighingButton_Click"
VerticalAlignment="Top" HorizontalAlignment="Right" Margin="10,42,10,10" Grid.Column="2"/> VerticalAlignment="Top" HorizontalAlignment="Right" Margin="10,10,10,10" Grid.Column="2"/>
<Button x:Name="WeighingBButton" Content="Wiegen B" Width="120" <Button x:Name="WeighingBButton" Content="Wiegen B" Width="120"
Click="WeighingButton_Click" Click="WeighingButton_Click"
VerticalAlignment="Top" HorizontalAlignment="Right" Margin="10,74,10,10" Grid.Column="2"/> VerticalAlignment="Top" HorizontalAlignment="Right" Margin="10,42,10,10" Grid.Column="2"/>
<Button x:Name="WeighingCButton" Content="Wiegen C" Width="120" <Button x:Name="WeighingCButton" Content="Wiegen C" Width="120"
Click="WeighingButton_Click" Click="WeighingButton_Click"
VerticalAlignment="Top" HorizontalAlignment="Right" Margin="10,106,10,10" Grid.Column="2"/> VerticalAlignment="Top" HorizontalAlignment="Right" Margin="10,74,10,10" Grid.Column="2"/>
<Button x:Name="WeighingDButton" Content="Wiegen D" Width="120" <Button x:Name="WeighingDButton" Content="Wiegen D" Width="120"
Click="WeighingButton_Click" Click="WeighingButton_Click"
VerticalAlignment="Top" HorizontalAlignment="Right" Margin="10,106,10,10" Grid.Column="2"/>
<Button x:Name="WeighingManualButton" Content="Handwiegung" Width="120"
Click="WeighingManualButton_Click"
VerticalAlignment="Top" HorizontalAlignment="Right" Margin="10,138,10,10" Grid.Column="2"/> VerticalAlignment="Top" HorizontalAlignment="Right" Margin="10,138,10,10" Grid.Column="2"/>
</Grid> </Grid>
</GroupBox> </GroupBox>

View File

@ -25,6 +25,7 @@ namespace Elwig.Windows {
private List<string> TextFilter = new(); private List<string> TextFilter = new();
private readonly RoutedCommand CtrlF = new(); private readonly RoutedCommand CtrlF = new();
private string? LastScaleError = null;
private string? ManualWeighingReason = null; private string? ManualWeighingReason = null;
private string? ScaleId = null; private string? ScaleId = null;
private string? WeighingId = null; private string? WeighingId = null;
@ -75,6 +76,7 @@ namespace Elwig.Windows {
if (n >= 2) WeighingBButton.Content = $"Wiegen {App.Scales[1].ScaleId}"; if (n >= 2) WeighingBButton.Content = $"Wiegen {App.Scales[1].ScaleId}";
if (n >= 3) WeighingCButton.Content = $"Wiegen {App.Scales[2].ScaleId}"; if (n >= 3) WeighingCButton.Content = $"Wiegen {App.Scales[2].ScaleId}";
if (n >= 4) WeighingDButton.Content = $"Wiegen {App.Scales[3].ScaleId}"; if (n >= 4) WeighingDButton.Content = $"Wiegen {App.Scales[3].ScaleId}";
WeighingManualButton.Margin = new Thickness(10, 10 + n * 32, 10, 10);
} else { } else {
WeighingManualButton.Visibility = Visibility.Hidden; WeighingManualButton.Visibility = Visibility.Hidden;
WeighingAButton.Visibility = Visibility.Hidden; WeighingAButton.Visibility = Visibility.Hidden;
@ -91,13 +93,13 @@ namespace Elwig.Windows {
AllSeasonsInput.IsChecked = true; AllSeasonsInput.IsChecked = true;
} }
private async void Window_Loaded(object sender, RoutedEventArgs evt) { private void Window_Loaded(object sender, RoutedEventArgs evt) {
OnSecondPassed(null, null); OnSecondPassed(null, null);
Timer.Start(); Timer.Start();
LockInputs(); LockInputs();
if (IsReceipt) { if (IsReceipt) {
NewDeliveryButton_Click(null, null); NewDeliveryButton_Click(null, null);
if ((await Context.Seasons.FindAsync(Utils.CurrentYear)) == null) { if ((Context.Seasons.Find(Utils.CurrentYear)) == null) {
MessageBox.Show("Die Saison für das aktuelle Jahr wurde noch nicht erstellt. Neue Lieferungen können nicht abgespeichert werden.", MessageBox.Show("Die Saison für das aktuelle Jahr wurde noch nicht erstellt. Neue Lieferungen können nicht abgespeichert werden.",
"Saison noch nicht erstellt", MessageBoxButton.OK, MessageBoxImage.Error); "Saison noch nicht erstellt", MessageBoxButton.OK, MessageBoxImage.Error);
} }
@ -126,8 +128,9 @@ namespace Elwig.Windows {
if (sender is not MenuItem m) return; if (sender is not MenuItem m) return;
var year = int.Parse(m.Header.ToString()?.Split(" ")[^1] ?? Utils.CurrentLastSeason.ToString()); var year = int.Parse(m.Header.ToString()?.Split(" ")[^1] ?? Utils.CurrentLastSeason.ToString());
var d = new SaveFileDialog() { var d = new SaveFileDialog() {
FileName = $"{App.Client.NameToken}-Traubentransportscheinliste-{year}", FileName = $"{App.Client.NameToken}-Traubentransportscheinliste-{year}.{Bki.FileExtension}",
DefaultExt = Bki.FileExtension, DefaultExt = Bki.FileExtension,
Filter = "CSV-Datei (*.csv)|*.csv",
Title = $"Traubentransportscheinliste (BKI) speichern unter - Elwig" Title = $"Traubentransportscheinliste (BKI) speichern unter - Elwig"
}; };
if (d.ShowDialog() == true) { if (d.ShowDialog() == true) {
@ -138,6 +141,22 @@ namespace Elwig.Windows {
} }
} }
private async void Menu_Print_ShowDeliveryJournalToday_Click(object sender, RoutedEventArgs evt) {
Mouse.OverrideCursor = Cursors.Wait;
var doc = new DeliveryJournal(Context, DateOnly.FromDateTime(Utils.Today));
await doc.Generate();
Mouse.OverrideCursor = null;
doc.Show();
}
private async void Menu_Print_ShowDeliveryJournalYesterday_Click(object sender, RoutedEventArgs evt) {
Mouse.OverrideCursor = Cursors.Wait;
var doc = new DeliveryJournal(Context, DateOnly.FromDateTime(Utils.Today.AddDays(-1)));
await doc.Generate();
Mouse.OverrideCursor = null;
doc.Show();
}
private void OnSecondPassed(object? sender, EventArgs? evt) { private void OnSecondPassed(object? sender, EventArgs? evt) {
if (IsReceipt && IsCreating) { if (IsReceipt && IsCreating) {
var now = DateTime.Now; var now = DateTime.Now;
@ -147,6 +166,11 @@ namespace Elwig.Windows {
} }
private void InitialInputs() { private void InitialInputs() {
LastScaleError = null;
WeighingId = null;
ScaleId = null;
ManualWeighingReason = null;
ClearOriginalValues(); ClearOriginalValues();
ClearDefaultValues(); ClearDefaultValues();
@ -188,9 +212,14 @@ namespace Elwig.Windows {
if (sender is not Control ctrl) return; if (sender is not Control ctrl) return;
if (evt.Key != Key.Enter) return; if (evt.Key != Key.Enter) return;
if (ctrl == MgNrInput || ctrl == MemberInput) { if (ctrl == MgNrInput || ctrl == MemberInput) {
SortIdInput.Focus(); SortIdInput.SelectAll(); SortIdInput.Focus();
SortIdInput.SelectAll();
} else if (ctrl == SortIdInput || ctrl == WineVarietyInput || ctrl == AttributesInput) { } else if (ctrl == SortIdInput || ctrl == WineVarietyInput || ctrl == AttributesInput) {
GradationOeInput.Focus(); GradationOeInput.SelectAll(); GradationOeInput.Focus();
GradationOeInput.SelectAll();
} else if (ctrl == GradationKmwInput || ctrl == GradationOeInput || ctrl == WineQualityLevelInput) {
if (WeighingAButton.IsVisible) WeighingAButton.Focus();
else WeighingManualButton.Focus();
} }
} }
@ -331,7 +360,8 @@ namespace Elwig.Windows {
.ToList(); .ToList();
} }
ControlUtils.RenewItemsSource(DeliveryList, deliveries, d => ((d as Delivery)?.Year, (d as Delivery)?.DId), DeliveryList_SelectionChanged, IsCreating ? ControlUtils.RenewSourceDefault.None : ControlUtils.RenewSourceDefault.IfOnly, !updateSort); ControlUtils.RenewItemsSource(DeliveryList, deliveries, d => ((d as Delivery)?.Year, (d as Delivery)?.DId),
DeliveryList_SelectionChanged, filter.Count > 0 ? ControlUtils.RenewSourceDefault.IfOnly : ControlUtils.RenewSourceDefault.None, !updateSort);
var members = deliveries.Select(d => d.Member).DistinctBy(m => m.MgNr).ToList(); var members = deliveries.Select(d => d.Member).DistinctBy(m => m.MgNr).ToList();
StatusMembers.Text = $"Mitglieder: {members.Count}" + (members.Count > 0 && members.Count <= 4 ? $" ({string.Join(", ", members.Select(m => m.AdministrativeName))})" : ""); StatusMembers.Text = $"Mitglieder: {members.Count}" + (members.Count > 0 && members.Count <= 4 ? $" ({string.Join(", ", members.Select(m => m.AdministrativeName))})" : "");
@ -402,8 +432,8 @@ namespace Elwig.Windows {
} }
} }
protected override async Task RenewContext() { protected override async Task OnRenewContext() {
await base.RenewContext(); await base.OnRenewContext();
if (Member != null) { if (Member != null) {
if (Context.Members.Find(Member.MgNr) is not Member m) { if (Context.Members.Find(Member.MgNr) is not Member m) {
@ -423,7 +453,6 @@ namespace Elwig.Windows {
Menu_Export_Bki.Items.Add(i); Menu_Export_Bki.Items.Add(i);
} }
// FIXME on "only one" delivery, RenewContext doees not work
await RefreshDeliveryList(); await RefreshDeliveryList();
var d = DeliveryList.SelectedItem as Delivery; var d = DeliveryList.SelectedItem as Delivery;
var y = d?.Year ?? Utils.CurrentLastSeason; var y = d?.Year ?? Utils.CurrentLastSeason;
@ -441,6 +470,7 @@ namespace Elwig.Windows {
if (IsCreating) await UpdateLsNr(); if (IsCreating) await UpdateLsNr();
await RefreshDeliveryParts(); await RefreshDeliveryParts();
RefreshInputs();
} }
private void FocusSearchInput(object sender, RoutedEventArgs evt) { private void FocusSearchInput(object sender, RoutedEventArgs evt) {
@ -521,6 +551,7 @@ namespace Elwig.Windows {
ScaleId = p?.ScaleId; ScaleId = p?.ScaleId;
WeighingId = p?.WeighingId; WeighingId = p?.WeighingId;
ManualWeighingReason = p?.WeighingReason;
FinishInputFilling(); FinishInputFilling();
} }
@ -551,7 +582,7 @@ namespace Elwig.Windows {
p.DPNr = dpnr; p.DPNr = dpnr;
d.DateString = string.Join("-", DateInput.Text.Split(".").Reverse()); d.DateString = string.Join("-", DateInput.Text.Split(".").Reverse());
if (IsCreating || InputHasChanged(DateInput)) { if (deliveryNew || InputHasChanged(DateInput)) {
d.LNr = await Context.NextLNr(d.Date); d.LNr = await Context.NextLNr(d.Date);
} }
if (IsCreating) { if (IsCreating) {
@ -582,8 +613,7 @@ namespace Elwig.Windows {
p.ManualWeighing = ManualWeighingInput.IsChecked ?? false; p.ManualWeighing = ManualWeighingInput.IsChecked ?? false;
p.ScaleId = ScaleId; p.ScaleId = ScaleId;
p.WeighingId = WeighingId; p.WeighingId = WeighingId;
if (ManualWeighingReason != null) p.WeighingReason = ManualWeighingReason;
p.Comment = (p.Comment != null ? $"{p.Comment} / " : "") + $"Begründung Handwiegung: {ManualWeighingReason}";
EntityEntry<Delivery>? dEntry = null; EntityEntry<Delivery>? dEntry = null;
EntityEntry<DeliveryPart>? pEntry = null; EntityEntry<DeliveryPart>? pEntry = null;
@ -643,18 +673,23 @@ namespace Elwig.Windows {
WeightInput.Text = $"{res.Weight:N0}"; WeightInput.Text = $"{res.Weight:N0}";
ScaleId = s.ScaleId; ScaleId = s.ScaleId;
WeighingId = res.FullWeighingId; WeighingId = res.FullWeighingId;
s.Empty();
} else { } else {
WeightInput.Text = ""; WeightInput.Text = "";
ScaleId = null; ScaleId = null;
WeighingId = null; WeighingId = null;
} }
ManualWeighingReason = null; LastScaleError = null;
ManualWeighingInput.IsChecked = false;
} catch (Exception e) { } catch (Exception e) {
LastScaleError = e.Message.Split(": ")[^1];
WeightInput.Text = "";
ScaleId = null;
WeighingId = null;
MessageBox.Show($"Beim Wiegen ist ein Fehler aufgetreten:\n\n{e.Message}", "Waagenfehler", MessageBox.Show($"Beim Wiegen ist ein Fehler aufgetreten:\n\n{e.Message}", "Waagenfehler",
MessageBoxButton.OK, MessageBoxImage.Error); MessageBoxButton.OK, MessageBoxImage.Error);
} }
ManualWeighingReason = null;
ManualWeighingInput.IsChecked = false;
base.TextBox_TextChanged(WeightInput, null);
EnableWeighingButtons(); EnableWeighingButtons();
UpdateButtons(); UpdateButtons();
} }
@ -743,12 +778,19 @@ namespace Elwig.Windows {
} }
} }
private void EmptyScale() {
var scale = App.Scales.Where(s => s.ScaleId == ScaleId).FirstOrDefault();
if (scale == null) return;
scale.Empty();
}
private async void NewDeliveryPartButton_Click(object sender, RoutedEventArgs evt) { private async void NewDeliveryPartButton_Click(object sender, RoutedEventArgs evt) {
FinishButton.IsEnabled = false; FinishButton.IsEnabled = false;
NewDeliveryPartButton.IsEnabled = false; NewDeliveryPartButton.IsEnabled = false;
NewDeliveryPartButton.Cursor = Cursors.Wait; NewDeliveryPartButton.Cursor = Cursors.Wait;
DeliveryPartList.IsEnabled = false; DeliveryPartList.IsEnabled = false;
var p = await UpdateDeliveryPart(DeliveryList.SelectedItem as Delivery, DeliveryPartList.SelectedItem as DeliveryPart); var p = await UpdateDeliveryPart(DeliveryList.SelectedItem as Delivery, DeliveryPartList.SelectedItem as DeliveryPart);
EmptyScale();
await RefreshDeliveryList(); await RefreshDeliveryList();
await RefreshDeliveryParts(); await RefreshDeliveryParts();
NewDeliveryPartButton.Cursor = null; NewDeliveryPartButton.Cursor = null;
@ -764,6 +806,7 @@ namespace Elwig.Windows {
FinishButton.Cursor = Cursors.Wait; FinishButton.Cursor = Cursors.Wait;
DeliveryPartList.IsEnabled = false; DeliveryPartList.IsEnabled = false;
var p = await UpdateDeliveryPart(DeliveryList.SelectedItem as Delivery, DeliveryPartList.SelectedItem as DeliveryPart); var p = await UpdateDeliveryPart(DeliveryList.SelectedItem as Delivery, DeliveryPartList.SelectedItem as DeliveryPart);
EmptyScale();
await RefreshDeliveryList(); await RefreshDeliveryList();
await RefreshDeliveryParts(); await RefreshDeliveryParts();
if (p?.Delivery != null) { if (p?.Delivery != null) {
@ -771,11 +814,16 @@ namespace Elwig.Windows {
using var doc = new DeliveryNote(p.Delivery, Context); using var doc = new DeliveryNote(p.Delivery, Context);
await doc.Generate(); await doc.Generate();
Mouse.OverrideCursor = null; Mouse.OverrideCursor = null;
if (App.Config.Debug) {
doc.Show(); doc.Show();
//await doc.Print(2); } else {
await doc.Print(2);
Activate();
}
} }
FinishButton.Cursor = null; FinishButton.Cursor = null;
DeliveryList.SelectedItem = null; DeliveryList.SelectedItem = null;
await RenewContext();
RefreshInputs(); RefreshInputs();
InitInputs(); InitInputs();
} }
@ -798,6 +846,7 @@ namespace Elwig.Windows {
DisableWeighingButtons(); DisableWeighingButtons();
HideFinishNewPartDeliveryCancelButtons(); HideFinishNewPartDeliveryCancelButtons();
ShowNewEditDeleteButtons(); ShowNewEditDeleteButtons();
await RenewContext();
RefreshInputs(); RefreshInputs();
ClearInputStates(); ClearInputStates();
LockInputs(); LockInputs();
@ -880,7 +929,7 @@ namespace Elwig.Windows {
} }
private void WeighingManualButton_Click(object sender, RoutedEventArgs evt) { private void WeighingManualButton_Click(object sender, RoutedEventArgs evt) {
var res = Utils.ShowManualWeighingDialog(); var res = Utils.ShowManualWeighingDialog(LastScaleError);
if (res == null) return; if (res == null) return;
WeightInput.Text = $"{res?.Item1:N0}"; WeightInput.Text = $"{res?.Item1:N0}";
ManualWeighingInput.IsChecked = true; ManualWeighingInput.IsChecked = true;

View File

@ -5,6 +5,10 @@ namespace Elwig.Windows {
public MainWindow() { public MainWindow() {
InitializeComponent(); InitializeComponent();
if (!App.Config.Debug) {
TestWindowButton.Visibility = Visibility.Hidden;
//QueryWindowButton.Visibility = Visibility.Hidden;
}
} }
private void Window_Loaded(object sender, RoutedEventArgs evt) { } private void Window_Loaded(object sender, RoutedEventArgs evt) { }

View File

@ -178,60 +178,64 @@
<ColumnDefinition Width="2*"/> <ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Label Content="E-Mail-Adresse:" Margin="10,10,0,0" Grid.Column="0"/> <Label Content="E-Mail-Adresse (1):" Margin="10,10,0,0" Grid.Column="0"/>
<TextBox x:Name="EmailAddressInput" Margin="0,10,10,0" Grid.Column="1" Grid.ColumnSpan="2" <TextBox x:Name="EmailAddress1Input" Margin="0,10,10,0" Grid.Column="1" Grid.ColumnSpan="2"
TextChanged="EmailAddressInput_TextChanged" LostFocus="EmailAddressInput_LostFocus"/> TextChanged="EmailAddressInput_TextChanged" LostFocus="EmailAddressInput_LostFocus"/>
<ComboBox x:Name="PhoneNr1TypeInput" DisplayMemberPath="Value" Margin="6,40,5,0" FontSize="12" Padding="6,4,4,4"/> <Label Content="E-Mail-Adresse (2):" Margin="10,40,0,0" Grid.Column="0"/>
<TextBox x:Name="PhoneNr1Input" Margin="0,40,5,0" Grid.Column="1" <TextBox x:Name="EmailAddress2Input" Margin="0,40,10,0" Grid.Column="1" Grid.ColumnSpan="2"
TextChanged="EmailAddressInput_TextChanged" LostFocus="EmailAddressInput_LostFocus"/>
<ComboBox x:Name="PhoneNr1TypeInput" DisplayMemberPath="Value" Margin="6,70,5,0" FontSize="12" Padding="6,4,4,4"/>
<TextBox x:Name="PhoneNr1Input" Margin="0,70,5,0" Grid.Column="1"
TextChanged="PhoneNrInput_TextChanged" LostFocus="PhoneNrInput_LostFocus"/> TextChanged="PhoneNrInput_TextChanged" LostFocus="PhoneNrInput_LostFocus"/>
<TextBox x:Name="PhoneNr1CommentInput" Margin="0,40,10,0" Grid.Column="2" <TextBox x:Name="PhoneNr1CommentInput" Margin="0,70,10,0" Grid.Column="2"
TextChanged="TextBox_TextChanged"/> TextChanged="TextBox_TextChanged"/>
<ComboBox x:Name="PhoneNr2TypeInput" DisplayMemberPath="Value" Margin="6,70,5,0" FontSize="12" Padding="6,4,4,4"/> <ComboBox x:Name="PhoneNr2TypeInput" DisplayMemberPath="Value" Margin="6,100,5,0" FontSize="12" Padding="6,4,4,4"/>
<TextBox x:Name="PhoneNr2Input" Margin="0,70,5,0" Grid.Column="1" <TextBox x:Name="PhoneNr2Input" Margin="0,100,5,0" Grid.Column="1"
TextChanged="PhoneNrInput_TextChanged" LostFocus="PhoneNrInput_LostFocus"/> TextChanged="PhoneNrInput_TextChanged" LostFocus="PhoneNrInput_LostFocus"/>
<TextBox x:Name="PhoneNr2CommentInput" Margin="0,70,10,0" Grid.Column="2" <TextBox x:Name="PhoneNr2CommentInput" Margin="0,100,10,0" Grid.Column="2"
TextChanged="TextBox_TextChanged"/> TextChanged="TextBox_TextChanged"/>
<ComboBox x:Name="PhoneNr3TypeInput" DisplayMemberPath="Value" Margin="6,100,5,0" FontSize="12" Padding="6,4,4,4"/> <ComboBox x:Name="PhoneNr3TypeInput" DisplayMemberPath="Value" Margin="6,130,5,0" FontSize="12" Padding="6,4,4,4"/>
<TextBox x:Name="PhoneNr3Input" Margin="0,100,5,0" Grid.Column="1" <TextBox x:Name="PhoneNr3Input" Margin="0,130,5,0" Grid.Column="1"
TextChanged="PhoneNrInput_TextChanged" LostFocus="PhoneNrInput_LostFocus"/> TextChanged="PhoneNrInput_TextChanged" LostFocus="PhoneNrInput_LostFocus"/>
<TextBox x:Name="PhoneNr3CommentInput" Margin="0,100,10,0" Grid.Column="2" <TextBox x:Name="PhoneNr3CommentInput" Margin="0,130,10,0" Grid.Column="2"
TextChanged="TextBox_TextChanged"/> TextChanged="TextBox_TextChanged"/>
<ComboBox x:Name="PhoneNr4TypeInput" DisplayMemberPath="Value" Margin="6,130,5,0" FontSize="12" Padding="6,4,4,4"/> <ComboBox x:Name="PhoneNr4TypeInput" DisplayMemberPath="Value" Margin="6,160,5,0" FontSize="12" Padding="6,4,4,4"/>
<TextBox x:Name="PhoneNr4Input" Margin="0,130,5,0" Grid.Column="1" <TextBox x:Name="PhoneNr4Input" Margin="0,160,5,0" Grid.Column="1"
TextChanged="PhoneNrInput_TextChanged" LostFocus="PhoneNrInput_LostFocus"/> TextChanged="PhoneNrInput_TextChanged" LostFocus="PhoneNrInput_LostFocus"/>
<TextBox x:Name="PhoneNr4CommentInput" Margin="0,130,10,0" Grid.Column="2" <TextBox x:Name="PhoneNr4CommentInput" Margin="0,160,10,0" Grid.Column="2"
TextChanged="TextBox_TextChanged"/> TextChanged="TextBox_TextChanged"/>
<ComboBox x:Name="PhoneNr5TypeInput" DisplayMemberPath="Value" Margin="6,160,5,0" FontSize="12" Padding="6,4,4,4"/> <ComboBox x:Name="PhoneNr5TypeInput" DisplayMemberPath="Value" Margin="6,190,5,0" FontSize="12" Padding="6,4,4,4"/>
<TextBox x:Name="PhoneNr5Input" Margin="0,160,5,0" Grid.Column="1" <TextBox x:Name="PhoneNr5Input" Margin="0,190,5,0" Grid.Column="1"
TextChanged="PhoneNrInput_TextChanged" LostFocus="PhoneNrInput_LostFocus"/> TextChanged="PhoneNrInput_TextChanged" LostFocus="PhoneNrInput_LostFocus"/>
<TextBox x:Name="PhoneNr5CommentInput" Margin="0,160,10,0" Grid.Column="2" <TextBox x:Name="PhoneNr5CommentInput" Margin="0,190,10,0" Grid.Column="2"
TextChanged="TextBox_TextChanged"/> TextChanged="TextBox_TextChanged"/>
<ComboBox x:Name="PhoneNr6TypeInput" DisplayMemberPath="Value" Margin="6,190,5,0" FontSize="12" Padding="6,4,4,4"/> <ComboBox x:Name="PhoneNr6TypeInput" DisplayMemberPath="Value" Margin="6,220,5,0" FontSize="12" Padding="6,4,4,4"/>
<TextBox x:Name="PhoneNr6Input" Margin="0,190,5,0" Grid.Column="1" <TextBox x:Name="PhoneNr6Input" Margin="0,220,5,0" Grid.Column="1"
TextChanged="PhoneNrInput_TextChanged" LostFocus="PhoneNrInput_LostFocus"/> TextChanged="PhoneNrInput_TextChanged" LostFocus="PhoneNrInput_LostFocus"/>
<TextBox x:Name="PhoneNr6CommentInput" Margin="0,190,10,0" Grid.Column="2" <TextBox x:Name="PhoneNr6CommentInput" Margin="0,220,10,0" Grid.Column="2"
TextChanged="TextBox_TextChanged"/> TextChanged="TextBox_TextChanged"/>
<ComboBox x:Name="PhoneNr7TypeInput" DisplayMemberPath="Value" Margin="6,220,5,0" FontSize="12" Padding="6,4,4,4"/> <ComboBox x:Name="PhoneNr7TypeInput" DisplayMemberPath="Value" Margin="6,250,5,0" FontSize="12" Padding="6,4,4,4"/>
<TextBox x:Name="PhoneNr7Input" Margin="0,220,5,0" Grid.Column="1" <TextBox x:Name="PhoneNr7Input" Margin="0,250,5,0" Grid.Column="1"
TextChanged="PhoneNrInput_TextChanged" LostFocus="PhoneNrInput_LostFocus"/> TextChanged="PhoneNrInput_TextChanged" LostFocus="PhoneNrInput_LostFocus"/>
<TextBox x:Name="PhoneNr7CommentInput" Margin="0,220,10,0" Grid.Column="2" <TextBox x:Name="PhoneNr7CommentInput" Margin="0,250,10,0" Grid.Column="2"
TextChanged="TextBox_TextChanged"/> TextChanged="TextBox_TextChanged"/>
<ComboBox x:Name="PhoneNr8TypeInput" DisplayMemberPath="Value" Margin="6,250,5,0" FontSize="12" Padding="6,4,4,4"/> <ComboBox x:Name="PhoneNr8TypeInput" DisplayMemberPath="Value" Margin="6,280,5,0" FontSize="12" Padding="6,4,4,4"/>
<TextBox x:Name="PhoneNr8Input" Margin="0,250,5,0" Grid.Column="1" <TextBox x:Name="PhoneNr8Input" Margin="0,280,5,0" Grid.Column="1"
TextChanged="PhoneNrInput_TextChanged" LostFocus="PhoneNrInput_LostFocus"/> TextChanged="PhoneNrInput_TextChanged" LostFocus="PhoneNrInput_LostFocus"/>
<TextBox x:Name="PhoneNr8CommentInput" Margin="0,250,10,0" Grid.Column="2" <TextBox x:Name="PhoneNr8CommentInput" Margin="0,280,10,0" Grid.Column="2"
TextChanged="TextBox_TextChanged"/> TextChanged="TextBox_TextChanged"/>
<ComboBox x:Name="PhoneNr9TypeInput" DisplayMemberPath="Value" Margin="6,280,5,0" FontSize="12" Padding="6,4,4,4"/> <ComboBox x:Name="PhoneNr9TypeInput" DisplayMemberPath="Value" Margin="6,310,5,0" FontSize="12" Padding="6,4,4,4"/>
<TextBox x:Name="PhoneNr9Input" Margin="0,280,5,0" Grid.Column="1" <TextBox x:Name="PhoneNr9Input" Margin="0,310,5,0" Grid.Column="1"
TextChanged="PhoneNrInput_TextChanged" LostFocus="PhoneNrInput_LostFocus"/> TextChanged="PhoneNrInput_TextChanged" LostFocus="PhoneNrInput_LostFocus"/>
<TextBox x:Name="PhoneNr9CommentInput" Margin="0,280,10,0" Grid.Column="2" <TextBox x:Name="PhoneNr9CommentInput" Margin="0,280,10,0" Grid.Column="2"
TextChanged="TextBox_TextChanged"/> TextChanged="TextBox_TextChanged"/>

View File

@ -89,7 +89,8 @@ namespace Elwig.Windows {
.ToList(); .ToList();
} }
ControlUtils.RenewItemsSource(MemberList, members, i => (i as Member)?.MgNr, MemberList_SelectionChanged, ControlUtils.RenewSourceDefault.IfOnly, !updateSort); ControlUtils.RenewItemsSource(MemberList, members, i => (i as Member)?.MgNr,
MemberList_SelectionChanged, TextFilter.Count > 0 ? ControlUtils.RenewSourceDefault.IfOnly : ControlUtils.RenewSourceDefault.None, !updateSort);
} }
private void RefreshInputs(bool validate = false) { private void RefreshInputs(bool validate = false) {
@ -130,8 +131,8 @@ namespace Elwig.Windows {
ValidateRequiredInputs(); ValidateRequiredInputs();
} }
protected override async Task RenewContext() { protected override async Task OnRenewContext() {
await base.RenewContext(); await base.OnRenewContext();
ControlUtils.RenewItemsSource(BranchInput, await Context.Branches.OrderBy(b => b.Name).ToListAsync(), i => (i as Branch)?.ZwstId); ControlUtils.RenewItemsSource(BranchInput, await Context.Branches.OrderBy(b => b.Name).ToListAsync(), i => (i as Branch)?.ZwstId);
ControlUtils.RenewItemsSource(DefaultKgInput, await Context.WbKgs.Select(k => k.AtKg).OrderBy(k => k.Name).ToListAsync(), i => (i as AT_Kg)?.KgNr); ControlUtils.RenewItemsSource(DefaultKgInput, await Context.WbKgs.Select(k => k.AtKg).OrderBy(k => k.Name).ToListAsync(), i => (i as AT_Kg)?.KgNr);
await RefreshMemberList(); await RefreshMemberList();
@ -265,7 +266,7 @@ namespace Elwig.Windows {
} }
private void Menu_Member_SendEmail_Click(object sender, RoutedEventArgs evt) { private void Menu_Member_SendEmail_Click(object sender, RoutedEventArgs evt) {
Utils.MailTo(((Member)MemberList.SelectedItem).Email); Utils.MailTo(((Member)MemberList.SelectedItem).EmailAddresses.First().Address);
} }
private void FocusSearchInput(object sender, RoutedEventArgs evt) { private void FocusSearchInput(object sender, RoutedEventArgs evt) {
@ -348,8 +349,6 @@ namespace Elwig.Windows {
m.PostalDestId = ((AT_PlzDest)OrtInput.SelectedItem).Id; m.PostalDestId = ((AT_PlzDest)OrtInput.SelectedItem).Id;
m.Address = AddressInput.Text; m.Address = AddressInput.Text;
m.Email = (EmailAddressInput.Text == "") ? null : EmailAddressInput.Text;
m.Iban = (IbanInput.Text == "") ? null : IbanInput.Text.Replace(" ", ""); m.Iban = (IbanInput.Text == "") ? null : IbanInput.Text.Replace(" ", "");
m.Bic = (BicInput.Text == "") ? null : BicInput.Text; m.Bic = (BicInput.Text == "") ? null : BicInput.Text;
@ -423,6 +422,27 @@ namespace Elwig.Windows {
} }
} }
for (int i = 0; i < 2; i++) {
var input = i == 0 ? EmailAddress1Input : EmailAddress2Input;
var emailAddr = m.EmailAddresses.FirstOrDefault(a => a.Nr - 1 == i);
if (input.Text == "") {
if (emailAddr != null) {
Context.Remove(emailAddr);
}
} else {
MemberEmailAddr a = emailAddr ?? Context.CreateProxy<MemberEmailAddr>();
a.Nr = i + 1;
a.Address = input.Text;
a.Comment = null;
if (emailAddr == null) {
a.MgNr = newMgNr;
await Context.AddAsync(a);
} else {
Context.Update(a);
}
}
}
await Context.SaveChangesAsync(); await Context.SaveChangesAsync();
if (newMgNr != m.MgNr) { if (newMgNr != m.MgNr) {
@ -474,7 +494,10 @@ namespace Elwig.Windows {
OrtInput.SelectedItem = null; OrtInput.SelectedItem = null;
} }
EmailAddressInput.Text = m.Email; var emailAddrs = m.EmailAddresses.OrderBy(a => a.Nr).ToList();
EmailAddress1Input.Text = emailAddrs.Count > 0 ? emailAddrs[0].Address : "";
EmailAddress2Input.Text = emailAddrs.Count > 1 ? emailAddrs[1].Address : "";
var phoneNrs = m.TelephoneNumbers.OrderBy(p => p.Nr).ToList(); var phoneNrs = m.TelephoneNumbers.OrderBy(p => p.Nr).ToList();
for (int i = 0; i < PhoneNrInputs.Length; i++) { for (int i = 0; i < PhoneNrInputs.Length; i++) {
if (i < phoneNrs.Count) { if (i < phoneNrs.Count) {
@ -524,7 +547,7 @@ namespace Elwig.Windows {
AreaCommitment.Text = $"{m.ActiveAreaCommitments.Select(c => c.Area).Sum():N0} m²"; AreaCommitment.Text = $"{m.ActiveAreaCommitments.Select(c => c.Area).Sum():N0} m²";
Menu_Member_SendEmail.IsEnabled = m.Email != null; Menu_Member_SendEmail.IsEnabled = m.EmailAddresses.Count > 0;
FinishInputFilling(); FinishInputFilling();
} }

View File

@ -2,6 +2,7 @@
[general] [general]
; Only needed, if more than one branch is stored in database ; Only needed, if more than one branch is stored in database
branch = Zweigstelle branch = Zweigstelle
;debug = true
[database] [database]
; Relative or absolute path to database file ; Relative or absolute path to database file

View File

@ -72,14 +72,14 @@ namespace Tests {
[Test] [Test]
public void Test_SplitAddress() { public void Test_SplitAddress() {
Assert.Multiple(() => { Assert.Multiple(() => {
Assert.That(Utils.SplitAddress("Winzerstra<EFBFBD>e 1"), Is.EqualTo(("Winzerstra<EFBFBD>e", "1"))); Assert.That(Utils.SplitAddress("Winzerstraße 1"), Is.EqualTo(("Winzerstraße", "1")));
Assert.That(Utils.SplitAddress("Auf dem Feld 12"), Is.EqualTo(("Auf dem Feld", "12"))); Assert.That(Utils.SplitAddress("Auf dem Feld 12"), Is.EqualTo(("Auf dem Feld", "12")));
Assert.That(Utils.SplitAddress("Winzerstra<EFBFBD>e 5a"), Is.EqualTo(("Winzerstra<EFBFBD>e", "5a"))); Assert.That(Utils.SplitAddress("Winzerstraße 5a"), Is.EqualTo(("Winzerstraße", "5a")));
Assert.That(Utils.SplitAddress("Winzerstra<EFBFBD>e 1-3/2"), Is.EqualTo(("Winzerstra<EFBFBD>e", "1-3/2"))); Assert.That(Utils.SplitAddress("Winzerstraße 1-3/2"), Is.EqualTo(("Winzerstraße", "1-3/2")));
Assert.That(Utils.SplitAddress("Winzerstra<EFBFBD>e 3/4/5"), Is.EqualTo(("Winzerstra<EFBFBD>e", "3/4/5"))); Assert.That(Utils.SplitAddress("Winzerstraße 3/4/5"), Is.EqualTo(("Winzerstraße", "3/4/5")));
Assert.That(Utils.SplitAddress("Winzerstra<EFBFBD>e 7/2/4/77"), Is.EqualTo(("Winzerstra<EFBFBD>e", "7/2/4/77"))); Assert.That(Utils.SplitAddress("Winzerstraße 7/2/4/77"), Is.EqualTo(("Winzerstraße", "7/2/4/77")));
Assert.That(Utils.SplitAddress("Winzerstra<EFBFBD>e 95b"), Is.EqualTo(("Winzerstra<EFBFBD>e", "95b"))); Assert.That(Utils.SplitAddress("Winzerstraße 95b"), Is.EqualTo(("Winzerstraße", "95b")));
Assert.That(Utils.SplitAddress("Winzerstra<EFBFBD>e 1, TOP 3"), Is.EqualTo(("Winzerstra<EFBFBD>e", "1, TOP 3"))); Assert.That(Utils.SplitAddress("Winzerstraße 1, TOP 3"), Is.EqualTo(("Winzerstraße", "1, TOP 3")));
}); });
} }