diff --git a/AA-Forms/FormArtikelVW.cs b/AA-Forms/FormArtikelVW.cs index 3720ff3..e534879 100644 --- a/AA-Forms/FormArtikelVW.cs +++ b/AA-Forms/FormArtikelVW.cs @@ -69,6 +69,9 @@ namespace Deckungsbeitrag } + /// + /// Die ObjectListView wird mit den Artikeln geladen bei denen Nachwäsche registriert wird. + /// private void OLV_Load_with_Artikel() { if (this.user.Rolle == BenutzerRolle.Expedit || this.user.Rolle == BenutzerRolle.Frottee || this.user.Rolle == BenutzerRolle.Master) @@ -99,22 +102,26 @@ namespace Deckungsbeitrag } else { - Generator.GenerateColumns(this.objectListViewArtikel, typeof(Artikel), true); - this.artikelList = Artikel.GetArtikelList("Alle"); + Generator.GenerateColumns(this.objectListViewArtikel, typeof(View_Artikel_Nachwaesche), true); + List artnwListe = View_Artikel_Nachwaesche.LadeNachwaesche(); - this.objectListViewArtikel.SetObjects(this.artikelList); - OLVColumn sortColumn = new OLVColumn(); - sortColumn = (OLVColumn)this.objectListViewArtikel.Columns[6]; + this.objectListViewArtikel.SetObjects(artnwListe); + OLVColumn sortColumn = (OLVColumn)this.objectListViewArtikel.Columns["Abteilung"]; this.objectListViewArtikel.Sort(sortColumn); - OLV_GroupCount(); - OLVColumn buttonColumn = new OLVColumn(); - buttonColumn = (OLVColumn)this.objectListViewArtikel.Columns[7]; - buttonColumn.IsButton = true; - buttonColumn.ButtonSizing = OLVColumn.ButtonSizingMode.CellBounds; + //OLV_GroupCount(); + //OLVColumn buttonColumn = new OLVColumn(); + //buttonColumn = (OLVColumn)this.objectListViewArtikel.Columns[7]; + //buttonColumn.IsButton = true; + //buttonColumn.ButtonSizing = OLVColumn.ButtonSizingMode.CellBounds; } OLV_ColumnsResize(this.objectListViewArtikel); } + + /// + /// Die ObjectListView wird mit Kunden geladen welche den in der ComboBox gewählten Artikel im Sortiment haben. + /// + /// Der gewählte Artikel aus der ComboBox private void OLV_Load_with_Kunden(Artikel art) { this.Cursor = Cursors.WaitCursor; diff --git a/AA-Forms/FormExpedit.Designer.cs b/AA-Forms/FormExpedit.Designer.cs index a3b8aa6..ac56bcc 100644 --- a/AA-Forms/FormExpedit.Designer.cs +++ b/AA-Forms/FormExpedit.Designer.cs @@ -336,6 +336,7 @@ this.objectListViewSonder.TabIndex = 2; this.objectListViewSonder.TintSortColumn = true; this.objectListViewSonder.UseAlternatingBackColors = true; + this.objectListViewSonder.UseCellFormatEvents = true; this.objectListViewSonder.UseCompatibleStateImageBehavior = false; this.objectListViewSonder.UseHotControls = false; this.objectListViewSonder.View = System.Windows.Forms.View.Details; diff --git a/AA-Forms/FormExpedit.cs b/AA-Forms/FormExpedit.cs index 1e6aa69..03de865 100644 --- a/AA-Forms/FormExpedit.cs +++ b/AA-Forms/FormExpedit.cs @@ -1,6 +1,7 @@ using BrightIdeasSoftware; using DatenDB; using Deckungsbeitrag.AA_Forms; +using Deckungsbeitrag.AA_Klassen; using Deckungsbeitrag.Properties; using Deckungsbeitrag.UserControls; using Microsoft.VisualBasic; @@ -69,6 +70,12 @@ namespace Deckungsbeitrag private bool isttest = true; private bool _doubleClickPending = false; private OnboardingSchritt onBoardingArt = OnboardingSchritt.Expedit; + + private List listAuftragToday; + private List listAuftragGeschaeft; + private List listVorbereitet; + private List listSonderAuftrag; + private List listRampe; #endregion public FormExpedit(Benutzer benutzer) { @@ -108,21 +115,18 @@ namespace Deckungsbeitrag { try { - await Task.WhenAll(GetAuftraege(null), GetSonderAuftraege()); + await Task.WhenAll( + GetAuftraegeAsync(null)); // UI-Update NACH Daten (Invoke!) this.Invoke(new Action(() => { // OLVs füllen - if (auftraglist != null & auftraglist.Count > 0) OLV_Load(this.objectListViewAuftrag, auftraglist); - if (sonderlist != null & sonderlist.Count > 0) OLV_Load(this.objectListViewSonder, sonderlist); - if (geschaeftlist != null & geschaeftlist.Count > 0) OLV_Load(this.objectListViewGeschaeft, geschaeftlist); - if (this.benutzer.Rolle != BenutzerRolle.Frottee) - { - if (rampenlist != null & rampenlist.Count > 0) OLV_Load(this.objectListViewRampe, rampenlist); - if (vorbereitetliste != null & vorbereitetliste.Count > 0) OLV_Load(this.objectListViewVorbereitet, vorbereitetliste); - - } + if (listAuftragToday.Count > 0) Load_OLV(this.objectListViewAuftrag, listAuftragToday); + if (listAuftragGeschaeft != null && listAuftragGeschaeft.Count > 0) Load_OLV(this.objectListViewGeschaeft, listAuftragGeschaeft); + if (listSonderAuftrag.Count > 0) Load_OLV(this.objectListViewSonder, listSonderAuftrag); + if (listVorbereitet != null && listVorbereitet.Count > 0) Load_OLV(this.objectListViewVorbereitet, listVorbereitet); + if (listRampe!= null && listRampe.Count > 0) Load_OLV(this.objectListViewRampe, listRampe); // Controls aktivieren und deaktivieren nach BenutzerRolle Enable_Controls(); @@ -176,10 +180,11 @@ namespace Deckungsbeitrag if (neuerAuftrag.ShowDialog() == DialogResult.OK) { this.letzterLiefertag = neuerAuftrag.letzterLiefertag; - await GetAuftraege(null); + await GetAuftraegeAsync(ListenArt.Auftragliste); + await GetAuftraegeAsync(ListenArt.Geschäftliste); //List auftraglist = Auftrag.GetAuftragListToday(DateTime.Today); - OLV_SetObjects(this.objectListViewAuftrag, auftraglist); - OLV_SetObjects(this.objectListViewGeschaeft, geschaeftlist); + OLV_SetObjects(this.objectListViewAuftrag, listAuftragToday); + OLV_SetObjects(this.objectListViewGeschaeft, listAuftragGeschaeft); } } private void buttonSWS_Drucken_Click(object sender, EventArgs e) @@ -273,241 +278,137 @@ namespace Deckungsbeitrag #region ObjectListView-Events - /// - /// Die ObjectListView wird komplett neu geladen. Mit Spalten etc. - /// - /// - /// - private void OLV_Load(ObjectListView olv, List auftraglist) + private void Load_OLV(ObjectListView olv, List auftragliste) { - // Layout- und Update-Änderungen pausieren, um Flackern zu verhindern + // ========== LAYOUT UND UPDATE PAUSIEREN ========== + olv.BeginUpdate(); // Stoppt Datenaktualisierungen/Redraws olv.SuspendLayout(); // Stoppt Layout-Berechnungen (Anchor/Dock) - // SpaltenHeader-Design anpassen - //this.objectListViewAuftrag.HeaderFormatStyle = Funktionen.GetHeader(); + // ========== SPALTEN AUTOMATISCH AUS MODEL ERTELLEN ========== + Generator.GenerateColumns(olv, typeof(View_Auftrag_Expedit), true); - // Automatisch alle Properties von Auftrag als Spalten generieren - Generator.GenerateColumns(olv, typeof(Auftrag), true); - - // ========== CHECKBOX COLUMNS FÜR ABTEILUNGEN =========== - // Spalten-Setup - var colFrottee = new OLVColumn("Frottee", "Frottee"); - colFrottee.Text = "FR"; - colFrottee.DisplayIndex = 6; - colFrottee.TextAlign = HorizontalAlignment.Center; - colFrottee.Width = 50; - colFrottee.AspectGetter = row => { - var auftrag = (Auftrag)row; - - if (!KundeArtikel.HatKategorieArtikel(auftrag.KundeID, ArtikelKategorie.Frottee) & !KundeArtikel.HatKategorieArtikel(auftrag.KundeID, ArtikelKategorie.Spannleintuch)) return string.Empty; - - int abteilungen = (int)auftrag.Abteilungen; - - bool begonnen = (abteilungen & (int)AbteilungsStatus.FrotteeBegonnen) != 0; - bool beendet = (abteilungen & (int)AbteilungsStatus.FrotteeBeendet) != 0; - - if (beendet) return "☑"; // Status 1 ✓ - if (begonnen) return "☐"; // Status 2 ✓ - return "☒"; // Status 0 ✓ - }; - - - var colKleinteile = new OLVColumn("Kleinteile", "Kleinteile"); - colKleinteile.Text = "KT"; - colKleinteile.DisplayIndex = 7; - colKleinteile.TextAlign = HorizontalAlignment.Center; - colKleinteile.Width = 50; - colKleinteile.AspectGetter = row => { - var auftrag = (Auftrag)row; - - if (!KundeArtikel.HatKategorieArtikel(auftrag.KundeID, ArtikelKategorie.Kleinteile)) return string.Empty; - - - int abteilungen = (int)auftrag.Abteilungen; - - bool begonnen = (abteilungen & (int)AbteilungsStatus.KleinteileBegonnen) != 0; - bool beendet = (abteilungen & (int)AbteilungsStatus.KleinteileBeendet) != 0; - - if (beendet) return "☑"; // Status 1 ✓ - if (begonnen) return "☐"; // Status 2 ✓ - return "☒"; // Status 0 ✓ - }; - - - var colGrosseTeile = new OLVColumn("Großteile", "Großteile"); - colGrosseTeile.Text = "GT"; - colGrosseTeile.DisplayIndex = 8; - colGrosseTeile.TextAlign = HorizontalAlignment.Center; - colGrosseTeile.Width = 50; - colGrosseTeile.AspectGetter = row => { - var auftrag = (Auftrag)row; - - if (!KundeArtikel.HatKategorieArtikel(auftrag.KundeID, ArtikelKategorie.Grossteile)) return string.Empty; - - int abteilungen = (int)auftrag.Abteilungen; - - bool begonnen = (abteilungen & (int)AbteilungsStatus.GrossteileBegonnen) != 0; - bool beendet = (abteilungen & (int)AbteilungsStatus.GrossteileBeendet) != 0; - - if (beendet) return "☑"; // Status 1 ✓ - if (begonnen) return "☐"; // Status 2 ✓ - return "☒"; // Status 0 ✓ - }; - - - olv.AllColumns.Add(colFrottee); - olv.AllColumns.Add(colKleinteile); - olv.AllColumns.Add(colGrosseTeile); - - // ========== COLUMNS DURCHLAUFEN =========== - foreach (OLVColumn col in olv.AllColumns) + // ========== SPALTEN ANPASSEN ========== + var aufgabeCol = olv.AllColumns.Cast().FirstOrDefault(col => col.Text == "Aufgabe"); + if (aufgabeCol != null) + { + aufgabeCol.ImageGetter = rowObject => { - switch (col.Text) - { - case "Abschließen": // Abschließen Spalte als Button-Spalte konfigurieren - OLVColumn fertigColumn = col; - fertigColumn.DisplayIndex = 11; - fertigColumn.IsButton = true; // Als Button rendern - fertigColumn.ButtonSizing = OLVColumn.ButtonSizingMode.CellBounds; // Button füllt gesamte Zelle - fertigColumn.HeaderImageKey = "abschließen"; - fertigColumn.ShowTextInHeader = false; - fertigColumn.MinimumWidth = fertigColumn.MaximumWidth = 80; - break; - case "Etikett": // Etikett Spalte als Button-Spalte konfigurieren - OLVColumn etikettColumn = col; - etikettColumn.DisplayIndex = 10; - etikettColumn.IsButton = true; // Als Button rendern - etikettColumn.ButtonSizing = OLVColumn.ButtonSizingMode.CellBounds; // Button füllt gesamte Zelle - etikettColumn.HeaderImageKey = "print"; - etikettColumn.ShowTextInHeader = false; - etikettColumn.MinimumWidth = etikettColumn.MaximumWidth = 80; - break; - case "Aufgabe": // Aufgabe Spalte als Icon-Spalte: zeigt Icon wenn AufgabeID vorhanden - OLVColumn iconColumn = col; - iconColumn.DisplayIndex = 9; - iconColumn.ImageGetter = rowObject => - { - var auftrag = rowObject as Auftrag; - if (auftrag.AufgabeID == null) return null; // null = kein Icon anzeigen - else return 0; // Index 0 aus SmallImageList - }; - break; - case "Kunde": // Kunde Spalte als Icon-Spalte: zeigt Icon und Kundename wenn Anmerkung vorhanden - OLVColumn iColumn = col; - iColumn.DisplayIndex = 0; - iColumn.ImageGetter = rowObject => - { - var _auftrag = rowObject as Auftrag; - if (string.IsNullOrWhiteSpace(Kunde.GetKunde(null, _auftrag.KundeID, null).Anmerkung)) return null; // null = kein Icon anzeigen - else return 1; // Index 0 aus SmallImageList - }; - break; - case "Liefertag": // Liefertag Spalte Zeigt Liefertag als String an. - OLVColumn dateColumn = col; - dateColumn.DisplayIndex = 1; - dateColumn.AspectToStringFormat = "{0:ddd dd.MM.}"; - // DateTime-Filter für Spalte 2 - dateColumn.ClusteringStrategy = new DateTimeClusteringStrategy(DateTimePortion.Day, "ddd dd.MM."); // DateTimeClustering damit Datum gefiltert werden kann - olv.SecondarySortColumn = dateColumn; // Primary Sortiert nach Spalte 5 (Status) Secundary Sortiert nach Spalte 2 (Liefertag) - break; - case "Status": // Spalte 5 als primäre Sortier-Spalte festlegen (nach Datenbindung!) - OLVColumn sortcolumn = col; - sortcolumn.DisplayIndex = 4; - olv.PrimarySortColumn = sortcolumn; // Primary Sortiert nach Spalte 5 (Status) Secundary Sortiert nach Spalte 2 (Liefertag) - break; - case "Auswählen": - col.IsVisible = false; - break; - case "Erstellt": - col.IsVisible = false; - break; - case "Gedruckt": - col.IsVisible = false; - break; - case "Erledigt": - col.IsVisible = false; - break; - case "schmutzig": - col.HeaderImageKey = "dirt"; - col.ShowTextInHeader = false; - col.MinimumWidth = col.MaximumWidth = 80; - col.DisplayIndex = 2; - break; - case "sauber": - col.HeaderImageKey = "clean"; - col.ShowTextInHeader = false; - col.MinimumWidth = col.MaximumWidth = 80; - col.DisplayIndex = 3; - break; - default: - break; - } - - } - //TODO: Reihenfolge Spalten richtig stellen. - //TODO: OLV State speichern. + var auftrag = rowObject as View_Auftrag_Expedit; + return string.IsNullOrEmpty(auftrag?.AufgabeBezeichnung) ? -1 : 0; + }; + } + var kundeCol = olv.AllColumns.Cast().FirstOrDefault(col => col.Text == "Kunde"); + if (kundeCol != null) + { + kundeCol.ImageGetter = rowObject => + { + var auftrag = rowObject as View_Auftrag_Expedit; + return string.IsNullOrEmpty(auftrag?.Zusatz) ? -1 : 1; + }; + } + var dirtCol = olv.AllColumns.Cast().FirstOrDefault(col => col.Text == "Schmutzig"); + if (dirtCol != null) + { + dirtCol.HeaderImageKey = "dirt"; + dirtCol.ShowTextInHeader = false; + dirtCol.MinimumWidth = dirtCol.MaximumWidth = 80; + } + var cleanCol = olv.AllColumns.Cast().FirstOrDefault(col => col.Text == "Sauber"); + if (cleanCol != null) + { + cleanCol.HeaderImageKey = "clean"; + cleanCol.ShowTextInHeader = false; + cleanCol.MinimumWidth = dirtCol.MaximumWidth = 80; + } + var primaryCol = olv.AllColumns.Cast().FirstOrDefault(col => col.Text == "Status"); + if (primaryCol != null) olv.PrimarySortColumn = primaryCol; + var secondaryCol = olv.AllColumns.Cast().FirstOrDefault(col => col.Text == "Liefertag"); + if (secondaryCol != null) olv.SecondarySortColumn = secondaryCol; + var druckenCol = olv.AllColumns.Cast().FirstOrDefault(col => col.Text == "Etikett"); + if (druckenCol != null) + { + druckenCol.IsButton = true; // Als Button rendern + druckenCol.ButtonSizing = OLVColumn.ButtonSizingMode.CellBounds; // Button füllt gesamte Zelle + druckenCol.HeaderImageKey = "print"; + druckenCol.ShowTextInHeader = false; + druckenCol.MinimumWidth = druckenCol.MaximumWidth = 80; + } + var fertigCol = olv.AllColumns.Cast().FirstOrDefault(col => col.Text == "Abschließen"); + if (fertigCol != null) + { + fertigCol.IsButton = true; // Als Button rendern + fertigCol.ButtonSizing = OLVColumn.ButtonSizingMode.CellBounds; // Button füllt gesamte Zelle + fertigCol.HeaderImageKey = "abschließen"; + fertigCol.ShowTextInHeader = false; + fertigCol.MinimumWidth = fertigCol.MaximumWidth = 80; + } + // ========== SPALTEN JE NACH TAB UND ROLLE AUSBLENDEN ========== GetUnvisibleColumns(olv); - - olv.RebuildColumns(); - if (_settings.OLV_State != null) olv.RestoreState(_settings.OLV_State); + //if (_settings.OLV_State != null) olv.RestoreState(_settings.OLV_State); // ========== IMAGE-LIST ZUWEISEN ========== // SmallImageList für Icons in Detail-View (24x24 Pixel standard) Program.imagelist.ImageSize = new Size(24, 24); olv.SmallImageList = Program.imagelist; // Voraussetzung: imagelist mit Icon Index 0 gefüllt - + // ========== TOOLTIP FÜR ICON-SPALTEN ========== - // Automatischer Cell-Tooltip bei Mouse-Hover über Spalte 10 und 1 + // Automatischer Cell-Tooltip bei Mouse-Hover olv.CellToolTipShowing += (s, e) => + { + // Nur für Icon-Spalte (Index 10) und gültiges Model + if (e.Column.Text == "Aufgabe" && e.Model is View_Auftrag_Expedit) { - // Nur für Icon-Spalte (Index 10) und gültiges Model - if (e.Column.Text == "Aufgabe" && e.Model is Auftrag auftrag) + Auftrag auftrag = Auftrag.GetAuftrag(((View_Auftrag_Expedit)e.Model).AuftragID); + // Lade Bezeichnung der Aufgabe als Tooltip-Text + e.Text = Aufgabe.GetAufgabe(null, auftrag.AufgabeID).Bezeichnung; + } + // Nur für Icon-Spalte (Index 1) und gültiges Model + if (e.Column.Text == "Kunde" && e.Model is View_Auftrag_Expedit) + { + Auftrag _auftrag = Auftrag.GetAuftrag(((View_Auftrag_Expedit)e.Model).AuftragID); + if (!string.IsNullOrWhiteSpace(Kunde.GetKunde(null, _auftrag.KundeID, null).Anmerkung)) { - // Lade Bezeichnung der Aufgabe als Tooltip-Text - e.Text = Aufgabe.GetAufgabe(null, auftrag.AufgabeID).Bezeichnung; + // Lade Anmerkung als Tooltip-Text + e.Text = Kunde.GetKunde(null, _auftrag.KundeID, null).Anmerkung; } - // Nur für Icon-Spalte (Index 1) und gültiges Model - if (e.Column.Text == "Kunde" && e.Model is Auftrag _auftrag) - { - if (!string.IsNullOrWhiteSpace(Kunde.GetKunde(null, _auftrag.KundeID, null).Anmerkung)) - { - // Lade Anmerkung als Tooltip-Text - e.Text = Kunde.GetKunde(null, _auftrag.KundeID, null).Anmerkung; - } - } - if (e.Column.Text == "Fahrer" && e.Model is Auftrag auftrag1) - { - e.Text = auftrag1.ZusatzInfo; - } - }; + } + if (e.Column.Text == "Fahrer" && e.Model is Auftrag auftrag1) + { + e.Text = auftrag1.ZusatzInfo; + } + }; // ========== DATEN LADEN ========== // WICHTIG: SetObjects NACH Column-Konfiguration aufrufen! - OLV_SetObjects(olv, auftraglist); - olv.RefreshObjects(auftraglist); - // ========== SORTIERUNG ========== - olv.Sort(); - - // ========== SPALTEN ANPASSEN ========== - olv = Funktionen.Columns_Resize(null, olv).olv; // Externe Funktion für responsive Spaltenbreiten + OLV_SetObjects(olv, auftragliste); + // ========== SORTIERUNG NACH SPALTEN ========== + olv.Sort(); + + // ========== SPALTENBREITE ANPASSEN ========== + olv = Funktionen.Columns_Resize(null, olv).olv; + + // ========== FILTER AKTIVIEREN UND ZUWEISEN ========== olv.FilterMenuBuildStrategy = new MeinFilterMenu(); + // ========== AUFRÄUMEN & AKTIVIEREN ========== olv.ResumeLayout(); // Layout-Pause beenden, Positionen neu berechnen + olv.EndUpdate(); // Update-Pause beenden, Daten neu zeichnen olv.Focus(); // OLV fokussieren (Tastaturbedienung aktivieren) this.UseWaitCursor = false; + } private void objectListViewAuftrag_FormatCell(object sender, FormatCellEventArgs e) { - - if (e.ColumnIndex == 11) - { // jede zweite Spalte + ObjectListView olv = (ObjectListView)sender; + + if (e.Column.IsButton) + { if(e.SubItem.BackColor != Color.LightBlue) { e.SubItem.BackColor = Color.AliceBlue; e.SubItem.ForeColor = Color.Black; - } else { @@ -542,9 +443,9 @@ namespace Deckungsbeitrag { itemlocation = new Point(e.Location.X, e.Location.Y); ObjectListView olv = (ObjectListView)sender; - Auftrag _auftrag = (Auftrag)e.Model; - if (e.Model == null) { chartFehlmenge.Visible = false; groupBoxKndInfo.Visible = false; return; } + Auftrag _auftrag = Auftrag.GetAuftrag(((View_Auftrag_Expedit)e.Model).AuftragID); + if (_auftrag.Status != AuftragStatus.Fertig) { this.auftrag = _auftrag; @@ -593,7 +494,7 @@ namespace Deckungsbeitrag // Überprüfung ob Click auf einem Item war. if (e.Model == null) return; - Auftrag _auftrag = (Auftrag)e.Model; + Auftrag _auftrag = Auftrag.GetAuftrag(((View_Auftrag_Expedit)e.Model).AuftragID); Kunde _kunde = Kunde.GetKunde(null, _auftrag.KundeID, null); string name = string.Empty; if (string.IsNullOrWhiteSpace(_kunde.Suchtext)) name = _kunde.KundeName; @@ -626,15 +527,11 @@ namespace Deckungsbeitrag _auftrag.Save(); olv.RefreshObject(e); - if (olv.Name.Contains("Sonder")) - { - await GetSonderAuftraege(); - OLV_SetObjects(olv, sonderlist); - } - - if (olv.Name.Contains("Geschaeft")) { await GetAuftraege(ListenArt.Geschäftliste); OLV_SetObjects(olv, geschaeftlist); } - if (olv.Name.Contains("Auftrag")) { await GetAuftraege(ListenArt.Auftragliste); OLV_SetObjects(olv, auftraglist); } - if (olv.Name.Contains("Rampe")) { await GetAuftraege(ListenArt.Rampenliste); OLV_SetObjects(olv, rampenlist); } + if (olv.Name.Contains("Geschaeft")) { await GetAuftraegeAsync(ListenArt.Geschäftliste); OLV_SetObjects(olv, listAuftragGeschaeft); } + if (olv.Name.Contains("Auftrag")) { await GetAuftraegeAsync(ListenArt.Auftragliste); OLV_SetObjects(olv, listAuftragToday); } + if (olv.Name.Contains("Rampe")) { await GetAuftraegeAsync(ListenArt.Rampenliste); OLV_SetObjects(olv, listRampe); } + if (olv.Name.Contains("Vorbereitet")) { await GetAuftraegeAsync(ListenArt.Vorbereitetliste); OLV_SetObjects(olv, listVorbereitet); } + if (olv.Name.Contains("Sonder")) { await GetAuftraegeAsync(ListenArt.Sonderliste); OLV_SetObjects(olv, listSonderAuftrag); } } break; case "Aufgabe": @@ -660,7 +557,7 @@ namespace Deckungsbeitrag private void objectListViewAuftrag_ButtonClick(object sender, BrightIdeasSoftware.CellClickEventArgs e) { ObjectListView olv = (ObjectListView)sender; - Auftrag _auftrag = (Auftrag)e.Model; + Auftrag _auftrag = Auftrag.GetAuftrag(((View_Auftrag_Expedit)e.Model).AuftragID); if (e.Column.Text == "Abschließen") { if (olv.CheckedItems.Count > 0) @@ -785,9 +682,7 @@ namespace Deckungsbeitrag if (this.auftrag.ContainerClean != 0) { - //AUFTRAG UPDATE letzterLiefertag = this.auftrag.Liefertag; - } else { @@ -808,8 +703,8 @@ namespace Deckungsbeitrag DialogResult result = Funktionen.Etikett_Drucken(auftrag, nocont); if (result == DialogResult.OK) { - this.auftrag.Gedruckt = this.auftrag.Erstellt = DateTime.Now; - this.auftrag.GedrucktVon = this.auftrag.ErstelltVon = (int)this.benutzer.BenutzerID; + this.auftrag.Gedruckt = DateTime.Now; + this.auftrag.GedrucktVon = (int)this.benutzer.BenutzerID; this.auftrag.Status = AuftragStatus.Vorbereitet; this.auftrag.Save(); this.auftrag = null; @@ -817,7 +712,6 @@ namespace Deckungsbeitrag } Neuladen_OLV(olv); - this.UseWaitCursor = false; } @@ -826,14 +720,12 @@ namespace Deckungsbeitrag /// /// /// - private void OLV_SetObjects(ObjectListView olv, List auftraglist) + private void OLV_SetObjects(ObjectListView olv, List auftraglist) { - if (olv.AllColumns.Count == 0) OLV_Load(olv, auftraglist); + if (olv.AllColumns.Count == 0) Load_OLV(olv, auftraglist); else { - olv.BeginUpdate(); // Stoppt Datenaktualisierungen/Redraws olv.SetObjects(auftraglist); // Bindet die Auftragsliste an die View - olv.EndUpdate(); // Update-Pause beenden, Daten neu zeichnen } } @@ -845,20 +737,14 @@ namespace Deckungsbeitrag { this.UseWaitCursor = true; olv.SuspendLayout(); - // Neu-Laden der Sonderaufträge ObjectListView - if (olv.Name.Contains("Sonder")) - { - await GetSonderAuftraege(); - OLV_SetObjects(olv, sonderlist); - } - else - { - // Neu-Laden der Standartaufträge ObjectListView - if (olv.Name.Contains("Geschaeft")) { await GetAuftraege(ListenArt.Geschäftliste); OLV_SetObjects(olv, geschaeftlist); } - if (olv.Name.Contains("Auftrag")) { await GetAuftraege(ListenArt.Auftragliste); OLV_SetObjects(olv, auftraglist); } - if (olv.Name.Contains("Rampe")) { await GetAuftraege(ListenArt.Rampenliste); OLV_SetObjects(olv, rampenlist); } - if (olv.Name.Contains("Vorbereitet")) { await GetAuftraege(ListenArt.Vorbereitetliste); OLV_SetObjects(olv, vorbereitetliste); } - } + + // Neu-Laden der ObjectListView + if (olv.Name.Contains("Geschaeft")) { await GetAuftraegeAsync(ListenArt.Geschäftliste); OLV_SetObjects(olv, listAuftragGeschaeft); } + if (olv.Name.Contains("Auftrag")) { await GetAuftraegeAsync(ListenArt.Auftragliste); OLV_SetObjects(olv, listAuftragToday); } + if (olv.Name.Contains("Rampe")) { await GetAuftraegeAsync(ListenArt.Rampenliste); OLV_SetObjects(olv, listRampe); } + if (olv.Name.Contains("Vorbereitet")) { await GetAuftraegeAsync(ListenArt.Vorbereitetliste); OLV_SetObjects(olv, listVorbereitet); } + if (olv.Name.Contains("Sonder")) { await GetAuftraegeAsync(ListenArt.Sonderliste); OLV_SetObjects(olv, listSonderAuftrag); } + GetUnvisibleColumns(olv); olv.ResumeLayout(false); this.UseWaitCursor = false; @@ -881,6 +767,7 @@ namespace Deckungsbeitrag col.HeaderCheckBox = true; col.HeaderCheckBoxUpdatesRowCheckBoxes = true; } + if (col.Text == "FR" || col.Text == "GT" || col.Text == "KT") col.IsVisible = false; break; case var t when t == "Rampe": if (col.IsButton) col.IsVisible = false; @@ -891,14 +778,15 @@ namespace Deckungsbeitrag if (col.Text == "Etikett") col.IsVisible = false; break; case var t when t == "Aufträge heute": - if (this.benutzer.Rolle == BenutzerRolle.Frottee) + if (col.Text == "Abschließen") { - if (col.Text == "Abschließen") col.IsVisible = true; + //Für alle BenutzerRollen Abschließen ausblenden. + //Nur FrotteeExpedit sieht Abschließen um Abteilung zu beenden. + if (this.benutzer.Rolle == BenutzerRolle.Frottee) col.IsVisible = true; + else col.IsVisible = false; } break; default: - //Für alle BenutzerRollen Abschließen ausblenden. - if (col.IsButton & col.Text == "Abschließen") col.IsVisible = false; break; } @@ -917,7 +805,7 @@ namespace Deckungsbeitrag private void objectListViewAuftrag_CellEditFinished(object sender, CellEditEventArgs e) { ObjectListView olv = (ObjectListView)sender; - this.auftrag = (Auftrag)e.RowObject; + this.auftrag = Auftrag.GetAuftrag(((View_Auftrag_Expedit)e.RowObject).AuftragID); if (e.Column.Text == "sauber") altecontclean = (int?)e.Value; if (!string.IsNullOrWhiteSpace(e.NewValue.ToString())) Save_Auftrag(this.auftrag, false); //Neuladen_OLV(olv); @@ -930,10 +818,10 @@ namespace Deckungsbeitrag /// private void objectListViewAuftrag_CellEditStarting(object sender, CellEditEventArgs e) { - if (e.Column.AspectName == "Kundename") + if (e.Column.AspectName == "KundeName") { ObjectListView olv = (ObjectListView)sender; - Auftrag _auftrag = e.RowObject as Auftrag; + Auftrag _auftrag = Auftrag.GetAuftrag(((View_Auftrag_Expedit)e.RowObject).AuftragID); if (_auftrag == null) return; Kunde _kunde = Kunde.GetKunde(null, _auftrag.KundeID, null); @@ -1003,58 +891,24 @@ namespace Deckungsbeitrag } - /// - /// Auftragslisten erstellen und in ObjectListViews laden. - /// - private async Task GetSonderAuftraege() + private async Task GetAuftraegeAsync(ListenArt? liste) { - var conn = new NpgsqlConnection(ConfigurationManager.AppSettings["ConnectionString"]); // Pro Task! - try - { - await conn.OpenAsync(); - if (this.benutzer.Rolle == BenutzerRolle.Frottee) - { - sonderlist = await Auftrag.GetSonderListsAsync((int)AuftragTyp.Inventur, conn, (int)AbteilungsStatus.FrotteeBegonnen); - } - else - { - sonderlist = await Auftrag.GetSonderListsAsync((int)AuftragTyp.Inventur, conn, null); - } - } - finally - { - if (conn.State == ConnectionState.Open) - conn.Close(); - conn.Dispose(); - } - } - private async Task GetAuftraege(ListenArt? liste) - { - var conn = new NpgsqlConnection(ConfigurationManager.AppSettings["ConnectionString"]); // Pro Task! - try - { - await conn.OpenAsync(); - if (this.benutzer.Rolle == BenutzerRolle.Frottee) - { - if (liste == null || liste == ListenArt.Auftragliste) auftraglist = await Auftrag.GetAuftragListTodayAsync(AuftragStatus.Vorbereitet, conn, null, (int)AbteilungsStatus.FrotteeBegonnen); - if (liste == null || liste == ListenArt.Geschäftliste) geschaeftlist = await Auftrag.GetAuftragListTodayAsync(null, conn, AuftragTyp.Geschäft, (int)AbteilungsStatus.FrotteeBegonnen); - } - else - { - if (liste == null || liste == ListenArt.Auftragliste) auftraglist = await Auftrag.GetAuftragListTodayAsync(AuftragStatus.Vorbereitet, conn, null, null); - if (liste == null || liste == ListenArt.Geschäftliste) geschaeftlist = await Auftrag.GetAuftragListTodayAsync(null, conn, AuftragTyp.Geschäft, null); - if (liste == null || liste == ListenArt.Rampenliste) rampenlist = await Auftrag.GetAuftragListTodayAsync(AuftragStatus.Abgeholt, conn, AuftragTyp.Standart, null); - if (liste == null || liste == ListenArt.Vorbereitetliste) vorbereitetliste = await Auftrag.GetAuftragListTodayAsync(AuftragStatus.Vorbereitet, conn, AuftragTyp.Standart, null); - } - } - finally - { - if (conn.State == ConnectionState.Open) - conn.Close(); - conn.Dispose(); - } - } + if (this.benutzer.Rolle != BenutzerRolle.Frottee) + { + if (liste == null || liste == ListenArt.Auftragliste) listAuftragToday = await View_Auftrag_Expedit.GetAuftragExpeditAsync(statusFilter: AuftragStatus.Vorbereitet, minStatusFilter: AuftragStatus.Gewaschen); + if (liste == null || liste == ListenArt.Geschäftliste) listAuftragGeschaeft = await View_Auftrag_Expedit.GetAuftragExpeditAsync(statusFilter: AuftragStatus.Fertig, minStatusFilter: AuftragStatus.Abgeholt, typFilter: AuftragTyp.Geschäft); + if (liste == null || liste == ListenArt.Vorbereitetliste) listVorbereitet = await View_Auftrag_Expedit.GetAuftragExpeditAsync(statusFilter: AuftragStatus.Vorbereitet); + if (liste == null || liste == ListenArt.Sonderliste) listSonderAuftrag = await View_Auftrag_Expedit.GetAuftragExpeditAsync(statusFilter: AuftragStatus.Fertig, minStatusFilter: AuftragStatus.Herrichten, typFilter: AuftragTyp.Einmalig, minTypFilter: AuftragTyp.Inventur); + if (liste == null || liste == ListenArt.Rampenliste) listRampe = await View_Auftrag_Expedit.GetAuftragExpeditAsync(statusFilter: AuftragStatus.Abgeholt, typFilter: AuftragTyp.Standart); + } + else + { + if (liste == null || liste == ListenArt.Auftragliste) listAuftragToday = await View_Auftrag_Expedit.GetAuftragExpeditAsync(statusFilter: AuftragStatus.Vorbereitet, minStatusFilter: AuftragStatus.Gewaschen, frottee: true); + if (liste == null || liste == ListenArt.Sonderliste) listSonderAuftrag = await View_Auftrag_Expedit.GetAuftragExpeditAsync(statusFilter: AuftragStatus.Fertig, minStatusFilter: AuftragStatus.Herrichten, typFilter: AuftragTyp.Einmalig, minTypFilter: AuftragTyp.Inventur, frottee: true); + } + + } /// /// Zeigt Fenster zur Eingabe von Text. /// diff --git a/AA-Forms/FormMain.cs b/AA-Forms/FormMain.cs index 7fe6606..66735e7 100644 --- a/AA-Forms/FormMain.cs +++ b/AA-Forms/FormMain.cs @@ -37,8 +37,8 @@ namespace Deckungsbeitrag #region Properties private Benutzer benutzer = null; - private Meldungen meldung = new Meldungen(); - private bool open = false; + private Meldungen meldung = new Meldungen(); + private bool open = false; private bool isDragging = false; private Point dragStartPoint; private Point newLocation; @@ -225,7 +225,6 @@ namespace Deckungsbeitrag tsb.BackColor = Program.Wirlblau; } } - private void tSBBenutzerVW_Click(object sender, EventArgs e) { FormBenutzerVW benutzerVW = new FormBenutzerVW(); diff --git a/AA-Klassen/DataClass.cs b/AA-Klassen/DataClass.cs index ecf388e..8decd0b 100644 --- a/AA-Klassen/DataClass.cs +++ b/AA-Klassen/DataClass.cs @@ -1,7 +1,9 @@ using BrightIdeasSoftware; using DatenDB; +using Npgsql; using System; using System.Collections.Generic; +using System.Configuration; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -49,4 +51,318 @@ namespace Deckungsbeitrag.AA_Klassen public int KundeID { get; set; } public int[] ContAnzahl { get; set; } = new int[3]; } + + /// + /// DB-View für Nachwäsche, NW2Müll und NW2Sauber Statistik. Tageseinträge von nw_artikel werden addiert/subtrahiert. + /// + public class View_Artikel_Nachwaesche + { + public static List LadeNachwaesche() + { + string _connectionString = ConfigurationManager.AppSettings["ConnectionString"]; + var result = new List(); + + using (var conn = new NpgsqlConnection(_connectionString)) + using (var cmd = new NpgsqlCommand(@" + SELECT artnr, abteilung, artname, nw, muell, sauber + FROM kundenverwaltung.vw_art_nachwaesche + ORDER BY artnr ASC", conn)) + { + conn.Open(); + using (var reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + result.Add(new View_Artikel_Nachwaesche + { + ArtNr = reader.GetInt32(0), + Abteilung = (ArtikelKategorie)reader.GetInt16(1), + ArtName = reader.GetString(2), + Nachwaesche = reader.IsDBNull(3) ? 0 : reader.GetInt32(3), + Muell = reader.IsDBNull(4) ? 0 : reader.GetInt32(4), + Sauber = reader.IsDBNull(5) ? 0 : reader.GetInt32(5) + }); + } + } + } + + return result; + } + [OLVColumn("ArtNr.", DisplayIndex = 0, IsEditable = false)] public int ArtNr { get; set; } + [OLVColumn("Abteilung", DisplayIndex = 1, IsEditable = false)] public ArtikelKategorie Abteilung { get; set; } + [OLVColumn("ArtName", DisplayIndex = 2, IsEditable = false)] public string ArtName { get; set; } + [OLVColumn("NW", DisplayIndex = 3, TextAlign = HorizontalAlignment.Center)] public int Nachwaesche { get; set; } + [OLVColumn("Müll", DisplayIndex = 4, TextAlign = HorizontalAlignment.Center)] public int Muell { get; set; } + [OLVColumn("Sauber", DisplayIndex = 5, TextAlign = HorizontalAlignment.Center)] public int Sauber { get; set; } + } + + /// + /// DB-View für Expedit. Sollte schneller bearbeitet werden können. Filtern ist einfacher. + /// + public class View_Auftrag_Expedit + { + /// + /// Holt die Aufträge aus der DB-View. + /// + /// Kleiner als Status + /// Größer/Gleich Status + /// Kleiner als Typ + /// Größer/Gleich Typ + /// true wenn Frottee-Expedit + /// + /// + public static async Task> GetAuftragExpeditAsync( + AuftragStatus? statusFilter = null, + AuftragStatus? minStatusFilter = null, + AuftragTyp? typFilter = null, + AuftragTyp? minTypFilter = null, + bool? frottee = null, + NpgsqlConnection conn = null) + { + string _connectionString = ConfigurationManager.AppSettings["ConnectionString"]; + var resultList = new List(); + + NpgsqlConnection connection = conn ?? new NpgsqlConnection(_connectionString); + try + { + await connection.OpenAsync(); + + NpgsqlCommand command = new NpgsqlCommand("SELECT * FROM kundenverwaltung.vw_auftrag_expedit WHERE 1=1", connection); + try + { + var conditions = new List(); + var parameters = new List(); + + // Status-Filter + if (statusFilter.HasValue) + { + if (minStatusFilter.HasValue) + { + conditions.Add("status < @status AND status >= @min_status"); + parameters.Add(new NpgsqlParameter("@status", (int)statusFilter.Value)); + parameters.Add(new NpgsqlParameter("@min_status", (int)minStatusFilter.Value)); + } + else + { + conditions.Add("status = @status"); + parameters.Add(new NpgsqlParameter("@status", (int)statusFilter.Value)); + } + } + + // Typ-Filter + if (typFilter.HasValue) + { + if (minTypFilter.HasValue) + { + conditions.Add("typ < @typ AND typ >= @min_typ"); + parameters.Add(new NpgsqlParameter("@typ", (int)typFilter.Value)); + parameters.Add(new NpgsqlParameter("@min_typ", (int)minTypFilter.Value)); + } + else + { + conditions.Add("typ = @typ"); + parameters.Add(new NpgsqlParameter("@typ", (int)typFilter.Value)); + } + } + + // Frottee-Filter + if (frottee.HasValue && frottee.Value) + conditions.Add($"frottee_status < 2"); + + if (conditions.Count > 0) + command.CommandText += " AND " + string.Join(" AND ", conditions); + + command.CommandText += " ORDER BY liefertag ASC"; + command.Parameters.AddRange(parameters.ToArray()); + + NpgsqlDataReader reader = await command.ExecuteReaderAsync(); + try + { + while (await reader.ReadAsync()) + { + resultList.Add(new View_Auftrag_Expedit + { + AuftragID = SafeInt(reader, "auftrag_id"), + BenutzerID = SafeInt(reader, "benutzer_id"), + AufgabeID = SafeInt(reader, "aufgabe_id"), + KundeID = SafeInt(reader, "kunde_id"), + Zusatz = SafeString(reader, "zusatz"), + Liefertag = SafeDateTime(reader, "liefertag"), + Status = (AuftragStatus)SafeInt(reader, "status"), + TourID = SafeIntNullable(reader, "tour_id"), + ContainerDirt = SafeInt(reader, "container_dirt"), + ContainerClean = SafeInt(reader, "container_clean"), + Typ = (AuftragTyp)SafeInt(reader, "typ"), + AufgabeErledigt = SafeBool(reader, "aufgabe_erledigt"), + AbteilungenStatus = (AbteilungsStatus)SafeInt(reader, "abteilungen_status"), + Rhythmus = (RegRhythmen)SafeInt(reader, "rhythmus"), + Priority = (AuftragPriority)SafeInt(reader, "priority"), + Gedruckt = SafeDateTime(reader, "gedruckt"), + AufgabeBezeichnung = SafeString(reader, "aufgabe_bez"), + KundeName = SafeString(reader, "suchtext"), + Fahrer = SafeString(reader, "fahrer"), + FrotteeStatus = SafeInt(reader, "frottee_status"), + KleinteileStatus = SafeInt(reader, "kleinteile_status"), + GrossteileStatus = SafeInt(reader, "grossteile_status") + }); + } + } + finally + { + reader.Dispose(); + } + } + finally + { + command.Dispose(); + } + } + finally + { + connection.Dispose(); + } + + return resultList; + } + // Auftrag-Felder (ACOLUMNS) + [OLVIgnore]public int AuftragID { get; set; } + [OLVIgnore]public int BenutzerID { get; set; } + [OLVIgnore]public int? AufgabeID { get; set; } + [OLVIgnore]public int KundeID { get; set; } + [OLVIgnore]public string Zusatz { get; set; } + [OLVColumn("Liefertag", AspectToStringFormat = "{0:ddd dd.MM}", DisplayIndex = 10)]public DateTime? Liefertag { get; set; } + [OLVColumn("Status", DisplayIndex = 40)]public AuftragStatus Status { get; set; } + [OLVIgnore]public int? TourID { get; set; } + [OLVColumn("Schmutzig", DisplayIndex = 20, TextAlign = HorizontalAlignment.Center)]public int ContainerDirt { get; set; } + [OLVColumn("Sauber", DisplayIndex = 30, TextAlign = HorizontalAlignment.Center)]public int ContainerClean { get; set; } + [OLVColumn("Typ", DisplayIndex = 50)]public AuftragTyp Typ { get; set; } + [OLVIgnore]public bool AufgabeErledigt { get; set; } + [OLVIgnore]public AbteilungsStatus AbteilungenStatus { get; set; } + [OLVIgnore]public RegRhythmen Rhythmus { get; set; } + [OLVColumn("Priority", DisplayIndex = 15)]public AuftragPriority Priority { get; set; } + [OLVIgnore]private DateTime? Gedruckt { get; set; } + + + // Join-Felder aus Table kunde & benutzer + [OLVColumn("Aufgabe", DisplayIndex = 55)]public string AufgabeBezeichnung { get; set; } + [OLVColumn("Kunde", DisplayIndex = 0)]public string KundeName { get; set; } + [OLVColumn("Fahrer", DisplayIndex = 70)]public string Fahrer { get; set; } + + // **3 Status-Spalten statt 12 Flags** + [OLVIgnore]public int FrotteeStatus { get; set; } + [OLVIgnore]public int KleinteileStatus { get; set; } + [OLVIgnore]public int GrossteileStatus { get; set; } + + // **Ein zentrales Dictionary für alle AbteilungStatus-Anzeigen** + private static readonly Dictionary StatusAnzeigen = new Dictionary + { + [0] = "☒", + [1] = "☐", + [2] = "☑", + [3] = string.Empty, + }; + + // **String Anzeigen von Properties** + [OLVColumn("FR", DisplayIndex = 60, TextAlign = HorizontalAlignment.Center)]public string FrotteeAnzeige + { + get { return StatusAnzeigen.TryGetValue(FrotteeStatus, out string text) ? text : "?"; } + } + [OLVColumn("KT", DisplayIndex = 61, TextAlign = HorizontalAlignment.Center)]public string KleinteileAnzeige + { + get { return StatusAnzeigen.TryGetValue(KleinteileStatus, out string text) ? text : "?"; } + } + [OLVColumn("GT", DisplayIndex = 62, TextAlign = HorizontalAlignment.Center)]public string GrossteileAnzeige + { + get { return StatusAnzeigen.TryGetValue(GrossteileStatus, out string text) ? text : "?"; } + } + [OLVColumn("Etikett", DisplayIndex = 80, TextAlign = HorizontalAlignment.Center)]public string DruckenAnzeige + { + get + { + // Wenn NICHT gedruckt (null oder MinValue) → Druck-Symbol + if (!Gedruckt.HasValue) + return "🖨"; + + // Gedruckt → Datum oder leer + return string.Empty; + } + } + [OLVColumn("Abschließen", DisplayIndex = 90, TextAlign = HorizontalAlignment.Center)]public string AbschliessenAnzeige + { + get + { + // Wenn NICHT gedruckt (null oder MinValue) → Druck-Symbol + if (Gedruckt.HasValue) + return "✅"; + + if (FrotteeStatus < 2) + return "✅"; + + // Gedruckt → Datum oder leer + return string.Empty; + } + } + + + private static int SafeInt(NpgsqlDataReader reader, string columnName) + { + int ordinal; + try { ordinal = reader.GetOrdinal(columnName); } + catch { return 0; } // Spalte existiert nicht + + return reader.IsDBNull(ordinal) ? 0 : reader.GetInt32(ordinal); + } + + private static int? SafeIntNullable(NpgsqlDataReader reader, string columnName) + { + int ordinal; + try { ordinal = reader.GetOrdinal(columnName); } + catch { return null; } + + return reader.IsDBNull(ordinal) ? (int?)null : reader.GetInt32(ordinal); + } + + private static string SafeString(NpgsqlDataReader reader, string columnName) + { + int ordinal; + try { ordinal = reader.GetOrdinal(columnName); } + catch { return null; } + + if (columnName == "suchtext") + { + if (reader.IsDBNull(ordinal)) + { + ordinal = reader.GetOrdinal("kunde_name"); + } + } + + return reader.IsDBNull(ordinal) ? null : reader.GetString(ordinal); + } + + private static bool SafeBool(NpgsqlDataReader reader, string columnName) + { + int ordinal; + try { ordinal = reader.GetOrdinal(columnName); } + catch { return false; } + + return !reader.IsDBNull(ordinal) && reader.GetBoolean(ordinal); + } + + private static DateTime? SafeDateTime(NpgsqlDataReader reader, string columnName) + { + int ordinal; + try + { + ordinal = reader.GetOrdinal(columnName); + } + catch + { + return null; // Spalte existiert nicht + } + + if (reader.IsDBNull(ordinal)) + return null; + else return reader.GetDateTime(ordinal); + } + } } diff --git a/Verwaltung_ReadMe.txt b/Verwaltung_ReadMe.txt index 74ced7c..2e6eb2f 100644 --- a/Verwaltung_ReadMe.txt +++ b/Verwaltung_ReadMe.txt @@ -5,7 +5,7 @@ NEUIGKEITEN - Version 1.0.9.1 Build-Info: - Build-Typ: Release Build - Erledigte TODOs: 19 -- Offene TODOs: 38 +- Offene TODOs: 36 - Install-Reminders: 4 - Changes: 15 @@ -56,7 +56,7 @@ Build-Info: - ✅ : Wenn RegAuftrag wird als augeliefert markiert, wird dieser automatisch neu erstellt laut hinterlegtem Rhythmus. [FormMain.cs] -=== 🔄 OFFENE TODOs (38) === +=== 🔄 OFFENE TODOs (36) === - 🔄 !!ÜBERLEGE!! DB-Query für Kundenanzahl und Containeranzahl Abgleich. (Aufträge haben TourID hinterlegt. So sollte alles vergleichbar sein.) [Tour.cs] - 🔄 !!ÜBERLEGE!! Tour Start und Ende automatisch erfassen. [Tour.cs] - 🔄 Alle Icons in einer Spalte anzeigen? I für Anmerkung und ! für Aufgabe?? [FormMain.cs] @@ -82,9 +82,7 @@ Build-Info: - 🔄 Nach Test und Rücksprache eventuell wieder umbauen. Benutzer.Rolle etc. [FormFehlmengeCount.cs] - 🔄 nicht ganze Aufträge holen sondern nur die Zahlen? [FormMain.cs] - 🔄 Non-Hard-Coded-Lösung für Priority finden. [Auftrag.cs] -- 🔄 OLV State speichern. [FormExpedit.cs] - 🔄 Reg.Aufträge einbauen. Besonderheit: Die Artikel sollen ebenfalls erscheinen. [Funktionen.cs] -- 🔄 Reihenfolge Spalten richtig stellen. [FormExpedit.cs] - 🔄 Settings hier ändern auf UserSettingsManager Klasse. [FormEinstellung.cs] - 🔄 Speichern etc. durchgehen und adaptieren [FormAuftragDetail.cs] - 🔄 TourenListe Entwurf muss überarbeitet werden. [FormNeuerAuftrag.cs] @@ -96,5 +94,5 @@ Build-Info: - 🔄 Wenn Frottee-Expedit auch Relamation bearbeitet, muss BenutzerRolle abgefragt werden. siehe CHANGES. [FormFehlmengeCount.cs] - 🔄 Zuweisung zu Fahrer muss geklärt werden. [Funktionen.cs] -Installation: 10.04.2026 13:40 +Installation: 14.04.2026 14:55 =====================================