Enterprise Resource Planning Blogs by SAP
Get insights and updates about cloud ERP and RISE with SAP, SAP S/4HANA and SAP S/4HANA Cloud, and more enterprise management capabilities with SAP blog posts.
cancel
Showing results for 
Search instead for 
Did you mean: 
PrasanthM
Product and Topic Expert
Product and Topic Expert
In this blog, I will take you through the steps for creating an API to convert number to words in SAP S/4HANA Cloud. I will then provide an example on how to make use of this API to display amount in words in a Form Template.

Introduction


When this requirement came up initially, my first instinct was to search for available APIs on R3 and the first API that I found was the function module SPELL_AMOUNT, which was universally used. One option to consume this would be to wrap this API in an RFC and call it via cloud connector

https://blogs.sap.com/2019/02/28/how-to-call-a-remote-function-module-in-your-on-premise-sap-system-...

But this option felt too cumbersome for me and I wanted to try something simpler. That is when I realized I could create a reusable API in Custom Reusable Elements found under Extensibility Tile and use this.

I found a similar API in python, which converts any number to words and I decided to reuse it. You can find the python APIs at https://stackoverflow.com/questions/8982163/how-do-i-tell-python-to-convert-integers-into-words, and try the APIs on your own.
You could follow the extensive list of tutorials written by ulrike.liebherr to know more about the extensibility options available in SAP S/4HANA Cloud

https://blogs.sap.com/2017/01/20/sap-s4hana-extensibility-tutorial/

Without any further ado, let me get into what I did.

As a pre-perquisite, please note that your user should need the business role with business catalog Extensibility SAP_CORE_BC_EXT for performing the following steps

Creation of a Custom Business Object


The first step would be to create a Custom Business Object to store the words that are reused for every number. These are as follows.



















































































































0 Zero
1 One
2 Two
3 Three
4 Four
5 Five
6 Six
7 Seven
8 Eight
9 Nine
10 Ten
11 Eleven
12 Twelve
13 Thirteen
14 Fourteen
15 Fifteen
16 Sixteen
17 Seventeen
18 Eighteen
19 Nineteen
20 Twenty
30 Thirty
40 Forty
50 Fifty
60 Sixty
70 Seventy
80 Eighty
90 Ninety

I will not be covering the steps on creating a custom business object here and that can be found in this link which I had mentioned earlier.

Create a Custom Business Object from the tile Custom Business Objects under the group Extensibility.


Create the business object with the following structure


Check the field UI Generation so that a UI is created where you could maintain the entries that are mentioned above. You could also maintain Determination and Validation, if you need to perform any data validation and check Service Generation so that you could use the oData, but these are optional.


Save and Publish the Custom Business Object.

Once this is done, click on Maintain catalogs to assign the Business Object to a Business catalog.

Add this under the Business catalog SAP_CORE_BC_EXT and click on OK and the Publish it. This will take a few minutes, but once this is published, you can close this screen.


The Custom Business Object application will now be added under the tile Extensibility


Open the App and maintain the entries.

You can add these entries by clicking on Create.



Click on save once the entries are maintained

 

The entries should look like as given below, once maintained.



Creation of Custom Reusable Element


The second step will be to create the actual logic to convert the number to words.

For this, select the tile Custom Reusable Elements under the group Extensibility

 


Create a new custom library by clicking on the + button under the tab Custom Library.

Maintain the following and click on create


Add a new method under the newly created custom library


Click on the method to add signature for the method as follows


Save and publish the custom library. You will be able to add logic to the method only after Publishing.

Once the library is published, click on the method id


This will open the method implementation.

Click on Create Draft and enter the following code.
    TYPES: BEGIN OF str_d,
num TYPE i,
word1 TYPE string,
word2 TYPE string,
END OF str_d.

DATA: ls_h TYPE str_d,
ls_k TYPE str_d,
ls_m TYPE str_d,
ls_b TYPE str_d,
ls_t TYPE str_d,
ls_o TYPE str_d.

