Skip to content

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, 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

sorting_job_position

Positionen eines Sortierauftrags. Pro konfigurierter 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")
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):

  1. Die Warengruppe der Partie wird aus dem EDBS gelesen (USWLager::findOne)
  2. Die konfigurierten Klassen für diese Warengruppe werden aus der Setting availableClasses geladen
  3. Ein neuer ManualSortingJob mit generierter sortNumber wird angelegt
  4. Für jede konfigurierte Klasse wird eine SortingJobPosition erstellt

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 via ProductGroups::findEdbs(), rendert View
  • POST (AJAX): Empfängt config als JSON-String, sanitisiert (leere Klassennamen entfernen, leere Gruppen entfernen), speichert via settingsHelper::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

KeyModulTypBeschreibung
availableClassesmanualSortingjsonSortierklassen pro Warengruppe
current_sort_numbermanualSortingstringAktuelle Sortiernummer für Sequenz

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 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

ActionMethodeBeschreibung
actionIndexGETGridView mit allen Sortieraufträgen und expandierbaren Positionen
actionUpdatePositionPOST (AJAX)Einzelne Position aktualisieren, gibt JSON zurück
actionCompleteGETAuftrag abschließen (mit Validierung), Redirect auf Index

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, unter ID_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.

ITeas iScan Applikation Dokumentation

Version: dev-master Version: dev-master
Commit: 7b49027e
Deployed at: 2026-02-26T10:16:08Z