Technical Articles
How to use I_JournalEntryTP in custom RAP BO
Business Object Journal Entry (I_JournalEntryTP) is available in S/4 HANA Cloud environment. It provides operations:
- Post
- Validate
- Reverse
- Change
You can try to build your own ‘Posting’ Fiori application by creating custom RAP business object. The posting can be achieved by calling the ‘Post’ action in Journal Entry object.
You can find an example in the documentation on how to call the ‘Post’ action from local program or class . This blog focus on how it work when calling within an RAP behavior class.
This blog will show a sample demo. Current it only support operations ‘Create’ & ‘Delete’. Please note: This demo is only a demonstration of the technology and does not provide any guidance for the business.
Currently extensibility is not support in I_JournalEntryTP. The implementation is ongoing and will available soon.
Highlights:
- I_JournalEntryTP~Post is defined as Save Action in RAP which can only be called during a specified RAP saver mehtod. Otherwise leads to a short dump.
- The allowed name of RAP save method is specified as finalize, adjustnumbers ( check the definition of underlying BO R_JournalEntryTP). It can be called from a finalize (determination on save in case Managed RAP BO ) or adjust_numbers (Late numbering) RAP saver method. In this example, post action is called in the determination ‘Post’.
- The Journal entry final key can be retrieved by using CONVERT KEY which only allowed to be called during RAP save method(late save phase).
- It is suggested to call the Validate before Post action. Error message should raised in early phase.
The Fiori application will look like:
Worklist
Input Transactional Data
Save
Steps:
- Create transaction & draft tables
- Create header table.
@EndUserText.label : 'Journal Entry Header' @AbapCatalog.enhancement.category : #NOT_EXTENSIBLE @AbapCatalog.tableCategory : #TRANSPARENT @AbapCatalog.deliveryClass : #A @AbapCatalog.dataMaintenance : #RESTRICTED define table zgje_header { key client : abap.clnt not null; key uuid : sysuuid_x16 not null; bukrs : bukrs; gjahr : gjahr; belnr : belnr_d; waers : waers; bldat : bldat; budat : budat; bktxt : bktxt; created_by : abp_creation_user; created_at : abp_creation_tstmpl; last_changed_by : abp_lastchange_user; last_changed_at : abp_lastchange_tstmpl; local_last_changed_at : abp_locinst_lastchange_tstmpl; }
- Create item table
@EndUserText.label : 'Journal Entry Item' @AbapCatalog.enhancement.category : #NOT_EXTENSIBLE @AbapCatalog.tableCategory : #TRANSPARENT @AbapCatalog.deliveryClass : #A @AbapCatalog.dataMaintenance : #RESTRICTED define table zgje_item { key client : abap.clnt not null; key uuid : sysuuid_x16 not null; key buzei : buzei not null; @Semantics.amount.currencyCode : 'zgje_header.waers' wrbtr : fins_vwcur12; sgtxt : sgtxt; hkont : hkont; kostl : kostl; prctr : prctr; item_created_by : abp_creation_user; item_created_at : abp_creation_tstmpl; item_last_changed_by : abp_lastchange_user; item_last_changed_at : abp_lastchange_tstmpl; item_local_last_changed_at : abp_locinst_lastchange_tstmpl; }
- Create draft table for header
@EndUserText.label : 'Journal Entry Header Draft Table' @AbapCatalog.enhancement.category : #EXTENSIBLE_ANY @AbapCatalog.tableCategory : #TRANSPARENT @AbapCatalog.deliveryClass : #A @AbapCatalog.dataMaintenance : #RESTRICTED define table zgje_header_d { key mandt : mandt not null; key uuid : sysuuid_x16 not null; belnr : belnr_d; bukrs : bukrs; gjahr : gjahr; waers : waers; bldat : bldat; budat : budat; bktxt : bktxt; created_by : abp_creation_user; created_at : abp_creation_tstmpl; last_changed_by : abp_lastchange_user; last_changed_at : abp_lastchange_tstmpl; local_last_changed_at : abp_locinst_lastchange_tstmpl; "%admin" : include sych_bdl_draft_admin_inc; }
- Create draft table for item
@EndUserText.label : 'Journal Entry Item Draft' @AbapCatalog.enhancement.category : #EXTENSIBLE_ANY @AbapCatalog.tableCategory : #TRANSPARENT @AbapCatalog.deliveryClass : #A @AbapCatalog.dataMaintenance : #RESTRICTED define table zgje_item_d { key mandt : mandt not null; key uuid : sysuuid_x16 not null; key buzei : buzei not null; @Semantics.amount.currencyCode : 'zgje_item_d.waers' wrbtr : fins_vwcur12; waers : waers; sgtxt : sgtxt; hkont : hkont; kostl : kostl; prctr : prctr; item_created_by : abp_creation_user; item_created_at : abp_creation_tstmpl; item_last_changed_by : abp_lastchange_user; item_last_changed_at : abp_lastchange_tstmpl; "%admin" : include sych_bdl_draft_admin_inc; }
- Create header table.
- Define business object structure
- Header root view.
@AccessControl.authorizationCheck: #NOT_REQUIRED @EndUserText.label: 'GL Journal Entry' define root view entity ZR_GeneralJournalEntry as select from zgje_header composition [0..*] of ZR_GeneralJournalEntryItem as _Item { key uuid as Uuid, belnr as belnr, bukrs as Bukrs, gjahr as Gjahr, waers as Waers, bldat as Bldat, budat as Budat, bktxt as Bktxt, @Semantics.user.createdBy: true created_by as Created_By, @Semantics.systemDateTime.createdAt: true created_at as Created_At, @Semantics.user.lastChangedBy: true last_changed_by as Last_Changed_By, @Semantics.systemDateTime.lastChangedAt: true last_changed_at as Last_Changed_At, @Semantics.systemDateTime.localInstanceLastChangedAt: true local_last_changed_at as Local_Last_Changed_At, _Item }
- Item child view
@AbapCatalog.viewEnhancementCategory: [#NONE] @AccessControl.authorizationCheck: #NOT_REQUIRED @EndUserText.label: 'GL Journal Entry Item' @Metadata.ignorePropagatedAnnotations: true @ObjectModel.usageType:{ serviceQuality: #X, sizeCategory: #S, dataClass: #MIXED } define view entity ZR_GeneralJournalEntryItem as select from zgje_item association to parent ZR_GeneralJournalEntry as _Header on $projection.Uuid = _Header.Uuid { key uuid as Uuid, key buzei as Buzei, @Semantics.amount.currencyCode: 'Waers' wrbtr as Wrbtr, _Header.Waers as Waers, sgtxt as sgtxt, hkont as hkont, kostl as Kostl, prctr as Prctr, @Semantics.user.createdBy: true item_created_by as Item_Created_By, @Semantics.systemDateTime.createdAt: true item_created_at as Item_Created_At, @Semantics.user.lastChangedBy: true item_last_changed_by as Item_Last_Changed_By, @Semantics.systemDateTime.localInstanceLastChangedAt: true item_last_changed_at as Item_Last_Changed_At, _Header }
- Header root view.
- Create class for local transactional buffer.which will be used in behavior pool implementation.
CLASS zgje_transaction_handler DEFINITION PUBLIC FINAL CREATE PUBLIC . PUBLIC SECTION. CLASS-DATA: go_instance TYPE REF TO zgje_transaction_handler. CLASS-METHODS: get_instance RETURNING VALUE(result) TYPE REF TO zgje_transaction_handler. TYPES: BEGIN OF ty_temp_key, cid TYPE abp_behv_cid, pid TYPE abp_behv_pid, END OF ty_temp_key, tt_temp_key TYPE STANDARD TABLE OF ty_temp_key WITH DEFAULT KEY, BEGIN OF ty_final_key, cid TYPE abp_behv_cid, bukrs TYPE bukrs, belnr TYPE belnr_d, gjahr TYPE gjahr, END OF ty_final_key, tt_final_key type STANDARD TABLE OF ty_final_key WITH DEFAULT KEY, tt_header TYPE STANDARD TABLE OF zgje_header WITH DEFAULT KEY. DATA: temp_key TYPE tt_temp_key. METHODS: set_temp_key IMPORTING it_temp_key TYPE tt_temp_key, convert_temp_to_final RETURNING VALUE(result) TYPE tt_final_key, additional_save IMPORTING it_create type tt_header it_delete TYPE tt_header, clean_up. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS zgje_transaction_handler IMPLEMENTATION. METHOD get_instance. IF go_instance IS NOT BOUND. go_instance = NEW #( ). ENDIF. result = go_instance. ENDMETHOD. METHOD additional_save. data: lt_create type TABLE of zgje_header. DATA(lt_je_key) = convert_temp_to_final( ). loop at it_create into data(ls_create). read TABLE lt_je_key into data(ls_je_key) with key cid = ls_create-uuid. if sy-subrc = 0. ls_create-belnr = ls_je_key-belnr. append ls_create to lt_create. endif. ENDLOOP. IF lt_create IS NOT INITIAL. INSERT zgje_header FROM TABLE @lt_create. ENDIF. IF it_delete IS NOT INITIAL. DELETE zgje_header FROM TABLE @it_delete. ENDIF. ENDMETHOD. METHOD clean_up. CLEAR temp_key. ENDMETHOD. METHOD convert_temp_to_final. DATA: ls_final_key TYPE ty_final_key. IF temp_key IS NOT INITIAL. LOOP AT temp_key INTO DATA(ls_temp_key). CONVERT KEY OF i_journalentrytp FROM ls_temp_key-pid TO FINAL(lv_root_key). ls_final_key-cid = ls_temp_key-cid. ls_final_key-bukrs = lv_root_key-companycode. ls_final_key-belnr = lv_root_key-accountingdocument. ls_final_key-gjahr = lv_root_key-fiscalyear. APPEND ls_final_key TO result. ENDLOOP. ENDIF. ENDMETHOD. METHOD set_temp_key. temp_key = it_temp_key. ENDMETHOD. ENDCLASS.
- Define behavior
managed with additional save implementation in class zbp_r_generaljournalentry unique; strict ( 2 ); with draft; define behavior for ZR_GeneralJournalEntry //alias <alias_name> //persistent table zgje_header with unmanaged save draft table zgje_header_d lock master total etag Last_Changed_At authorization master ( instance ) etag master Local_Last_Changed_At { create; update ; delete ; association _Item { create; with draft; } draft action Resume; draft action Edit; draft action Activate optimized; draft action Discard; draft determine action Prepare; determination Post on save {create;} mapping for zgje_header corresponding; field ( readonly, numbering : managed ) Uuid; field ( readonly ) belnr; } define behavior for ZR_GeneralJournalEntryItem //alias <alias_name> persistent table zgje_item draft table zgje_item_d lock dependent by _Header authorization dependent by _Header etag master Item_Last_Changed_At { update ; delete ; field ( readonly ) Uuid; field ( mandatory: create,readonly : update ) Buzei; association _Header { with draft; } mapping for zgje_item corresponding; }
- Use ADT tool to generate behavior pool calss. Double click highlight code.
- Implementation of behavior pool (local type).
CLASS lhc_zr_generaljournalentry DEFINITION INHERITING FROM cl_abap_behavior_handler. PRIVATE SECTION. METHODS get_instance_authorizations FOR INSTANCE AUTHORIZATION IMPORTING keys REQUEST requested_authorizations FOR zr_generaljournalentry RESULT result. METHODS post FOR DETERMINE ON SAVE IMPORTING keys FOR zr_generaljournalentry~post. ENDCLASS. CLASS lhc_zr_generaljournalentry IMPLEMENTATION. METHOD get_instance_authorizations. ENDMETHOD. METHOD post. DATA: lt_entry TYPE TABLE FOR ACTION IMPORT i_journalentrytp~post, ls_entry LIKE LINE OF lt_entry, ls_glitem LIKE LINE OF ls_entry-%param-_glitems, ls_amount LIKE LINE OF ls_glitem-_currencyamount, lt_temp_key TYPE zgje_transaction_handler=>tt_temp_key, ls_temp_key LIKE LINE OF lt_temp_key. READ ENTITIES OF zr_generaljournalentry IN LOCAL MODE ENTITY zr_generaljournalentry ALL FIELDS WITH CORRESPONDING #( keys ) RESULT FINAL(header) ENTITY zr_generaljournalentry BY \_item ALL FIELDS WITH CORRESPONDING #( keys ) RESULT FINAL(item). "start to call I_JournalEntryTP~Post LOOP AT header REFERENCE INTO DATA(ls_header). CLEAR ls_entry. ls_entry-%cid = ls_header->uuid. "use UUID as CID ls_entry-%param-companycode = ls_header->bukrs. ls_entry-%param-businesstransactiontype = 'RFPO'. ls_entry-%param-accountingdocumenttype = 'AB'. ls_entry-%param-accountingdocumentheadertext = ls_header->bktxt. ls_entry-%param-documentdate = ls_header->bldat. ls_entry-%param-postingdate = ls_header->budat. ls_entry-%param-createdbyuser = ls_header->created_by. LOOP AT item REFERENCE INTO DATA(ls_item) USING KEY entity WHERE uuid = ls_header->uuid. CLEAR ls_glitem. ls_glitem-glaccountlineitem = ls_item->%data-buzei. ls_glitem-glaccount = ls_item->%data-hkont. ls_glitem-costcenter = ls_item->%data-kostl. ls_glitem-profitcenter = ls_item->%data-prctr. ls_glitem-documentitemtext = ls_item->%data-sgtxt. CLEAR ls_amount. ls_amount-currencyrole = '00'. ls_amount-currency = ls_header->waers. ls_amount-journalentryitemamount = ls_item->%data-wrbtr. APPEND ls_amount TO ls_glitem-_currencyamount. APPEND ls_glitem TO ls_entry-%param-_glitems. ENDLOOP. APPEND ls_entry TO lt_entry. ENDLOOP. IF lt_entry IS NOT INITIAL. MODIFY ENTITIES OF i_journalentrytp ENTITY journalentry EXECUTE post FROM lt_entry MAPPED FINAL(ls_post_mapped) FAILED FINAL(ls_post_failed) REPORTED FINAL(ls_post_reported). IF ls_post_failed IS NOT INITIAL. LOOP AT ls_post_reported-journalentry INTO DATA(ls_report). APPEND VALUE #( uuid = ls_report-%cid %create = if_abap_behv=>mk-on %is_draft = if_abap_behv=>mk-on %msg = ls_report-%msg ) TO reported-zr_generaljournalentry. ENDLOOP. ENDIF. LOOP AT ls_post_mapped-journalentry INTO DATA(ls_je_mapped). ls_temp_key-cid = ls_je_mapped-%cid. ls_temp_key-pid = ls_je_mapped-%pid. APPEND ls_temp_key TO lt_temp_key. ENDLOOP. ENDIF. zgje_transaction_handler=>get_instance( )->set_temp_key( lt_temp_key ). ENDMETHOD. ENDCLASS. CLASS lsc_zr_generaljournalentry DEFINITION INHERITING FROM cl_abap_behavior_saver. PROTECTED SECTION. METHODS save_modified REDEFINITION. METHODS cleanup_finalize REDEFINITION. ENDCLASS. CLASS lsc_zr_generaljournalentry IMPLEMENTATION. METHOD save_modified. "unmanaged save for table ZGJE_HEADER DATA: Lt_create type TABLE of ZGJE_HEADER, lt_delete type TABLE of ZGJE_HEADER. lt_create = CORRESPONDING #( create-zr_generaljournalentry mapping from entity ). lt_delete = CORRESPONDING #( delete-zr_generaljournalentry mapping from entity ). zgje_transaction_handler=>get_instance( )->additional_save( it_create = lt_create it_delete = lt_delete ). ENDMETHOD. METHOD cleanup_finalize. zgje_transaction_handler=>get_instance( )->clean_up( ). ENDMETHOD. ENDCLASS.
- Create projection business object.
- Header projection root view
@EndUserText.label: 'GL Journal Entry Projection' @AccessControl.authorizationCheck: #NOT_REQUIRED @Metadata.allowExtensions: true define root view entity ZC_GeneralJournalEntry provider contract transactional_query as projection on ZR_GeneralJournalEntry { key Uuid, belnr, Bukrs, Gjahr, Waers, Bldat, Budat, Bktxt, @Semantics.user.createdBy: true Created_By, @Semantics.systemDateTime.createdAt: true Created_At, @Semantics.user.lastChangedBy: true Last_Changed_By, @Semantics.systemDateTime.lastChangedAt: true Last_Changed_At, @Semantics.systemDateTime.localInstanceLastChangedAt: true Local_Last_Changed_At, _Item : redirected to composition child ZC_GeneralJournalEntryItem }
- Item projection view.
@EndUserText.label: 'GL Journal Item Projection' @AccessControl.authorizationCheck: #NOT_REQUIRED @Metadata.allowExtensions: true define view entity ZC_GeneralJournalEntryItem as projection on ZR_GeneralJournalEntryItem { key Uuid, key Buzei, @Semantics.amount.currencyCode: 'Waers' Wrbtr, Waers, sgtxt, hkont, Kostl, Prctr, @Semantics.user.createdBy: true Item_Created_By, @Semantics.systemDateTime.createdAt: true Item_Created_At, @Semantics.user.lastChangedBy: true Item_Last_Changed_By, @Semantics.systemDateTime.localInstanceLastChangedAt: true Item_Last_Changed_At, _Header : redirected to parent ZC_GeneralJournalEntry }
- Header projection root view
- Create metadata extension
- Metadata extension for header projection view
@Metadata.layer: #CUSTOMER annotate view ZC_GeneralJournalEntry with { @UI.facet: [ { id: 'Header', purpose: #STANDARD, type: #IDENTIFICATION_REFERENCE, label: 'Entry', position: 10 } , { id: 'Items', purpose: #STANDARD, type: #LINEITEM_REFERENCE, label: 'Items', position: 20, targetElement: '_Item'}] // @UI.identification: [{ position: 10 }] // Uuid; @Consumption.valueHelpDefinition: [{ entity: { name:'I_CompanyCode', element: 'CompanyCode' } }] @UI: { lineItem: [{ position: 10}],selectionField: [{ position: 10 }],identification: [{ position: 20 }] } Bukrs; @UI: { lineItem: [{ position: 20}],selectionField: [{ position: 20 }],identification: [{ position: 30 }] } Gjahr; @UI: { lineItem: [{ position: 30}],selectionField: [{ position: 30 }],identification: [{ position: 40 }] } @Consumption.semanticObject: 'AccountingDocument' belnr; @Consumption.valueHelpDefinition: [{ entity: { name:'I_Currency', element: 'Currency' } }] @UI: { lineItem: [{ position: 40}],selectionField: [{ position: 40 }],identification: [{ position: 50 }] } Waers; @UI: { lineItem: [{ position: 50}],selectionField: [{ position: 50 }],identification: [{ position: 60 }] } Bldat; @UI: { lineItem: [{ position: 60}],selectionField: [{ position: 60 }],identification: [{ position: 70 }] } Budat; @UI: { lineItem: [{ position: 70}],identification: [{ position: 80 }] } Bktxt; }
- Metadata extension for item projection view
@Metadata.layer: #CUSTOMER annotate view ZC_GeneralJournalEntryItem with { @UI.facet: [ { id: 'Item', purpose: #STANDARD, type: #IDENTIFICATION_REFERENCE, label: 'Item', position: 10 } ] @UI: { lineItem: [{ position: 10}],identification: [{ position: 10 }] } Buzei; @UI: { lineItem: [{ position: 20}],identification: [{ position: 20 }] } sgtxt; @UI: { lineItem: [{ position: 30}],identification: [{ position: 30 }] } Wrbtr; @UI: { lineItem: [{ position: 40}],identification: [{ position: 40 }] } @Consumption.valueHelpDefinition: [{ entity: { name:'I_GLAccount', element: 'GLAccount' } }] hkont; @UI: { lineItem: [{ position: 50}],identification: [{ position: 50 }] } @Consumption.valueHelpDefinition: [{ entity: { name:'I_CostCenter', element: 'CostCenter' } }] Kostl; @UI: { lineItem: [{ position: 60}],identification: [{ position: 60 }] } @Consumption.valueHelpDefinition: [{ entity: { name:'I_ProfitCenterStdVH', element: 'ProfitCenter' } }] Prctr; }
- Metadata extension for header projection view
- Behavior projection .
projection; strict ( 2 ); use draft; define behavior for ZC_GeneralJournalEntry //alias <alias_name> { use create; use update; use delete; use action Resume; use action Edit; use action Activate; use action Discard; use action Prepare; use association _Item { create; with draft; } } define behavior for ZC_GeneralJournalEntryItem //alias <alias_name> { use update; use delete; use association _Header { with draft; } }
- Right click view ZC_GeneralJournalEntry on the left tree navigation, choose ‘New Service Definition’.
@EndUserText.label: 'Manage_GL_Posting' define service Z_EXT_GL_POSTING { expose ZC_GeneralJournalEntry; expose ZC_GeneralJournalEntryItem; }
- Right click service definition that created in step 10, choose ‘New Service Binding’., Give a name and binding type Odata V4 – UI. Activate and publish. Use ‘Preview’ button to test.
Hi Zhou,
Excellent blog. Thanks a lot for sharing.. Please share JSON to test
Hi Patil,
I didn't get your point. There is no JSON for testing.
Best regards,
Take
Thank you so much for your quick response
i have to call as API, When i trying to execute using FIORI (preview) option , getting error when i am going to add items
"At create the mandatory element 'BUZEI' of entity 'ZC_GeneralJournalEntryItem' was not provided"
Hi Patil,
Please check demo video for the fiori applicatoin.
https://video.sap.com/media/t/1_7e2vd94j
Best regards,
Take
Hi Take,
I am not able to open this demo video.
Thanks..
Anita
I inserted the video in the blog. Please check.
Is I_JournalEntryTP also released for the S4 onprem version? Should we utilize it instead of the former BAPI?
Thanks
Natalia
Hi Rios,
It depend on the OP version. At least it avaiable on OP2021. Please check whether this object exist in your system.
Best regards,
Take
I am not able to open this demo video. I am in China.
Thanks..
I also encountered the same problem:
"At create the mandatory element 'BUZEI' of entity 'ZC_GeneralJournalEntryItem' was not provided"
Hi Simon,
Would you please send me the error detial ? My Email: take.zhou@sap.com.
Best regards,
Take