The internal number range is a beautiful concept, but if the actual documents on your system are in an internal range (typically because of a migration) the system will eventually cause collisions Here is an example of a function module that works like a protection shell around the NUMBER_GET_NEXT
. All it does is check an actual database table for the existance of the "next number" - as R/3 does not do this. R/3 assumes (correclty) that an internal number range will never be used for external numbering. The example will repeat "pulling a new number" until the result is an actual new number.
This function module should be called instead of (replacing) the NUMBER_GET_NEXT
function module to get a new number from a number range.
FUNCTION Z_UM_NUMBER_RANGE_SECURITY. *"---------------------------------------------------------------------- *"*"Local interface: *" IMPORTING *" REFERENCE(OBJECT) LIKE NRIV-OBJECT DEFAULT 'EINKBELEG' *" REFERENCE(NRRANGENR) LIKE NRIV-NRRANGENR DEFAULT '70' *" REFERENCE(SUBOBJECT) LIKE NRIV-SUBOBJECT DEFAULT SPACE *" EXCEPTIONS *" SECURITY_FAILURE *"---------------------------------------------------------------------- *----------------------------------------------------------------------* * This function module checks whether the following number that is * * available on a number range object/nrRangeNr/subobject is already * * available on the database. If it is, the number is reserved, avoiding* * an update error. This was done because some purchase orders were * * created with numbers within an internal number range. * *----------------------------------------------------------------------* data: l_nrlevel like nriv-nrlevel, l_check_ok, l_ekko_ebeln like ekko-ebeln. clear: l_check_ok. *--- as long as the check is not done or a problem NR was found: while l_check_ok eq space. select single nrlevel from nriv into l_nrlevel where object eq object and nrrangenr eq nrrangenr and SUBOBJECT eq SUBOBJECT. if sy-subrc ne 0. raise SECURITY_FAILURE. endif. * The number range level holds the last number that was USED, here * we need to check whether the next number is available for use, hence: add 1 to l_nrlevel. * Check the relevant objects: case OBJECT. * Purchase documents: table EKKO! when 'EINKBELEG'. write l_nrlevel+10(10) to l_ekko_ebeln. select single ebeln from ekko into l_ekko_ebeln where ebeln eq l_ekko_ebeln. if sy-subrc eq 0. "Alert! PO already available * Don't set the check_ok flag... else. l_check_ok = 'X'. endif. when others. * Function was called with unknown object... ask a developer to * add a check like the one above first... raise SECURITY_FAILURE. endcase. if l_check_ok eq space. CALL FUNCTION 'NUMBER_GET_NEXT' EXPORTING NR_RANGE_NR = NRRANGENR OBJECT = OBJECT SUBOBJECT = SUBOBJECT EXCEPTIONS OTHERS = 1. IF SY-SUBRC <> 0. raise SECURITY_FAILURE. ENDIF. endif. endwhile. ENDFUNCTION. |