DATA lv_int TYPE i.
DATA lv_inp1 TYPE string.
DATA lv_inp2 TYPE string.

IF iv_num IS INITIAL.
RETURN.
ENDIF.

ls_h-num = 100.
ls_h-word1 = 'Hundred'.
ls_h-word2 = 'Hundred and'.

ls_k-num = ls_h-num * 10.
ls_k-word1 = 'Thousand'.
ls_k-word2 = 'Thousand'.

ls_m-num = ls_k-num * 1000.
ls_m-word1 = 'Million'.
ls_m-word2 = 'Million'.

ls_b-num = ls_m-num * 1000.
ls_b-word1 = 'Billion'.
ls_b-word2 = 'Billion'.

* Use the following if this is required in Lakhs/Crores instead of Millions/Billions
*
* ls_h-num = 100.
* ls_h-word1 = 'Hundred'.
* ls_h-word2 = 'Hundred and'.

* ls_k-num = ls_h-num * 10.
* ls_k-word1 = 'Thousand'.
* ls_k-word2 = 'Thousand'.

* ls_m-num = ls_k-num * 100.
* ls_m-word1 = 'Lakh'.
* ls_m-word2 = 'Lakh'.

* ls_b-num = ls_m-num * 100.
* ls_b-word1 = 'Crore'.
* ls_b-word2 = 'Crore'.

lv_int = iv_num.

SELECT * FROM yy1_number2string INTO TABLE @DATA(lt_d).

IF lt_d IS NOT INITIAL.
IF lv_int <= 20.
READ TABLE lt_d REFERENCE INTO DATA(ls_d) WITH KEY num = lv_int.
rv_words = ls_d->word.
RETURN.
ENDIF.

IF lv_int < 100 AND lv_int > 20.
DATA(mod) = lv_int MOD 10.
DATA(floor) = floor( lv_int DIV 10 ).
IF mod = 0.
READ TABLE lt_d REFERENCE INTO ls_d WITH KEY num = lv_int.
rv_words = ls_d->word.
RETURN.
ELSE.
READ TABLE lt_d REFERENCE INTO ls_d WITH KEY num = floor * 10.
DATA(pos1) = ls_d->word.
READ TABLE lt_d REFERENCE INTO ls_d WITH KEY num = mod.
DATA(pos2) = ls_d->word.
rv_words = |{ pos1 } | && |{ pos2 } |.
RETURN.
ENDIF.
ELSE.
IF lv_int < ls_k-num.
ls_o = ls_h.
ELSEIF lv_int < ls_m-num.
ls_o = ls_k.
ELSEIF lv_int < ls_b-num.
ls_o = ls_m.
ELSE.
ls_o = ls_b.
ENDIF.
mod = lv_int MOD ls_o-num.
floor = floor( iv_num DIV ls_o-num ).
lv_inp1 = floor.
lv_inp2 = mod.

IF mod = 0.
DATA(output2) = num2words( lv_inp1 ).
rv_words = |{ output2 } | && |{ ls_o-word1 } |.
RETURN.
ELSE.
output2 = num2words( lv_inp1 ).
DATA(output3) = num2words( lv_inp2 ).
rv_words = |{ output2 } | && |{ ls_o-word2 } | && |{ output3 } |.
RETURN.
ENDIF.
ENDIF.
ENDIF.


Save and Publish the code.

You could reuse this code in use cases within your SAP S/4HANA Cloud Instance.

Use Case


Display amount in words in Purchase Order output form.

Create a Custom Field


Create a custom field by selecting the tile Custom fields and Logic under the Group Extensibility


Maintain the following along with the following usages


UI and Reports


Form Templates


Save and Publish the custom field.

Add the column Amount in words to the form via Adobe LiveCycle Designer and bind it to the field YY1_AmountInWords_PDI


After the custom form is updated, this will have to be uploaded back to the SAP S/4HANA Cloud system.

