Appearance
Manueller Produktionsauftrag Modul
Das Modul bildet den EDBS-Prozess „Produktion manuell" auf dem Scanner und im Web ab. Der Anwender wählt einen Produktionsauftrag aus dem EDBS und passt die produzierten Mengen an. Bisher war das nur direkt im EDBS möglich.
Das Modul läuft neben dem älteren Modul manualProduction. Beide teilen keinen Code und keine Tabelle. manualProduction erfasst Eingangsmaterial je Auftrag. manualProductionV2 pflegt die Ausgangsmengen eines EDVA-Auftrags.
Architektur
Modulstruktur
src/modules/manualProductionV2/
├── assets/
│ └── ManualProductionV2Asset.php # Asset-Bundle für booking-form.js
├── controllers/
│ └── OrderController.php # Web: Liste, Auftragsansicht, Buchung
├── messages/
│ └── de/
│ └── manualproductionv2.php # Übersetzungen
├── migrations/ # Namespace: app\modules\manualProductionV2\migrations
│ ├── M260818080000AddManualProductionV2License.php
│ ├── M260818081000CreateProductionTable.php
│ └── M260818082000AddProdOrderDtoTemplateSetting.php
├── models/
│ ├── db/
│ │ ├── ProductionBase.php # Schema-Abbild der Tabelle production
│ │ └── Production.php # Domänenlogik: Deltas, Merge, Guard
│ └── search/
│ └── ProdOrderSearch.php # Filtermodell der Weboberfläche
├── modules/
│ └── rest/
│ ├── Module.php # REST-Submodul
│ ├── controllers/v1/
│ │ ├── OrderController.php # Lesen
│ │ └── BookingController.php # Schreiben
│ └── models/dto/
│ ├── ProdOrderDto.php # Antwort inklusive htmlLabel
│ └── BookingDto.php # Anfrage
├── views/order/
│ ├── index.php # GridView der Aufträge
│ └── detail.php # Auftragsansicht mit Eingabefeldern
├── web/js/
│ └── booking-form.js # Zugang und Gesamtmenge synchron halten
└── Module.php # Modul-Bootstrap, Sidebar, i18nDas EDBS-Lesemodell liegt nach Konvention außerhalb des Moduls in src/models/edbs/ProdOrder.php.
Datenfluss
- Lesen.
ProdOrderliest die ViewEDBSOn.EDBSOnManProdAuftragüberYii::$app->edbs_db. Der Zugriff ist read-only. - Schreiben. Scanner und Web erzeugen Zeilen in der lokalen Tabelle
productionmitedbs_fetched_date = NULL. - Abholen. Der EDBS-Worker liest die nicht abgeholten Zeilen, addiert die Deltas im ERP und stempelt
edbs_fetched_date. - Anzeigen. Der aktuelle Wert eines Feldes ist der EDBS-Live-Wert plus die Summe der nicht abgeholten Deltas. Der Anwender sieht seine Eingabe damit sofort, auch vor dem nächsten Worker-Lauf.
EDBS-View
Die View EDBSOn.EDBSOnManProdAuftrag entsteht über php yii migrate-edbs. Sie liefert alle sao.EDVA-Datensätze mit I_EDVA > 0 und DT_DELETED IS NULL, verbunden mit TYPELOOKUP_M und TYPEDETAIL_M für den lesbaren Statustext.
| Spalte der View | EDVA-Feld | Beschreibung |
|---|---|---|
| edva_id | I_EDVA | Primärschlüssel, Buchungsschlüssel |
| status | N_STATUS | 5 ist „Produktion manuell" |
| status_desc | Lookup | Statustext für die Anzeige |
| trvp_count | N_TRVPQUANT | Koli, beschreibbar |
| abfall_gewicht | N_ABFALL | Abfallgewicht, beschreibbar |
| ausschuss_gewicht | N_AUSSCHUSS | Ausschussgewicht, beschreibbar |
| zweitware_gewicht | N_ZWEITEWARE | Zweite Ware Gewicht, beschreibbar |
| chargennummer | S_INTERNVANR | Schlüssel der RV und der Weboberfläche |
| artikel_desc | S_FRUITDESC | Frucht |
| auftragsbezeichnung | S_VADESC | Bezeichnung |
| gebinde_desc | S_PACKDESC | Verpackung |
| auftragsdatum | D_VADATE | Fertigungsdatum |
| erstelldatum | DT_INSERTED | Sortierung der Liste |
ProdOrder ist ein yii\db\ActiveRecord auf dieser View. Die View trägt keinen Primärschlüssel, deshalb gibt primaryKey() die Spalte edva_id zurück. Die Finder heißen findAllActiveEdbs(), findEdbs($chargeNr) und findByIdEdbs($edbsVaId). Alle laufen über findActive(), das nach erstelldatum absteigend sortiert.
Datenmodell
production
Buchungsjournal des Moduls. Jede Buchung schreibt eine neue Zeile mit vorzeichenbehafteten Deltas. Zeilen werden nie geändert und nie gelöscht. Eine Korrektur ist eine neue Zeile mit umgekehrtem Vorzeichen.
| Spalte | Typ | Beschreibung |
|---|---|---|
| id | int | Primary Key |
| edbs_va_id | int | EDVA.I_EDVA, Gruppierungsschlüssel |
| intern_va_nr | string(45) | EDVA.S_INTERNVANR, Chargennummer |
| TRVP_count | int | Delta Koli, EDBS N_TRVPQUANT |
| abfall_gewicht | decimal(10,3) | Delta Abfallgewicht in kg, EDBS N_ABFALL |
| zweite_ware_gewicht | decimal(10,3) | Delta Zweite Ware in kg, EDBS N_ZWEITEWARE |
| ausschussgewicht | decimal(10,3) | Delta Ausschuss in kg, EDBS N_AUSSCHUSS |
| fk_user_id | int | FK auf user, Verursacher der Buchung |
| created | datetime | Automatischer Timestamp |
| modified | datetime | Automatischer Timestamp bei Änderung |
| edbs_fetched_date | datetime | Vom EDBS-Worker gesetzt, NULL heißt offen |
| mad | tinyint | Soft-Delete |
Die Spaltennamen der vier Mengenfelder sind Teil des Vertrags mit dem EDBS-Worker.
Domänenlogik
Production::book(ProdOrder $order, array $values) ist der einzige Einstieg für REST und Web.
normalizeDeltas()prüft die Feldnamen gegenProduction::VALUE_COLUMNS, rundet auf die Genauigkeit der Spalte und verwirft leere Felder sowie Deltas, die auf null runden.- Bleibt nichts übrig, endet die Buchung mit
BadRequestHttpException. getCurrentValues()liest den EDBS-Live-Wert und addiert die nicht abgeholten Deltas.guardCumulated()lehnt jedes Feld ab, dessen kumulierter Wert unter null fiele.- Alle Deltas landen in einer Zeile. Eine Buchung ist damit ohne Transaktion vollständig oder gar nicht.
VALUE_COLUMNS verbindet Journalspalte und View-Spalte. Die Namen unterscheiden sich, weil das Journal dem Ticket folgt und die View dem EDBS:
| Journalspalte | Spalte der View |
|---|---|
| TRVP_count | trvp_count |
| abfall_gewicht | abfall_gewicht |
| zweite_ware_gewicht | zweitware_gewicht |
| ausschussgewicht | ausschuss_gewicht |
REST API
Basis /manualProductionV2/rest/v1/. Authentifizierung über Bearer Token oder die Web-Session. Rollen admin und storeman.
| Methode | Endpunkt | Beschreibung |
|---|---|---|
| GET | /order/active | Alle Aufträge im Status 5 mit aktuellen Werten |
| GET | /order/info?chargeNr= | Auftragsdetail zu einer Chargennummer inklusive htmlLabel |
| POST | /booking/create | Mengenänderung buchen |
order/active und order/info
Je Auftrag steht unter values ein Eintrag pro beschreibbarem Feld:
json
"values": {
"TRVP_count": { "edbs": 480, "unfetched": 20, "current": 500 }
}current ist der Bezugswert für eine Gesamtmengen-Eingabe im Client. order/active holt die nicht abgeholten Summen für die ganze Liste mit einer Abfrage.
booking/create
json
{
"edbsVaId": 41287,
"values": { "TRVP_count": 8, "abfall_gewicht": 2.5 }
}Jeder Wert ist ein Delta. Der Server kennt keine Gesamtmenge. Ein Client, der eine Gesamtmenge eingeben lässt, rechnet vorher um: Delta = neue Gesamtmenge - current. Die Antwort ist der Auftrag nach der Buchung.
Fehlercodes: 400 bei unbekanntem Feld, nicht numerischem Wert, leerer Buchung oder verletztem Guard. 404 bei unbekanntem Auftrag. 405 bei falscher Methode.
Die Rückverfolgbarkeit braucht keinen eigenen Endpunkt. Der Scanner ruft dafür GET /tracing/rest/v1/production/info?scancode=<Chargennummer> auf.
Web-Controller
OrderController
| Action | Methode | Beschreibung |
|---|---|---|
actionIndex | GET | GridView der Aufträge, gefiltert und sortiert über ProdOrderSearch |
actionDetail | GET | Auftragsansicht zu chargeNr aus dem URL-Parameter |
actionBook | POST | Buchung schreiben, danach Redirect auf actionDetail |
actionDetail nimmt denselben Parameter wie tracing/trace/detail. Beide Ansichten verlinken sich gegenseitig. Die Liste bietet je Zeile zwei Schaltflächen, eine in die Rückverfolgbarkeit und eine in die Auftragsansicht.
Die Auftragsansicht zeigt je Feld den EDBS-Wert, die nicht abgeholte Summe und den aktuellen Wert. Daneben stehen zwei Eingabefelder, „Zugang" und „Neue Gesamtmenge". web/js/booking-form.js hält beide synchron. Abgeschickt wird nur der Zugang.
Gewichte erscheinen mit drei Nachkommastellen und der Einheit kg. Koli erscheint ohne Einheit als ganze Zahl. Die Formatierung läuft über den formatter mit Locale de-DE.
Settings
| Key | Modul | Typ | Beschreibung |
|---|---|---|---|
ProdOrderDto_template | rest | string | HTML-Template des Auftragskopfs für den Scanner |
Das Template wird von ProdOrderDto::getHtmlLabel() über den StringTemplateParser gerendert. ProdOrderDto ist im Template-Editor unter src/controllers/admin/TemplateEditorController.php registriert.
Sidebar-Integration
Module::initSideBar() fügt den Eintrag „Manuelle Produktion" mit dem Gewicht 900 hinzu. Ziel ist /manualProductionV2/order/index. Der Eintrag erscheint nur bei aktiver Lizenz.
Internationalisierung
Übersetzungskategorie: manualproductionv2 Basispfad: @app/modules/manualProductionV2/messages Konfiguriert in Module::initConfig(). Fehlertexte laufen über die globale Kategorie error.
Lizenzierung
Das Modul ist lizenzbasiert. Die Lizenz manualProductionV2 muss in der Tabelle licenses aktiviert sein. Das Modul ist als Scanner-Modul markiert.
Tests
| Datei | Umfang |
|---|---|
tests/codeception/unit/ManualProductionBookingTest.php | Deltas, Merge, Guards, nicht abgeholte Summen |
tests/codeception/functional/rest/manualProductionV2/…Cest.php | Authentifizierung, Methoden, Validierung der REST-API |
tests/codeception/functional/web/manualProductionV2/…WebCest.php | Zugriffsschutz und Methoden der Weboberfläche |
Alles hinter der Validierung liest live aus dem EDBS. Dieser Teil ist bewusst nicht getestet. Die Rechenlogik ist EDBS-frei über Unit-Tests abgedeckt.
Offene Punkte
- Der Statusfilter in
ProdOrder::findActive()ist derzeit auskommentiert. Liste und Finder liefern damit alle Produktionsaufträge, nicht nur Status 5. - Ein Fetch-HealthCheck für die Tabelle
productionfehlt noch. Vorlage istsrc/checks/fetch_checks/EdbsFetchCheck_Base.php. - Der EDBS-Worker muss die Deltas addieren, nicht setzen. Das ist mit dem EDBS-Team zu bestätigen.