Willkommen, Gast
Home › Foren › Nuclos Konfiguration › Businessprozesse › Automatisch fortlaufende Nummer
Ich 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
Mit 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
Habe ich gefunden, aber ich kann die Informationen nicht wirklich nutzen.
Wenn 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!
Ich 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=@intid
return @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");
}
Hi,
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.
ja, 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.
Schö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.
Wir 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 Typ
In 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,
Matthias
Hallo,
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.php
Wir 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,
nuclosian
Hallo,
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,
Matthias
Super 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);
}
}
}
Hallo,
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,
Matthias
Habe 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]
Danke 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
Du musst angemeldet sein, um auf dieses Thema antworten zu können.