Skip to content

Manuelle Sortierung Modul

Das Modul dient zur manuellen Erfassung von Sortierergebnissen. Sortierklassen werden pro Warengruppe aus dem EDBS geladen und beim Erstellen eines Auftrags anhand der Warengruppe der Partie zugewiesen. Über eine Admin-Konfigurationsseite kann festgelegt werden, welche EDBS-Klassen pro Warengruppe aktiv sind.

Architektur

Modulstruktur

src/modules/manualSorting/
├── controllers/
│   ├── SortingController.php              # Web-Ansicht für Sortierergebnisse
│   ├── admin/
│   │   └── ConfigController.php           # Admin: Sortierklassen-Konfiguration
│   └── api/
│       └── SupplierController.php         # Select2-Suche für Lieferanten
├── messages/
│   └── de/
│       └── manualsorting.php              # Übersetzungen
├── migrations/                            # Namespace: app\modules\manualSorting\migrations
│   ├── M260223075838AddManualSortingLicense.php
│   ├── M260223075858CreateManualSortingResultsTable.php
│   ├── M260223075926AddManualSortingUsedSortClassSetting.php
│   ├── M260223091644AddTimestampsToManualSortingResults.php
│   ├── M260223092035AddSettingForCurrentSortNumber.php
│   ├── M260223094957AddCompletedFlagToManualSortingResults.php
│   ├── M260223100040AddSortingJobPositionTableAndRenameManualSortingResults.php
│   ├── M260223101752AddForeignKeyForSortingJobs.php
│   ├── M260224075803ChangeAvailableClassesSettingToJsonType.php
│   ├── M260224095600ChangeChargeNumberToPartieNr.php
│   ├── M260225074054AddSortingJobDtoHtmlTemplateSetting.php
│   ├── M260225125753AdjustDataStructureToEDBSRRequirements.php
│   ├── M260303062016AddEdbsFetchedColumnsToTables.php
│   ├── M260316075051RemoveAvailableClassesSetting.php
│   ├── M260318073638AddInfoFieldsToManualSortingTables.php
│   ├── M260407135243AddWgColumn.php
│   ├── M260408072100AddColumnArtikelGrpKurz.php
│   ├── M260408090047AddActiveClassesSetting.php
│   └── M260408110723AddAverageWeightPerPackageColumn.php
├── models/
│   ├── ManualSortingJob.php               # Sortierauftrag (Job)
│   └── SortingJobPosition.php             # Einzelne Sortierklasse pro Job
├── views/
│   ├── sorting/
│   │   ├── index.php                      # GridView Sortierergebnisse
│   │   ├── edit.php                       # Sortierauftrag bearbeiten
│   │   └── _positions.php                 # Positionen-Teilansicht (ExpandRow)
│   └── admin/
│       └── config/
│           └── classes.php                # Admin: Sortierklassen-Konfiguration
├── modules/
│   └── rest/
│       ├── Module.php                     # REST-Submodul Bootstrap
│       ├── controllers/
│       │   └── SortingController.php      # REST API Endpunkte
│       └── models/
│           └── dto/
│               └── SortingJobDTO.php      # API-Serialisierung
└── Module.php                             # Modul-Bootstrap, Sidebar, i18n

Datenmodell

manual_sorting_job

Enthält die Sortieraufträge. Jeder Auftrag referenziert eine Partie aus dem EDBS.

SpalteTypBeschreibung
idintPrimary Key
sortNumberstring(45)Eindeutige Sortiernummer (z.B. 260014)
partieNrstring(255)Partienummer aus dem EDBS
sortDatedateDatum der Sortierung
modifieddatetimeAutomatischer Timestamp bei Änderung
completedboolean0 = offen, 1 = abgeschlossen
countintGebindeanzahl
supplierNrstringLieferantennummer
supplierNamestringLieferantenname
fruitInfostringFrucht/Artikelgruppe
commentstringSortierbemerkung
WarenGrpKurzstring(45)Warengruppe Kurzbezeichnung
ArtikelGrpKurzstring(45)Artikelgruppe Kurzbezeichnung
averageWeightPerPackagedecimalDurchschnittliches Gewicht pro Gebinde
edbs_fetched_datedatetimeZeitpunkt des EDBS-Datenabrufs

