Beispiel-Nuclet zur Abbildung eines Lagerwesens.
Name: | Lager |
---|---|
Package: | org.nuclet.lager |
Namensraum: | LAG |
Version: | 1.0.1 |
Datum: | 19.06.2013 |
Überblick
Kurzbeschreibung
Das Lager-Nuclet liefert Funktionalität für ein Lagerwesen:
Lager, Lagerorte, Lagerbestände und Lagerbewegungen können erfasst werden
zusätzlich sind Lagerinventuren und Lagerumbuchungen möglich
Bei der Einbindung des Lager-Nuclets ist zu beachten, dass für die Lagerfunktionalität die Existenz gewisser Entitäten im Ziel-Nuclet vorausgesetzt wird. Diese Entitäten können bereits vor der Integration existieren, sie können aber auch nachträglich erstellt werden.
Bestandsdaten
Das Lager-Nuclet basiert einerseits auf einer Entität, die einen zu lagernden Artikel repräsentiert. Diese Artikel-Entität wird innerhalb des Lager-Nuclets „Artikel“ genannt und derart referenziert, sie ist jedoch nicht Bestandteil des Lager-Nuclets selbst sondern sollte Teil des Ziel-Nuclets sein. Die dahinterliegende, zu hinterlegende bzw. tatsächliche Entität kann einen davon abweichenden Namen tragen (Material, Ware, Produkt, o.ä.).
Prozessdaten
Grundlage des Lager-Nuclets ist andererseits die Abbildung eines Prozesses, den die Artikel-Bestandsdaten durchlaufen können: Auftrag, Bestellung, Wareneingang, Warenausgang. Dieser Prozess ist im Lager-Nuclet durch vier Entitäten abgebildet, die ebenso wie die Artikel-Entität nicht Bestandteil des Lager-Nuclets sind, sondern Teil des Ziel-Nuclets sein sollten. Die von Ihnen zu bestimmenden, tatsächlichen Entitäten können frei benannt werden (bspw. ist es denkbar, dass ein Warenausgang als „Lieferschein“ realisiert wurde), nur sollte dabei beachtet werden, dass diese Entitäten gleichermaßen Funktionsträger des Lager-Nuclets sein werden.
Abbildung 1: Lager-Prozess
Anmerkung: Entitäten, die im Lager-Nuclet verwendet werden, jedoch nicht Bestandteil des Lager-Nuclets sind, werden im folgenden „Schnittstellen-Entitäten“ genannt.
Mehr zur Einbindung und Anbindung des Lager-Nuclets in Ihre Anwendung finden Sie im Abschnitt „Integration“. Eine Integration des Lager-Nuclets ist im Basistemplate („Einkauf Verkauf“) realisiert worden und dort einzusehen.
Nuclet-Bestandteile
Das Lager-Nuclet umfasst im Rahmen der .nuclet-Datei
diverse Entitäten (für Lager, Lagerorte, Lagerbestände, etc.),
die Layouts für diese Entitäten,
zwei Statusmodelle (für Lagerinventuren und Lagerumbuchungen),
diverse Java-Regeln (verteilt auf Packages),
eine Benutzergruppe „Lager“,
eine Arbeitsumgebung „Lager“.
Typ | Name, englisch | Name, deutsch | Kurzbeschreibung |
---|---|---|---|
Entität | Lager | Lager |
|
| Lagerbestand | Lagerbestand |
|
| Lagerinventur | Lagerinventur |
|
| Lagerinventurbestand | Lagerinventurbestand |
|
| Lagerinventurgruppe | Lagerinventurgruppe |
|
| Lagerumbuchung | Lagerumbuchung |
|
| Lagerumbuchungsposition | Lagerumbuchungsposition |
|
Layout | Lager |
|
|
| Lagerinventur |
|
|
| Lagerumbuchung |
|
|
Statusmodell | Lagerinventur |
|
|
| Lagerumbuchung |
|
|
Java-Package | org.nuclet.lager.facade | entitätenbezogene Datenbankzugriffe | |
| org.nuclet.lager.logic | Geschäftslogik | |
| org.nuclet.lager.parameter | Konstantenklassen zur Parametrisierung | |
| org.nuclet.lager.rule | Steuerung von Insert-/Update-/Delete-Events, sowie Regeln für Statuswechsel | |
| org.nuclet.lager.wrapper | Wrapper-Klassen für Verallgemeinerungen und als Schnittstellen für die Java-Regeln des Lager-Nuclets | |
Benutzergruppe | Lager |
| Standard-Benutzergruppe |
Arbeitsumgebung | Lager |
|
Tabelle 1: Nuclet-Bestandteile
Java-Package-Struktur
Die Java-Regeln sind in fünf Packages unterteilt:
Regeln für maskengesteuerte Events (org.nuclet.lager.rule)
Regeln für die Geschäftslogik (org.nuclet.lager.logic)
Regeln für entitätsbezogene Datenbankzugriffe (org.nuclet.lager.facade)
Regeln für enitätsübergreifende Verallgemeinerungen und als Schnittstelle für die Java-Klassen des Lager-Nuclets (org.nuclet.lager.wrapper)
Konstantenklassen für Preisinformationen (org.nuclet.lager.parameter)
Die Abhängigkeiten der Packages sind in der folgenden Abbildung veranschaulicht.
Abbildung 2: Java-Package-Struktur
Integration
Notwendige Schritte zur Integration
Die Integration des Lager-Nuclets erfolgt in 4 Schritten:
Download
Nuclet-Import
Konfiguration von System-Parametern (entfällt bis auf weiteres)
Anpassungen im Entitäten-Wizard
Anpassungen in den Java-Regeln
Einhängen der Java-Regeln im Regel-Management
Alle Integrationschritte werden im folgenden im Detail erläutert.
Schritt 1: Download
Download der ZIP-Datei „Lager-v1.0.1.zip“ auf der Nuclos-Webpage unter „Nuclos Services“ > „Download“ > „Nuclet Download“. Das ZIP anschließend lokal entpacken.
Schritt 2: Nuclet-Import
Import des Basistemplate-Nuclets unter „Konfiguration“ > „Nuclet Management“ > „Importieren“ in Ihre bestehende Nuclos-Instanz, Auswahl der Datei „Lager-v1.0.1.nuclet“
Schritt 3: Konfiguration von System-Parametern (entfällt bis auf weiteres)
Die Einrichtung der verwendeten Nuclos-Systemparameter über „Administration“ > „Parameter“.
Parameter | Kurzbeschreibung |
---|---|
LAGERBESTAND_UEBERBUCHUNG | Lagerbestandsüberbuchung zulässig (true), oder nicht (false)? |
Tabelle 2: System-Parameter
Anmerkung: Dieser Schritt wird erst in einer zukünfigen Version notwendig, d.h. sobald die neue Nuclos-API das Auslesen von System-Parametern unterstützt. Solange dies nicht der Fall ist, erfolgt die Konfiguration in Schritt 5, durch Anpassung von entsprechenden Konstanten im Java-Code.
Schritt 4: Anpassungen im Entitäten-Wizard
Im Entitätenmodell des Lager-Nuclets werden drei Entitäten referenziert, die nicht Bestandteil des Lager-Nuclets sind:
Artikel (Artikel, Material, Ware, Produkt, o.ä.)
Artikelgruppe (Artikelgruppierung bzw. -klassifizierung)
Kunde (Kundendaten)
Artikel
Die Entität, die den Artikel (bzw. Material, Ware, Produkt, o.ä.) repräsentiert, wird in vier Entitäten referenziert:
Lagerbestand
Lagerbewegung
Lagerinventurbestand
Lagerumbuchungsposition
Diese Referenzen sind an die tatsächlich genutzte Entität anzubinden.
Artikelgruppe
Die Entität, die die Artikelgruppe repräsentiert, wird nur in der Entität „Lagerinventurgruppe“ referenziert.
Lager
Die Entität, die den Kunden repräsentiert, wird nur in der Entität „Lager“ referenziert.
Die folgende Abbildung stellt das Entitätenmodell des Lager-Nuclets schematisch dar. Die bei der Integration nachzutragenden Referenzen, sind all jene Referenzen, die die Entitäten des Lager-Nuclets (schwarz) mit den „Schnittstellen-Entitäten“ (rot) verbinden.
Abbildung 3: Entitäten-Modell
Schritt 5: Source-Code Anpassungen in Java-Regeln
Java-Klasse / Java-Package | Kurzbeschreibung |
---|---|
org.nuclet.lager.facade.ArtikelFacadeFactory | Eintragen einer anwendungsspezifischen ArtikelFacade |
org.nuclet.lager.parameter.SystemParameter | Konfiguration, ob Lagerbestände überbucht werden dürfen (LAGERBESTAND_UEBERBUCHUNG) |
org.nuclet.lager.rule.LoeseBestellungAus | Auslösen von Bestellungen |
org.nuclet.lager.rule.ReserviereLagerbestand | Reservierung von Lagerbeständen |
org.nuclet.lager.rule.StorniereBestelldifferenz | Stornierung von Bestelldifferenzen |
org.nuclet.lager.rule.StorniereBestellung | Stornierung von Bestellungen |
org.nuclet.lager.rule.StorniereLagerbestandsreservierung | Stornierung von Bestandsreservierungen |
org.nuclet.lager.rule.StorniereReservierungsdifferenz | Stornierung von Reservierungsdifferenzen |
org.nuclet.lager.rule.VerbucheWarenausgang | Verbuchung von Warenausgängen |
org.nuclet.lager.rule.VerbucheWareneingang | Verbuchung von Wareneingängen |
org.nuclet.lager.wrapper.* | Wrapper-Klassen für Schnittstellen-Entitäten |
Tabelle 3: Anwendungsspezifische Anpassungen in Java-Regeln
Alle notwendigen Anpassungen werden nun der Reihe nach erläutert.
a) org.nuclet.lager.wrapper.*
Im Java-Package org.nuclet.lager.wrapper sind all jene Klassen als „Wrapper“ definiert, die als Schnittstelle für die Schnittstellen-Entitäten Artikel, Auftrag, Bestellung, Wareneingang und Warenausgang dienen:
Artikel: AbstractArtikelWrapper
Auftrag: AbstractAuftragWrapper und AbstractAuftragspositionWrapper
Bestellung: AbstractBestellungWrapper und AbstractBestellpositionWrapper
Warenausgang: AbstractWarenausgangWrapper und AbstractWarenausgangspositionWrapper
Wareneingang: AbstractWareneingangWrapper
Diese Wrapper-Klassen werden im Java-Code des Lager-Nuclets verwendet und sind bei der Nuclet-Integration mit eigenen, konkreten Ausprägungen zu ergänzen. Diese konkreten Implementierungen liefern dann den Zugriff auf die tatsächlichen Business-Objekte bzw. Entitäten.
Das folgende Diagramm veranschaulicht die Beziehungen zwischen diesen Entitäten und listet je Entität all jene Attribute auf, die über die Definition der abstrakten Wrapper-Klassen vorausgesetzt werden.
Zu beachten ist:
Für jede Wrapper-Klasse muss eine eigene konkrete Implementierung angelegt werden.
Hinter jeder konkreten Implementierung eines Wrappers sollte eine tatsächliche Entität mit ihrem Business-Objekt (d.h. der von Nuclos generierten Java-Klasse) stehen.
Jede konkrete Wrapper-Klasse sollte die in der abstrakten Wrapper-Klasse definierten Getter- und Setter-Methoden so implementieren, dass diese Methoden auf den Attributen der tatsächlichen Entität bzw. des entsprechenden Business-Objektes operieren (Beispiele, s.u.).
Abbildung 4: Schnittstellen-Entitäten
Achtung: Die fünf Schnittstellen-Entitäten Auftragsposition, Bestellposition, Lieferscheinposition, Warenausgangsposition und Wareneingang referenzieren die Lager-Entitäten "Lager" und "Lagerort" (teilweise doppelt über "Lager Bestellt", "Lagerort Bestellt", "Lager Reserviert", "Lagerort Reserviert". Es ist sinnvoll, diese Referenzen in die tatsächlich verwendeten Entitäten einzufügen.
Hier nun ein Beispiel für die abstrakte Definition und eine konkrete Implementierung einer solchen Wrapper-Klasse für die Artikel-Entität.
Zunächst die abstrakte Klasse:
/** * Abstrakte Wrapper-Klasse für Artikel-Objekte * * @note Schnittstelle bei Nuclet-Integration * */ public abstract class AbstractArtikelWrapper extends AbstractWrapper { /** * Liefert die Datenbank-ID des Artikels * * @return die Datenbank-ID des Artikels * */ public abstract Long getId(); /** * Liefert die Information, ob dieser Artikel im Lager geführt wird * * @return true, fall dieser Artikel im Lager geführt wird * */ public abstract Boolean getLagerfuehrung(); }
Die konkrete Implementierung dazu könnte bspw. die folgende Form annehmen, vorausgesetzt eine Entität bzw. ein Business-Objekt mit dem Namen „Artikel“ wäre vorhanden:
/** * Konkrete Implementierung von org.nuclet.lager.AbstractArtikelWrapper. * Setzt den Lager-Artikel gleich mit der Entität "Artikel". * */ public class ArtikelWrapper extends AbstractArtikelWrapper { public ArtikelWrapper(final BusinessObject businessObject) { if (businessObject instanceof Artikel) { this.businessObject = businessObject; } } public Long getId() { if (this.businessObject != null) { return ((Artikel)this.businessObject).getId(); } else { return null; } } public Boolean getLagerfuehrung() { if (this.businessObject != null) { return ((Artikel)this.businessObject).getLagerfuehrung(); } else { return null; } } }
b) org.nuclet.lager.parameter.SystemParameter
Es ist notwendig, die Konstante LAGERBESTAND_UEBERBUCHUNG für den eigenen Anwendungszweck zu konfigurieren:
LAGERBESTAND_UEBERBUCHUNG == true: eine Bestandsüberbuchung ist zulässig
LAGERBESTAND_UEBERBUCHUNG == false: eine Bestandsüberbuchung ist nicht zulässig
/** * Nuclos-System-Parameter * */ public class SystemParameter { // // @replace // // Konfiguration, ob eine Lagerbestandsüberbuchung zulässig ist (true) oder nicht (false): // public static final boolean LAGERBESTAND_UEBERBUCHUNG = false; }
Anmerkung: Dieser Schritt wird in einer zukünfigen Version entfallen, d.h. sobald die neue Nuclos-API das Auslesen von System-Parametern unterstützt. Sobald dies der Fall ist, wird diese Anpasung über Schritt 3 geregelt (s.o.).
b) org.nuclet.lager.facade.AbstractArtikelFacade
In diesem Schritt geht es darum, gewisse Zugriffsmethoden auf die Artikel-Entität in anwendungsspezifischer Form bereitzustellen. Hintergrund: Die Java-Regeln des Lager-Nuclets setzen diese Methoden voraus, da die Artikel-Entität jedoch kein Bestandteil des Nuclets ist (und je nach Anwendung unterschiedliche Formen annehmen kann), müssen diese Methoden für die tatsächlich verwendeten Entitäten und Business-Objekte erstellt werden.
Zunächst die abstrakte Fassaden-Klasse, in der die notwendigen Zugriffsmethoden definiert sind:
/** * Abstrakte Artikel-Facade * * */ public abstract class AbstractArtikelFacade { /** * Ermittelt alle Artikel zur gegebenen Artikelgruppe * * @param lngArtikelgruppeId die Datenbank-ID einer Artikelgruppe * * @return alle Artikel zur gegebenen Artikelgruppe * */ public abstract List<AbstractArtikelWrapper> getArtikelByArtikelgruppe(final Long lngArtikelgruppeId); /** * Ermittelt den Artikel zur gegebenen Datenbank-ID eines Artikels * * @param lngArtikelId die Datenbank-ID eines Artikels * * @return der Artikel zur gegebenen Datenbank-ID eines Artikels * */ public abstract AbstractArtikelWrapper getArtikelById(final Long lngArtikelId); }
Bitte beachten Sie, dass die Rückgabewerte stets auf den Wrapper-Klassen (s.o.) basieren. D.h. das empfohlene Vorgehen bei einer Implementierung dieser Fassade ist es, nach außen hin zu „wrappen“, weil die Java-Regeln des Lager-Nuclets auf diesen Wrapper-Klassen arbeiten. Innerhalb der Methoden aber muss mit den tatsächlichen Business-Objekten gearbeitet, um die Datenbankzugriffe realisieren zu können.
Hier ein Beispiel für eine konkrete Implementierung dieser Fassaden-Klasse – vorausgesetzt wird an dieser Stelle wiederum, eine Entität bzw. ein Business-Objekt mit dem Namen „Artikel“ wäre vorhanden:
/** * Facade für Artikel-bezogene Datenbankzugriffe * */ public class ArtikelFacade extends AbstractArtikelFacade { private static final ArtikelFacade instance = new ArtikelFacade(); /** * Liefert die Singleton-Instanz dieser Klasse * */ public static ArtikelFacade getInstance() { return instance; } public List<AbstractArtikelWrapper> getArtikelByArtikelgruppe(final Long lngArtikelgruppeId) { final List<AbstractArtikelWrapper> lstArtikelWrapper = new ArrayList<AbstractArtikelWrapper>(); final Query qryByArtikelgruppe = QueryProvider.create(Artikel.class) .where(Artikel.Artikelgruppe.eq(lngArtikelgruppeId)); final List<Artikel> lstArtikel = QueryProvider.execute(qryByArtikelgruppe); for (final Artikel artikel : lstArtikel) { lstArtikelWrapper.add(new ArtikelWrapper(artikel)); } return lstArtikelWrapper; } public AbstractArtikelWrapper getArtikelById(final Long lngArtikelId) { return new ArtikelWrapper(QueryProvider.getById(Artikel.class, lngArtikelId)); } }
Wenn eine derartige Fassaden-Klasse erstellt wurde, ist es schließlich noch notwendig, die Methode getArtikelFacade() in der Klasse org.nuclet.facade.ArtikelFacadeFactory anzupassen:
/** * Factory für konkrete Artikel-Facade * * */ public class ArtikelFacadeFactory { /** * Liefert eine Instanz einer konkreten Fassaden-Klasse für die Artikel-Entität * * @return eine Instanz einer konkreten Fassaden-Klasse für die Artikel-Entität * */ public static AbstractArtikelFacade getArtikelFacade() { // // @replace Bitte bei Nuclet-Integration mit eigenem Code ersetzen! // // Beispiel: // // return ArtikelFacade.getInstance(); // return null; } }
c) org.nuclet.lager.rule.*
Das Java-Package org.nuclet.lager.rule umfasst alle diejenigen Regeln, die die Insert/Update/Delete-Events und Statuswechsel von Objekten steuern.
Java-Klasse | Business-Objekt | Typ |
---|---|---|
LoeseBestellungAus | Bestellung | Statuswechsel |
ReserviereLagerbestand | Auftrag | Statuswechsel |
StorniereBestelldifferenz | Bestellung | Statuswechsel |
StorniereBestellung | Bestellung | Statuswechsel |
StorniereLagerbestandsreservierung | Auftrag | Statuswechsel |
StorniereReservierungsdifferenz | Auftrag | Statuswechsel |
VerbucheWarenausgang | Warenausgang | Statuswechsel |
VerbucheWareneingang | Bestellung | Insert |
Tabelle 10: Anpassungen im Package org.nuclet.lager.rule
Diese Regeln müssen derart gestaltet werden, dass die tatsächlich verwendeten Business-Objekte vom jeweiligen Context (InsertContext, UpdateContext, DeleteContext oder StateChangeContext) entgegengenommen werden, um sie anschließend in ein Wrapper-Objekt verpackt an die Methoden der Klasse org.nuclet.lager.LagerLogik weiterzureichen.
Die Regeln sind so vorbereitet, dass bereits geeignete Code-Fragmente auskommentiert in den Methodenrümpfen eingetragen sind. Diese Fragmente müssen bei der Integration also nur aktiviert und evtl. noch an die tatsächlich genutzten Java-Objekte (Business-Objekte und Wrapper-Klassen) angepasst werden.
Ggf. muss auch noch der Typ einiger Regeln variiert werden, wenn z.B. eine dieser Regeln eher für ein Insert/Update/Delete-Event verwendet werden müsste als für einen Statuswechsel.
Hier folgt nun der Source-Code der Klasse org.nuclet.lager.VerbucheWareneingang, um kurz zu zeigen, wie diese Regeln im Lager-Nuclet vor einer Integration aussehen. Im auskommentierten Beispiel wird als tatsächliche Ausprägung der Warenausgangs-Entität ein Business-Objekt „Lieferschein“ verwendet. An die Logik-Klasse LagerLogik wird ein entsprechendes Wrapper-Objekt weitergereicht:
/** @name VerbucheWarenausgang * @description Verbucht einen Warenausgang * @usage * @change */ @Rule(name="VerbucheWarenausgang", description="Verbucht einen Warenausgang") public class VerbucheWarenausgang implements StateChangeRule { public void changeState(StateChangeContext context) throws BusinessException { // // @replace Bei Nuclet-Integration zu Ersetzen mit eigenem Java-Code! // // // // Beispiel: // // final LagerLogik logik = new LagerLogik(context); // // final Lieferschein lieferschein = context.getBusinessObject(Lieferschein.class); // // logik.verbucheWarenausgang(new WarenausgangWrapper(lieferschein)); } }
Schritt 6: Einhängen der Java-Regeln im Regel-Management
Alle Java-Regeln, die in Schritt 5 angepasst worden sind, müssen im letzten Schritt noch den tatsächlichen Entitäten (bzw. deren Events oder Statuswechseln) zugeordnet werden. Dies erfolgt über den Menüpunkt „Konfiguration“ > „Regel Management“.
Diejenigen Regeln hingegen, die auf Entitäten des Lager-Nuclets operieren, sind im Regel-Baum bereits eingehängt.
Versionen
Version | Datum | Typ | Änderungen |
---|---|---|---|
1.0.0 | 25.04.2013 | initiale Version | - |
1.0.1 | 19.06.2013 | Fehlerkorrekturen |
|