Details on how to download the form, edit and the reupload back to the SAP S/4HANA system can be found in Steps 2 and 3 of the blog by arun.nair https://blogs.sap.com/2018/03/12/extend-form-template-using-sap-s4-hana-cloud-in-app-extensibility/

You could refer to the Best Practices for 1LQ for more details on forms and template.

Populate the Custom Field


This field can now be populated by creating an Enhancement implementation via Custom Flows and Logic

For this, selecting the tile Custom fields and Logic under the Group Extensibility and Go to the Tab Custom Logic.

Add a new entry by selecting the following and click on create


Enter the following code, save and Publish
DATA: lv_am1 TYPE string,
lv_am2 TYPE string,
lv_amount TYPE string.

lv_amount = purchaseorderitem-netpriceamount.

SPLIT lv_amount AT '.' INTO lv_am1 lv_am2.

purchaseorderitemchange-yy1_amountinwords_pdi = yy1_num2words=>num2words( iv_num = lv_am1 ).

You can see that the reusable library is called from the enhancement as

yy1_num2words=>num2words( iv_num = lv_am1 )

 

Now, create a new Purchase order and generate the output form from the Output Management Tab.

You will be able to see the Net Value converted to words as follows.



 

Please note that this logic does not handle decimals as of now, but you could add this by tweaking the existing logic 🙂

 

Hope this helped
12 Comments
Andre_Fischer
Product and Topic Expert
Product and Topic Expert
Nice and useful blog!
PrasanthM
Product and Topic Expert
Product and Topic Expert
0 Kudos
Thanks Andre 🙂
matt
Active Contributor
Interesting and well presented, but it would be nice if modern ABAP were used throughout

  • No need for CONCATENATE for example, when && is available.

  • Try READ TABLE lt_d INTO REFERENCE data(ls_d) WITH KEY ..., then you can use instead of ls_d-word, ls_d->word. It's just that little bit better performing.


Meaningful variable names will make it easier to understand the code, and of course in a real implementation, you'd modularise far more (I hope!). Also, I prefer to follow the SAP style guide advice and not use prefixes for variables.

Otherwise, a good read and I learned something. Thanks.
PrasanthM
Product and Topic Expert
Product and Topic Expert
0 Kudos
Thanks Matthew for your feedback 🙂
ThomasSchneider
Product and Topic Expert
Product and Topic Expert
A very, very, very cool blog.

Just one comment from my side. Instead of using a custom BO, you could also use a custom code list (created in the Fiori app Custom Reusable Elements). The advantage of a custom code list over a custom BO is that the content (= mapping table between number and words) is transported from Q to P system.
PrasanthM
Product and Topic Expert
Product and Topic Expert
0 Kudos
Thank you Thomas. I will try this using custom code list as suggested 🙂
former_member185587
Participant
Thank you for such a nice blog post Prashanth.

Here is the extension of your solution for handling decimals as well.
PrasanthM
Product and Topic Expert
Product and Topic Expert
0 Kudos
Hi Kiran,

 

Good one 🙂

 

Best Regards,

Prasanth
BijeshRB
Participant
0 Kudos
Hi Prasanth,

Wonderful blog, this helps me a lot particularly catalog assigning.

 

 

 

Thanks ,

Bijesh.RB
former_member728975
Active Participant
0 Kudos
Hello Prasanth, nice blog!

I have one doubt about this scenario, how is it work when it's a negative amount? I can see it doesn't "translate" the negative signal.

Thank you so much.
KR,
Iza
PrasanthM
Product and Topic Expert
Product and Topic Expert
0 Kudos
Thanks Izabelle,

The code that is covered as part of the blog, does not handle negative amounts. But it could be easily handled by adding a check to identify whether the number is < 0 convert it to >0, then convert it to words and then add a negative along with the converted text. It should be a minor change that can be handled via code.

Best Regards,

Prasanth
former_member841372
Discoverer
0 Kudos
Good post,

How can I use something like this from Hana for Business One?