sorting_job_position

Positionen eines Sortierauftrags. Pro aktiver Klasse der Warengruppe wird eine Position erstellt.

SpalteTypBeschreibung
idintPrimary Key
sortingJobIdintFK zu manual_sorting_job.id (CASCADE)
sortClassstring(255)Name der Sortierklasse (z.B. "Klasse I 65-75")
edbsFruitClassIDintSortierklassen-ID aus dem EDBS
sortResultdecimal(10,2)Erfasstes Ergebnis (NULL = noch nicht erfasst)
modifieddatetimeAutomatischer Timestamp bei Änderung

Beziehungen

manual_sorting_job 1 ──── * sorting_job_position
                          FK: sortingJobId → id (CASCADE/CASCADE)

Sortiernummer-Vergabe

Eine Sortiernummer ist eine eindeutige Nummer, welche einen manuellen Sortierauftrag beschreibt. Sortiernummern werden sequentiell vergeben und im Setting current_sort_number gespeichert. Das Format ist JJNNNN:

  • JJ = zweistelliges Jahr
  • NNNN = vierstellige, aufsteigende Sequenz
php
// ManualSortingJob::createNewSortNumber()
$sortNumber = Yii::$app->settings->getSetting('current_sort_number', 'manualSorting');
$seq = substr($sortNumber, 2);
$sortNumber = (new DateTime())->format('y') . str_pad((int)$seq + 1, 4, '0', STR_PAD_LEFT);
Yii::$app->settings->saveSetting($sortNumber, 'current_sort_number', 'manualSorting');

Beispiel: 260001, 260002, ..., 269999.

Auftragserstellung

Die Erstellung eines Sortierauftrags erfolgt über ManualSortingJob::createNewJob($partieNr, $count):

  1. Die Warengruppe der Partie wird aus dem EDBS gelesen (USWLager::findOne)
  2. Alle Sortierklassen für diese Warengruppe werden aus dem EDBS geladen (SortierKlasse::findEdbs($key))
  3. Die aktiven Klassen werden anhand des activeClasses-Settings gefiltert (siehe Aktive Sortierklassen)
  4. Dabei wird geprüft, ob die konfigurierten aktiven Klassen tatsächlich noch im EDBS existieren (Schnittmenge)
  5. Ein neuer ManualSortingJob mit generierter sortNumber wird angelegt
  6. Für jede aktive Klasse wird eine SortingJobPosition erstellt

Wenn keine Klassen für die Warengruppe im EDBS existieren oder nach dem Filtern keine aktiven Klassen übrig bleiben, wird eine InvalidDataException geworfen.

Aktive Sortierklassen

Sortierklassen werden aus dem EDBS geladen (SortierKlasse::findEdbs). Da nicht immer alle EDBS-Klassen in iScan benötigt werden, kann pro Warengruppe konfiguriert werden, welche Klassen aktiv sind.

Setting activeClasses

KeyModulTypBeschreibung
activeClassesmanualSortingjsonAktive Sortierklassen-IDs pro Warengruppe

Die Struktur ist ein JSON-Objekt mit Warengruppen-Kurzbezeichnungen als Schlüssel und Arrays von sortierklasseID-Werten:

json
{
  "01": ["1", "3", "5"],
  "10": ["2", "4"],
  "010": ["10", "12", "15"]
}

Wichtig: Warengruppen-Nummern werden immer als Strings behandelt, da numerisch ähnliche Kombinationen (z.B. "10" und "010") unterschiedliche Warengruppen darstellen. json_decode konvertiert numerische String-Schlüssel zu Integers — beim Auslesen müssen die Schlüssel daher explizit zurück zu Strings gecastet werden (siehe ConfigController::getActiveClasses()).

Wenn für eine Warengruppe kein Eintrag im Setting existiert, werden alle EDBS-Klassen als aktiv betrachtet.

Admin-Konfigurationsseite

Erreichbar unter /manualSorting/admin/config/classes (nur für Benutzer mit admin-Rolle).

