Technical Articles
How to use Early Numbering with Semantic Keys – RAP Managed BO
In my previous blog post, I discussed how to use Late Numbering in RAP Unmanaged Business Object.
If you are new to RESTful Application Programming (RAP) model, then this blog post by Carine Tchoutouo Djomo is a great starting place.
For this post, I assume you have some knowledge of RAP, Core Data Services (CDS) views and so on.
Source code for all artifacts including tables and CDS views are available in this GitHub repository.
Early Numbering – Managed & Unmanaged
Early numbering is a scenario in which instance keys are generated in the interaction phase of RAP as opposed to Late Numbering where keys are generated during save phase.
If your Business Object has GUID based keys, then you can use managed
early numbering. It is managed
because RAP runtime engine generates and assigns values to primary key fields.
In this post, I am going to discuss unmanaged
early numbering. It is unmanaged
because:
- RAP runtime engine assigns values to primary key fields
- How this assignment takes place is defined by the application developer in the behavior implementation pool inside specially defined methods for this purpose. Such methods are defined using keywords
FOR NUMBERING
Demo Business Object – the “Document”
This demo business object, called the “Document”, named so for the lack of any kind of creativity on my part, has 3 tables:
Tables and Foreign Key Relationships
Here are the CDS view entities where ZDH_MngdDocumentHeader
is the root entity:
CDS Model
Initial Behavior Definition (BDEF) (Managed)
When you generate the BDEF, it would look like this initially:
Initial Behavior Definition as generate
Let’s add some more details to this BDEF such as “alias” for each entity, authorization, etag and lock.
Define Unmanaged Early Numbering
This is done by adding the keywords early numbering
for each entity that needs to implement this. Notice the highlighted lines in the BDEF below:
Behavior Definition Updated
Since, field names in tables and respective CDS views are different, you also need to add mapping for each entity. It looks like something like below. Refer to GitHub folder for complete listing. This is not required for early numbering, per se.
Field Mapping
Activate BDEF and then use quick help to generate the BIL class. It should look something like this:
Initial Behavior Implementation Class
Notice the highlighted methods – for each entity that has early numbering
defined, there is a method generated. Notice the FOR NUMBERING
in the method definition.
These methods are called when instances of those entities are “created”. In other words when you execute MODIFY ENTITIES OF... CREATE...
or MODIFY ENTITIES OF.... CREATE BY...
for an entity, respective FOR NUMBERING
method is called.
Our goal is to add some lines of code here to generate the keys for each entity instances.
Pause and Note
This post is for educational purpose only. It is to demonstrate “how” to implement early numbering. Therefore, numbers are generated in a very simplistic manner. In a productive implementation, you will want to draw these numbers from Number Range object. How to do that is not in the scope of this post.
Also, note that, when keys are generated early in the interaction phase, validation failures in the later phase may cause gaps in the numbering. Therefore, if gap-less numbering is important or numbers need to be sequential, take extra caution while using this method!
Generate keys
I created this class ZCL_DH_MNGD_DOCUMENT_HANDLER
which has 3 methods:
GET_NEXT_DOC_NUMBER
-> returns next available document number. How it is done is not so importantGET_NEXT_ITEM_NUMBER
-> returns next item number for a given documentGET_NEXT_ACCOUNT_NUMBER
-> returns next account number for a given document item
Implement Numbering methods in BIL
In EARLYNUMBERING_
methods of BIL class, for each created instance (%CID), generate a new number and then fill “mapped” parameter.
These methods are called before any
determination ... on modify { create; }
are called
In EARLYNUMBERING_CREATE
method, notice that we are filling MAPPED-HEADER
by calling GET_NEXT_DOC_NUMBER()
method:
METHOD earlynumbering_create.
DATA(lo_doc_handler) = zcl_dh_mngd_document_handler=>get_instance( ).
LOOP AT entities ASSIGNING FIELD-SYMBOL(<ls_entity>).
INSERT VALUE #( %cid = <ls_entity>-%cid
DocumentNumber = lo_doc_handler->get_next_doc_number( ) ) INTO TABLE mapped-header.
ENDLOOP.
ENDMETHOD.
In EARLYNUMBERING_CBA_ITEM
method, we are filling MAPPED-ITEM
by calling GET_NEXT_ITEM_NUMBER()
method. Notice that we are passing the DocumentNumber
to this method which is available in the importing parameter entities
:
METHOD earlynumbering_cba_Item.
DATA(lo_doc_handler) = zcl_dh_mngd_document_handler=>get_instance( ).
LOOP AT entities ASSIGNING FIELD-SYMBOL(<ls_entity>).
LOOP AT <ls_entity>-%target ASSIGNING FIELD-SYMBOL(<ls_item_create>).
INSERT VALUE #( %cid = <ls_item_create>-%cid
DocumentNumber = <ls_entity>-DocumentNumber
ItemNumber = lo_doc_handler->get_next_item_number( iv_doc_number = <ls_entity>-DocumentNumber ) ) INTO TABLE mapped-item.
ENDLOOP.
ENDLOOP.
ENDMETHOD.
Similar logic is implemented in method EARLYNUMBERING_CBA_ACCOUNT
as well.
METHOD earlynumbering_cba_Account.
DATA(lo_doc_handler) = zcl_dh_mngd_document_handler=>get_instance( ).
LOOP AT entities ASSIGNING FIELD-SYMBOL(<ls_entity>).
LOOP AT <ls_entity>-%target ASSIGNING FIELD-SYMBOL(<ls_account_create>).
INSERT VALUE #( %cid = <ls_account_create>-%cid
DocumentNumber = <ls_entity>-DocumentNumber
ItemNumber = <ls_entity>-ItemNumber
AccountNumber = lo_doc_handler->get_next_account_number( iv_doc_number = <ls_entity>-DocumentNumber
iv_item_number = <ls_entity>-ItemNumber ) ) INTO TABLE mapped-account.
ENDLOOP.
ENDLOOP.
ENDMETHOD.
Apart from this, we have also added a determination for each entity in our BDEF named Defaults
to fill administrative fields such as CreatedBy, CreatedOn
. Complete listing of BIL class as well as ZCL_DH_MNGD_DOCUMENT_HANDLER
is available on the GitHub repo.
EML Test – Deep Create:
Let’s test it by writing an EML test.
Below EML will create 1 document with 1 item and 1 account line. Use valid company code, purchase organization and cost center depending on in which system you are writing this:
MODIFY ENTITIES OF ZDH_MngdDocumentHeader
ENTITY Header
CREATE SET FIELDS WITH VALUE #( ( %cid = 'doc1'
CompanyCode = '0001'
PurchasingOrganization = '0001' ) )
CREATE BY \_Item SET FIELDS WITH VALUE #( ( %cid_ref = 'doc1'
%target = VALUE #( ( %cid = 'item1'
itemdescription = 'EML Test Item 1' ) ) ) )
ENTITY Item
CREATE BY \_Account SET FIELDS WITH VALUE #( ( %cid_ref = 'item1'
%target = VALUE #( ( %cid = 'acc1'
costcenter = 'SVC_001' ) ) ) )
MAPPED DATA(mapped)
FAILED DATA(failed)
REPORTED DATA(reported).
COMMIT ENTITIES.
You can find complete test implemented as A Unit on GitHub repo. This listing should go into “local test classes” of our BIL class.
Summary
- Define
early numbering
in BDEF for each entity where you need to generate and assign primary keys - Implement a method
FOR NUMBERING
for each such entity - Methods should map “%CID”s to generated number and fill respective
mapped
parameter
That’s it for this post. I hope this was helpful. Let me know in the comments how I could improve this post.
Thanks, it helped me a lot!
Best Regards.
I cannot use early numbering in my managed behavior , i do not know why .
me too
using early numbering and strict is possibel only on BTP (cloud) ... for on-premise systems it is not allowed ...
so, is there any alternative solution for thıs situation?
May be on higher versions of S4 (2021 and later) it works on on-premise too.
Hi,
I'm new to RAP,
I've tried this Early Numbering in Managed Scenario for Purchase Order Creation but I had to write the EML in determination<det_name> on Modify {create;} ---------> This Method
This method is triggering after entering the values and giving create (Basically while saving)
also, this method which is created when early numbering(in Bdef) is given.
METHODS earlynumbering_create FOR NUMBERING
IMPORTING entities FOR CREATE ZPJ_I_ekko.
This method is triggering only after the Create button is clicked (while saving)
When I give the create PO action button and try to enter the values at that time the PO number is blank. but only after creating the Po, the Po Number is visible.
So isn't this called Late Numbering and not Early numbering?
Someone help me and thanks in advance.