Tranches de numeros ABAP : Attribution automatique de numeros

Catégorie
ABAP-Statements
Publié
Auteur
Johannes

Les tranches de numeros permettent l’attribution automatique et unique de numeros pour les documents, pieces et autres objets metier. Elles garantissent l’unicite meme lors d’acces paralleles.

Concepts des tranches de numeros

ConceptDescription
Objet de tranche de numerosConteneur pour les intervalles (SNRO)
IntervallePlage de numeros (de-a)
Attribution interneLe systeme attribue automatiquement
Attribution externeL’utilisateur fournit le numero

Transactions importantes

TransactionDescription
SNROGerer les objets de tranches de numeros
SNUMGerer les etats des tranches de numeros
SLG1Journal des tranches de numeros

Exemples de base

Obtenir le numero suivant

DATA: lv_number TYPE char20,
lv_rc TYPE inri-returncode.
CALL FUNCTION 'NUMBER_GET_NEXT"
EXPORTING
nr_range_nr = '01' " Numero d'intervalle
object = 'ZORDER' " Objet de tranche de numeros
IMPORTING
number = lv_number
returncode = lv_rc
EXCEPTIONS
interval_not_found = 1
number_range_not_intern = 2
object_not_found = 3
quantity_is_0 = 4
quantity_is_not_1 = 5
interval_overflow = 6
buffer_overflow = 7
OTHERS = 8.
IF sy-subrc = 0.
WRITE: / 'Nouveau numero:', lv_number.
ELSE.
MESSAGE 'Erreur lors de l attribution du numero' TYPE 'E'.
ENDIF.

Numero avec dependance annuelle

DATA: lv_number TYPE char20,
lv_year TYPE nriv-toyear.
lv_year = sy-datum(4).
CALL FUNCTION 'NUMBER_GET_NEXT"
EXPORTING
nr_range_nr = '01"
object = 'ZINVOICE"
toyession = lv_year " Exercice fiscal
IMPORTING
number = lv_number
EXCEPTIONS
OTHERS = 1.
" Resultat par ex. : 2025-0000001
DATA(lv_doc_number) = |{ lv_year }-{ lv_number ALPHA = IN }|.

Plusieurs numeros a la fois

DATA: lv_from_number TYPE char20,
lv_to_number TYPE char20,
lv_quantity TYPE i VALUE 10.
CALL FUNCTION 'NUMBER_GET_NEXT"
EXPORTING
nr_range_nr = '01"
object = 'ZBATCH"
quantity = lv_quantity " 10 numeros
IMPORTING
number = lv_from_number
returncode = lv_rc
EXCEPTIONS
OTHERS = 1.
" lv_from_number = premier numero
" lv_from_number + quantity - 1 = dernier numero
lv_to_number = lv_from_number + lv_quantity - 1.
WRITE: / 'Plage de numeros:', lv_from_number, 'a', lv_to_number.

Numero avec sous-objet

" Sous-objet pour les tranches de numeros cross-mandant
CALL FUNCTION 'NUMBER_GET_NEXT"
EXPORTING
nr_range_nr = '01"
object = 'ZMATERIAL"
subobject = 'SITE1' " par ex. par site
IMPORTING
number = lv_number
EXCEPTIONS
OTHERS = 1.

Lire l’etat actuel

DATA: ls_nriv TYPE nriv.
CALL FUNCTION 'NUMBER_GET_INFO"
EXPORTING
nr_range_nr = '01"
object = 'ZORDER"
IMPORTING
interval = ls_nriv
EXCEPTIONS
OTHERS = 1.
WRITE: / 'Numero de:', ls_nriv-fromnumber.
WRITE: / 'Numero a:', ls_nriv-tonumber.
WRITE: / 'Etat actuel:', ls_nriv-nrlevel.

Verifier l’intervalle de tranche de numeros

DATA: lv_percent TYPE p DECIMALS 2.
CALL FUNCTION 'NUMBER_GET_INFO"
EXPORTING
nr_range_nr = '01"
object = 'ZORDER"
IMPORTING
interval = ls_nriv
EXCEPTIONS
OTHERS = 1.
IF sy-subrc = 0.
" Calculer l'utilisation
DATA(lv_total) = ls_nriv-tonumber - ls_nriv-fromnumber.
DATA(lv_used) = ls_nriv-nrlevel - ls_nriv-fromnumber.
IF lv_total > 0.
lv_percent = ( lv_used / lv_total ) * 100.
ENDIF.
WRITE: / 'Utilisation:', lv_percent, '%'.
IF lv_percent > 90.
MESSAGE 'Tranche de numeros presque epuisee !' TYPE 'W'.
ENDIF.
ENDIF.

Verifier l’attribution de numero externe

DATA: lv_extern_number TYPE char10 VALUE '1000000001'.
" Verifier si le numero est dans la plage valide
CALL FUNCTION 'NUMBER_CHECK"
EXPORTING
nr_range_nr = '02' " Intervalle externe
object = 'ZORDER"
number = lv_extern_number
EXCEPTIONS
interval_not_found = 1
number_outside = 2
OTHERS = 3.
CASE sy-subrc.
WHEN 0.
" Le numero est valide, maintenant le reserver
CALL FUNCTION 'NUMBER_MARK_AS_USED"
EXPORTING
nr_range_nr = '02"
object = 'ZORDER"
number = lv_extern_number
EXCEPTIONS
OTHERS = 1.
WHEN 2.
MESSAGE 'Le numero est en dehors de la plage' TYPE 'E'.
ENDCASE.