Ablauf:

  1. Warengruppe aus Dropdown auswählen (Daten aus ProductGroups::findEdbs())
  2. Alle Sortierklassen der gewählten Warengruppe werden aus dem EDBS geladen
  3. Klassen werden als GridView mit Checkboxen angezeigt (aktiviert = in iScan sichtbar)
  4. Beim Speichern wird geprüft, ob die ausgewählten Klassen-IDs noch im EDBS vorhanden sind
  5. Nicht mehr existierende Klassen werden mit einer Fehlermeldung gemeldet und nicht gespeichert

Validierung bei Auftragserstellung

Beim Erstellen eines neuen Auftrags (createNewJob) werden die aktiven Klassen gegen die aktuellen EDBS-Klassen validiert. Nur Klassen, die sowohl im activeClasses-Setting als auch im EDBS vorhanden sind, werden als Positionen erstellt.

Settings

KeyModulTypBeschreibung
current_sort_numbermanualSortingstringAktuelle Sortiernummer für Sequenz
activeClassesmanualSortingjsonAktive Sortierklassen-IDs pro Warengruppe

REST API

Authentifizierung via Bearer Token. Alle Endpunkte erfordern einen authentifizierten Benutzer (@).

MethodeEndpunktBeschreibung
GET/manualSorting/rest/sorting/get-job?sortNumber=Einzelnen Auftrag mit Positionen laden
GET/manualSorting/rest/sorting/list-open-jobsAlle offenen Aufträge auflisten
POST/manualSorting/rest/sorting/create-new-job?partieNr=Neuen Auftrag für Partie erstellen
PUT/manualSorting/rest/sorting/update-positionsPositionen eines Auftrags aktualisieren
POST/manualSorting/rest/sorting/complete-job?sortNumber=Auftrag abschließen

create-new-job

Erstellt einen neuen Auftrag basierend auf der Partienummer. Liest die Warengruppe aus dem EDBS, filtert die Sortierklassen anhand der activeClasses-Konfiguration und erstellt Positionen für alle aktiven Klassen. Gibt den Auftrag mit Positionen als SortingJobDTO zurück.

update-positions

Erwartet im Body ein Objekt mit id (Job-ID) und positions-Array. Jede Position muss id, sortingJobId und sortResult enthalten. Validiert, dass alle Positionen zum angegebenen Job gehören.

complete-job

Schließt einen Auftrag ab. Prüft vorher, ob alle Positionen ein Ergebnis haben (sortResult !== null). Gibt einen Fehler zurück, wenn Positionen ohne Ergebnis existieren.

Web-Controller

SortingController

ActionMethodeBeschreibung
actionIndexGETGridView mit allen Sortieraufträgen (mit Datumsbereichsfilter, Lieferanten-Select2, Fruchtsuche) und expandierbaren Positionen
actionExpandDetailPOST (AJAX)Positionen eines Auftrags als Teilansicht laden (für ExpandRowColumn)
actionEditGET/POSTSortierauftrag bearbeiten (Positionen, Kommentar, etc.)
actionCompletePOSTAuftrag abschließen (mit Validierung), Redirect auf Index

admin/ConfigController

ActionMethodeBeschreibung
actionClassesGETKonfigurationsseite für aktive Sortierklassen anzeigen
actionClassesPOSTAktive Sortierklassen für eine Warengruppe speichern (mit EDBS-Validierung)

Das Modul registriert Sidebar-Einträge in Module::initSideBar():

Hauptnavigation (für alle Benutzer mit Lizenz):

  • Gruppe "Manuelle Sortierung" (m_manualsorting, Gewicht 650)
  • Kind "Sortierergebnisse" → /manualSorting/sorting/index

Admin-Bereich (nur für admin-Rolle, unter "Modulkonfiguration"):

  • Gruppe "Manuelle Sortierung" (m_manualsorting_admin)
  • Kind "Sortierklassen" → /manualSorting/admin/config/classes

Internationalisierung

Übersetzungskategorie: manualsorting Basispfad: @app/modules/manualSorting/messages Konfiguriert in Module::initConfig().

Lizenzierung

Das Modul ist lizenzbasiert. Die Lizenz manualSorting muss in der Tabelle licenses aktiviert sein. Sidebar-Einträge und Scanner-Modul werden nur angezeigt, wenn die Lizenz aktiv ist.

ITeas iScan Applikation Dokumentation

Version: dev-develop Version: dev-develop
Commit: 456e8b89
Deployed at: 2026-04-23T12:08:37Z