Zum Inhalt

Liefertage-Einstellungen

Übersicht

Die Liefertage-Einstellungen ermöglichen die Konfiguration von: - Wochentage: An welchen Tagen geliefert wird (Mo-So) - Feiertage: Deutsche Feiertage, an denen geliefert wird (automatisch berechnet) - Betriebsurlaub: Zeiträume, in denen das Unternehmen geschlossen ist - Ausnahmetage: Einzelne Tage, die von der normalen Lieferroutine abweichen

Komponenten

1. Model: DeliveryDaysSettings

Datei: lib/models/system_settings/delivery_days_settings.dart

Enthält: - deliveryWeekdays: List (1=Montag, 7=Sonntag) - publicHolidays: List (IDs der Feiertage, an denen geliefert wird) - vacationPeriods: List (Betriebsurlaub-Zeiträume) - exceptionDays: List (Einzelne Ausnahmetage)

2. Service: HolidayService

Datei: lib/services/holiday_service.dart

Funktionen: - calculateEasterSunday(int year): Berechnet Ostersonntag mit Gauß-Algorithmus - calculateHolidays(int year, List holidayIds): Berechnet alle Feiertage für ein Jahr - availableHolidays: Map mit 14 deutschen Feiertagen: - 9 bundesweite Feiertage (Neujahr, Karfreitag, Ostermontag, Tag der Arbeit, Christi Himmelfahrt, Pfingstmontag, Tag der Deutschen Einheit, 1./2. Weihnachtstag) - 5 regionale Feiertage (Heilige Drei Könige, Fronleichnam, Mariä Himmelfahrt, Reformationstag, Allerheiligen)

3. UI: DeliveryDaysSettingsPage

Datei: lib/pages/settings/delivery_days_settings/delivery_days_settings_page.dart

Features: - Wochentag-Chips: Visuell ansprechende Auswahl der Liefertage - Feiertags-Schalter: Auswahl der Feiertage, an denen geliefert wird (mit Datumsanzeige) - Betriebsurlaub-Management: Hinzufügen und Löschen von Urlaubszeiträumen mit EsDatePicker - Ausnahmetage: Einzelne Tage mit EsDatePicker hinzufügen

4. BLoC Integration

Dateien: - lib/blocs/system_settings_bloc/system_settings_bloc_events.dart - lib/blocs/system_settings_bloc/system_settings_bloc.dart

Event: - UpdateDeliveryDaysSettings: Aktualisiert die Liefertage-Einstellungen

State Management: - _deliveryDaysSettings: Privates Feld im SystemSettingsBloc - deliveryDaysSettings: Getter für Zugriff - _onUpdateDeliveryDaysSettings: Handler für Updates

5. Firebase Service

Datei: lib/services/firebase_services/system_settings_firebase_service.dart

Methoden: - getDeliveryDaysSettings(): Lädt Einstellungen aus Firestore - updateDeliveryDaysSettings(DeliveryDaysSettings settings): Speichert Einstellungen

Dokument: systemSettings/delivery_days_settings

Verwendung

Die Liefertage-Einstellungen sind in den Einstellungen unter "Liefertage" erreichbar (nach "Bestellungen").

Datenstruktur in Firestore

{
  "deliveryWeekdays": [1, 2, 3, 4, 5],
  "publicHolidays": ["neujahr", "karfreitag", "tag_der_arbeit"],
  "vacationPeriods": [
    {
      "startDate": "2024-07-15",
      "endDate": "2024-07-31",
      "description": "Sommerurlaub"
    }
  ],
  "exceptionDays": ["2024-12-24", "2024-12-31"]
}

Feiertagsberechnung

Der HolidayService verwendet den Gauß-Algorithmus zur Berechnung des Ostersonntags, der die Basis für alle beweglichen Feiertage ist:

  • Karfreitag: Ostersonntag - 2 Tage
  • Ostermontag: Ostersonntag + 1 Tag
  • Christi Himmelfahrt: Ostersonntag + 39 Tage
  • Pfingstmontag: Ostersonntag + 50 Tage
  • Fronleichnam: Ostersonntag + 60 Tage

Feste Feiertage werden direkt aus dem Jahr berechnet.

Beispiel-Integration

// In einem Widget:
final settings = context.read<SystemSettingsBloc>().deliveryDaysSettings;

// Prüfen, ob heute ein Liefertag ist
final today = DateTime.now();
final isDeliveryDay = settings?.deliveryWeekdays.contains(today.weekday) ?? false;

// Prüfen, ob heute ein Feiertag ist
final holidays = HolidayService.calculateHolidays(
  today.year, 
  settings?.publicHolidays ?? []
);
final isHoliday = HolidayService.isHoliday(today, holidays);

Zukünftige Erweiterungen

Mögliche Verbesserungen: - Automatische Feiertags-Updates für neue Jahre - Import/Export von Feiertagen - Lokalisierung der UI-Strings - Kalenderansicht für bessere Übersicht - Automatische Benachrichtigungen bei bevorstehenden Ausnahmetagen

N-Gram Suche für Kunden

Übersicht

Implementierung einer hochperformanten N-Gram basierten Suchfunktionalität für Kunden. Die Suche ermöglicht schnelle Teil-String Suchen sowohl nach Kundenname als auch Kundennummer.

Funktionsweise

N-Gram Generierung

Beispiel: Kundenname "Huber"

{
  "name": {
    "3": ["hub", "ube", "ber"],
    "4": ["hube", "uber"],
    "5": ["huber"]
  }
}

Beispiel: Kundennummer "123456"

