Home Forum Nuclos Konfiguration Businessprozesse Automatisch fortlaufende Nummer

Ansicht von 15 Beiträgen - 1 bis 15 (von insgesamt 52)
  • Autor
    Beiträge
  • #4110
    Thorsten Schwarzer
    Teilnehmer

    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

    #4115
    Jan Giebels
    Teilnehmer
    #4116
    Thorsten Schwarzer
    Teilnehmer

    Habe ich gefunden, aber ich kann die Informationen nicht wirklich nutzen.

    #4123
    Jan Giebels
    Teilnehmer

    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!

    #4126
    Markus Glitzner
    Teilnehmer

    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");
    }

    #4127
    Jan Giebels
    Teilnehmer

    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.

    #4134
    Markus Glitzner
    Teilnehmer

    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.

    #4141
    Stephan Frenkel
    Teilnehmer

    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.

    #4142
    Matthias Haake
    Teilnehmer

    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

    #4143
    Ramin Goettlich
    Teilnehmer

    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

    #4144
    Matthias Haake
    Teilnehmer

    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

    #4153
    Thorsten Schwarzer
    Teilnehmer

    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);
    }
    }
    }

    #4154
    Matthias Haake
    Teilnehmer

    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

    #4176
    Markus Glitzner
    Teilnehmer

    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]

    Attachments:
    #4183
    Matthias Haake
    Teilnehmer

    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

Ansicht von 15 Beiträgen - 1 bis 15 (von insgesamt 52)