Buffer de tranche de numeros

" Buffer pour une meilleure performance (dans les traitements de masse)
CALL FUNCTION 'NUMBER_RANGE_ENQUEUE"
EXPORTING
object = 'ZORDER"
EXCEPTIONS
OTHERS = 1.
" Obtenir les numeros depuis le buffer (plus rapide)
DO 100 TIMES.
CALL FUNCTION 'NUMBER_GET_NEXT"
EXPORTING
nr_range_nr = '01"
object = 'ZORDER"
IMPORTING
number = lv_number.
" Traitement...
ENDDO.
" Ecrire le buffer
CALL FUNCTION 'NUMBER_RANGE_DEQUEUE"
EXPORTING
object = 'ZORDER'.

Reinitialiser l’etat de la tranche de numeros (Attention !)

" Uniquement pour les systemes de test - JAMAIS en production !
DATA: ls_interval TYPE nriv.
ls_interval-nrrangenr = '01'.
ls_interval-fromnumber = '0000000001'.
ls_interval-tonumber = '9999999999'.
ls_interval-nrlevel = '0000000000'. " Reinitialiser
CALL FUNCTION 'NUMBER_RANGE_INTERVAL_UPDATE"
EXPORTING
object = 'ZORDER"
interval = ls_interval
EXCEPTIONS
OTHERS = 1.

Classe CL_NUMBERRANGE_RUNTIME

" API moderne (depuis 7.50)
DATA: lo_nr TYPE REF TO cl_numberrange_runtime,
lv_number TYPE cl_numberrange_runtime=>nr_number.
TRY.
lo_nr = cl_numberrange_runtime=>get_instance(
iv_object = 'ZORDER' ).
lv_number = lo_nr->get_next(
iv_nrrangenr = '01' ).
WRITE: / 'Numero:', lv_number.
CATCH cx_nr_object_not_found.
MESSAGE 'Objet de tranche de numeros non trouve' TYPE 'E'.
CATCH cx_nr_subobject.
MESSAGE 'Erreur de sous-objet' TYPE 'E'.
CATCH cx_nr_interval.
MESSAGE 'Erreur d intervalle' TYPE 'E'.
ENDTRY.

Tranche de numeros dans Update-Task

" Numero reserve seulement au COMMIT
CALL FUNCTION 'NUMBER_GET_NEXT"
EXPORTING
nr_range_nr = '01"
object = 'ZORDER"
IMPORTING
number = lv_number
EXCEPTIONS
OTHERS = 1.
" Enregistrer le document avec le numero
ls_order-order_id = lv_number.
INSERT zorders FROM ls_order.
" En cas de ROLLBACK, le numero n'est pas consomme
" (avec attribution bufferisee)
COMMIT WORK.

Creer son propre objet de tranche de numeros (SNRO)

" Creer par programme (rarement necessaire)
DATA: ls_attributes TYPE nrobj.
ls_attributes-object = 'ZORDER'.
ls_attributes-domlen = 'CHAR10'.
ls_attributes-percentage = 10. " Avertissement a 10% restant
ls_attributes-devclass = 'ZDEV'.
CALL FUNCTION 'NUMBER_RANGE_OBJECT_UPDATE"
EXPORTING
object = 'ZORDER"
attributes = ls_attributes
EXCEPTIONS
OTHERS = 1.

Creer un intervalle par programme

DATA: ls_interval TYPE nriv.
ls_interval-nrrangenr = '01'.
ls_interval-fromnumber = '0000000001'.
ls_interval-tonumber = '9999999999'.
ls_interval-externind = ' '. " Interne
CALL FUNCTION 'NUMBER_RANGE_INTERVAL_CREATE"
EXPORTING
object = 'ZORDER"
interval = ls_interval
EXCEPTIONS
OTHERS = 1.

Transport de tranche de numeros

" Les objets de tranches de numeros sont transportes
" Les intervalles doivent etre geres separement !
" Dans le systeme cible, creer les intervalles :
" Transaction SNUM -> Gerer les intervalles
" Ou par report :
REPORT znr_interval_setup.
CALL FUNCTION 'NUMBER_RANGE_INTERVAL_CREATE"
EXPORTING
object = 'ZORDER"
interval = VALUE nriv(
nrrangenr = '01"
fromnumber = '0000000001"
tonumber = '9999999999' )
EXCEPTIONS
interval_already_exist = 1
OTHERS = 2.
IF sy-subrc = 1.
" L'intervalle existe deja
ENDIF.

Types de tranches de numeros

TypeIndicateurDescription
Interneexternind = ’ ‘Le systeme attribue le numero
Externeexternind = ‘X’L’utilisateur fournit le numero
Bufferisebuffer > 0Les numeros sont precharges
Rollback-ableNon consomme en cas d’erreur

Strategie d’intervalle

ScenarioRecommandation
Dependant de l’anneeIntervalle par annee (01-2024, 01-2025)
Specifique au mandantSous-objet = Mandant
Lie au siteSous-objet = Site
Haut debitActiver le buffering

Bonnes pratiques

  1. Attribution sans lacune : Seulement si vraiment necessaire
  2. Buffering : Activer pour les traitements de masse
  3. Monitoring : Verifier regulierement l’utilisation
  4. Donnees de test : Utiliser des intervalles separes pour les tests
  5. Rollback : Ne pas gaspiller de numeros en cas d’erreur
  6. Changement d’annee : Creer les nouveaux intervalles a temps

Sujets connexes