Appearance
Manuelle Sortierung Modul
Das Modul dient zur manuellen Erfassung von Sortierergebnissen. Sortierklassen werden pro Warengruppe konfiguriert und beim Erstellen eines Auftrags anhand der Warengruppe der Partie zugewiesen.
Architektur
Modulstruktur
src/modules/manualSorting/
├── controllers/
│ ├── SortingController.php # Web-Ansicht für Sortierergebnisse
│ └── admin/
│ └── ConfigController.php # Admin-Konfiguration Sortierklassen
├── 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
├── models/
│ ├── ManualSortingJob.php # Sortierauftrag (Job)
│ └── SortingJobPosition.php # Einzelne Sortierklasse pro Job
├── views/
│ ├── sorting/
│ │ └── index.php # GridView Sortierergebnisse
│ └── admin/
│ └── config/
│ └── classes.php # Admin-UI Sortierklassen
├── modules/
│ └── rest/
│ ├── Module.php # REST-Submodul Bootstrap
│ ├── controllers/
│ │ └── SortingController.php # REST API Endpunkte
│ └── models/
│ └── dto/
│ └── SortingJobDTO.php # API-Serialisierung
└── Module.php # Modul-Bootstrap, Sidebar, i18nDatenmodell
manual_sorting_job
Enthält die Sortieraufträge. Jeder Auftrag referenziert eine Partie aus dem EDBS.
| Spalte | Typ | Beschreibung |
|---|---|---|
| id | int | Primary Key |
| sortNumber | string(45) | Eindeutige Sortiernummer (z.B. 260014) |
| partieNr | string(255) | Partienummer aus dem EDBS |
| sortDate | date | Datum der Sortierung |
| modified | datetime | Automatischer Timestamp bei Änderung |
| completed | boolean | 0 = offen, 1 = abgeschlossen |
sorting_job_position
Positionen eines Sortierauftrags. Pro konfigurierter Klasse der Warengruppe wird eine Position erstellt.
| Spalte | Typ | Beschreibung |
|---|---|---|
| id | int | Primary Key |
| sortingJobId | int | FK zu manual_sorting_job.id (CASCADE) |
| sortClass | string(255) | Name der Sortierklasse (z.B. "Klasse I 65-75") |
| sortResult | decimal(10,2) | Erfasstes Ergebnis (NULL = noch nicht erfasst) |
| modified | datetime | Automatischer 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 JahrNNNN= 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):
- Die Warengruppe der Partie wird aus dem EDBS gelesen (
USWLager::findOne) - Die konfigurierten Klassen für diese Warengruppe werden aus der Setting
availableClassesgeladen - Ein neuer
ManualSortingJobmit generiertersortNumberwird angelegt - Für jede konfigurierte Klasse wird eine
SortingJobPositionerstellt
Wenn keine Klassen für die Warengruppe konfiguriert sind, wird eine InvalidDataException geworfen.
Sortierklassen-Konfiguration
Datenstruktur
Die Konfiguration wird als JSON im Setting availableClasses (Modul manualSorting, Typ json) gespeichert:
json
{
"01": ["Klasse I 65-75", "Klasse I 75-85", "Klasse II 65-75"],
"02": ["Klasse I", "Klasse III", "Ausschuss"]
}Die Schlüssel sind productGroupNr-Werte aus dem EDBS (ProductGroups::findEdbs()).
Admin-Controller
ConfigController::actionClasses() behandelt:
- GET: Lädt aktuelle Konfiguration via
settingsHelper::getSetting(), Warengruppen viaProductGroups::findEdbs(), rendert View - POST (AJAX): Empfängt
configals JSON-String, sanitisiert (leere Klassennamen entfernen, leere Gruppen entfernen), speichert viasettingsHelper::saveSetting(), gibt JSON-Response zurück
Admin-View
Die View rendert die Konfiguration vollständig in JavaScript (kein Server-Roundtrip):
- Die gesamte Konfiguration wird als JS-Objekt gehalten
- Jede Änderung (Gruppe hinzufügen/entfernen, Klasse hinzufügen/entfernen/umbenennen) löst einen debounced AJAX-Save aus (400ms)
- Visuelles Feedback über Bootstrap-Validierungsklassen (
is-valid/is-invalid) am betroffenen Input
Settings
| Key | Modul | Typ | Beschreibung |
|---|---|---|---|
availableClasses | manualSorting | json | Sortierklassen pro Warengruppe |
current_sort_number | manualSorting | string | Aktuelle Sortiernummer für Sequenz |
REST API
Authentifizierung via Bearer Token. Alle Endpunkte erfordern einen authentifizierten Benutzer (@).
| Methode | Endpunkt | Beschreibung |
|---|---|---|
| GET | /manualSorting/rest/sorting/get-job?sortNumber= | Einzelnen Auftrag mit Positionen laden |
| GET | /manualSorting/rest/sorting/list-open-jobs | Alle offenen Aufträge auflisten |
| POST | /manualSorting/rest/sorting/create-new-job?partieNr= | Neuen Auftrag für Partie erstellen |
| PUT | /manualSorting/rest/sorting/update-positions | Positionen 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 und erstellt Positionen für alle konfigurierten 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
| Action | Methode | Beschreibung |
|---|---|---|
actionIndex | GET | GridView mit allen Sortieraufträgen und expandierbaren Positionen |
actionUpdatePosition | POST (AJAX) | Einzelne Position aktualisieren, gibt JSON zurück |
actionComplete | GET | Auftrag abschließen (mit Validierung), Redirect auf Index |
Sidebar-Integration
Das Modul registriert zwei Sidebar-Bereiche:
Hauptnavigation (für alle Benutzer mit Lizenz):
- Gruppe "Manuelle Sortierung" (
m_manualsorting, Gewicht 650) - Kind "Sortierergebnisse" →
/manualSorting/sorting/index
Admin-Sidebar (für Benutzer mit admin-Rolle):
- Gruppe "Manuelle Sortierung" (
m_manualsorting_admin, unterID_MODULES) - 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.