*-----------------------------------------------------------------------
* SELEKTIONSBILD
*-----------------------------------------------------------------------
SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE text-001.
* Radiobutton 1 -> Deactivate Fields
SELECTION-SCREEN BEGIN OF LINE.
PARAMETERS: p_radio1 RADIOBUTTON GROUP rad1 DEFAULT 'X' USER-COMMAND rad.
SELECTION-SCREEN COMMENT 6(37) text-t01 FOR FIELD p_radio1.
SELECTION-SCREEN : END OF LINE.
* Radiobutton 2 -> Activate Fields
SELECTION-SCREEN : BEGIN OF LINE.
PARAMETERS: p_radio2 RADIOBUTTON GROUP rad1.
SELECTION-SCREEN COMMENT 6(37) text-t02 FOR FIELD p_radio2.
SELECTION-SCREEN : END OF LINE.
* Input fields
PARAMETERS:
p_vorna TYPE vorna OBLIGATORY DEFAULT 'Max',
p_nachn TYPE nachn OBLIGATORY DEFAULT 'Mustermann'.
SELECTION-SCREEN END OF BLOCK b1.
*----------------------------------------------------------------------
* AT SELECTION-SCREEN
*----------------------------------------------------------------------
AT SELECTION-SCREEN OUTPUT. " PBO
LOOP AT SCREEN.
CASE screen-name.
WHEN 'P_VORNA' OR 'P_NACHN'.
screen-input = COND #( WHEN p_radio2 = abap_true THEN 1 ELSE 0 ).
MODIFY SCREEN.
ENDCASE.
ENDLOOP.
Tag: SAP
[ABAP] JSON to ABAP with dereferencing
Recently I had to fetch an attachment from SuccessFactors. The API returns a huge JSON. Here only a few lines of that json.
{
"d": {
"__metadata": {
"uri": "https://apihostname.successfactors.com:443/odata/v2/Attachment(1000)",
"type": "SFOData.Attachment"
},
"attachmentId": "1000",
"fileName": "Testdokument.pdf",
"mimeType": "application/pdf",
"moduleCategory": "HRIS_ATTACHMENT",
"userId": "10000555",
"fileExtension": "pdf",
"fileContent": "JVBERi0xLjcKjp2jtMXW5/gKMiAwIG9iag0KWy9JQ0NCYXNlZCAzIDAgUl0NCmVuZG9iag0KMyAw\r\nIG9iag0KPDwNCi9GaWx0ZXIgL0ZsYXRlRGVjb2RlIA0KL0xlbmd0aCAyNTk2IA0KL04gMyANCj4+\r\nDQpzdHJlYW0NCnicnZZ3VFPZFofPvTe9UJIQipTQa2hSAkgNvUiRLioxCRBKwJAAIjZEVHBEUZGm\r\nCDIo4ICjQ5GxIoqFAVGx6wQZRNRxcBQblklkrRnfvHnvzZvfH/d+a5+9z91n733WugCQ/IMFwkxY\r\nCYAMoVgU4efFiI2LZ2AHAQzwAANsAOBws7NCFvhGApkCfNiMbJkT+Be9ug4g+fsq0z+MwQD/n5S5\r\nWSIxAFCYjOfy+NlcGRfJOD1XnCW3T8mYtjRNzjBKziJZgjJWk3PyLFt89pllDznzMoQ8GctzzuJl\r\n8OTcJ+ONORK+jJFgGRfnCPi5Mr4mY4N0SYZAxm/ksRl8TjYAKJLcLuZzU2RsLWOSKDKCLeN5AOB......"
...
}
}
Parsing the JSON to ABAP
SAP provides two classes /ui2/cl_json
and /ui2/cl_data_access
to work with JSONs and there are also many cool tools on https://dotabap.org/ for that.
Because it’s just a simple JSON I tried to avoid importing another class to the system. So I stayed with SAPs classes.
First deserialize the JSON with /ui2/cl_json
.
" Constants for properties
CONSTANTS gc_filecontent TYPE string VALUE 'FILECONTENT' ##NO_TEXT.
CONSTANTS gc_filename TYPE string VALUE 'FILENAME' ##NO_TEXT.
CONSTANTS gc_doc_cat TYPE string VALUE 'DOCUMENTCATEGORY' ##NO_TEXT.
DATA: lr_data TYPE REF TO data.
/ui2/cl_json=>deserialize( EXPORTING json = lv_responce "the repsonse contains the json string
CHANGING data = lr_data ).
I found three similiar ways to use the class /ui2/cl_data_access
to get the relevant data out of the JSON.
1. Using the class construktor and the value( )
method for earch property.
DATA: lv_filecontent_base64 TYPE string,
lv_filename TYPE string,
lv_documentcategory TYPE string.
/ui2/cl_data_access=>create( ir_data = lr_data iv_component = |D-{ gc_filecontent }| )->value( IMPORTING ev_data = lv_filecontent_base64 ).
/ui2/cl_data_access=>create( ir_data = lr_data iv_component = |D-{ gc_filename }| )->value( IMPORTING ev_data = lv_filename).
/ui2/cl_data_access=>create( ir_data = lr_data iv_component = |D-{ gc_doc_cat }| )->value( IMPORTING ev_data = lv_documentcategory ).
2. Create an instance as first step and pass the component. Reuse the instance with the value( )
method.
DATA: lv_filecontent_base64 TYPE string,
lv_filename TYPE string,
lv_documentcategory TYPE string.
DATA(lo_data_access) = /ui2/cl_data_access=>create( ir_data = lr_data
iv_component = |D-| ).
lo_data_access->at( |{ gc_filecontent }| )->value( IMPORTING ev_data = lv_filecontent_base64 ).
lo_data_access->at( |{ gc_filename }| )->value( IMPORTING ev_data = lv_filename ).
lo_data_access->at( |{ gc_doc_cat }| )->value( IMPORTING ev_data = lv_documentcategory ).
3. Use the ref( )
method to get a reference of a property value. Because it returns a generic data type (and you cannot dereference generic references) you have to use CAST
combined with dereferencing (->*
) to get the concret value.
DATA(lo_data_access) = /ui2/cl_data_access=>create( ir_data = lr_data
iv_component = |D-| ).
DATA(lv_filecontent_base64) = CAST string( lo_data_access->at( gc_filecontent )->ref( ) )->*.
DATA(lv_filename) = CAST string( lo_data_access->at( gc_filename )->ref( ) )->*.
DATA(lv_documentcategory) = CAST string( lo_data_access->at( gc_doc_cat )->ref( ) )->*.
In the end I stayed with version 3 because I prefere using inline declarations. The complete result looked like this:
" Constants for properties
CONSTANTS gc_filecontent TYPE string VALUE 'FILECONTENT' ##NO_TEXT.
CONSTANTS gc_filename TYPE string VALUE 'FILENAME' ##NO_TEXT.
CONSTANTS gc_doc_cat TYPE string VALUE 'DOCUMENTCATEGORY' ##NO_TEXT.
DATA: lr_data TYPE REF TO data.
/ui2/cl_json=>deserialize( EXPORTING json = lv_response "the repsonse contains the json string
CHANGING data = lr_data ).
DATA(lo_data_access) = /ui2/cl_data_access=>create( ir_data = lr_data
iv_component = |D-| ).
DATA(lv_filecontent_base64) = CAST string( lo_data_access->at( gc_filecontent )->ref( ) )->*.
DATA(lv_filename) = CAST string( lo_data_access->at( gc_filename )->ref( ) )->*.
DATA(lv_documentcategory) = CAST string( lo_data_access->at( gc_doc_cat )->ref( ) )->*.
" Decode BASE64 PDF to XString
DATA(lv_decodedx) = cl_http_utility=>if_http_utility~decode_x_base64( lv_filecontent_base64 ).
" XString to binary
DATA(lt_data) = cl_bcs_convert=>xstring_to_solix( lv_decodedx ).
" Download file
cl_gui_frontend_services=>gui_download( EXPORTING bin_filesize = xstrlen( lv_decodedx )
filename = lv_filename
filetype = 'BIN'
show_transfer_status = ' '
CHANGING data_tab = lt_data ).
When /ui2/cl_data_access
is not available (SAP_UI has to be at least 7.51, see note 2526405), you can do it the oldschool way.
" Constants for properties
CONSTANTS gc_filecontent TYPE string VALUE 'FILECONTENT' ##NO_TEXT.
CONSTANTS gc_filename TYPE string VALUE 'FILENAME' ##NO_TEXT.
CONSTANTS gc_doc_cat TYPE string VALUE 'DOCUMENTCATEGORY' ##NO_TEXT.
DATA: lr_data TYPE REF TO data.
/ui2/cl_json=>deserialize( EXPORTING json = lv_response "the repsonse contains the json string
CHANGING data = lr_data ).
ASSIGN lr_data->* TO FIELD-SYMBOL(<fs_d>).
ASSIGN COMPONENT 'D' OF STRUCTURE <fs_d> TO FIELD-SYMBOL(<fs_components>).
ASSIGN <fs_components>->* TO FIELD-SYMBOL(<fs_fields>).
ASSIGN COMPONENT gc_doc_cat OF STRUCTURE <fs_fields> TO FIELD-SYMBOL(<documentcategory>).
ASSIGN COMPONENT gc_filename OF STRUCTURE <fs_fields> TO FIELD-SYMBOL(<filename>).
ASSIGN COMPONENT gc_filecontent OF STRUCTURE <fs_fields> TO FIELD-SYMBOL(<filecontent>).
ASSIGN <documentcategory>->* TO FIELD-SYMBOL(<documentcategory_value>).
ASSIGN <filename>->* TO FIELD-SYMBOL(<filename_value>).
ASSIGN <filecontent>->* TO FIELD-SYMBOL(<filecontent_value>).
"...
[BTP] Difference between Platform Users and Business Users
“Platform users are usually developers, administrators or operators who deploy, administer, and troubleshoot applications and services on SAP BTP.”
“Business users use the applications that are deployed to SAP BTP. For example, the end users of your deployed application or users of subscribed apps or services, such as SAP Business Application Studio or SAP Web IDE, are business users.”
[ABAP] Report Template
*&---------------------------------------------------------------------*
*& Report Z_REPORT
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
REPORT Z_REPORT.
*-----------------------------------------------------------------------
* SELEKTIONSBILD
*-----------------------------------------------------------------------
*-----------------------------------------------------------------------
* Zeitpunkt INITIALIZATION.
*-----------------------------------------------------------------------
INITIALIZATION.
*----------------------------------------------------------------------
* Zeitpunkt AT SELECTION-SCREEN
*----------------------------------------------------------------------
AT SELECTION-SCREEN OUTPUT. "PBO
*-----------------------------------------------------------------------
* Zeitpunkt START-OF-SELECTION.
*-----------------------------------------------------------------------
START-OF-SELECTION.
*----------------------------------------------------------------------
* Zeitpunkt END-OF-SELECTION
*----------------------------------------------------------------------
END-OF-SELECTION.
[SAP] Systemzugehörigkeit von Objekten ändern
Die Systemzugehörigkeit eines Objektes kann man in der Tabelle TADIR einsehen.
Tabelle: TADIR
Feld: SRCSYSTEM
Einfache Änderung via SE03: https://l3consulting.de/systemzugehoerigkeit-von-objekten-ueber-se03-aendern-massenaenderung/
Danach ggf. noch die Transportschicht im Paket anpassen. Beim Speichern muss man dafür einen lokalen Transportauftrag anlegen. Dieser kann nach der Änderung wieder gelöscht werden.
[ABAP] OM – Lese Personen auf und unterhalb einer OE
Auswertungsweg O-O-S-P liefert unter einer gegebenen Org. Einheit alle Personen, auch aus tieferen OE.
T-Code: OOAW
DATA(lt_actor) = VALUE tswhactor( ).
CALL FUNCTION 'RH_STRUC_GET'
EXPORTING
act_otype = 'O'
act_objid = lv_oe " die Org. Einheit, von der gestartet werden soll
act_wegid = 'O-O-S-P'
act_plvar = '01'
act_begda = sy-datum
act_endda = sy-datum
act_tflag = space
act_vflag = space
authority_check = space
TABLES
result_tab = lt_actor
EXCEPTIONS
no_plvar_found = 1
no_entry_found = 2
OTHERS = 3.
IF sy-subrc <> 0.
" do error handling
ENDIF.
" Nur Pernr's relevant
DELETE lt_actor WHERE otype <> 'P'.
" Doppelte Pernr's entfernen
DELETE ADJACENT DUPLICATES FROM lt_actor.
Zum Testen des Auswertungsweges kann man den Report RHSTRU00 verwenden. Einfach Planvariante, Objekttyp und eine ObjektId einer Org. Einheit eingeben, sowie den Auswertungsweg und Statusvektor 1 (aktiv).
[SAPUI5] MyInbox: Integration of Detail View – EmbedIntoDetail
https://launchpad.support.sap.com/#/notes/2305401 (App to App Navigation CookBook.pdf)
https://blogs.sap.com/2020/07/31/fiori-my-inbox-integration-of-custom-detail-page/
Target:
Go to /n/ui2/fpld_cust and define a second target for your App, i.e. approve.
The approve target needs the “emdedIntoDetails” parameter:
SWFVISU:
Add the new target for your WF Task. Here you have access to all attributes of your Workitem-Container. Pass all your mandatory fields you’ve defined in your oData Entity.
Some examples: https://blogs.sap.com/2016/05/31/my-inbox-open-task-swfvisu-configuration/
If your missing some parameters, just add them in your Workitem Task and pass the values directly into it right from your Workflow Container. This looks much better.
Manifest:
Add a route to navigate via Inbox. The pattern has to match your inbox url.
"routes": [
{
"pattern": "",
"name": "master",
"target": "master"
},
{
"pattern": "DataSet/{Pernr},{Datum},{Infty}",
"name": "object",
"target": [
"master",
"object"
]
},
{
"pattern": "detail/LOCAL_INBOX/{wfInstanceId}/{taskPath}",
"name": "wfobject",
"target": "object"
}
Detail.Controller:
onInit: function () {
// Model used to manipulate control states. The chosen values make sure,
// detail page is busy indication immediately so there is no break in
// between the busy indication for loading the view's meta data
var oViewModel = new JSONModel({
busy: false,
delay: 0
});
this.getRouter().getRoute("object").attachPatternMatched(this._onObjectMatched, this);
//My Inbox Integration
this.getRouter().getRoute("wfobject").attachPatternMatched(this._onWFObjectMatched, this);
this.setModel(oViewModel, "detailView");
this.getOwnerComponent().getModel().metadataLoaded().then(this._onMetadataLoaded.bind(this));
},
_onWFObjectMatched: function (oEvent) {
this.getModel("appView").setProperty("/layout", "MidColumnFullScreen");
var compData = this.getOwnerComponent().getComponentData();
if (compData && compData.startupParameters && compData.startupParameters.PERNR && Array.isArray(compData.startupParameters.PERNR) &&
compData.startupParameters.PERNR[0]) {
var sPernr = compData.startupParameters.PERNR[0];
var sDatum = compData.startupParameters.DATUM[0];
var sInfty = compData.startupParameters.INFTY[0];
this.byId("detailPage").addStyleClass("myInboxPage");
this.getModel().metadataLoaded().then(function () {
var sObjectPath = this.getModel().createKey("/DataSet", {
Pernr: sPernr,
Datum: sDatum,
Infty: sInfty
});
this._bindView(sObjectPath);
}.bind(this));
}
},
[ABAP] ALV column header
DATA: o_salv TYPE REF TO cl_salv_table.
cl_salv_table=>factory( IMPORTING r_salv_table = o_salv
CHANGING t_table = l_lines ).
LOOP AT o_salv->get_columns( )->get( ) REFERENCE INTO DATA(l_column).
DATA(lo_column) = CAST cl_salv_column( l_column->r_column ).
lo_column->set_fixed_header_text( 'L' ).
ENDLOOP.
o_salv->get_columns( )->get_column( 'TEST1' )->set_long_text( 'Test1 Header' ).
o_salv->get_columns( )->get_column( 'TEST2' )->set_long_text( 'Test2 Header' ).
[Fiori] Debug deployed Fiori App
When opening the Dev-Tools for a deployed Fiori App, it will look like this:
You won’t see any controller.js to debug.
What to do? Close the Debugger-Tools and hit CTRL+ALT+SHIFT+P to open the Technical Information Dialog
Check the Checkbox (or choose a specific controller) and reload the app.
It reloads with a new URL parameter and if you open the Dev-Tools, you will now see the controller.js.
Other options to debug or at least to collect some information about your app are the UI5 Diagnostics (hit CTRL+ALT+SHIFT+S) and the UI5 Inspector which is a Brower Addon.