Home › Forum › Nuclos Konfiguration › Businessprozesse › Automatisch fortlaufende Nummer
- Dieses Thema hat 51 Antworten und 15 Teilnehmer, und wurde zuletzt aktualisiert vor 9 Jahre, 1 Monat von
caf.
-
AutorBeiträge
-
13 September 2011 um 15:09 Uhr #4110
Thorsten Schwarzer
TeilnehmerIch beschäftige mich seit einigen Tagen mit nuclos, bin also noch recht neu. Habe das Thema „Automatisch fortlaufende Nummer generieren“ gelesen aber nicht so recht verstanden wie das mit der automatischen Nummernvergabe läuft.
Nummernkreise müssen in einem Wawi Projekt ständig vergeben werden wi z.B:
Kundennummer
Lieferantennummer
Rechnungsnummer usw.Ich hoffe mir kann das hier jemand näher bringen. Danke
Thorsten Schwarzer
13 September 2011 um 21:09 Uhr #4115Jan Giebels
TeilnehmerMit der Suchfunktion währe man auf dieses Ergebnis gestoßen:
https://www.nuclos.de/index.php/de/forum/advsearch?q=fortlaufende+nummer&exactname=1&childforums=1
14 September 2011 um 14:03 Uhr #4116Thorsten Schwarzer
TeilnehmerHabe ich gefunden, aber ich kann die Informationen nicht wirklich nutzen.
16 September 2011 um 09:31 Uhr #4123Jan Giebels
TeilnehmerWenn dir Die Statusmodellabhängige SystemID nicht reicht, erkläre doch mal, wo genau Dein Problem liegt. Wir nutzen auch solche „Nummernkreise“ und haben damit keinerlei Probleme!
16 September 2011 um 15:53 Uhr #4126Markus Glitzner
TeilnehmerIch hatte auch dasselbe Problem allerdings gibt es meiner Meinung nach keine Möglichkeit fortlaufende Nummern mit Nuclos Boardmitteln abzubilden.
Soweit ich weis, fängt die System-ID alle 5 Wochen neu zu zählen an und man hat auf die Gestaltung der Nummer auch keinen Einfluss. Mal ehrlich, gefällt dir diese Nummer auf einer Rechnung? Mir nicht.
Und was ist mit Entitäten ohne Statusmodell, wie z.B. den Kunden oder Artikel, hier wäre auch eine fortlaufende Nummer mit einem bestimmten Format nützlich, so wie halt in anderen Systemen das auch der Fall ist.
Ich habe mir dazu was Eigenes gebaut. Das Konzept sieht wie folgt aus:
Entität Nummernkreise: (ist hoffentlich soweit selbsterklärend)
Name, Preview, Prefix, Next Value, Pad Count (siehe Anhang)DB Funktion CA_NEXTVALUE: (für das berechnende Attribute Preview)
create function CA_NEXTVALUE(
@intid int
) returns varchar(255)
as
begin
declare @value varchar(255)select @value = coalesce(Prefix,'')+ coalesce(replicate('0', PadCount-len(coalesce(NextValue,1))),'')
+ cast(coalesce(NextValue,1)as varchar(255))
from T_EO_NUMMERNKREISE
where intid=@intidreturn @value
end
DB Prozedur SET_NEXTVALUE: (wird aufgerufen um den Next Value um eins zu erhöhen)
create procedure SET_NEXTVALUE
@name as varchar(255)
as
begin
update T_EO_NUMMERNKREISE set
NextValue=coalesce(NextValue,1)+1
where [Name]=@name
end
Bibliotheksregel Helper.setNextValue: (setzt die laufende Nummer):
//package für RuleInterface u. NuclosBusinessRuleException
import org.nuclos.server.ruleengine.*;public abstract class Helper {
public static void setNextValue(RuleInterface server, String field, String key) throws NuclosBusinessRuleException {
//field: the field name of the entity e.g. Aufträge
//key: the value in the name field of the entity Nummernkreise//only if the object is new
if (server.isObjectNew()){
//get the next value and increase it
String value = server.callDbFunction("GET_NEXTVALUE", String.class, key);
server.callDbProcedure("SET_NEXTVALUE", key);//get the current entity name and set the value
String entity = org.nuclos.server.genericobject.Modules.getInstance().getEntityNameByModuleId(server.getModuleId());
server.setFieldValue(entity, field, value);
}
}
}
Geschäftsregel z.B. Auftragsnummer: (unter Verwendung die jeweiligen Entität beim Speichern anhängen)
public void rule(RuleInterface server) throws NuclosBusinessRuleException {
Helper.setNextValue(server, "auftragsnummer", "Auftragsnummer");
}
Attachments:17 September 2011 um 12:47 Uhr #4127Jan Giebels
TeilnehmerHi,
ja .. uns gefällt diese Nummer, da sie 2 Vorzuege hat:1. Ist es mal was anderes und sie enthält Informationen, wie den Ausstellungsmonat
2. ist sie „charismatischer“ und somit fällt sie direkt auf. Durch die Vorangestellten Kürzel wissen wir direkt worum es geht, (Auftrag, Bestellung, Kunde etc.pp.Deine Lösung sieht schick aus, ist aber auch etwas aufwendiger. Wir bevorzugen da gerne gegebene Funktionen.
19 September 2011 um 09:32 Uhr #4134Markus Glitzner
Teilnehmerja, es ist wirklich etwas umständlich. Das kommt daher, weil ich es mit reinen Geschäftsregeln nicht zusammengebracht habe und ich mir mit DB-Funtkionen leichter tue. Ich abe so meine liebe Not in Nuclos die richtigen Funktionen zu finden.
Schön wäre es natürlich wenn so eine Nummernkreis Funtkion direkt in Nuclos integriert wäre.
21 September 2011 um 13:32 Uhr #4141Stephan Frenkel
TeilnehmerSchön wäre es natürlich wenn so eine Nummernkreis Funtkion direkt in Nuclos integriert wäre.
GANZ MEINE MEINUNG.
In fast jedem Projekt wird man Nummernkreise definieren müssen.
21 September 2011 um 14:03 Uhr #4142Matthias Haake
TeilnehmerWir haben sowas bereits fertig implementiert.
Jeder Nummernkreis besitzt (beliebig viele anlegbar):
– Name
– Prefix (Text / optional)
– Suffix (Text / optional)
– Eine Länge (INT / z.B. 5stellig)
– Einen Startwert (INT)
– Einen Endwert (INT)
– Eine Schrittweite (INT)
– Einen TypIn einer Entität (z.B. Mitarbeiter) werden dann mittels Klappbox alle angelegten Nummernkreise vom Typ „Mitarbeiter-Nummernkreis“ angeboten. Bei Wahl eines Nummernkreises wird beim Speichern eine neue Nummer generiert und der Entität zugeordnet.
Wenn die Nuclets verfügbar sind, können wir gerne austauschen 🙂
Viele Grüße,
Matthias21 September 2011 um 14:11 Uhr #4143Ramin Goettlich
TeilnehmerHallo,
Das klingt ja hochinteressant! 🙂
Wo und wie erfolgt die Zuordnung zu einer Entität genau? Im Entitätenwizard??
Funktioniert das auch z.B. für Positionsnummern in Unterformularen?
Interessant wäre das natürlich auch über zwei Ebenen hinweg, z.B. Auftragsnummern je Kunde, s.a. http://www.varlena.com/GeneralBits/130.phpWir haben auch schon über bessere generische Mechanismen für eine Nummernvergabe nachgedacht sowie deren Integration in Nuclos. Da die individuellen Anforderungen sich typischerweise doch immer unterscheiden (siehe Nummervergabe über mehrere Ebenen) und sich das mit Regeln doch immer lösen lässt, schieben wir das bisher zugunsten anderer Prioritäten immer vor uns her.
Vielleicht wäre das hier ja eine wertvolle Contribution, die sich in den Nucloskern integrieren liesse 😉
Grüsse,
nuclosian21 September 2011 um 14:33 Uhr #4144Matthias Haake
TeilnehmerHallo,
hier ein paar Details zu unserer Lösung. Diese bildet die bei uns vorhandenen Anforderungen ab – auf besondere generische Eigenschaften haben wir nicht geachtet. Ziel war für uns, dass wir die Nummernkreis-Entität überall verwenden können und unterschiedlichste Berechnungsregeln hinterlegen wollen ohne dass die Auswahlbox überläuft.
***Entität „NumberRangeType“:
-Name (Text)
-Abkürzung (Text)
-Hier können beliebig viele Typen definiert werden, um später danach zu filtern***Entität „NumberRange“:
-Name (Text)
-Prefix (Text / optional)
-Suffix (Text / optional)
-Länge (int)
-Startwert (int)
-Endwert (int)
-Schrittweite (int)
-Letzte vergebene Nummer (int / im Layout readonly)
-Typ (Referenz zu „NumberRangeType“)
-Es lassen sich beliebig viele Nummernkreise definieren.***Entität „Employee“
-Numberrange (Referenz zu „NumberRange“)
-EmployeeNumber (Text / optional)Im Layout der Entität „Employee“ ist eine Combobox mit einem ValueListProvider. Dieser filtert alle Nummernkreise vom Typ „Employee“ heraus. Das ist quasi das gleiche Prinzip wie bei den Aktionen von Nuclos.
Als letztes habe ich eine Geschäftsregel geschrieben, die beim Speichern eines Mitarbeiters anspringt. Die Logik des Nummernkreises (berechne die nächste Nummer anhand des gewählten Nummernkreises) ist in einer Bibliotheksregel hinterlegt (NumberRangerHelper).
if(server.hasFieldChanged("employee", "numberrange") || server.getFieldValue("employee", "employeenumber") == null)
{
try
{
// load number range object
MasterDataVO numberRange = server.getMasterData("numberrange", server.getAttribute("numberrange").getValueId());
tools.NumberRangeHelper helper = new tools.NumberRangeHelper(numberRange);// update employee number
server.setFieldValue("employee", "employeenumber", helper.CalculateNextNumberString());
// remember last calculated number
server.setFieldValue("numberrange", numberRange.getIntId(), "nextvalue", helper.GetNextValue());
}
catch (Exception e)
{
throw new NuclosBusinessRuleException(e);
}
}
Sinnvolle Ergänzungen könnten z. B. Platzhalter sein, in die automatisch bei Nummernvergabe bestimmte Werte eingefügt werden (%MONTH%, %DAY% etc.)
Wenn es in den Kern wandert – wunderbar 🙂 Einfach per E-Mail melden für Bibliotheksregel usw.
Viele Grüße,
Matthias22 September 2011 um 18:19 Uhr #4153Thorsten Schwarzer
TeilnehmerSuper und danke für die vielen antworten.
matthias ich habe dienen vorschlag mal versucht umzusetzen, bekomme aber die fehlermeldung
Business rule „NumberEmloyee“ package tools does not exist
was mache ich falsch?
So habe ich die Regel eingebaut:
public void rule(RuleInterface server) throws NuclosBusinessRuleException {
if(server.hasFieldChanged(„employee“, „numberrange“) || server.getFieldValue(„employee“, „employeenumber“) == null)
{
try
{
// load number range object
MasterDataVO numberRange = server.getMasterData(„numberrange“, server.getAttribute(„numberrange“).getValueId());
tools.NumberRangeHelper helper = new tools.NumberRangeHelper(numberRange);// update employee number
server.setFieldValue(„employee“, „employeenumber“, helper.CalculateNextNumberString());
// remember last calculated number
server.setFieldValue(„numberrange“, numberRange.getIntId(), „nextvalue“, helper.GetNextValue());
}
catch (Exception e)
{
throw new NuclosBusinessRuleException(e);
}
}
}22 September 2011 um 18:47 Uhr #4154Matthias Haake
TeilnehmerHallo,
da fehlt noch die Bibliotheksregel mit der „Logik“ (Berechnung der nächsten Nummer anhand des gewählten Nummernkreises).
Im Endeffekt könnte diese Klasse wie folgt aussehen. Ich habe unsere Klasse mal ein wenig zusammengekürzt, da ich im Fehlerfall noch diverse Sachen mache, die nicht unbedingt zur Funktionalität gehören.
Die Initialisierung der internen Variablen müsste hier nachgerüstet werden, was ein einfaches masterDataVO.getField(„foo“) bedeutet. Unser einlesen ist automatisierter und in zusätzlichen Klassen abstrahiert. Alternativ kann man auch den zweiten Konstruktor verwenden und alle Werte direkt übergeben:
package tools;import java.util.*;
import org.nuclos.server.masterdata.valueobject.*;
import org.nuclos.server.ruleengine.*;/**
* This class provides methods for working with number ranges.
* @author matthias.haake
*/
public class NumberRangeHelper
{
private Integer _endValue;
private Integer _increment;
private Integer _length;
private String _name;
private Integer _nextValue;
private String _prefix;
private Integer _startValue;
private String _suffix;/**
* Initializes the number range helper.
* @param object The MasterDataVO.
*/
public NumberRangeHelper(MasterDataVO object)
throws NuclosBusinessRuleException
{/* ToDo: Init vars from MasterDataVO */
this.Validate();
}/**
* Initializes the number range helper.
* @param name The name of the number range.
* @param prefix The prefix string (optional).
* @param suffix The suffix string (optional).
* @param length The length of the number range (without prefix and suffix). The leading spaces will be filled with "0".
* @param increment The increment of the number range to generate the next number.
* @param startValue The start value of the number range.
* @param endValue The end value of the number range.
* @param nextValue The next value of the number range.
* @throws Exception
*/
public NumberRangeHelper(String name, String prefix, String suffix, Integer length, Integer increment, Integer startValue, Integer endValue, Integer nextValue)
throws NuclosBusinessRuleException
{
_name = name;
_prefix = prefix;
_suffix = suffix;
_length = length;
_increment = increment;
_startValue = startValue;
_endValue = endValue;
_nextValue = nextValue;if (_nextValue == null)
_nextValue = _startValue;
if (_nextValue _endValue)
throw new NuclosBusinessRuleException("The last number in the selected number range "" + _name + "" was already taken. Please extend the number range.");// format number
String formatedNumber = _prefix + String.format("%0" + _length + "d", _nextValue) + _suffix;
// calculate next number
_nextValue += _increment;return formatedNumber;
}/**
* Gets the next value of the number range.
*
* @return
* The next value
*/
public Integer GetNextValue()
{
return _nextValue;
}/**
* Validates the parameter of the current number range.
*
* @throws Exception
*/
public void Validate()
throws NuclosBusinessRuleException
{
if (_startValue >= _endValue)
throw new NuclosBusinessRuleException("The "Start value" must be lower than the "End value".");
if (_increment < 1)
throw new NuclosBusinessRuleException("The "Increment" must be a positive number.");
}
}Ich hoffe, das hilft Dir weiter.
Viele Grüße und viel Erfolg,
Matthias29 September 2011 um 01:11 Uhr #4176Markus Glitzner
TeilnehmerHabe nun meine Lösung umgebaut und alles in eine Bibliotheksregel gepackt. Sämtliche Datenbankfunktionen, was das Ganze recht umständlich gemacht hat, werden nicht mehr benötigt.
Entität: Nummernkreise
Name [name] (Text, Eindeutig, Pflichtfeld)
Prefix [prefix] (Text)
Pad Count [padcount] (Ganzzahl)
Next Value [nextvalue] (Ganzzahl)Helper Klasse:
import org.nuclos.common.collect.collectable.searchcondition.*;
import org.nuclos.server.masterdata.valueobject.*;
import org.nuclos.server.ruleengine.*;
import java.util.*;public abstract class Helper {
public static void setNextValue(RuleInterface server, String sEntity, String sField, String sKey) throws NuclosBusinessRuleException {
//sEntity: the entity name e.g. Aufträge
//sField: the number field name e.g. auftragsnummer
//sKey: the name of Nummernkreis e.g. Auftragsnummer//only if the object is new
if (server.isObjectNew()){
//default values
String prefix = "";
Integer padcount = 0;
Integer nextvalue = 1;CollectableComparison cond = org.nuclos.common.SearchConditionUtils.newMDComparison(org.nuclos.server.common.MasterDataMetaCache.getInstance().getMetaData("Nummernkreise"), "name", ComparisonOperator.EQUAL, sKey);
Collection ids = server.getMasterDataIds("Nummernkreise", new org.nuclos.server.genericobject.searchcondition.CollectableSearchExpression(cond));if (!ids.isEmpty()) {
//there is only one entry in the collection
Integer id = (Integer)ids.iterator().next();
MasterDataVO item = server.getMasterData("Nummernkreise", id);//get the values from Nummernkreise
prefix = (String)Helper.isNull(item.getField("prefix"), "");
padcount = (Integer)Helper.isNull(item.getField("padcount"), padcount);
nextvalue = (Integer)Helper.isNull(item.getField("nextvalue"), nextvalue);//set the new number to the called entity
String format = String.format("%%0%dd", padcount);
server.setFieldValue(sEntity, sField, prefix + String.format(format, nextvalue));//set the new value in Nummernkreise
server.setFieldValue("Nummernkreise", id, "nextvalue", nextvalue+1);
}
else {
throw new NuclosBusinessRuleException("Der Nummernkreis " + sKey + " ist nicht vorhanden!");
}
}
}public static Object isNull(Object o, Object defaultvalue) {
if (o != null) {
return o;
}else{
return defaultvalue;
}
}public static Boolean isInt(String s) {
try {
int i = Integer.parseInt(s);
return true;
}
catch (NumberFormatException e) {
return false;
}
}public static Integer toInt(String s, Integer defaultvalue) {
try {
return Integer.parseInt(s);
}
catch (NumberFormatException e) {
return defaultvalue;
}
}
}
Der Aufruf erfolgt in einer Geschäftsregel, die an die jeweilige Entität gebunden ist und beim Speichern ausgeführt wird:
Helper.setNextValue(server, "Auftrag", "auftragsnummer", "Auftragsnummer");
Anbei noch ein Beispiel Nuclet
[attachment]C:fakepathNummernkreis.nuclet[/attachment]Attachments:29 September 2011 um 10:47 Uhr #4183Matthias Haake
TeilnehmerDanke für das Posting Deiner Lösung. Ich finde es gut, wenn es mehr Quellcode-Beispiele hier im Forum gibt, das erleichtert das Einsteigen in die API sehr.
Nur als Anregung: ich vermeide gerne I/O-Zugriffe in den Helper-Klassen, sondern mache das über eine extra Klasse. So braucht man nicht viel anpassen, wenn sich am setFieldValue, SearchConditionUtils u.ä. mal was ändert. Allerdings ist der Quellcode ja in der DB und mit ein bisschen SQL ließe sich ja auch Suchen/Ersetzen machen…
Viele Grüße,
Matthias -
AutorBeiträge