{
  "number": {
    "3": ["123", "234", "345", "456"],
    "4": ["1234", "2345", "3456"],
    "5": ["12345", "23456"],
    "6": ["123456"]
  }
}

Suchlogik

  1. Mindestlänge: Suche startet erst ab 3 eingegebenen Zeichen
  2. Optimale Array-Auswahl:
  3. 3 Zeichen eingegeben → Suche in "3"-Arrays
  4. 4 Zeichen eingegeben → Suche in "4"-Arrays
  5. usw. bis maximal 6 Zeichen
  6. Automatische Feld-Erkennung:
  7. Numerische Eingabe → Suche in searchNgrams.number.X
  8. Text-Eingabe → Suche in searchNgrams.name.X

Vorteile

Performance

  • Schnelle Firestore Queries mit arrayContains statt where >= ... && where <
  • Optimierte Array-Größen durch Längen-basierte Speicherung
  • Reduzierte Datenübertragung da nur relevante Arrays geladen werden

Benutzererfahrung

  • Substring-Suche möglich (nicht nur Prefix wie bei Standard-Firestore)
  • Schnelle Reaktionszeit ab 3 Zeichen Eingabe
  • Intelligente Sortierung (Exakt > StartsWith > Contains)

Skalierbarkeit

  • Effiziente Indizierung durch Firestore Array-Indizes
  • Geringe Speichernutzung durch optimierte N-Gram Längen
  • Ein Feld für beide Such-Dimensionen (Name + Nummer)

Datenstruktur

Customer Model

class Customer {
  // ... bestehende Felder ...

  final Map<String, dynamic>? searchNgrams;
  // Struktur:
  // {
  //   "name": { "3": [...], "4": [...], "5": [...] },
  //   "number": { "3": [...], "4": [...], "5": [...], "6": [...] }
  // }
}

Firestore Dokument

{
  "companyName": "Huber GmbH",
  "customerNumber": "123456",
  "searchNgrams": {
    "name": {
      "3": ["hub", "ube", "ber", " gm", "gmb", "mbh"],
      "4": ["hube", "uber", "ber ", "er g", "r gm", " gmb", "gmbh"],
      "5": ["huber", "uber ", "ber g", "er gm", "r gmb", " gmbh"]
    },
    "number": {
      "3": ["123", "234", "345", "456"],
      "4": ["1234", "2345", "3456"],
      "5": ["12345", "23456"],
      "6": ["123456"]
    }
  }
}

Firestore Index

Wichtig: Folgender Index muss in Firestore angelegt werden:

Collection: customers
Fields:
  - searchNgrams.name.3 (Array)
  - searchNgrams.name.4 (Array)
  - searchNgrams.name.5 (Array)
  - searchNgrams.number.3 (Array)
  - searchNgrams.number.4 (Array)
  - searchNgrams.number.5 (Array)
  - searchNgrams.number.6 (Array)

Migration

Bestehende Kunden aktualisieren

cd functions
node migrate_customer_ngrams.js

Das Script: - Lädt alle bestehenden Kunden - Generiert N-Grams für Name und Nummer - Aktualisiert die Dokumente in Batches (500er Pakete) - Zeigt Fortschritt und Statistiken

Automatische Generierung

Bei neuen/aktualisierten Kunden werden N-Grams automatisch generiert: - createCustomer() - fügt N-Grams beim Erstellen hinzu - updateCustomer() - aktualisiert N-Grams beim Ändern

API

NgramHelper

// Generiere N-Grams für Kundensuche
final ngrams = NgramHelper.generateCustomerSearchNgrams(
  companyName: "Huber GmbH",
  customerNumber: "123456",
);

// Bestimme Suchlänge
final length = NgramHelper.getSearchNgramLength("hub"); // returns 3

// Generiere Such-N-Gram
final searchNgram = NgramHelper.generateSearchNgram("Hub"); // returns "hub"

CustomerFirebaseService

// Suche wird automatisch mit N-Grams durchgeführt
final result = await customerService.getCustomersPaged(
  searchText: "hub",  // Suche erst ab 3 Zeichen
  limit: 20,
);

Performance-Vergleich

Alte Methode (Prefix-Suche)

  • 2 parallele Queries (Name + Nummer)
  • where >= "search" && where < "search\uf8ff"
  • Langsam bei großen Datenmengen
  • Nur Prefix-Suche möglich

Neue Methode (N-Gram)

  • 1 Query mit arrayContains
  • Optimiert durch Array-Index
  • Schnell auch bei großen Datenmengen
  • Substring-Suche möglich

Erwartete Verbesserung: 60-80% schneller bei >1000 Kunden

Speicherverbrauch

Für einen typischen Kunden: - Name "Huber GmbH" (10 Zeichen) → ~8 N-Grams á 3-5 Zeichen = ~35 Bytes - Nummer "123456" (6 Zeichen) → 10 N-Grams á 3-6 Zeichen = ~45 Bytes - Total: ~80 Bytes zusätzlich pro Kunde

Bei 10.000 Kunden: ~0.8 MB zusätzlicher Speicher

Limitierungen

  • Mindestlänge: 3 Zeichen (konfigurierbar)
  • Max Nummer-Länge: 6 Zeichen für N-Grams (längere Nummern werden gecappt)
  • Case-Insensitive: Alle Suchen in Kleinbuchstaben
  • Leerzeichen: Werden in N-Grams inkludiert

Zukünftige Erweiterungen

Mögliche Optimierungen: - [ ] N-Grams für weitere Felder (Stadt, Straße, etc.) - [ ] Phonetische Suche für Namen - [ ] Fuzzy-Matching bei Tippfehlern - [ ] Multi-Field Suche (Name + Stadt gleichzeitig)