Formelstücklisten
Categories:
Stückliste mit Formeln
in Ihrem Kieselstein ERP stehen auch Formeln für die Errechnung von Mengen und weiteren Eingabefeldern je Stücklistenposition bzw. Arbeitsplanposition zur Verfügung.
Wenden Sie sich für die Freischaltung dieser Funktion bitte vertrauensvoll an Ihren Kieselstein ERP Betreuer.
In manchen Anwendungen wird diese Funktionalität auch Produktkonfigurator genannt.
Die Idee hinter dieser Funktionalität ist, dass abhängig von verschiedenen Eingabeparametern, welche je Stückliste unterschiedlich sein können, entsprechende Berechnungen für die Ermittlung der Positionsdaten wie Menge, Abmessungen (B x H x T) und Artikel durchgeführt werden können. In weiterer Folge kann anhand der errechneten Daten eine echte Stückliste erzeugt werden, mit der die Produktion dann die entsprechenden Vorgaben bekommt.
Das bedeutet, dass die grundsätzliche Idee ist, dass anhand der Parameter “nur” die Menge der jeweiligen Stücklistenposition bzw. Arbeitsplanposition verändert wird.
Beispiel: Hat man nun verschiedene Werte oder auch Maschinen, die abhängig von Parametern zum Einsatz kommen, so definiert man alle Maschinen mit den vorerst gedachten Rüst und Stückzeiten. In den Formeln ändert man dann die jeweilige Rüst bzw. Stückzeit so ab, dass nur die gewünschte Maschine eine echte Sollzeit hat.
Analog wird bei den Positionen vorgegangen.
ACHTUNG
Die Verwendung der Formelstücklisten in der Überleitung in das Angebot, stehen derzeit nur OHNE KUNDEN_POSITIONSKONTIERUNG zur Verfügung.Vorgehensweise
Identifizieren Sie die Stücklisten bei denen Sie die Formeln hinterlegen möchten. In aller Regel werden dies neue Stücklisten sein. Haken Sie bei diesen Stücklisten mit Formeln an. Damit wird der Reiter Parameter freigeschaltet. Definieren Sie im Reiter Parameter nun die Parameter die für diese Stückliste gelten sollten. Dies könnte z.B. wie folgt aussehen:
Das bedeutet, dass die Kennung, mit der Sie dann weiter rechnen, LH ist und die Bezeichnung entsprechend sprechend für Ihre Anwender. Ist Pflichtfeld angehakt, so muss hier etwas eingegeben werden. Sind Min bzw. Max-Wert definiert, so darf der erfasste Wert nur zwischen diesen Grenzen liegen.
Zusätzlich steht noch bei der Texteingabe auch die Möglichkeit der Combobox zur Verfügung. D.h. wird bei String noch Combobox angehakt, so ist der Bereich zu definieren. Die auswählbaren Werte sind jeweils durch einen senkrechten Strich | (vertical Bar, Pipe) getrennt. Ist Pflichtfeld nicht agehakt, so kann auch leer ausgewählt werden, sonst wird der erste Wert aus Bereich vorgeschlagen.
Kopieren von Parametern
Gerade wenn neue Stücklisten Bäume aufgebaut werden, so müssen die Parameter durchgängig definiert sein.
Das kann natürlich manuell gemacht werden, es können aber zusätzlich von übergeordneten Stücklisten aus der Baumstruktur heraus die Parameter übernommen werden. Klicken Sie dazu bitte in der Parameterauswahlliste auf fehlende Parameter nachtragen. Sie erhalten nun eine Auswahlliste in der die über dieser (Formel-)Stückliste liegenden Formelstücklisten enthalten Stücklisten aufgelistet sind. In anderen Worten man baut von oben nach unten den Stücklistenbaum auf und übernimmt dann ebenfalls von oben nach unten die Parameter.
Da dies nicht immer so sein wird gibt es in der Auswahlliste der Formelstücklisten auch die Möglichkeit
alle Formelstücklisten anzuhaken.
Was bedeuten die verschiedenen Fehlermeldungen?
Da bei der Eingabe der Formeln direkt oder nur indirekt erkennbare Fehler auftreten können, haben wir entsprechende Fehlermeldungen eingebaut. Diese können sowohl bei der Erfassung der Formel, als auch bei der Interpretation der Formel auftreten.
So könnte z.B. folgender Fehler bei der Interpretation auftreten:
Dies bedeutet, dass in einer Stückliste auf einer Position eine fehlerhafte Formel gespeichert wurde. Da bei der Speicherung bereits ein Fehler gemeldet wurde, wurde das erforderliche Class-File nicht erzeugt. Um die richtige Stücklistenposition zu finden, klicken Sie einfach auf den GoTo Button bei Stücklistenposition und Sie stehen direkt auf der fehlerhaften Formel. Bessern Sie bitte die falsche Formel entsprechend aus.
Diese Meldung, welche z.B. beim Speichern der Formel auftritt besagt, dass eine entsprechende Methode nicht gefunden wurde.
Nachfolgend finden Sie eine Liste oft verwendeter Funktionen.
Tritt diese Meldung beim Ausführen der Gesamtkalkulation auf, so bedeutet dies, dass eine Formel hinterlegt wurde, deren Rückgabewert nicht den geforderten Werten entspricht. Bitte beachten Sie, dass in den Positionen für die Menge ein BigDecimal und im Arbeitsplan kein Rückgabewert (nur setzen von Stück- und Rüstzeit) vorgegeben sind. Das würde in obigem Beispiel bedeuten, dass im Arbeitsplan ein Wert retourniert wird, weil z.B. eine Formel aus der Position kopiert wurde.
Hier liegt ein Fehler in der Formel vor, der erst bei der Ausführung festgestellt wird.
Woran erkennt man, ob hinter einer Stücklistenposition eine Formel hinterlegt ist?
Stücklistenpositionen mit Formeln werden in Kieselstein ERP blau dargestellt.
Es können über die Zwischenablage keine neuen Positionen eingefügt werden?
Bitte prüfen Sie ob alle Parameter die in der/den Formeln enthalten sind, auch in der neuen Stückliste, in die eingefügt werden sollte, vorhanden sind.
Wie werden Variablen aufgelöst?
Wichtig bei der Verwendung von Variablen ist deren Einsatz
- in ihrer Reihenfolge
- in ihrer Ebene / Unterebene
D.h. Werte aus Variablen können erst verwendet werden, wenn sie initialisiert und errechnet sind.
Zusätzlich ist zu beachten dass die Berechnung der Stücklisten immer je Stückliste erfolgt und danach erst die Unterstücklisten berechnet werden.
Dies hat den Effekt, wenn in einer Stückliste(n Ebene) die Variable einer Unterstückliste benötigt werden, so stehen diese, da die übergeordnete Stückliste zuerst durchlaufen wird, nicht zur Verfügung. Erst durch den “zweiten” Lauf, in dem die Unterstücklisten aufgelöst werden, werden die Variablen initialisiert und stehen somit immer erst eine Ebene darunter zur Verfügung.
Wie wirkt der Parameter Kunde?
Wenn in einer Formelstückliste Kunden mit dem Parameter KundeId abgefragt wird, so bewirkt dies, dass der vom Anwender gewählte Kunde, der dann in aller Regel ein Pflichtfeld sein sollte, bei der Überleitung in Produktstücklisten, in alle (Unter-)Stücklisten die Aufgrund der Formeln neu erzeugt werden, eingetragen wird.
Wie können Produktstücklisten erzeugt werden?
Neben der Variante, dass aus dem Angebot heraus direkt Stücklisten in Verkaufssicht vorkalkuliert und dann durch die Erzeugung eines Angebotes auch Produktstücklisten angelegt werden können, können auch aus dem Modul Stücklisten heraus, Menüpunkt, Bearbeiten, Konfigurieren eine entsprechende Produktstückliste mit den gegebenen Werten / Parametern angelegt werden.
Es wird dazu, die Formelstückliste mit allen formelbehafteten Unterstücklisten kopiert und anstelle der Formeln die errechneten Werte eingetragen. Die Artikelnummer der Stücklisten werden aus den Formelstücklisten übernommen und um eine laufende 2+4 stellige Nummer ergänzt. Die ersten zwei Stellen sind das Geschäftsjahr der Anlage gefolgt von einer vierstelligen laufenden Nummer. Diese wird auf die angelegte maximale Länge der Artikelnummer rechtsbündig durch Ergänzung um _ (Underline / Unterstrich) aufgefüllt.
Um eine entsprechende Durchgängigkeit zu erreichen, werden diese Produktstücklistennummern zentrale verwaltet und über alle Arten von Formelstücklisten hochgezählt. Damit wird erreich, dass eventuell angelegte nur Unterstücklisten, z.B. für die Fertigung von Ersatzteilen, nicht mit anderen Formelstücklisten kollidieren.
Bei der Erzeugung der Produktstücklisten wird weiters, bei eingeschaltetem Parameter DIMENSIONEN_BESTELLEN diejenigen Artikel angelegt, bei denen die Dimensionen für die stückgenaue Beschaffung der für Sie gefertigten Artikel benötigt werden. Details siehe
Praktische Formeln / Anwendung
Hier der Versuch einer Beschreibung, wie die einfache Berechnung eines Fenster aussehen könnte.
Bitte bedenke du bist hier in der Programmiersprache Java. D.h. alles was in Java7 zur Verfügung steht kann verwendet werden. So kann auch durch Endlosschleifen der Server zum Absturz gebracht werden. Das bedeutet, Schleifen nur sehr vorsichtig verwenden.
Hinweis: Reservierte Worte wie do, while, for usw. dürfen natürlich NICHT für Variablen verwendet werden.
Die Fehlermeldung die dann kommt sagt …. error not a statement
Übersicht
Die Zusatzfunktionsberechtigung muss aktiv sein.
Das Häkchen in der Stückliste Kopfdaten “mit Formel” muss gesetzt sein. Wenn gesetzt, werden auch Formeln ausgewertet (sofern gesetzt). Ist das Häkchen nicht gesetzt, wird auch nicht ausgewertet.
Formel kann in der jeweiligen Position (im Reiter Position bzw. Arbeitsplan) eingegeben werden.
Der Editor ist sehr einfach gehalten. So wird z.B. die Formatierung vernichtet.
Beim Speichern/Erzeugen der Stücklistenposition wird die jeweils aktuelle Formel übersetzt.
D.h. gibt es einen Compile-Fehler beim Speichern, hat der Editor immer noch den neuen - vom Anwender geänderten Source-Text.
Speichert man nun ein zweites Mal, wird scheinbar fehlerfrei gespeichert, jedoch ist die Formel nicht aktualisiert.
Im Reiter Parameter können die in dieser Stückliste vom Benutzer abzufragenden Parameter hinterlegt werden.
Im Menü Bearbeiten gibt es einen zusätzlichen Menüpunkt “Konfigurieren”, mit dem der
Anwender die definierten Parameter erfassen kann. Mittels Klick auf OK wird dann eine Gesamtkalkulation der Stückliste (mit Formeln) durchgeführt. Hier bitte die Reportvariante mit Formeln auswählen / hinterlegen. Siehe Reportsammlung
Details zu den Formeln / Arbeitsweise in der Stücklistenposition
Im einfachsten Falle ist das so etwas wie: “return new BigDecimal(getMenge().multiply(new BigDecimal(“3”)));” um die in der Position vorhandene Menge mit 3 zu multiplizieren.
WICHTIG:
Die Methode muss immer(!) ein BigDecimal zurückgeben. Dieser wird als Positionsmenge verwendet.
java.lang und java.math sind implizit vorhanden (importiert). Alle anderen Pakete müssen mit dem kompletten Klassennamen aufgerufen werden.
Z.B. BigDecimal pi = com.lp.util.Helper.rundeKaufmaennisch(new BigDecimal(“3.141592”));
In den Formeln steht die gesamte Mächtigkeit des vom Wildfly verwendeten Java zur Verfügung. D.h. bis 0.x.x Java 8 ab 1.x.x Java 11. Bitte beachte, dass machen in Java 8 vorhandene Methoden / Classen welche schon als Debricated gekennzeichnet sind, eventuell in Java 11 nicht mehr zur Verfügung stehen. Für weitere Details sei auf die Java Dokumentation im Web verwiesen.
Der Zugriff auf Parameter ist mittels “$P{Parametername}” möglich.
Zum Zeitpunkt des compiles wird dann zuerst gesucht, ob diese/aktuelle(!) Stückliste den Parameter kennt.
Übersetzt wird das in eine Art “(Datentyp) getParam(String parametername)”.
D.h. wenn man einen Parameter “Laenge” mit java.math.BigDecimal. definiert hat, und
dann “…. $P{Laenge}.multiply(BigDecimal.TEN) " macht (also die Länge mit 10 multiplizieren),
wird intern " … ((java.math.BigDecimal)getParam(“Laenge”)).multiply(BigDecimal.TEN) " daraus.
Parameter können nicht verändert werden.
Das bedeutet auch, dass wenn in der Kopfstückliste ein Parameter definiert ist, muss dieser auch(!) in der Unterstückliste definiert (Reiter Parameter) werden, sofern in der Unterstückliste darauf zugegriffen wird (was der compile ja feststellt). Zum Zeitpunkt des Compilierens der Unterstückliste kennt die ja nicht die aufrufende Stückliste.
Wenn die “Gesamtkalkulation” aufgerufen wird und es sich um eine Formelstückliste handelt, wird am Beginn der jeweiligen Stückliste diese “kompiliert”. Hat sich die Klasse ansich nicht geändert, wird die alte/bekannte instanziert. Wenn sie sich geändert hat, wird die neue Klasse geladen und instanziert.
Grundsätzliche Definition einer Formel
Bewährt hat sich folgende Vorgehensweise.
- Beschreibung was dieser Block genau macht / machen sollte
- Deklaration der übernommenen Parameter aus den Eingaben
- Denke daran, dass immer die Menge der Position zurückgegeben werden muss.
/* Übertragen des Parameters Scheiben auf die Menge */
Integer anz=$P{Scheiben}; /* Übertragen des vom Anwender eingegebenen Wertes für den Parameter Scheiben in das Objekt anz */
double mng; /* Deklaration einer Rechenvariablen */
mng = anz.doubleValue(); /* Umwandeln des Integer-Objektes in ein double */
/* Übertragen des Parameters Breite in die Dimension1 */
Integer breite=$P{Breite};
Double BreiteInM = new Double ((breite.doubleValue() - 0.0) / 1000.0); /* 0 = Zugabe etc. */
setDimension1( BreiteInM );
/* Übertragen des Parameters Hoehe in die Dimension2 */
Integer hoehe=$P{Hoehe};
Double HoeheInM = new Double ((hoehe.doubleValue() - 0.0) / 1000.0); /* 0 = Zugabe etc. */
setDimension2( HoeheInM );
return new BigDecimal(mng);
Welche Funktionen stehen zur Verfügung
Funktion | Beschreibung |
---|---|
setDimension1( double d ); | Setzen der Breite |
setDimension2( double h ); | Setzen der Höhe |
setDimension1( double t ); | Setzen der Tiefe |
Double getDimension1(); | Auslesen der Breite |
Double getDimension2(); | Auslesen der Höhe |
Double getDimension3(); | Auslesen der Tiefe |
String getEinheitCnr(); | Auslesen der Mengeneinheit der Position |
setEinheitCnr(String einheit); | Setzen der Mengeneinheit der Position |
BigDecimal getMenge(); | Auslesen der Menge der Position |
setMenge(BigDecimal menge); | Setzen der Menge der Position |
setArtikel($P{Artikel}); | Setzen des verwendeten Artikels in der Stücklistenposition $P{Artikel} ist jener Parameter, der zu Beginn des Konfigurieren beim Anwender abgefragt wird. Ist derzeit nur in der Stücklistenposition implementiert. Es kann nur dieser Parameter gesetzt werden. |
FLRArtikelliste getArtikel(); | Öffnen der Artikelauswahl, damit der Anwender seinen Artikel eingeben kann. |
String getKundeKurznr(KundeId kundeId); | Holen der KundenKurznummer des ausgewählten Kunden. Liefert null, wenn kein Kunde gewählt oder die Kundenkurznummer nicht gesetzt. |
Die ID des Artikels | com.lp.server.stueckliste.service.ItemId artikel = $P{Artikel}; // Der vom Anwender ausgewählte Artikel, Integer artikeliid = artikel.getId(); |
Zusätzlich Funktionen, damit man ins Logfile des Servers schreiben kann:
Log-Funktion | Beschreibung |
---|---|
debug(String message) | um eine Nachricht mit Priorität DEBUG ins log zu schreiben |
info(String message) | um eine INFO Message ins log zu bekommen |
warn(String message) | für eine WARN Message |
error(String message) | für eine ERROR Message |
Meldungen die an den Report der Gesamtkalkulation übergeben werden können:
Meldungs-Funktion | Beschreibung |
---|---|
report.debug(“Nachricht…”); | Ausgabe der Nachricht im Feld “ReportDebug” |
report.info(“Nachricht…”); | Ausgabe der Nachricht im Feld “ReportInfo” |
report.warn(“Nachricht…”); | Ausgabe der Nachricht im Feld “ReportWarn” |
report.error(“Nachricht…”); | Ausgabe der Nachricht im Feld “ReportError” |
Ein mittels “report.debug(“wichtige DebugInformation”)” erstellter Text landet im Report der Gesamtkalkulation im Feld “ReportDebug” usw..
Die Felder “Report(Debug|Info|Warn|Error)” sind vom Datentyp java.lang.String.
Die Methoden report.debug(…) nehmen ebenfalls einen String entgegen.
Die gleichen report.xxx Methoden können innerhalb einer Formel mehrfach aufgerufen werden. Jede einzelne Nachricht wird gespeichert. Bei der Übergabe an den Report werden dann - für den Fall, dass mehrere gleichartige Nachrichten in der Formel ausgegeben worden sind, die Einzelnachrichten mittels “\r\n” miteinander verkettet.
Das Report-Feld enthält null, wenn keine Nachricht dieser Priorität in der Formel ausgegeben wurde.
weitere Funktionen für die Stücklistenpositionen
Log-Funktion | Beschreibung |
---|---|
generiereArtikelCnr(String artikelnummer); | erzeugen einer Artikelnummer siehe unten generiereUebergeordneteArtikelCnr |
String getArtikelCnr(); | ACHTUNG: Liefert nur das was gesetzt wurde, aber NICHT den erzeugten Artikel |
setUebergeordneteArtikelCnr(String artikelnummer); | Erzeugen einer Artikelnummer für den Kopf der aktuellen Stückliste |
generiereUebergeordneteArtikelCnr(String artikelnummer); | |
String getUebergeordneteArtikelCnr(); | |
setArtikelBezeichnung(String bez, String kbez, String zbez, String zbez2); | Setzen der Artikelbezeichnungen. Wird "” übergeben, wird das Feld auf null gesetzt. Wenn null übergeben wird wird NICHTS verändert, also der Text aus dem Originalartikel übernommen. |
setUebergeordneteArtikelBezeichnung(String bez, String kbez, String zbez, String zbez2); |
Diese Methoden können zwar sowohl im Kontext Berechnen (Gesamtkalkulation) als auch der Produktionsstückliste verwendet werden, haben aber nur im Zuge der Produktionsstückliste eine Wirkung. Beide Methoden können auch “null” übergeben (Beispiel: setArtikelCnr(null);)
Bei “setArtikelCnr(“gewuenschteArtikelnummer”)” wird dabei beim Erzeugen der Produktionsstückliste jener Artikel der aktuell mit “getArtikel()” ermittelt werden kann mit der “gewuenschtenArtikelnummer” erzeugt. Bei “generiereArtikelCnr(“gewuenschteArtikelnummer”)” wird beim Erzeugen der Produktionsstückliste jener Artikel mit “gewuenschterArtikelnummer” durch die “generiereArtikelnummer(…)” Methode am Server geschickt.
setUebergeordneteArtikelCnr(“gewuneschteArtikelnummer”) bestimmt beim Erzeugen der Produktionsstückliste die Artikelnummer jener Stueckliste die die aktuelle Position beeinhaltet. Wird diese Methode von mehreren Positionen aufgerufen, wird die Artikelnummer der ersten Stücklistenposition verwendet die die übergeordnete Artikelnummer gesetzt hat. Mit “generiereUebergeordneteArtikelCnr(“gewuenschteArtikelnummer”)” wird die “gewuenschteArtikelnummer” durch die “generiereArtikelnummer(…” Methode an den Server übergeben.
Sowohl generiereArtikelCnr() als auch generiereUebergeordneteArtikelCnr() setzen automatisch die korrespondierende “getArtikelCnr()” bzw. “getUebergeordneteArtikelCnr()”.
Mit “setArtikelBezeichnung(…)” bzw. “setUebergeordneteArtikelBezeichnung(…)” können die einzelnen Eigenschaften “Bezeichnung” (bez), “Kurzbezeichung” (kbez), “Zusatzbezeichnung” (zbez) und “Zusatzbezeichnung2” (zbez2) des korrespondierenden Artikels während der Erzeugung der Produktionsstückliste gesetzt werden.
Es muss diese Vorgangsweise beim Ablauf der Formeln berücksichtigt werden. Formeln (und damit Positionen) werden jeweils pro zugehöriger Stückliste komplett für diese Stückliste durchlaufen. Erst danach wird eine etwaige Unterstückliste einer Position durchlaufen. Dies ist anders, als der Server-Code, der die Stückliste durchgeht. Dieser durchläuft sie Position für Position, und steigt sofort in die Unterstückliste ein.
Beispiel:
generiereUebergeordneteArtikelCnr(artnr+“0000”); // und GENERIERE_ARTIKELNUMMER_ZIFFERNBLOCK = 1 !!
D.h. es wird hinter der generischen Artikelnummer auch 0000 dazugehängt UND wenn eine weitere Stkl/Artikel des gleichen bereiches erzeugt wird um eins raufgezählt. Funktioniert auch bei generiereArtikelnummer
Beispiele
Division
BigDecimal lh = $P{LH};
return (lh.divide(new BigDecimal(100)));
Der Parameter LH wird durch 100 dividiert und als Menge zurückgegeben.
Ein Tausenstel von LL mit 4 multipliziert und zum Ergebnis 5 dazu
BigDecimal ll = $P{LL};
return (ll.multiply(new BigDecimal(0.001)).multiply(new BigDecimal(4.0))).add(new BigDecimal(5));
Auf eine gewisse Anzahl erhöhen / runden
BigDecimal ll = $P{LL};
int anzahl;
anzahl = ll.intValue() / 1000;
anzahl += 4;
return new BigDecimal(anzahl);
In Worten: LL auf ganzzahlige Anzahl umrechnen (pro einem Meter ein Artikel) und dann noch vier dazuzählen und dies als Menge retour.
Bedingung
In Worten: Wenn LL größer 1000 dann gib 1 zurück, sonst 0,5
BigDecimal ll = $P{LL};
if(ll.compareTo(new BigDecimal(1000))>0) {
return (new BigDecimal(1));
}
return(new BigDecimal(0.5));
Bitte beachten, dass die Menge immer als BigDecimal zurückgegeben werden muss.
Bedingung anhand von Texten
String af = $P{AF};
BigDecimal m;
if (af.toUpperCase().contains("ALU")) {
m = new BigDecimal(1.00);
} else {
m = new BigDecimal(0.00); }
return m;
Formeln im Arbeitsplan:
Formelrückgabewert ist java.lang.Long(!) (im Gegensatz zur Stücklistenposition, wo es java.math.BigDecimal ist). Es wird die Stückzeit zurückgegeben.
Funktion | Beschreibung |
---|---|
Long getStueckzeit(); | Stückzeit lesen in ms |
setStueckzeit(Long stueckzeit); | Setzen der Stückzeit in ms |
Long getRuestzeit(); | Rüstzeit lesen in ms |
setRuestzeit(Long ruestzeit); | Setzen der Rüstzeit in ms |
Beispiel für Stückzeit aus Zykluszeitberechnung:
/* Spritzen errechnet sich aus der Zykluszeit und den Kavitäten
Die Zeiten sind in Millisekunden anzugeben
*/
BigDecimal zykluszeit = $P{Zykluszeit}; /* in Sekunden */
Integer kavitaeten = $P{Kavitaeten};
double Zeit = zykluszeit.doubleValue() / kavitaeten.doubleValue() * 1000.0;
long stkzeit = new Double(Zeit).longValue();
return (new Long(stkzeit));
Beispiel für einfachen Rüstzeit Eintrag:
/* Rüsten, sind immer die fixen Stunden umgerechnet auf millisekunden */
BigDecimal Ruestzeit = $P{Ruestzeit}; /* in Stunden */
BigDecimal R = Ruestzeit.multiply(new BigDecimal(1000)).multiply(new BigDecimal(3600)); /* in ms */
long rz;
rz = R.longValue();
setRuestzeit(new Long(rz));
return getStueckzeit();
Beispiel für Rüstzeit für eine bestimmte Maschine:
Beachte dass du durch Long(0L) definierst, dass diese Zahl ein long und kein integer ist.
/* Berechnung für die Maschine 280t */
String masch = $P{Maschine}; /* Maschine 100t|150t-160t|25t|280t|35t|50t-60t */
if (!(masch.startsWith("280t"))) { return new Long(0L);}
BigDecimal Ruestzeit = $P{Ruestzeit}; /* in Stunden */
BigDecimal R = Ruestzeit.multiply(new BigDecimal(1000)).multiply(new BigDecimal(3600)); /* in ms */
long rz;
rz = R.longValue();
setRuestzeit(new Long(rz));
return getStueckzeit();
Fehler die trotz Prüfung zur Laufzeit auftreten können:
Je nach Content der Formel kann es sein, dass die Prüfung beim Speichern keinen Fehler ergibt, aber beim Aufruf während der Berechnung ein entsprechender Fehler auftritt.
Das kann z.B. dann auftreten wenn die Rückgabewerte nicht richtig deklariert sind (Long anstatt BigDecimal usw.)
Derzeit bekommen wir bei der Interpretation der Formel zur Laufzeit zu wenig Infos um eine gute sprechende Fehlermeldung ausgeben zu können.
D.h. die Fehlersuche kann mühsam werden. Ändere daher die Stückliste Schritt für Schritt (so wie beim Anpassen von komplexen Formularen auch)
Punkte auf die man gerne reinfällt und nicht so schnell findet:
1.) Eine Variable wird deklariert aber nicht initialisiert (gesetzt) und dann damit gerechnet.
Bitte in jedem Falle initialisieren, sonst kommt ein Compiler Fehler.
2.) Wenn das Speichern = Compilieren geht, aber par too die Gesamtkalkulation doch immer wieder Fehler meldet. Dann doch mal den Kieselstein ERP Server neu starten (der Client kann da ruhig offen bleiben)
Bedingungen
Es gehen auch die “iReport” If-Konstrukte. D.h. z.B.
double lh = $P{LH}.doubleValue();
lh == null ? return das eine : return das andere
usw.
Es gibt zusätzlich drei Methoden um mit “globalen Variablen” arbeiten zu können:
1.) setVar(String variablenname, Object wert)
Zum Setzen einer Variable mit einem bestimmten Wert.
Beispiel: setVar(“Gewicht”, new BigDecimal(“25.89”));
2.) getVar(String variablenname)
Zum Ermitteln des Werts der Variable
Beispiel: BigDecimal gewicht = (BigDecimal) getVar(“Gewicht”);
3.) existsVar(String variablenname)
Zum Überprüfen, ob die Variable existiert
Beispiel:
if(existsVar("Gewicht")) {
info("Es wurde das Gewicht '" +
((BigDecimal)getVar("Gewicht)).toPlainString() + "' erfasst.");
In welcher (Stücklisten) Ebene die Variable gesetzt wird, ist dabei egal.
Auch in welcher Ebene die Variable gelesen wird. Ein sinnvoller Wert (also != null) kann natürlich nur gelesen werden, wenn die Variable zuerst gesetzt wird.
Übersteuern der erzeugten Kopf-Stücklisten-Artikelnummer und der Artikelnummer
Es geht darum, dass aus der Formel strukturierte Stücklisten und dazugehörende “Einkaufs-“Artikel angelegt werden können.
Dafür gibt es:
1.) setUebergeordneteArtikelCnr(String artikelnummer);
Bedeutet wenn auf Produktionsstückliste erzeugen geklickt wird, wird die soeben erzeugte Produktionsstückliste auf diese CNr gesetzt.
Es darf diese Funktion nur einmal je Stückliste(nebene) verwendet werden.
2.) setArtikelCnr(String artikelnummer);
Bedeutet, dass der Artikel der bearbeiteten Stücklistenposition (also der Artikel der hinter der Zeile mit der Formel liegt) auf die (neue) Artikelnummer kopiert wird.
3.) generiereUebergeordneteArtikelCnr(artnr+“0000”); // und GENERIERE_ARTIKELNUMMER_ZIFFERNBLOCK = 1 !!
Schleifen
Es können, da der gesamte Java Syntax zur Verfügung steht auch Schleifen usw. eingebaut werden.
Damit sind auch unendliche Schleifen möglich, welche zum Stillstand des Kieselstein ERP führen können.
Daher bitte mit Hirn verwenden.
// === Eine while-Schleife
BigDecimal laenge = $P{LL};
/* Vielfache von Zehn ermitteln */
int l = laenge.intValue();
int zehner = 0;
while(l > 0) {
zehner++;
l -= 10; /* alternativ l = l - 10; */
}
setMenge(new BigDecimal(zehner));
return BigDecimal.ZERO;
// === Eine while-Schleife mit vorzeitigem Ende
BigDecimal laenge = $P{LL};
/* Vielfache von Zehn ermitteln */
int l = laenge.intValue();
int zehner = 0;
while(l > 0) {
zehner++;
l -= 10;
if(l < 500) {
break;
}
}
setMenge(new BigDecimal(zehner));
return BigDecimal.ZERO;
// === Eine For-Schleife mit 10er Inkrement
BigDecimal laenge = $P{LL};
/* Vielfache von Zehn ermitteln */
int lMax = laenge.intValue();
int zehner = 0;
for(int l = 0; l < lMax; l += 10) {
zehner++;
}
setMenge(new BigDecimal(zehner));
return BigDecimal.ZERO;
// === Eine einfache For-Schleife zaehlt nach oben
BigDecimal laenge = $P{LL};
/* Simples nach oben durchzaehlen */
int lMax = laenge.intValue();
int zaehler = 0;
for(int l = 0; l < lMax; l++) {
zaehler++;
}
setMenge(new BigDecimal(zaehler));
return BigDecimal.ZERO;
// === Eine einfache For-Schleife zaehlt nach unten
BigDecimal laenge = $P{LL};
/* Simples nach oben durchzaehlen */
int lMax = laenge.intValue();
int zaehler = 0;
for(int l = lMax; l >= 0; l--) {
zaehler++;
}
setMenge(new BigDecimal(zaehler));
return BigDecimal.ZERO;
weitere Formel-Beispiele
/* Prüfen ob Parameter Laenge gesetzt, falls größer 100 wird 3 zurückgegeben, ansonsten 2 */
if($P{Laenge} == null) {
return BigDecimal.ONE;
}
if($P{Laenge}.compareTo(new BigDecimal("100")) > 0) {
return new BigDecimal("3");
} else {
return new BigDecimal("2");
}
/* Die Einheit auf mm setzen, die Menge auswerten, mit 1000 multiplizieren und 12460mm dazuzählen (x = 12460 + n * 1000) */
setEinheitCnr("mm");
return new BigDecimal("12460").add(getMenge().movePointRight(3));
/* Abhängig eines Stringinhaltes was berechnen */
String af = $P{AF};
BigDecimal m;
if (af.toUpperCase().contains("ALU")) {
m = new BigDecimal(1.00);
} else {
m = new BigDecimal(0.00);
}
return m;
/* Abhängig von einer Länge eine Stückzahl über int herausrechnen */
BigDecimal ll = $P{LL};
int anzahl;
anzahl = ll.intValue() / 1000;
anzahl += 4;
return new BigDecimal(anzahl);
/* bei einem Eindimensionalen Artikel die Breite (=Dimension1) setzen und die Menge gleich belassen */
BigDecimal ll = $P{LL};
BigDecimal mng = getMenge();
Double d1 = new Double ((ll.doubleValue() - 175) / 1000);
setDimension1( d1 );
return (mng);
/* oder auch */
BigDecimal ll = $P{LL};
double l;
l = (ll.doubleValue()-175)/1000;
setDimension1(new Double(l));
return getMenge();
weitere Formeln im Arbeitsplan
/* im Arbeitsplan muss die Ruestzeit als Long gesetzt werden
Die Stückzeit muss als Long zurückgegeben werden
sowohl Stückzeit wie Rüstzeit sind in MilliSekunden */
BigDecimal ll = $P{LL};
long x;
x = ll.longValue() * 1000;
setRuestzeit(new Long(x) );
return getStueckzeit();
/* je 1000mm 10Minuten Rüstzeit
im Arbeitsplan muss die Ruestzeit als Long zurückgegeben werden
Die Stückzeit muss immer und als Long zurückgegeben werden
sowohl Stückzeit wie Rüstzeit sind in MilliSekunden
D.h. 1000 = 1 Sekunde
60.000 = 1 Minute
3600.000 = 1 Std.
long = langer int(eger)
double = fließkomma ähnlich float
Es muss sowohl Stück wie Rüstzeit explizit gesetzt werden */
BigDecimal ll = $P{LL};
int anzahl;
long rz;
long sz;
anzahl = ll.intValue() / 1000; /* das sind die Meter */
rz = anzahl * 10 * 60000;
sz = 0;
setRuestzeit(new Long(rz) );
return (new Long(sz)); /* Das ist auch die Stückzeit, die gesetzt werden muss */
Fehler auf die man gerne reinfällt
- man verwendet eine Variable und die ist noch nicht initialisiert, dann kommt beim Compilieren kein Fehler aber bei der Ausführung null / Methode nicht (initialisiert oder so ähnlich) und es ist eigentlich der Fehler unlogisch
- Man macht einen SQLEXECUTE und der DB Zugriff geht nicht, weil Anwender Parameter auf die DB falsch
- Es kommt auch der Ausführungsfehler (Methode nicht initialisiert)
per SQl Query auf DB Felder zugreifen
Sowohl in Formeln für die Stuecklistenpositionen als auch Arbeitsplan(positionen) stehen zusätzlich zur Verfügung:
Object sqlExecute(String sql);
Object[] sqlExecutes(String sql); // Hinweis: Das sqlExecutes nur verwenden wenn wirklich mehrere Felder erwartet werden.
sqlExecute liefert - wie P_SQLEXEC.execute() aus den Reports - genau eine Spalte einer Zeile zurück.
sqlExecutes liefert - wie P_SQLEXEC.executes() aus den Reports - mehrere Spalten einer Zeile zurück.
Beispiel:
// === sqlExecute im Script
/* Auf Basis der Artikel-Id möchte ich die C_NR ermitteln */
Integer artikelId = getArtikel().getI_id();
String cnr = (String) sqlExecute("SELECT C_NR FROM WW_ARTIKEL WHERE I_ID = " + artikelId.toString() + ";");
Hinweis: sqlExecute liefert Daten vom Typ Object. Da wir wissen, dass in der C_NR in der Tabelle ein “String” (character varying(25)) ist, können/müssen wir dieses “Object” in einen “String” casten, was mit “(String)” passiert. Vergisst man das, wird mit hoher Wahrscheinlichkeit zwar der compile des Scripts noch korrekt sein, aber beim “Konfigurieren” (Stückliste::Bearbeiten::Konfigurieren) gibt es einen Fehler bezüglich “Datentypen sind nicht kompatibel”, weil der Compiler hier beim Erstellen der kompletten Klasse feststellt, dass sqlExecute nur Object liefern kann, aber die Zuweisung an eine Variable vom Typ String erfolgt.
Natürlich können innerhalb des Scripts mehrere sqlExecute(s)() durchgeführt werden. Sie werden genau in der Reihenfolge abgearbeitet, wie sie im Script stehen.
Object sqlExecutes im Script
/* Auf Basis der Artikel-Id möchte ich das Artikelgewicht und das Materialgewicht ermitteln */
Integer artikelId = getArtikel().getI_id();
Object[] o = sqlExecutes("SELECT C_NR, F_GEWICHTKG, F_MATERIALGEWICHT FROM WW_ARTIKEL " +
"WHERE I_ID = " + artikelId.toString() + ";");
String cnr = (String) o[0];
Double artikelgewicht = (Double) o[1];
Double materialgewicht = (Double) o[2];
warn("Artikelgewicht in kg: " + (artikelgewicht == null ? "keines angegeben": artikelgewicht.toString()));
Runden:
.setScale(4,BigDecimal.ROUND_HALF_EVEN)