Merge branch 'running-sheets'

# Conflicts:
#	MainWindow.axaml.cs
#	Tasks/AddressCreation.cs
#	Tasks/PdfBuilder.cs
This commit is contained in:
2026-06-04 08:28:52 +02:00
6 changed files with 374 additions and 168 deletions
+17
View File
@@ -178,6 +178,23 @@ public class KasPerson
public string abteilung { get; set; } public string abteilung { get; set; }
public string funktionad { get; set; } public string funktionad { get; set; }
public string used_plz { get; set; } = "";
public static void SetUsedPLZ(int id, string plz)
{
foreach (var set in Settings._instance.addressSets.addresses)
{
foreach (var add in set.KasPersons)
{
if (add.id == id)
{
add.used_plz = plz;
return;
}
}
}
}
public static int GenerateNewID(int base_id) public static int GenerateNewID(int base_id)
{ {
//var newid = 100000 + base_id; //var newid = 100000 + base_id;
+16
View File
@@ -67,6 +67,9 @@ public class PdfExportSettings
public double fontSize { get; set; } = 9; public double fontSize { get; set; } = 9;
public double smallFontSize { get; set; } = 6; public double smallFontSize { get; set; } = 6;
public bool exportRunningSheets { get; set; } = true;
public int rsNumGrouped { get; set; } = 25;
public int rsPlzStartpoint { get; set; } = 2;
} }
public class Global public class Global
@@ -169,6 +172,19 @@ public class Customer
public char separator { get; set; } = ','; public char separator { get; set; } = ',';
public int ID { get; } public int ID { get; }
public static Customer GetCustomerByID(int id)
{
foreach (var customer in Settings._instance.customers.customers)
{
if (id == customer.ID)
{
return customer;
}
}
return null;
}
// public static int GetIDByCustomerListItem(string item_content) // public static int GetIDByCustomerListItem(string item_content)
// { // {
+9
View File
@@ -254,6 +254,7 @@
<Label Grid.Column="0" Content="Zellenrand rechts (mm)"></Label> <Label Grid.Column="0" Content="Zellenrand rechts (mm)"></Label>
<NumericUpDown Grid.Column="1" x:Name="NudExpMargCellPaddingRight" Minimum="0" Maximum="20" Value="5"></NumericUpDown> <NumericUpDown Grid.Column="1" x:Name="NudExpMargCellPaddingRight" Minimum="0" Maximum="20" Value="5"></NumericUpDown>
</Grid> </Grid>
<CheckBox Content="Laufzettel erstellen" x:Name="CbExpRnsEnable"></CheckBox>
</StackPanel> </StackPanel>
<StackPanel Grid.Column="1" Orientation="Vertical" Spacing="10"> <StackPanel Grid.Column="1" Orientation="Vertical" Spacing="10">
@@ -273,6 +274,10 @@
<Label Content="Zellenabstand links"></Label> <Label Content="Zellenabstand links"></Label>
<NumericUpDown Grid.Column="1" x:Name="TbExpMargMarginLeft" Minimum="0" Maximum="20" Value="0"></NumericUpDown> <NumericUpDown Grid.Column="1" x:Name="TbExpMargMarginLeft" Minimum="0" Maximum="20" Value="0"></NumericUpDown>
</Grid> </Grid>
<Grid ColumnDefinitions="*,*">
<Label Grid.Column="0" Content="Anzahl gruppierter Sendungen"></Label>
<NumericUpDown Grid.Column="1" x:Name="NudExpRnsPlzcount" Minimum="1" Maximum="10000" Value="25"></NumericUpDown>
</Grid>
</StackPanel> </StackPanel>
<StackPanel Grid.Column="2" Orientation="Vertical" Spacing="10"> <StackPanel Grid.Column="2" Orientation="Vertical" Spacing="10">
@@ -292,6 +297,10 @@
<Label Grid.Column="0" Content="Schriftgröße (klein)"></Label> <Label Grid.Column="0" Content="Schriftgröße (klein)"></Label>
<NumericUpDown Grid.Column="1" x:Name="NudExpMargSmallFontSize" Minimum="3" Maximum="30" Value="6"></NumericUpDown> <NumericUpDown Grid.Column="1" x:Name="NudExpMargSmallFontSize" Minimum="3" Maximum="30" Value="6"></NumericUpDown>
</Grid> </Grid>
<Grid ColumnDefinitions="*,*">
<Label Grid.Column="0" Content="Gruppierpunkt"></Label>
<NumericUpDown Grid.Column="1" x:Name="NudExpRnsPlzStartpoint" Minimum="1" Maximum="10" Value="2"></NumericUpDown>
</Grid>
</StackPanel> </StackPanel>
</Grid> </Grid>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center"> <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
+5 -4
View File
@@ -772,8 +772,9 @@ public partial class MainWindow : Window
list.Add((KasAddressList)item); list.Add((KasAddressList)item);
try try
{ {
StartCombine(list, Convert.ToInt32(LstCustomers.SelectedItem), "difference", GetCombiningTyp()); StartCombine(list, Convert.ToInt32((LstCustomers.SelectedItem as Customer).ID), "difference", GetCombiningTyp());
}catch (Exception ex) }
catch (Exception ex)
{ {
Logger.Log($"Error while combining (difference): {ex.Message}", Logger.LogType.Error); Logger.Log($"Error while combining (difference): {ex.Message}", Logger.LogType.Error);
} }
@@ -802,7 +803,7 @@ public partial class MainWindow : Window
list.Add((KasAddressList)item); list.Add((KasAddressList)item);
try try
{ {
StartCombine(list, Convert.ToInt32(LstCustomers.SelectedItem.ToString().Split(" - ")[0]), "intersection", GetCombiningTyp()); StartCombine(list, Convert.ToInt32((LstCustomers.SelectedItem as Customer).ID), "intersection", GetCombiningTyp());
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -829,7 +830,7 @@ public partial class MainWindow : Window
foreach (var item in LstCustomerAdressSets.SelectedItems) foreach (var item in LstCustomerAdressSets.SelectedItems)
list.Add((KasAddressList)item); list.Add((KasAddressList)item);
StartCombine(list, Convert.ToInt32(LstCustomers.SelectedItem.ToString().Split(" - ")[0]), "symdiff", GetCombiningTyp()); StartCombine(list, Convert.ToInt32((LstCustomers.SelectedItem as Customer).ID), "symdiff", GetCombiningTyp());
} }
private async void BtnGenerateLabels_OnClick(object? sender, RoutedEventArgs e) private async void BtnGenerateLabels_OnClick(object? sender, RoutedEventArgs e)
+26 -12
View File
@@ -43,8 +43,7 @@ public static class AddressCreator
public static string? CreateFinalMarkdownString(int id) public static string? CreateFinalMarkdownString(int id)
{ {
// Maximum seven lines of information // Maximum seven lines of information
try
{
// find the address // find the address
KasPerson? address = null; KasPerson? address = null;
var string_address = ""; var string_address = "";
@@ -105,7 +104,9 @@ public static class AddressCreator
// Alternative A: pplz valid and city existing // Alternative A: pplz valid and city existing
if (!string.IsNullOrEmpty(address.ort) && CheckPLZ(address.pplz, address.land)) if (!string.IsNullOrEmpty(address.ort) && CheckPLZ(address.pplz, address.land))
{ {
string_address = address.pplz + " " + address.ort + "\n" + string_address; string pplz = NormalizeGermanPLZ(address.pplz);
KasPerson.SetUsedPLZ(id, pplz);
string_address = pplz + " " + address.ort + "\n" + string_address;
address_line_count++; address_line_count++;
if (!string.IsNullOrWhiteSpace(address.postfach)) if (!string.IsNullOrWhiteSpace(address.postfach))
{ {
@@ -151,7 +152,9 @@ public static class AddressCreator
} // Alternative B: plz valid and city existing } // Alternative B: plz valid and city existing
else if (!string.IsNullOrEmpty(address.ort) && CheckPLZ(address.plz, address.land)) else if (!string.IsNullOrEmpty(address.ort) && CheckPLZ(address.plz, address.land))
{ {
string_address = address.plz + " " + address.ort + "\n" + string_address; string plz = NormalizeGermanPLZ(address.plz);
KasPerson.SetUsedPLZ(id, plz);
string_address = plz + " " + address.ort + "\n" + string_address;
address_line_count++; address_line_count++;
if (!string.IsNullOrWhiteSpace(address.strasse)) if (!string.IsNullOrWhiteSpace(address.strasse))
{ {
@@ -198,13 +201,6 @@ public static class AddressCreator
if (address_line_count > 1) return string_address; if (address_line_count > 1) return string_address;
return null; return null;
} }
catch (Exception ex)
{
Logger.Log($"Error while creating markdown string: {ex.Message}", Logger.LogType.Error);
}
return null;
}
public static string CreateNameLine(string anredezus, string anrede, string titel, string vorname, string adel, public static string CreateNameLine(string anredezus, string anrede, string titel, string vorname, string adel,
string name, string namezus) string name, string namezus)
@@ -231,7 +227,6 @@ public static class AddressCreator
} }
return null; return null;
} }
/// <summary> /// <summary>
@@ -277,4 +272,23 @@ public static class AddressCreator
return false; return false;
} }
public static string NormalizeGermanPLZ(string plz)
{
if(plz.Length == 5) return plz;
if(plz.Length > 5)
{
return plz.Substring(0, 5);
}
if (plz.Length < 5)
{
int toadd = 5 - plz.Length;
for (int i = 0; i < toadd; i++)
{
plz = "0" + plz;
}
}
return plz;
}
} }
+149
View File
@@ -134,6 +134,17 @@ public class PdfBuilder
addresses.Add(addr); addresses.Add(addr);
} }
if (addresses.Count == 0)
{
MessageBox.Show(MainWindow._instance, "Keine validen Adressen konnten generiert werden. Abbruch.", "Fehler");
return;
}
CreateAddressLabelPdfWithPlaceholder(addresses, placeholderText, outputPath);
if (_settings.exportRunningSheets)
{
ExportRunningSheets(addressSetId, outputPath);
}
CreateAddressLabelPdfWithPlaceholder(addresses, placeholderText, outputPath); CreateAddressLabelPdfWithPlaceholder(addresses, placeholderText, outputPath);
} }
catch (Exception ex) catch (Exception ex)
@@ -480,4 +491,142 @@ public class PdfBuilder
if (left < 0 || top < 0 || right < 0 || bottom < 0) if (left < 0 || top < 0 || right < 0 || bottom < 0)
throw new ArgumentException("Margins cannot be negative"); throw new ArgumentException("Margins cannot be negative");
} }
public void ExportRunningSheets(int setID, string path)
{
if (path.EndsWith(".pdf"))
{
path = path.Substring(0, path.Length - 4);
path = path + "-Laufzettel.pdf";
}
else
{
path = path + "-Laufzettel.pdf";
}
CreateRunningSheets(setID, path);
}
public void CreateRunningSheets(int setID, string path)
{
KasAddressList list = Settings._instance.addressSets.GetAddressSetByID(setID);
var document = new PdfDocument();
document.Info.Title = $"Laufzettel für {list.Name}";
document.Info.Subject = "powered by logofclient";
document.Info.Author = "logofclient";
int margin = 50;
var grouped_nums = GroupAddresses(setID);
foreach (var result in grouped_nums)
{
var page = document.AddPage();
page.Size = PageSize.A4;
var gfx = XGraphics.FromPdfPage(page);
var width = page.Width.Point-margin;
var height = page.Height.Point-margin;
gfx.DrawLine(XPens.Black, margin, margin, margin, height);
gfx.DrawLine(XPens.Black, margin, margin, width, margin);
gfx.DrawLine(XPens.Black, width, margin, width, height);
gfx.DrawLine(XPens.Black, margin, height, width, height);
var boldfont = new XFont("Cantarell", 11, XFontStyleEx.Bold);
var font = new XFont("Cantarell", 11, XFontStyleEx.Regular);
var bigboldfont = new XFont("Cantarell", 35, XFontStyleEx.Bold);
// Versandinfo
gfx.DrawString($"Versand {list.Name}", boldfont, XBrushes.Black,
new XRect(margin+5, margin, width-margin, 25), XStringFormats.CenterLeft);
gfx.DrawString($"Start: ", font, XBrushes.Black,
new XRect(margin+5, margin+25, width-margin, 25), XStringFormats.CenterLeft);
gfx.DrawString($"{result.Item3}", font, XBrushes.Black,
new XRect(margin+75, margin+25, width-margin, 25), XStringFormats.CenterLeft);
gfx.DrawString($"Ende: ", font, XBrushes.Black,
new XRect(margin+5, margin+40, width-margin, 25), XStringFormats.CenterLeft);
gfx.DrawString($"{result.Item4}", font, XBrushes.Black,
new XRect(margin+75, margin+40, width-margin, 25), XStringFormats.CenterLeft);
gfx.DrawString($"Kunde: ", font, XBrushes.Black,
new XRect(margin+5, margin+55, width-margin, 25), XStringFormats.CenterLeft);
gfx.DrawString($"{Customer.GetCustomerByID(list.owner_id).name}", font, XBrushes.Black,
new XRect(margin+75, margin+55, width-margin, 25), XStringFormats.CenterLeft);
gfx.DrawString($"Absender: ", font, XBrushes.Black,
new XRect(margin+5, margin+70, width-margin, 25), XStringFormats.CenterLeft);
gfx.DrawString($"{Customer.GetCustomerByID(list.owner_id).sender_address}", font, XBrushes.Black,
new XRect(margin+75, margin+70, width-margin, 25), XStringFormats.CenterLeft);
gfx.DrawString($"Anzahl: ", font, XBrushes.Black,
new XRect(margin+5, margin+85, width-margin, 25), XStringFormats.CenterLeft);
gfx.DrawString($"{result.Item5}", font, XBrushes.Black,
new XRect(margin+75, margin+85, width-margin, 25), XStringFormats.CenterLeft);
// logofclient ad
gfx.DrawString($"powered by logofclient", font, XBrushes.Black,
new XRect(margin+5, height-55, width-margin, 25), XStringFormats.CenterLeft);
gfx.DrawString($"(c) 2026 MyPapertown", font, XBrushes.Black,
new XRect(margin+5, height-40, width-margin, 25), XStringFormats.CenterLeft);
gfx.DrawString($"mypapercloud.de/logof", font, XBrushes.Black,
new XRect(margin+5, height-25, width-margin, 25), XStringFormats.CenterLeft);
int total_frac = 0;
foreach (var item in grouped_nums)
{
if (item.Item2 == result.Item2) total_frac++;
}
// group number
gfx.DrawString($"{result.Item2}", bigboldfont, XBrushes.Black,
new XRect(margin, margin, width-margin, (height-margin)/2), XStringFormats.Center);
gfx.DrawString($"Fraktion {result.Item1}/{total_frac}", font, XBrushes.Black,
new XRect(margin, margin, width-margin, (height-margin)/2 + 50), XStringFormats.Center);
}
document.Save(path);
}
/// <summary>
/// Calculates address groups to summarize for the single pages of the running sheets.
/// </summary>
/// <param name="setID"></param>
/// <returns>List of quadruples consisting of a number and the starting of the plz, as well as first, last plz and total amount of addresses</returns>
public List<(int, string, string, string, int)> GroupAddresses(int setID)
{
int grpcount = Settings._instance.pdfExport.rsNumGrouped; // Amount of addresses per group
int stpoint = Settings._instance.pdfExport.rsPlzStartpoint; // group starting point (first n characters of the plz)
KasAddressList list = Settings._instance.addressSets.GetAddressSetByID(setID);
if (list == null)
throw new Exception("AddressSet nicht gefunden");
List<(int, string, string, string, int)> output = new();
List<IGrouping<string, KasPerson>> sorted_list = list.KasPersons
.Where(x => !string.IsNullOrEmpty(x?.used_plz) &&
x.used_plz.Length >= stpoint)
.OrderBy(x => x.used_plz)
.GroupBy(x => x.used_plz.Substring(0, stpoint))
.ToList();
foreach (var group in sorted_list)
{
string start = group.Key;
int fraktion = 0;
for (int count = 0; count < group.Count(); count += grpcount)
{
fraktion++;
int currentGroupSize = Math.Min(grpcount, group.Count() - count);
string first = group.ElementAt(count).used_plz;
string last = group.ElementAt(count + currentGroupSize - 1).used_plz;
output.Add((fraktion, start, first, last, currentGroupSize));
}
}
return output;
}
} }