ABAP Cloud - Nummernkreise
Wie kannst du Nummernkreise in ABAP Cloud verwenden und macht dies eigentlich noch Sinn? In diesem Artikel schauen wir uns ein paar Hintergründe dazu an.
Inhaltsverzeichnis
In den verschiedenen Fachmodulen von SAP sind Nummernkreisobjekte und Nummernkreise Standard. Wie sieht es damit in ABAP Cloud aus und benötigen wir solche Objekte noch? In diesem Artikel werden wir auf die neuen Objekte eingehen und wie du sie nutzen kannst.
Einleitung
Bisher hast du On-Premise vor allem die Transaktion SNRO verwendet, um Nummernkreise anzulegen und zu verwalten. In ABAP Cloud gibt es keine Transaktionen mehr und damit kannst du erst einmal nicht mehr die Intervalle pflegen. Dafür werden von SAP verschiedene ABAP APIs und eine Fiori App zur Verfügung gestellt, die wir uns auch einmal im Detail anschauen wollen.
Wieso brauchen wir eigentlich Nummernkreise und fortlaufende Nummern im System? Daten werden auf Datenbanken gespeichert und Datensätze in relationalen Datenbanken benötigen in den meisten Fällen einen eindeutigen Schlüssel. Für eine automatische Nummernvergabe könnten wir deshalb eigentlich immer auf die Datenbank schauen und die aktuelle ID plus 1 rechnen, um einen neuen eindeutigen Schlüssel zu erhalten. Da wir aber auf dem System nicht allein sind und mehrere Buchungsprozesse gleichzeitig laufen können, wäre damit nicht sichergestellt, dass wir immer eine eindeutige Nummer erhalten. Nummernkreisobjekte verwalten daher die einzelnen Nummernkreisstände und geben uns über eine Funktion immer eine eindeutige Nummer zurück und kümmern sich um die Erhöhung.
ABAP Cloud
In der Entwicklung mit ABAP Cloud setzen wir auf das ABAP RESTful Programming Model, kurz RAP, welches sehr oft GUIDs für die Verwaltung der Schlüssel nutzt. Die GUIDs werden zufällig generiert und wir müssen uns keine Gedanken über die Verwaltung des Schlüssels machen. Weiterhin können wir im Arbeitsfluss jedes Feld im Datensatz ändern, wenn wir das wollen. Benötigen wir einen lesbaren oder eindeutigen Schlüssel in unserem Datensatz, können wir auch einen semantischen Schlüssel verwenden, den wir auch als eindeutig deklarieren können, müssen hier aber die Überprüfung selbst durchführen.
Allerdings können wir bei dieser Methode keine Reihenfolge oder Lückenlosigkeit in den Daten nachweisen. Daher macht es in bestimmten fachlichen Szenarien immer noch Sinn, Nummernkreise zu verwenden, um einen semantischen Schlüssel zu erzeugen.
Anlage
Das Nummernkreisobjekt kannst du bequem über die ABAP Development Tools anlegen. In den folgenden Schritten legen wir eine Domäne an und dann das passende Objekt.
Domäne
Damit wir einen Nummernkreis anlegen können, brauchen wir im ersten Schritt eine Domäne, die den Datentyp bestimmt. Dazu erzeugen wir über das Kontextmenü auf unserem System eine neue Domäne.
Im Anschluss geben wir der Domäne auch einen Typen, der die Anzahl und die Möglichkeiten der generierten Nummern bestimmt.
Number Range Object (ADT)
Nun können wir ein Nummernkreisobjekt anlegen, hier müssen wir darauf achten, dass der Name nicht zu lang wird, da das Feld aktuell nur 10 Zeichen länge hat.
Zum Abschluss tragen wir in das Formular noch die Domäne ein, den Rest der Konfiguration können wir initial lassen. Möchtest du weiter Informationen zur Pflege und zu den verschiedenen Feldern haben, kannst du über F1 die Hilfe in den ABAP Development Tools aufrufen und erhältst weitere Informationen.
Number Range Object (API)
Hat dein System noch nicht das nötige Release, kannst du auch die ABAP Klasse CL_NUMBERRANGE_OBJECTS verwenden, um das Objekt im System zu erzeugen. Die Klasse bietet die verschiedenen CRUD Operationen für die Nummernkreisobjekte an. Dazu das folgende Beispiel:
cl_numberrange_objects=>create(
EXPORTING attributes = VALUE #( object = c_object
domlen = 'ZBS_DEMO_NURANGE'
percentage = 10
devclass = c_package
corrnr = c_transport )
obj_text = VALUE #( langu = 'E'
object = c_object
txtshort = 'Numbers (API)'
txt = 'Number range (API)' )
IMPORTING errors = DATA(lt_errors)
returncode = DATA(ld_return) ).
Wir legen das neue Nummernkreisobjekt an und ordnen es einem Paket, sowie Transport, zu. Dabei geben wir die Domäne mit und auch den Text für das Objekt. Prozent ist dabei ein Pflichtfeld und muss bei der Anlage mitgegeben werden, es wird kein Default gesetzt.
Pflege
Im nächsten Schritt wollen wir die Intervalle für das Nummernkreisobjekt pflegen, dafür gibt es zwei Methoden.
Fiori App
Im ersten Schritt wollen wir die Nummernkreise über die Fiori App "Manage Number Range Intervals" (F4290) verwenden, aktuell scheint die App nur für S/4 HANA Cloud und das ABAP Environment zu existieren.
In der App finden wir auch die Nummernkreisobjekte, die wir über die API angelegt haben.
Auf der Objektseite des Nummernkreisobjekts wählen wir im Bereich "Number Ranges" den "Create" Button und legen einen neuen Nummernkreis an.
ABAP API
Es steht auch die Anlage eines Nummernkreises über die ABAP Klasse CL_NUMBERRANGE_INTERVALS zur Verfügung, wenn dir die App nicht angeboten wird. Mit dem folgenden Aufruf erzeugen wir die gleiche Einstellung in unserem API-Objekt:
cl_numberrange_intervals=>create(
EXPORTING interval = VALUE #( ( nrrangenr = '01' fromnumber = '100000' tonumber = '199999' procind = 'I' ) )
object = c_object
IMPORTING error = DATA(ld_error)
error_inf = DATA(ls_error)
error_iv = DATA(lt_error_iv)
warning = DATA(ld_warning) ).
Da es sich um Customizing handelt, benötigen wir keinen Transport bei der Angabe, sondern müssen die Pflege auf jedem System durchführen.
Vergabe
Wollen wir nun eine Nummer aus dem Nummernkreis ziehen und vergeben, steht uns die freigegebene Klasse CL_NUMBERRANGE_RUNTIME zur Verfügung. Die Klasse bietet auch noch weitere Methoden, um zu prüfen, ob eine Nummer im Intervall liegt oder korrekt ist. Mit der Methode NUMBER_GET, können wir die nächste Nummer ermitteln.
cl_numberrange_runtime=>number_get(
EXPORTING nr_range_nr = '01'
object = c_object
IMPORTING number = DATA(ld_number)
returncode = DATA(ld_rcode) ).
Da wir die Nummer als NUMC 20 zurückbekommen, müssen wir noch einen Cast auf unser Datenelement/Domäne machen. Prüfen wir nun nach einige Versuchen die App, erhalten wir dort auch Informationen zur Nutzung der Range und dem aktuellen Nummernstand.
Komplettes Beispiel
Hier findest du noch einmal die kompletten ABAP Ressourcen, die wir in diesem Beispiel verwendet haben.
CLASS zcl_bs_demo_number_range DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
PRIVATE SECTION.
CONSTANTS c_object TYPE cl_numberrange_objects=>nr_attributes-object VALUE 'ZBSDMONUMA'.
CONSTANTS c_package TYPE cl_numberrange_objects=>nr_attributes-devclass VALUE 'ZBS_DEMO_NUMBERING'.
CONSTANTS c_transport TYPE cl_numberrange_objects=>nr_attributes-corrnr VALUE ''.
METHODS create_number_range_object
IMPORTING io_out TYPE REF TO if_oo_adt_classrun_out.
METHODS create_number_range
IMPORTING io_out TYPE REF TO if_oo_adt_classrun_out.
METHODS draw_number
IMPORTING io_out TYPE REF TO if_oo_adt_classrun_out.
ENDCLASS.
CLASS zcl_bs_demo_number_range IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
* create_number_range_object( out ).
* create_number_range( out ).
draw_number( out ).
ENDMETHOD.
METHOD create_number_range_object.
TRY.
cl_numberrange_objects=>create( EXPORTING attributes = VALUE #( object = c_object
domlen = 'ZBS_DEMO_NURANGE'
percentage = 10
devclass = c_package
corrnr = c_transport )
obj_text = VALUE #( langu = 'E'
object = c_object
txtshort = 'Numbers (API)'
txt = 'Number range (API)' )
IMPORTING errors = DATA(lt_errors)
returncode = DATA(ld_return) ).
CATCH cx_number_ranges INTO DATA(lo_error).
io_out->write( lo_error->get_text( ) ).
ENDTRY.
io_out->write( lt_errors ).
io_out->write( ld_return ).
ENDMETHOD.
METHOD create_number_range.
TRY.
cl_numberrange_intervals=>create(
EXPORTING interval = VALUE #( ( nrrangenr = '01' fromnumber = '100000' tonumber = '199999' procind = 'I' ) )
object = c_object
IMPORTING error = DATA(ld_error)
error_inf = DATA(ls_error)
error_iv = DATA(lt_error_iv)
warning = DATA(ld_warning) ).
CATCH cx_root INTO DATA(lo_error).
io_out->write( lo_error->get_text( ) ).
ENDTRY.
io_out->write( ld_error ).
io_out->write( ls_error ).
io_out->write( lt_error_iv ).
io_out->write( ld_warning ).
ENDMETHOD.
METHOD draw_number.
TRY.
cl_numberrange_runtime=>number_get( EXPORTING nr_range_nr = '01'
object = c_object
IMPORTING number = DATA(ld_number)
returncode = DATA(ld_rcode) ).
CATCH cx_root INTO DATA(lo_error).
io_out->write( lo_error->get_text( ) ).
ENDTRY.
io_out->write( ld_number ).
io_out->write( ld_rcode ).
ENDMETHOD.
ENDCLASS.
On-Premise
Solange dir die App On-Premise nicht zur Verfügung steht, kannst du die Nummernkreis-Intervalle auch über die Transaktion SNRO pflegen und musst nicht unbedingt über die API gehen.
Fazit
Für Nummernkreisobjekte und die Verwaltung der Bereiche gibt es eine neue App und einige Klassen. Im Inneren der Klasse wirst du allerdings auf einen alten Bekannten namens NUMBER_GET_NEXT treffen. Deshalb handelt es sich hier auch nicht um ein komplettes Redesign der API, wie zum Beispiel bei den Application Jobs.