When I saw this video I said "Hey !! That's my life ! my daily job !"
Fred
When I saw this video I said "Hey !! That's my life ! my daily job !"
Fred
This blog has been inspired by Bruno Esperança and his thought provoking The last runtime buffer you'll ever need? The thing is, I wrote such a thing a few years ago, that's widely used by one of my clients. There's a few areas it could be improved
interface zif_lookup
public .
constants c_dateto type fieldname value 'DATETO'. "#EC NOTEXT
methods lookup
exporting
es_data type any
eo_type type ref to cl_abap_structdescr
e_notfound_flag type char1
exceptions
sql_error .
methods set_key_val
importing
i_component type clike
i_value type any .
methods set_val_component
importing
i_component type clike .
methods get_ref2_lookup
returning
value(rp_data) type ref to data
exceptions
sql_error .
methods set_tim_val
importing
i_component type clike optional
i_value type any .
methods set_keyval_range
importing
it_keytab type any table .
methods get_val_struc
returning
value(ro_valstruc) type ref to cl_abap_structdescr .
methods get_notfound_flag
returning
value(r_notfound_flag) type flag .
endinterface.
Well, the constructor is missing, so just showing you the interface doesn't really help! So, imagine a class with this attribute.
DATA: buffer TYPEREFTO zif_lookup.
Then we have a method in some class that reads materials from the MARC table, with i_matnr, i_werks, exporting e_bwtty and e_mmsta.
IF buffer IS NOT bound.
CREATEOBJECT buffer TYPE zcl_table_lookup EXPORTING
i_table_name = 'MARC'
i_whole_tab = abap_false.
" The data I want to get back
buffer->set_val_component( 'BWTTY' ).
buffer->set_val_component( 'MMSTA' ).
ENDIF.
" The key data
buffer->set_key_val( i_component = 'MATNR' i_value = i_matnr )
buffer->set_key_val( i_component = 'WERKS' i_value = i_werks ).
" Now look it up.
DATA: BEGIN OF looked_up,
bwtty TYPE bwtty_d,
mmsta TYPE mmsta,
END OF looked up.
buffer->lookup( IMPORTING es_data = looked_up ).
e_bwtty = looked_up-bwtty.
e_mmsta = looed_up-mmsta.
What the class ZCL_TABLE_LOOKUP does is take the supplied components through set_val_component and set_key_val, and constructs two hashed tables (using RTTS) with the key components (in this case, MATNR and WERKS) as key. The first contains data looked up, the second contains data looked up and not found.
After the first lookup, you can't change the component fields.
If the i_whole_tab parameter is set, then the whole table will be buffered, rather than doing line by line buffering.
I created a BW style look up, that uses the table look up above, and the same interface. It specialises into two further classes - one for looking up InfoObject master data, the other reading from a DSO.
Their constructors take an InfoObject name / DSO name, convert that to the underlying transparent tables, and instantiates a table lookup instance for this table. Oh - and for InfoObjects there's a flag on the constructor for whether the data is time dependent.
The component setting methods similarly take InfoObject names (instead of field names). The InfoObject names are then converted to field names, and passed to the table lookup instance.
I bet you want to know the details of the implementation. I will update this blog shortly with that information, but thought I'd give you something to whet your appetites. In any case, it's better this way than supplying the information as comments to Bruno's blog!
Hey SCN,
I was reading Bruno Esperança's post ( The last runtime buffer you'll ever need?) yesterday and it inspired me to think about the way I cache data in my own classes. I got to google-ing and found a nice blog about Caching with Decorator pattern and I thought I might give it a try in ABAP. I think the pattern works nicely for caching and as the author of Caching with Decorator pattern says:
I think this is a good way of applying caching, logging or any other things that you want to do before or after hitting your database. It leaves your existing system in place and does not pollute your pure data access code (repositories) with other concerns. In this case both classes have their own responsibilities, when it’s not in the cache the decorator class delegates the task to the repository and let it deal with the database. Do I hear Single Responsibility Principal -
So lets jump right in to it. I just used the normal SAP example - SBOOK. For our fictitious program we just need to be able to select a single entry from SBOOK and we happen to know all the key fields.
I started with an interface:
INTERFACE ZIF_SBOOK_DB
PUBLIC.
METHODS:
FIND_BY_KEY IMPORTING CARRID TYPE S_CARR_ID
CONNID TYPE S_CONN_ID
FLDATE TYPE S_DATE
BOOKID TYPE S_BOOK_ID
RETURNING VALUE(RS_SBOOK) TYPE SBOOK.
ENDINTERFACE.
Then I created the basic implementation - selecting from the database directly:
CLASS ZCL_SBOOK_DB_IMPL DEFINITION
PUBLIC
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES: ZIF_SBOOK_DB.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS ZCL_SBOOK_DB_IMPL IMPLEMENTATION.
METHOD ZIF_SBOOK_DB~FIND_BY_KEY.
SELECT SINGLE *
INTO RS_SBOOK
FROM SBOOK
WHERE CARRID = CARRID
AND CONNID = CONNID
AND FLDATE = FLDATE
AND BOOKID = BOOKID.
ENDMETHOD.
ENDCLASS.
Now we could just stop there... We have a perfectly good database layer and it meets the requirements of whatever fictitious program we are creating. Lets assume we have some performance problems, or maybe we just noticed in ST05 that the same query is being executed multiple times. This is where the decorator pattern comes in to play:
CLASS ZCL_SBOOK_DB_CACHE_DECORATOR DEFINITION
PUBLIC
FINAL
CREATE PUBLIC
INHERITING FROM ZCL_SBOOK_DB_IMPL.
PUBLIC SECTION.
METHODS: ZIF_SBOOK_DB~FIND_BY_KEY REDEFINITION.
PROTECTED SECTION.
PRIVATE SECTION.
DATA: _CACHE TYPE HASHED TABLE OF SBOOK WITH UNIQUE KEY CARRID CONNID FLDATE BOOKID.
ENDCLASS.
CLASS ZCL_SBOOK_DB_CACHE_DECORATOR IMPLEMENTATION.
METHOD ZIF_SBOOK_DB~FIND_BY_KEY.
READ TABLE _CACHE INTO RS_SBOOK WITH KEY CARRID= CARRID CONNID = CONNID FLDATE = FLDATE BOOKID = BOOKID.
IF SY-SUBRC NE 0.
RS_SBOOK= SUPER->ZIF_SBOOK_DB~FIND_BY_KEY( CARRID = CARRID CONNID = CONNID FLDATE = FLDATE BOOKID = BOOKID ).
INSERT RS_SBOOK INTO TABLE _CACHE.
ENDIF.
ENDMETHOD.
ENDCLASS.
I think this is pretty easy to understand. We have defined a class that inherits from our basic implementation. It checks a private attribute (the cache) to see if it already has the item you need. If it doesn't have it, then it delegates to the super class - our basic implementation - and queries the database then puts the result in to the cache.
I see a couple of advantages in using the decorator pattern in this way to implement caching:
Finally, I decided I better test the performance. I was pretty confident that the cache would be faster, but I guess you never know:
REPORT Z_TEST_SBOOK_DB_LAYER.
DATA: T1 TYPE I,
T2 TYPE I,
TDIFF TYPE I.
DATA: LV_CARRID TYPE S_CARRID VALUE 'AA',
LV_CONNID TYPE S_CONN_ID VALUE '17',
LV_FLDATE TYPE S_DATE VALUE '20121031',
LV_BOOKID TYPE S_BOOK_ID VALUE '23'.
DATA: LO_SBOOK_CACHE TYPE REF TO ZIF_SBOOK_DB.
CREATE OBJECT LO_SBOOK_CACHE TYPE ZCL_SBOOK_DB_CACHE_DECORATOR.
WRITE: /'First read from the cache decorator will be from the database.'.
SET RUN TIME CLOCK RESOLUTION HIGH.
GET RUN TIME FIELD T1.
LO_SBOOK_CACHE->FIND_BY_KEY( CARRID = LV_CARRID
CONNID= LV_CONNID
FLDATE= LV_FLDATE
BOOKID= LV_BOOKID ).
GET RUN TIME FIELD T2.
TDIFF= ( T2 - T1 ).
WRITE: /'It took ', TDIFF, ' microseconds to read from the database.'.
WRITE: /'Second read from the cache decorator will be from the cache.'.
GET RUN TIME FIELD T1.
LO_SBOOK_CACHE->FIND_BY_KEY( CARRID = LV_CARRID
CONNID= LV_CONNID
FLDATE= LV_FLDATE
BOOKID= LV_BOOKID ).
GET RUN TIME FIELD T2.
TDIFF= ( T2 - T1 ).
WRITE: /'It took ', TDIFF, ' microseconds to read from the cache.'.
And here are the results.
So as you can see, it's a bit of an improvement I hope you find this useful in your own development!
Sometimes we need to search for the use of RFCs but Where-Used is only available if function modules exist in the caller system and/or client.
One solution is using ABAP source scan technique with available reports for your SAP platform and/or version. Depending of your search criteria this can take long processing time and spend system resources.
To be possible to use Where-Used I build this tool using existent repository information system functions to find nonexistent remote function modules calls. Try it, is very fast and support direct object code navigation.
How to implement:
If you are not able to activate the program because of nonexistent standard objects please downgrade for earlier SAP versions. If you need help on it, please kept me informed.
Copy past the code bellow or download the attached file:
REPORT znm_find_rfc MESSAGE-ID 00.
*----------------------------------------------------------------------*
* Created by NM to Search RFCs calls
*----------------------------------------------------------------------*
* Text Symbols
* A01 Description
* A02 Desc.
* A03 Sub Object
* B01 RFC Selection
* C04 Rotine
* M01 Not found
* M02 Error displaying result
*
* Selection Texts
* P_RFC Function
*
*----------------------------------------------------------------------*
* GLOBAL DATA
*----------------------------------------------------------------------*
TYPE-POOLS abap. "Only for old versions
*----------------------------------------------------------- Variables *
DATA gt_founds TYPE TABLE OF rsfindlst. "#EC NEEDED
*----------------------------------------------------------------------*
* CLASS gcl_handle_events DEFINITION
*----------------------------------------------------------------------*
CLASS gcl_handle_events DEFINITION FINAL.
PUBLIC SECTION.
METHODS on_double_click FOR EVENT double_click OF cl_salv_events_table
IMPORTING row column. "#EC NEEDED
ENDCLASS. "lcl_handle_events DEFINITION
*----------------------------------------------------------------------*
* SELECTION SCREEN
*----------------------------------------------------------------------*
*------------------------------------------------- RFC Function Module *
SELECTION-SCREEN BEGIN OF BLOCK b01 WITH FRAME TITLE text-b01.
SELECTION-SCREEN SKIP 1.
PARAMETERS p_rfc TYPE rs38l_fnam OBLIGATORY. "Name of Function Module
SELECTION-SCREEN SKIP 1.
SELECTION-SCREEN END OF BLOCK b01.
*----------------------------------------------------------------------*
* REPORT EVENTS
*----------------------------------------------------------------------*
START-OF-SELECTION.
PERFORM search_rfc.
END-OF-SELECTION.
PERFORM display_results.
*----------------------------------------------------------------------*
* CLASS lcl_handle_events IMPLEMENTATION
*----------------------------------------------------------------------*
CLASS gcl_handle_events IMPLEMENTATION.
*---------- Row dbclick ----------*
METHOD on_double_click.
DATA:
ls_founds LIKE LINE OF gt_founds, "Found object
lt_report TYPE TABLE OF string, "Report source code
lt_results TYPE match_result_tab, "Match results
ls_results TYPE match_result.
*---------- Get selected line ----------*
READ TABLE gt_founds INTO ls_founds INDEX row.
IF sy-subrc IS INITIAL.
*---------- Find position ----------*
READ REPORT ls_founds-object INTO lt_report.
FIND p_rfc IN TABLE lt_report RESULTS lt_results.
READ TABLE lt_results INTO ls_results INDEX 1.
*---------- Display objects ----------*
CALL FUNCTION 'RS_TOOL_ACCESS' "#EC FB_RC
EXPORTING
operation = 'SHOW'
object_name = ls_founds-object
object_type = 'PROG'
position = ls_results-line
EXCEPTIONS
not_executed = 1
invalid_object_type = 2
OTHERS = 3.
ENDIF.
ENDMETHOD. "on_double_click
ENDCLASS. "lcl_handle_events IMPLEMENTATION
*----------------------------------------------------------------------*
* FORMS
*----------------------------------------------------------------------*
*&---------------------------------------------------------------------*
*& Form SEARCH_RFC
*&---------------------------------------------------------------------*
FORM search_rfc .
CONSTANTS lc_obj_type TYPE seu_obj VALUE 'FF'.
DATA:
lt_findstring TYPE TABLE OF rsfind,
ls_findstring LIKE LINE OF lt_findstring.
ls_findstring-object = p_rfc.
APPEND ls_findstring TO lt_findstring.
REFRESH gt_founds.
CALL FUNCTION 'RS_EU_CROSSREF' "#EC FB_RC
EXPORTING
i_find_obj_cls = lc_obj_type
no_dialog = abap_true
TABLES
i_findstrings = lt_findstring
o_founds = gt_founds
EXCEPTIONS
not_executed = 1
not_found = 2
illegal_object = 3
no_cross_for_this_object = 4
batch = 5
batchjob_error = 6
wrong_type = 7
object_not_exist = 8
OTHERS = 9.
IF gt_founds IS INITIAL.
MESSAGE s398 WITH text-m01 space space space DISPLAY LIKE 'W'. "Not found
ENDIF.
ENDFORM. " SEARCH_RFC
*&---------------------------------------------------------------------*
*& Form DISPLAY_RESULTS
*&---------------------------------------------------------------------*
FORM display_results .
DATA:
lo_results TYPE REF TO cl_salv_table, "ALV
lr_functions TYPE REF TO cl_salv_functions_list, "ALV Functions
lr_events TYPE REF TO cl_salv_events_table, "ALV Events
lr_display TYPE REF TO cl_salv_display_settings, "ALV Output Appearance
lr_columns TYPE REF TO cl_salv_columns_table, "ALV Columns
lr_column TYPE REF TO cl_salv_column_table,
lr_selections TYPE REF TO cl_salv_selections, "ALV Selections
lo_event_handler TYPE REF TO gcl_handle_events. "ALV Events Handler
DATA:
lt_column_ref TYPE salv_t_column_ref, "Columns of ALV List
ls_column_ref TYPE salv_s_column_ref.
IF gt_founds IS NOT INITIAL.
TRY.
*---------- Create ALV ----------*
cl_salv_table=>factory( IMPORTING r_salv_table = lo_results CHANGING t_table = gt_founds ).
*---------- Set ALV selections ----------*
lr_selections = lo_results->get_selections( ).
lr_selections->set_selection_mode( if_salv_c_selection_mode=>single ).
*---------- Set ALV Display and Title ----------*
lr_display = lo_results->get_display_settings( ).
lr_display->set_striped_pattern( if_salv_c_bool_sap=>true ).
*---------- Set Functions ----------*
lr_functions = lo_results->get_functions( ).
lr_functions->set_export_localfile( ).
lr_functions->set_filter( ).
lr_functions->set_print( ).
lr_functions->set_sort_asc( ).
lr_functions->set_sort_desc( ).
lr_functions->set_find( ).
lr_functions->set_detail( ).
*---------- Set ALV Columns ----------*
lr_columns = lo_results->get_columns( ).
lr_columns->set_key_fixation( ).
lr_columns->set_optimize( ).
lt_column_ref = lr_columns->get( ).
lr_columns->set_column_position( columnname = 'ENCL_OBJEC' position = 1 ).
lr_columns->set_column_position( columnname = 'TEXTLINE' position = 4 ).
LOOP AT lt_column_ref INTO ls_column_ref. "Default format for all columns
lr_column ?= lr_columns->get_column( ls_column_ref-columnname ).
lr_column->set_f4( if_salv_c_bool_sap=>false ).
lr_column->set_alignment( if_salv_c_alignment=>left ).
lr_column->set_visible( if_salv_c_bool_sap=>false ).
lr_column->set_technical( if_salv_c_bool_sap=>true ).
IF ls_column_ref-columnname = 'ENCL_OBJEC' OR ls_column_ref-columnname = 'OBJECT' OR
ls_column_ref-columnname = 'PROGRAM'.
CASE ls_column_ref-columnname.
WHEN 'OBJECT'. "Sub Object
lr_column->set_long_text( text-a03 ).
lr_column->set_medium_text( text-a03 ).
lr_column->set_short_text( text-a03 ).
WHEN 'PROGRAM'. "Rotine
lr_column->set_long_text( text-c04 ).
lr_column->set_medium_text( text-c04 ).
lr_column->set_short_text( text-c04 ).
ENDCASE.
lr_column->set_key( if_salv_c_bool_sap=>true ).
lr_column->set_visible( if_salv_c_bool_sap=>true ).
lr_column->set_technical( if_salv_c_bool_sap=>false ).
ENDIF.
IF ls_column_ref-columnname = 'OBJECT_CLS'.
lr_column->set_key( if_salv_c_bool_sap=>true ).
lr_column->set_visible( if_salv_c_bool_sap=>true ).
lr_column->set_alignment( if_salv_c_alignment=>centered ).
lr_column->set_technical( if_salv_c_bool_sap=>false ).
ENDIF.
IF ls_column_ref-columnname = 'TEXTLINE'. "Description
lr_column->set_long_text( text-a01 ).
lr_column->set_medium_text( text-a01 ).
lr_column->set_short_text( text-a02 ).
lr_column->set_visible( if_salv_c_bool_sap=>true ).
lr_column->set_alignment( if_salv_c_alignment=>left ).
lr_column->set_technical( if_salv_c_bool_sap=>false ).
ENDIF.
ENDLOOP.
*---------- Register ALV Events ----------*
lr_events = lo_results->get_event( ).
CREATE OBJECT lo_event_handler.
SET HANDLER lo_event_handler->on_double_click FOR lr_events.
*---------- Display Objects ALV ----------*
lo_results->display( ).
CATCH cx_root. "#EC CATCH_ALL
MESSAGE s398 WITH text-m02 space space space DISPLAY LIKE 'E'. "Error displaying result
ENDTRY.
ENDIF.
ENDFORM. " DISPLAY_RESULTS
Selection screen layout after implementation:
Result ALV layout:
How to use:
ZNM_FIND_RFC is an IT tool to be used only for nonexistent remote function modules. Please use standard Where-Used functionality for all others situations.
Nuno Morais
WebWork 2014
I am sharing few not often used tips of IDOCs in this article. Generally i have seen people trying to achieve many things programmatically by coding in the user exits etc. While we have some SAP standard ways of achieving them like idoc Views,encryption,acknowledgements etc which can easily be achieved by configuration.
Suppressing unwanted segments-The standard Idoc types are assigned to various message types and applications. An idoc may contain various segments which are not required in some scenarios. Also, sometimes some unwanted data is sent to other applications. We may manually suppress the unwanted segments inside some user exit of the processing function module through ABAP code. But there can be some consequences of using this technique and this may not be a reliable method. Instead of this approach, Standard SAP provides reduced message type and Idoc View techniques to achieve the same solution.
Specify the view name in the partner profile while doing the configuration.
Basic Level data encryption in IDOCs- Anidoc can contain some sensitive information like credit card details of customer, phone numbers, pricing information etc. If we want this data to be encrypted for display purpose only. We can encrypt some data in the Idocs for display purpose only, like the customer care representative can see the last 5 characters of the credit card number or phone number (Phone XXXXX-53108).The transaction display authorization to some particular users can be managed by standard idoc authorization objects but if we don't want some particular fields in segments to be displayed to the users. We can use transaction WECRYPTDISPLAY.
This transaction is just a maintenance view of table EDCRYPTDISPLAY. We can maintain particular segments of an idoc in this transaction. Once data is maintained, In all the display transactions like WE02, WE05,WE07, WE09,WE10 etc. This sensitive data will be displayed as '*'.
We can also change the masked character by creating a custom function module. This method has limitations that the data is actually not encrypted in the database. Anyone can check the correct values in the database table if they have the access.
Change IDOC Data/Control parameters programmatically- The failed Idoc can be reprocessed from the transaction BD87. Like, if an idoc fails due to master data issue, we can correct the master data and then reprocess the idoc. But there is a limitation - we cannot change the idoc data for reprocessing. If our idoc has wrong data, we cannot reprocess it as it will fail once again.
*** try at your own risk***
So for few idoc status, we can programmatically change the contents of an IDOC, to change the data of an IDOC follow the below steps.
If we want to add the idoc to the inbound queue directly after editing. While calling the FM EDI_DOCUMENT_CLOSE_EDIT we can set 'status_75' flag as X. The Idoc status will change to 75 and the IDoc will be added to the queue.
We can also use EDI_CHANGE_CONTROL_SEGMENT to change the control data.
Idoc Acknowledgement for ALE and EDI scenarios
Idoc acknowledgement is an idoc by receiver just to inform the sender about the state of the outbound Idoc. The acknowledgment Idoc changes the status of the outbound idoc of the sender to a particular status depending upon negative or a positive acknowledgement. There are several Idoc status which can tell the state of the outbound idoc in the receiver system.
SAP has provided different idocs for ALE and EDI Scenarios.
The acknowledgement idoc changes the status of the outbound idoc. The below Idoc status can be changed by the outbound IDoc.
IDoc Status | Description |
---|---|
14 | Interchange Acknowledgement positive |
15 | Interchange acknowledgement negative |
16 | Functional acknowledgement |
17 | Functional acknowledgement negative |
40 | Application document not created in target system |
41 | Application document created in receiving system |
A few weeks back I was debugging some issue with the status management of an order in SAP CRM. That was the first time that I noticed, that the general status management functionality is part of the core functionality of SAP Netweaver. As I like to use SAP standard whenever possible I was wondering whether it is possible to use the standard status management in custom development.
Status management in custom developments is a requirement I encountered regularly in the past. Most of the time I implemented a basic status management myself on the basis of some custom domain with numerical status values. This basic status management notable lagged most of the features the standard status management provides, like e.g.
Searching SDN I could only find little information regarding the standard status management. While there is a wiki page in the CRM area of the SDN wiki (Status Management - CRM - SCN Wiki) and a few threads on the topic (e.g. Integrating a Z Business Object with SAP Standard general status mangement?
with some very helpful comment by Rüdiger Plantiko) I couldn't find any complete example or tutorial on the topic. Therefore, I decided to create one myself. I this blog I'll provide a complete example consisting of creating a custom status object, customizing the status schema and finally using it in a simple example program.
For the purpose of this blog I create a simple database table ZCD_D_STATUS_OBJ as an example business object. This table only contains the three field MANDT, OBJECT_ID and OBJECT_TEXT.
The first thing that is needed to create a new status object for this table is a new object type including the necessary control parameters. The control parameters basically specify in which database table the custom object is stored and which are the key fields identifying an entry. For this example I create an new object type "Z1" with the value "ZCD_D_STATUS_OBJ" for the fields "Table" and "Ref.Struc." and "OBJECT_ID" for the field "Key Field":
Next a new object type needs to be created using transaction BS12. For this example I created the object type ZT1. No further customizing is needed here for this example.
With this basic setup in place, it is now possible to customize the status schema for our new status object. Customizing the status schema is done via transaction BS12. I created a test status schema ZCDT0001 for this example. The status schema consists only of the following three status:
CREA is set as the initial status value. The lowest and highest status numbers are set up in such a way that it is always only possible to go to a higher status, e.g. from PROC to FINI.
Now all the customizing is in place to use the custom status object.
The function modules necessary to use the standard status management are locate in the function group BSVA in the package BSV. The following simple test program shows how to use these function modules to create and update the custom status object. The test program consists of the following parts:
REPORT zcd_test_status_object. TYPES: BEGIN OF object_key, object_id TYPE char10, END OF object_key. DATA: status_test_obj TYPE zcd_d_status_obj, object_key TYPE object_key, status_obj_nr TYPE j_objnr, object_type TYPE j_obtyp, status_schema TYPE j_stsma, status_number TYPE j_stonr, status_table TYPE ttjstat, s TYPE string. FIELD-SYMBOLS: <status> TYPE jstat. """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" "Initialize the object key with an unique value """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" CALL FUNCTION 'NUMBER_GET_NEXT' EXPORTING nr_range_nr = '01' object = 'BU_PARTNER' IMPORTING number = status_test_obj-object_id. status_test_obj-object_text = 'Test Status Obj ' && status_test_obj-object_id. INSERT zcd_d_status_obj FROM status_test_obj. object_key-object_id = status_test_obj-object_id. """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" "Creation of the status object """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" CALL FUNCTION 'OBJECT_NUMBER_GET_GENERIC' EXPORTING i_obart = 'Z1' i_objectkey = object_key IMPORTING e_objnr = status_obj_nr EXCEPTIONS number_already_exists = 1 obart_invalid = 2 objectkey_missing = 3 OTHERS = 4. IF sy-subrc <> 0. MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4. ENDIF. CALL FUNCTION 'STATUS_OBJECT_CREATE' EXPORTING objnr = status_obj_nr obtyp = 'ZT1' stsma = 'ZCDT0001' EXCEPTIONS obtyp_invalid = 1 status_object_already_exists = 2 stsma_invalid = 3 stsma_obtyp_invalid = 4 OTHERS = 5. IF sy-subrc <> 0. MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4. ENDIF. COMMIT WORK AND WAIT. """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" "Read the initial status values and print it """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" CALL FUNCTION 'STATUS_READ' EXPORTING objnr = status_obj_nr IMPORTING obtyp = object_type stsma = status_schema stonr = status_number TABLES status = status_table EXCEPTIONS object_not_found = 1 OTHERS = 2. IF sy-subrc <> 0. MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4. ENDIF. WRITE / 'Initial status values'. s = |Object Type: | && object_type && | - Status Schema: | && status_schema && | - Status Number: | && status_number. WRITE / s. WRITE / 'Status Table:'. LOOP AT status_table ASSIGNING <status>. s = |Status: | && <status>-stat && | - Inactive: | && <status>-inact. WRITE / s. ENDLOOP. ULINE. """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" "Set some external and internal status values and print it """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" CALL FUNCTION 'STATUS_CHANGE_EXTERN' EXPORTING objnr = status_obj_nr user_status = 'E0003' EXCEPTIONS object_not_found = 1 status_inconsistent = 2 status_not_allowed = 3 OTHERS = 4. IF sy-subrc <> 0. MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4. ENDIF. CLEAR status_table. APPEND INITIAL LINE TO status_table ASSIGNING <status>.<status>-stat = 'I0098'. CALL FUNCTION 'STATUS_CHANGE_INTERN' EXPORTING objnr = status_obj_nr TABLES status = status_table EXCEPTIONS object_not_found = 1 status_inconsistent = 2 status_not_allowed = 3 OTHERS = 4. IF sy-subrc <> 0. MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4. ENDIF. CLEAR status_table. CALL FUNCTION 'STATUS_READ' EXPORTING objnr = status_obj_nr " Objektnummer IMPORTING obtyp = object_type " Objekttyp stsma = status_schema " Statusschema stonr = status_number " Statusordnungsnummer TABLES status = status_table " Tabelle der Einzelstatus zum Objekt EXCEPTIONS object_not_found = 1 OTHERS = 2. IF sy-subrc <> 0. MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4. ENDIF. WRITE / 'New Status values'. s = |Object Type: | && object_type && | - Status Schema: | && status_schema && | - Status Number: | && status_number. WRITE / s. WRITE / 'Status Table:'. LOOP AT status_table ASSIGNING <status>. s = |Status: | && <status>-stat && | - Inactive: | && <status>-inact. WRITE / s. ENDLOOP. ULINE.
Running this program produces the following result:
After the status object has initially been created the user status E0001 is automatically set for the status object. This is the status that was defined in the status schema ZCDT0001. After setting the internal status I0098 and the user status E0003, the status E0001 is set to inactive.
I hope this blog provides an useful introduction for anyone trying to use the standard status management in a custom development.
Christian
Here, for updating long text at line item level, we have 2 approaches.
1st Approach without using Implicit Enhancement
2nd Approach using Implicit Enhancement
What is Implicit Enhancement?
The implicit enhancement is a new technology to enhance SAP’s standard objects such as includes, function modules, forms,global classes and all source code units.
The enhancement option makes it possible to add your own functionality to standard SAP objects without changing the original object. The additional functionality you added to the system by enhancement does not create any problems while the system upgrades and can be available without making any adjustment.
Enhancement options are positions where we can add our code, SAP has provides with these positions where we can put our code as per the requirement, we can add an implementation element without modifying the original code of SAP.
Enhancement implantation elements are stored in the package with own transport objects thus avoiding any conflict in modification in later stages.
Explicit and Implicit Enhancement Options
Implicit Enhancement options are for free, provided by the framework, while the explicit ones need to be inserted explicitly, as the name indicates.
Sometimes you have requirements to set a default value for a standard field, or you have to add an extra column in the standard SAP List Viewer (ALV). Or you might have to include a custom include in standard code. All such requirements can be fulfilled by using implicit enhancements. Without using implicit enhancements, you have to modify the standard code, which can cause problems when upgrading your system.
Updating Long text using implicit enhancements
In bapi ‘BAPI_ACC_DOCUMENT_POST’, there is table called EXTENSION1.This table can be used to pass fields to edit the accounting document before it is transferred to the accounting components for the update.
Pass item number and its long text to EXTENSION1 table with fields
Extension1-field1 = ‘LONG_TEXT’
Extension1-field2 = long text
Extension1-field3 = Item no.
Declare global internal table by creating implicit enhancement in Global Data of BAPI_ACC_DOCUMENT _POST.
Write Implicit Enhancement in form call_customer_function, to get line item number and its long text in
one global internal table from EXTENSION1 table.
Write Implicit Enhancement in
FORM document_post
USING r_compo LIKE bapiache09-compo_acc.
To update Long Text at line item level.
Here we will get Document number generated for posting in field gs_aw-awkey+0(10).
In Function Module write a code to update Long Text
FUNCTION zde_fm_update_long_text.
*"----------------------------------------------------------------------
*"*"Local Interface:
*" IMPORTING
*" VALUE(IM_ITEM) TYPE CHAR3
*" VALUE(IM_LONG_TEXT) TYPE ZDE_DE_LONG_TEXT
*" VALUE(IM_BUKRS) TYPE BUKRS
*" VALUE(IM_BELNR) TYPE BELNR_D
*" VALUE(IM_GJAHR) TYPE GJAHR
*" EXPORTING
*" REFERENCE(EX_RETURN) TYPE BAPIRET2
*"----------------------------------------------------------------------
"Type Declartions
TYPES: BEGIN OF lt_type_temp,
line(132) TYPE c,
END OF lt_type_temp.
"Data Declarations
DATA : lt_temp TYPE STANDARD TABLE OF lt_type_temp,
lt_flines TYPE STANDARD TABLE OF tline,
l_fname TYPE thead-tdname,
l_length TYPE i,
ls_flines TYPE tline,
ls_temp TYPE lt_type_temp,
l_long_text(500) TYPE c.
"Constants
CONSTANTS : c_fid TYPE thead-tdid VALUE '0001',
c_fobject TYPE thead-tdobject VALUE 'DOC_ITEM'.
CONCATENATE im_bukrs
im_belnr
im_gjahr
im_item INTO l_fname.
l_length = strlen( im_long_text ).
l_long_text = im_long_text.
IF l_length > 132.
CALL FUNCTION 'SPLIT_LINE'
EXPORTING
text = l_long_text
len = l_length
maxlen = '132'
TABLES
result_tab = lt_temp.
IF lt_temp[] IS NOT INITIAL.
LOOP AT lt_temp INTO ls_temp.
ls_flines-tdformat = '*'.
ls_flines-tdline = ls_temp-line.
APPEND ls_flines TO lt_flines.
CLEAR ls_flines.
ENDLOOP.
ENDIF.
ELSE.
ls_flines-tdformat = '*'.
ls_flines-tdline = im_long_text.
APPEND ls_flines TO lt_flines.
CLEAR ls_flines.
ENDIF.
*long Text udated line item level
CALL FUNCTION 'CREATE_TEXT'
EXPORTING
fid = c_fid
flanguage = sy-langu
fname = l_fname
fobject = c_fobject
save_direct = 'X'
TABLES
flines = lt_flines
EXCEPTIONS
no_init = 1
no_save = 2
OTHERS = 3.
IF sy-subrc = 0.
CLEAR: l_fname, lt_flines[].
ELSE.
IF sy-subrc <> 0.
"Message Long Text Not Updated for Doc No &1
MESSAGE e054(zde_mc_message) INTO g_msg1 WITH im_belnr.
CALL FUNCTION 'BALW_BAPIRETURN_GET2' "#EC FB_RC
EXPORTING
type = sy-msgty
cl = sy-msgid
number = sy-msgno
par1 = sy-msgv1
par2 = sy-msgv2
par3 = sy-msgv3
par4 = sy-msgv4
IMPORTING
return = ex_return.
ENDIF.
ENDIF.
ENDFUNCTION.
In my new blog I thought I bring a theme up, which hits everyone of us.
The passion being a developer. I want to share things about my passion why I want to be a good developer at all, how to reach it and moreover how to stay there.
I mean, it is more than just having a job, going to work and earn money to live my life. For me, my work is a passion, ok sometimes there might be moments I do not got that much passion to it, but you know, all in all I’m really one of these persons, which got the luck to have a job they love.
But enough of those none catchable reasons back to the main topic.
I’m thought quite a while about this blog here and how I want to transfer my message. I mean, should I do a counting? Oh yeah, I love counting points but in this special case I’m not sure, if this is a good method. I mean, there are more than one blog out there talking about good developing and I also shared one.
Also I wasn't sure about the space, but I think this one is the best and contains a lot of people who are interested in facts like that.
But is this the same, good developer = passionate developer?
I don't think so, I’m pretty sure a very young developer with (nearly) zero expertise could also be a very passionate developer. That means, it is not the way first to get a good developer and then to find the passion. In my opinion I would say it is exact the other way. Start your job as developer and recognize your passion to it and you will get a good developer for sure.
It’s not rocket science all the time
There is also a lot of stuff which doesn't have that much passion in it. You know, it is not all the time developing cool stuff. When I used to be student I developed most of the time very cool stuff, a CD-player, games, an app with different webservices and so on. I mean I did that for getting my school-projects and because I got a lot of fun with it. The messie parts weren't in the middle of the day.
Starting my career changed it a little. Being a developer isn't all the time doing rocket science. I mean, we also have to earn our money and that means there are also parts of just getting a job done. There will be always boring tasks to do, but your job becomes more interesting over time, because you will take more senior responsibilities day for day.
Yeah, it is that easy. Remember that thing if you got a bad day. But a very important thing is that it is also from time to time the rocket science thing. I mean you need to life your passion to not lost her (in my opinion passion is a girl, everybody should decide by it's own)
Lost the passion because of not having rocket science, what now?
Good developers might lose their passion for doing that mentioned above. I cannot understand those people, I mean as an developer we got a big advantage in our job. You know, we are part of the introducers which can show new ways of working. We are able to change thinking of people in a wise not that much people can do it. I’m not thinking about big new designs and stuff like that… not at all. I also think about the small features. You develop or enhance written source and improve it. Perhaps it is just one click not to do right now and if you got some knowledge of the industry you know what efforts are made by just saving a click
What I want to say with it:
You just have to change the perspective about the things you have to do. And if you are not happy with your things you have to do, let the team around know, that you want to get into something different. I mean, if you are not talking about things that drive you crazy you are not going to change these things.
I’m a developer, do I have to communicate?
Yes you have to. Perhaps this is the hardest part to understand, what this skill has to do with being a passionate developer. IT is not just 1 0 1 1 0 1. When I talk about my job a lot of times there is this picture drawn, that I’m a introvert guy, sitting in the basement, not having daylight and get my food delivered to not leave my chair
This perception has changed, we are considered now almost like rock-stars (ok, perhaps not that much, but you know what I want to say). Today apart from the technical skills you need to be an awesome communicator, negotiator and team player. Normal workplace contains a team and we are part of it, isn’t it?
I read in an interview, that passionate developers would do their job also for free, without getting paid, just because they love it.
I won’t go that far, moreover I would say, that the passionate doesn’t stop at the end of the day. I think it is worse to spend some of my leisure time to explore things I’m not able to do at my working hours. But also make sure you can relax and do not try to even get 24/7 into developing. That is also not helpful…
Do you know a lot?
Whenever you think that you are wrong. And that is exact the difference between the people just doing a job and having passion for it. I mean, developing and the technology is changing too fast, but if you are passionate in your job, it doesn’t matter. I like exact that thing, that there is every day something new to learn out there. Whenever I thought there is nothing to add I always was wrong and that is great. That means, there are that much content out there, that I can spend always time to discover something I didn’t know yet.
That’s all Folks!
Upps, I needed a lot more words than I want to use in the beginning. But there is so much to say about and I hope you enjoyed reading it.
If I’m wrong with something or if you think, you have to add something, feel free to leave me a comment.
Thank you for reading to the end.
Cheers
Florian
BTW: I know that this is extensive area with a lot of different opinions but in the end I think we all driving the same highway
All pictures are out of my collection I made through my surfing. So if one or more is limited for public, let me know and I will remove it immediately.
There's no real documentation on this BAPI or on BAPI_QUOTATION_CREATEFROMDATA2. Had a lot of trouble with it considering that there was no test data in the development box. As a result I thought I'd share this.
This sample uses Conditions and Characteristics, which turned out to be very difficult to find working information on. Unfortunately no clue on how the sub-items work as it wasn't part of my requirement.
A very useful transaction to analyze any errors with is CUTRC which I never knew about. Definitely going to start using it more.
Another interesting thing that I figured out is dynamically assigning table structures to FieldSymbols. I had heard that you couldn't pass a dynamically assigned field symbol (table) to a function but mine works perfectly.
*&---------------------------------------------------------------------*
*& Report ZUPL_QUOTATION
*&
*&---------------------------------------------------------------------*
*&
*&
*& Should've used the second BAPI. More info around on it.
*&---------------------------------------------------------------------*
REPORT zupl_quotation.
"Parameters for screen
SELECTION-SCREEN BEGIN OF BLOCK c1 WITH FRAME TITLE text-002.
* Sold-to-party, ship-to-party, Sales Organization, Distribution Channel, Division and a Sales office
PARAMETERS: p_sld_p TYPE vbak-kunnr,
p_shp_p TYPE vbpa-kunnr,
p_slorg TYPE vbak-vkorg,
p_distr TYPE vbak-vtweg,
p_div TYPE vbak-spart,
p_sloff TYPE vbak-vkbur,
p_dfrom TYPE datum,
p_dto TYPE datum.
SELECTION-SCREEN END OF BLOCK c1.
SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE text-001.
PARAMETERS: r_sect RADIOBUTTON GROUP rad1 DEFAULT 'X',
r_plat RADIOBUTTON GROUP rad1.
PARAMETERS: p_file TYPE ibipparms-path.
SELECTION-SCREEN END OF BLOCK b1.
AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_file.
CALL FUNCTION 'F4_FILENAME'
IMPORTING
file_name = p_file.
END-OF-SELECTION.
"Section table
TYPES: BEGIN OF t_datatab_s,
quan TYPE string,
vc TYPE string,
su TYPE string,
ch_cu_quality TYPE string,
ch_cu_size TYPE string,
ch_cu_component TYPE string,
ch_zz_length TYPE string,
ch_zz_scrap TYPE string,
ch_cu_prc_opt TYPE string,
ch_drawing_number TYPE string,
ch_mark_number TYPE string,
ch_zz_bundle_size TYPE string,
ch_cu_time TYPE string,
kbetr TYPE string,
kpein TYPE string,
kmein TYPE string,
END OF t_datatab_s.
"Plates table
TYPES: BEGIN OF t_datatab_p,
quan TYPE string,
vc TYPE string,
su TYPE string,
ch_ps_quality TYPE string,
ch_ps_size TYPE string,
ch_ps_component TYPE string,
ch_zz_length TYPE string,
ch_zz_width TYPE string,
ch_zz_scrap TYPE string,
ch_pl_prc_opt TYPE string,
ch_drawing_number TYPE string,
ch_mark_number TYPE string,
ch_zz_bundle_size TYPE string,
ch_mass_item_sn TYPE string,
ch_cu_time TYPE string,
kbetr TYPE string,
kpein TYPE string,
kmein TYPE string,
END OF t_datatab_p.
"Excel Variables
DATA: lt_filestable TYPE STANDARD TABLE OF t_datatab_s,
lt_fileptable TYPE STANDARD TABLE OF t_datatab_p,
ls_file_s LIKE LINE OF lt_filestable,
ls_file_p LIKE LINE OF lt_fileptable,
lv_file TYPE string,
lv_rc TYPE sy-subrc,
lv_path TYPE char255,
it_raw TYPE truxs_t_text_data.
"Quoatation Variables
DATA: order_header_in TYPE bapisdhead,
salesdocument TYPE bapivbeln-vbeln,
sold_to_party TYPE bapisoldto,
ship_to_party TYPE bapishipto,
billing_party TYPE bapipayer,
order_items_in TYPE STANDARD TABLE OF bapiitemin WITH HEADER LINE,
order_partners TYPE STANDARD TABLE OF bapipartnr WITH HEADER LINE,
order_items_out TYPE STANDARD TABLE OF bapiitemex WITH HEADER LINE,
order_cfgs_ref TYPE STANDARD TABLE OF bapicucfg WITH HEADER LINE,
order_cfgs_inst TYPE STANDARD TABLE OF bapicuins WITH HEADER LINE,
order_cfgs_part_of TYPE STANDARD TABLE OF bapicuprt WITH HEADER LINE,
order_cfgs_value TYPE STANDARD TABLE OF bapicuval WITH HEADER LINE,
lv_instid TYPE cu_inst_id,
lv_itemid TYPE posnr_va,
lv_configid TYPE cux_cfg_id.
DATA: BEGIN OF li_return OCCURS 1.
INCLUDE STRUCTURE bapiret1.
DATA: END OF li_return.
FIELD-SYMBOLS: <f_table> TYPE STANDARD TABLE,
<f_wa> TYPE any,
<field> TYPE any.
DATA: it_knvp TYPE TABLE OF knvp,
lv_parvw TYPE parvw.
TABLES: knvp.
lv_parvw = 'SP'.
CALL FUNCTION 'CONVERSION_EXIT_PARVW_INPUT'
EXPORTING
input = lv_parvw
IMPORTING
OUTPUT = lv_parvw.
SELECT * FROM knvp
WHERE kunnr = p_sld_p
AND kunn2 = p_shp_p
AND parvw = lv_parvw.
ENDSELECT.
IF sy-subrc = 4.
MESSAGE E000(ZATS_MSG) WITH 'The Ship-to-Party is not linked' 'to the selected Sold-to-Party'.
ENDIF.
"Radio buttons
IF r_sect = 'X'. "Sections File
ASSIGN lt_filestable TO <f_table>.
ASSIGN ls_file_s TO <f_wa>.
ELSE. "Plates File
ASSIGN lt_fileptable TO <f_table>.
ASSIGN ls_file_p TO <f_wa>.
ENDIF.
"Initialize values.
lv_itemid = '000010'.
lv_configid = '000001'.
lv_instid = '00000001'.
"Import data
CALL FUNCTION 'TEXT_CONVERT_XLS_TO_SAP'
EXPORTING
i_line_header = 'X'
i_tab_raw_data = it_raw
i_filename = p_file
TABLES
i_tab_converted_data = <f_table>
EXCEPTIONS
conversion_failed = 1
OTHERS = 2.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
"Mapping section from Excel file to Quoatation data.
order_header_in-doc_type = 'ZQT1'.
order_header_in-sales_org = p_slorg.
order_header_in-distr_chan = p_distr.
order_header_in-division = p_div.
* order_header_in-ref_1 = 'Your Reference Number'.
order_header_in-qt_valid_f = p_dfrom. "Quotation start date
order_header_in-qt_valid_t = p_dto. "Quotation end date
order_partners-partn_role = 'SP'.
order_partners-partn_numb = p_sld_p. "Sold to party
CALL FUNCTION 'CONVERSION_EXIT_PARVW_INPUT' "Required as the data is stored different on the database.
EXPORTING
input = order_partners-partn_role
IMPORTING
output = order_partners-partn_role.
APPEND order_partners.
order_partners-partn_role = 'SH'. "Ship to party
order_partners-partn_numb = p_shp_p.
CALL FUNCTION 'CONVERSION_EXIT_PARVW_INPUT' "Required as the data is stored different on the database.
EXPORTING
input = order_partners-partn_role
IMPORTING
output = order_partners-partn_role.
APPEND order_partners.
LOOP AT <f_table> INTO <f_wa>.
order_items_in-itm_number = lv_itemid. "Item Number
order_items_in-po_itm_no = lv_itemid. "Points to the Characteristics... Without it none are populated.
"Don't exist in this structure.
* ORDER_ITEMS_IN-CONFIG_ID = lv_configid.
* ORDER_ITEMS_IN-INST_ID = lv_instid.
ASSIGN COMPONENT 'VC' OF STRUCTURE <f_wa> TO <field>.
order_items_in-material = <field>. "Material Number
CALL FUNCTION 'CONVERSION_EXIT_ALPHA_INPUT'
EXPORTING
input = order_items_in-material
IMPORTING
output = order_items_in-material.
ASSIGN COMPONENT 'QUAN' OF STRUCTURE <f_wa> TO <field>.
order_items_in-req_qty = <field>. "Quantity
MULTIPLY order_items_in-req_qty BY 1000.
ASSIGN COMPONENT 'SU' OF STRUCTURE <f_wa> TO <field>.
order_items_in-target_qu = <field>. "Measurement
order_items_in-COND_TYPE = 'ZPRM'. "Should this be hardcoded to work?? Apparently so.
ASSIGN COMPONENT 'KBETR' OF STRUCTURE <f_wa> TO <field>.
order_items_in-cond_value = <field>. "Rate
DIVIDE order_items_in-cond_value BY 10.
ASSIGN COMPONENT 'KPEIN' OF STRUCTURE <f_wa> TO <field>.
order_items_in-cond_p_unt = <field>. "Condition Pricing Unit
ASSIGN COMPONENT 'KMEIN' OF STRUCTURE <f_wa> TO <field>.
order_items_in-cond_d_unt = <field>. "Condition Unit
APPEND order_items_in.
"Header texts section.
order_cfgs_value-config_id = lv_configid.
order_cfgs_value-inst_id = lv_instid.
order_cfgs_value-charc = 'CH_ZZ_LENGTH'.
ASSIGN COMPONENT 'CH_ZZ_LENGTH' OF STRUCTURE <f_wa> TO <field>.
order_cfgs_value-value = <field>.
APPEND order_cfgs_value.
order_cfgs_value-config_id = lv_configid.
order_cfgs_value-inst_id = lv_instid.
order_cfgs_value-charc = 'CH_ZZ_SCRAP'.
ASSIGN COMPONENT 'CH_ZZ_SCRAP' OF STRUCTURE <f_wa> TO <field>.
order_cfgs_value-value = <field>.
APPEND order_cfgs_value.
order_cfgs_value-config_id = lv_configid.
order_cfgs_value-inst_id = lv_instid.
order_cfgs_value-charc = 'CH_DRAWING_NUMBER'.
ASSIGN COMPONENT 'CH_DRAWING_NUMBER' OF STRUCTURE <f_wa> TO <field>.
order_cfgs_value-value = <field>.
APPEND order_cfgs_value.
order_cfgs_value-config_id = lv_configid.
order_cfgs_value-inst_id = lv_instid.
order_cfgs_value-charc = 'CH_MARK_NUMBER'.
ASSIGN COMPONENT 'CH_MARK_NUMBER' OF STRUCTURE <f_wa> TO <field>.
order_cfgs_value-value = <field>.
APPEND order_cfgs_value.
order_cfgs_value-config_id = lv_configid.
order_cfgs_value-inst_id = lv_instid.
order_cfgs_value-charc = 'CH_ZZ_BUNDLE_SIZE'.
ASSIGN COMPONENT 'CH_ZZ_BUNDLE_SIZE' OF STRUCTURE <f_wa> TO <field>.
order_cfgs_value-value = <field>.
APPEND order_cfgs_value.
order_cfgs_value-config_id = lv_configid.
order_cfgs_value-inst_id = lv_instid.
order_cfgs_value-charc = 'CH_CU_TIME'.
ASSIGN COMPONENT 'CH_CU_TIME' OF STRUCTURE <f_wa> TO <field>.
order_cfgs_value-value = <field>.
APPEND order_cfgs_value.
IF r_sect = 'X'. "Section File
order_cfgs_value-config_id = lv_configid.
order_cfgs_value-inst_id = lv_instid.
order_cfgs_value-charc = 'CH_CU_COMPONENT'.
ASSIGN COMPONENT 'CH_CU_COMPONENT' OF STRUCTURE <f_wa> TO <field>.
order_cfgs_value-value = <field>.
APPEND order_cfgs_value.
order_cfgs_value-config_id = lv_configid.
order_cfgs_value-inst_id = lv_instid.
order_cfgs_value-charc = 'CH_CU_PRC_OPT'.
ASSIGN COMPONENT 'CH_CU_PRC_OPT' OF STRUCTURE <f_wa> TO <field>.
order_cfgs_value-value = <field>.
APPEND order_cfgs_value.
order_cfgs_value-config_id = lv_configid.
order_cfgs_value-inst_id = lv_instid.
order_cfgs_value-charc = 'CH_CU_QUALITY'.
ASSIGN COMPONENT 'CH_CU_QUALITY' OF STRUCTURE <f_wa> TO <field>.
order_cfgs_value-value = <field>.
APPEND order_cfgs_value.
order_cfgs_value-config_id = lv_configid.
order_cfgs_value-inst_id = lv_instid.
order_cfgs_value-charc = 'CH_CU_SIZE'.
ASSIGN COMPONENT 'CH_CU_SIZE' OF STRUCTURE <f_wa> TO <field>.
order_cfgs_value-value = <field>.
APPEND order_cfgs_value.
ELSEIF r_plat = 'X'. "Plates File
order_cfgs_value-config_id = lv_configid.
order_cfgs_value-inst_id = lv_instid.
order_cfgs_value-charc = 'CH_PS_COMPONENT'.
ASSIGN COMPONENT 'CH_PS_COMPONENT' OF STRUCTURE <f_wa> TO <field>.
order_cfgs_value-value = <field>.
APPEND order_cfgs_value.
order_cfgs_value-config_id = lv_configid.
order_cfgs_value-inst_id = lv_instid.
order_cfgs_value-charc = 'CH_PL_PRC_OPT'.
ASSIGN COMPONENT 'CH_PL_PRC_OPT' OF STRUCTURE <f_wa> TO <field>.
order_cfgs_value-value = <field>.
APPEND order_cfgs_value.
order_cfgs_value-config_id = lv_configid.
order_cfgs_value-inst_id = lv_instid.
order_cfgs_value-charc = 'CH_PS_QUALITY'.
ASSIGN COMPONENT 'CH_PS_QUALITY' OF STRUCTURE <f_wa> TO <field>.
order_cfgs_value-value = <field>.
APPEND order_cfgs_value.
order_cfgs_value-config_id = lv_configid.
order_cfgs_value-inst_id = lv_instid.
order_cfgs_value-charc = 'CH_PS_SIZE'.
ASSIGN COMPONENT 'CH_PS_SIZE' OF STRUCTURE <f_wa> TO <field>.
order_cfgs_value-value = <field>.
APPEND order_cfgs_value.
order_cfgs_value-charc = 'CH_ZZ_WIDTH'.
ASSIGN COMPONENT 'CH_ZZ_WIDTH' OF STRUCTURE <f_wa> TO <field>.
order_cfgs_value-value = <field>.
APPEND order_cfgs_value.
order_cfgs_value-charc = 'CH_MASS_ITEM_SN'.
ASSIGN COMPONENT 'CH_MASS_ITEM_SN' OF STRUCTURE <f_wa> TO <field>.
order_cfgs_value-value = <field>.
APPEND order_cfgs_value.
ENDIF.
"End of texts (Characteristics)
"Need to fill in order_cfgs_ref & order_cfgs_inst and possibly order_cfgs_part_of too.
"Got the information from an example using BAPI_QUOTATION_GETDETAILBOS
order_cfgs_ref-posex = lv_itemid.
order_cfgs_ref-config_id = lv_configid.
order_cfgs_ref-root_id = lv_instid. "The type is inst_id.
APPEND order_cfgs_ref.
order_cfgs_inst-config_id = lv_configid.
order_cfgs_inst-inst_id = lv_instid.
order_cfgs_inst-obj_type = 'MARA'.
order_cfgs_inst-class_type = '300'.
order_cfgs_inst-obj_key = order_items_in-material.
order_cfgs_inst-quantity = order_items_in-target_qty.
APPEND order_cfgs_inst.
"Only for configurable sub-items..
* order_cfgs_part_of-config_id = lv_configid.
* order_cfgs_part_of-parent_id = lv_itemid.
* order_cfgs_part_of-inst_id = lv_instid.
* order_cfgs_part_of-class_type = '300'.
* order_cfgs_part_of-obj_type = 'MARA'.
* order_cfgs_part_of-obj_key = order_items_in-material.
* APPEND order_cfgs_part_of.
ADD 10 TO lv_itemid. "Items count in tens. Will be derived though if left open apparently.
ADD 1 TO lv_configid. "Appears to increase per line item.
CALL FUNCTION 'CONVERSION_EXIT_ALPHA_INPUT'
EXPORTING
input = lv_itemid
IMPORTING
output = lv_itemid.
CALL FUNCTION 'CONVERSION_EXIT_ALPHA_INPUT'
EXPORTING
input = lv_configid
IMPORTING
output = lv_configid.
* lv_instid = lv_instid + 1. "Apparently this stays 1 as per the GETDETAILBOS example.
ENDLOOP.
CALL FUNCTION 'BAPI_QUOTATION_CREATEFROMDATA'
EXPORTING
order_header_in = order_header_in
* without_commit = ' '
* convert_parvw_auart = ' '
IMPORTING
salesdocument = salesdocument
sold_to_party = sold_to_party
ship_to_party = ship_to_party
* billing_party =
return = li_return
TABLES
order_items_in = order_items_in
order_partners = order_partners
order_items_out = order_items_out
order_cfgs_ref = order_cfgs_ref
order_cfgs_inst = order_cfgs_inst
order_cfgs_part_of = order_cfgs_part_of
order_cfgs_value = order_cfgs_value.
IF NOT li_return IS INITIAL.
WRITE:/ li_return-type,
li_return-message.
ELSE.
WRITE:/ 'Quotation ', salesdocument, ' created successfully.'.
ENDIF.
In my new blog I thought I bring a theme up, which hits everyone of us.
The passion being a developer. I want to share things about my passion why I want to be a good developer at all, how to reach it and moreover how to stay there.
I mean, it is more than just having a job, going to work and earn money to live my life. For me, my work is a passion, ok sometimes there might be moments I do not got that much passion to it, but you know, all in all I’m really one of these persons, which got the luck to have a job they love.
But enough of those none catchable reasons back to the main topic.
I’m thought quite a while about this blog here and how I want to transfer my message. I mean, should I do a counting? Oh yeah, I love counting points but in this special case I’m not sure, if this is a good method. I mean, there are more than one blog out there talking about good developing and I also shared one.
Also I wasn't sure about the space, but I think this one is the best and contains a lot of people who are interested in facts like that.
But is this the same, good developer = passionate developer?
I don't think so, I’m pretty sure a very young developer with (nearly) zero expertise could also be a very passionate developer. That means, it is not the way first to get a good developer and then to find the passion. In my opinion I would say it is exact the other way. Start your job as developer and recognize your passion to it and you will get a good developer for sure.
It’s not rocket science all the time
There is also a lot of stuff which doesn't have that much passion in it. You know, it is not all the time developing cool stuff. When I used to be student I developed most of the time very cool stuff, a CD-player, games, an app with different webservices and so on. I mean I did that for getting my school-projects and because I got a lot of fun with it. The messie parts weren't in the middle of the day.
Starting my career changed it a little. Being a developer isn't all the time doing rocket science. I mean, we also have to earn our money and that means there are also parts of just getting a job done. There will be always boring tasks to do, but your job becomes more interesting over time, because you will take more senior responsibilities day for day.
Yeah, it is that easy. Remember that thing if you got a bad day. But a very important thing is that it is also from time to time the rocket science thing. I mean you need to life your passion to not lost her (in my opinion passion is a girl, everybody should decide by it's own)
Lost the passion because of not having rocket science, what now?
Good developers might lose their passion for doing that mentioned above. I cannot understand those people, I mean as an developer we got a big advantage in our job. You know, we are part of the introducers which can show new ways of working. We are able to change thinking of people in a wise not that much people can do it. I’m not thinking about big new designs and stuff like that… not at all. I also think about the small features. You develop or enhance written source and improve it. Perhaps it is just one click not to do right now and if you got some knowledge of the industry you know what efforts are made by just saving a click
What I want to say with it:
You just have to change the perspective about the things you have to do. And if you are not happy with your things you have to do, let the team around know, that you want to get into something different. I mean, if you are not talking about things that drive you crazy you are not going to change these things.
I’m a developer, do I have to communicate?
Yes you have to. Perhaps this is the hardest part to understand, what this skill has to do with being a passionate developer. IT is not just 1 0 1 1 0 1. When I talk about my job a lot of times there is this picture drawn, that I’m a introvert guy, sitting in the basement, not having daylight and get my food delivered to not leave my chair
This perception has changed, we are considered now almost like rock-stars (ok, perhaps not that much, but you know what I want to say). Today apart from the technical skills you need to be an awesome communicator, negotiator and team player. Normal workplace contains a team and we are part of it, isn’t it?
I read in an interview, that passionate developers would do their job also for free, without getting paid, just because they love it.
I won’t go that far, moreover I would say, that the passionate doesn’t stop at the end of the day. I think it is worse to spend some of my leisure time to explore things I’m not able to do at my working hours. But also make sure you can relax and do not try to even get 24/7 into developing. That is also not helpful…
Do you know a lot?
Whenever you think that you are wrong. And that is exact the difference between the people just doing a job and having passion for it. I mean, developing and the technology is changing too fast, but if you are passionate in your job, it doesn’t matter. I like exact that thing, that there is every day something new to learn out there. Whenever I thought there is nothing to add I always was wrong and that is great. That means, there are that much content out there, that I can spend always time to discover something I didn’t know yet.
That’s all Folks!
Upps, I needed a lot more words than I want to use in the beginning. But there is so much to say about and I hope you enjoyed reading it.
If I’m wrong with something or if you think, you have to add something, feel free to leave me a comment.
Thank you for reading to the end.
Cheers
Florian
BTW: I know that this is extensive area with a lot of different opinions but in the end I think we all driving the same highway
All pictures are out of my collection I made through my surfing. So if one or more is limited for public, let me know and I will remove it immediately.
One of the features that I like to do to make my applications more user friendly and I dare to say that users of my applications think the same to large extent… is the quick navigation between my custom development and the SAP standard transactions. Of course SAP standard tools cannot navigate to my custom development (changing SAP standard code is not an option for me), but that does not prevent me from making the work flow, data flow and business process flow fluent and very user friendly from my side.
Most of the custom development pieces that I can see around me are anyway reports and UI / functionality aggregating cockpits. These two types of custom development are even more powerful when you can double-click everything you see and you’re taken to the SAP standard maintenance transaction for master data etc.
Because of all these reasons plus the fact that I am just one little mortal and SAP is huge and the SAP functionality is the same for everyone, it makes perfect sense to collect the information about how to make jumps to the most used transactions and share that with everyone for the benefit of everyone. I plan to start small with the navigation possibilities that I can find in my recent notes and improve this text over time if you, dear readers, can share your code for navigation with me.
My proposal is not a rocket science – a decent developer can find a suitable function or copy the CALL TRANSACTION (with some parameters typically) in 20 seconds (not always, read further about the “Challenge” section). What I want to do here is to create a list that will spare the developers those five minutes and will encourage the use of stable interfaces at the same time. Last but not least I want to empower the business user and application consultants that don’t know how easy or difficult it is to implement these super-user-friendly on-clicks in ABAP with something they can mail to their developers and ask them to add that to their programs in a minute.
I have never been a good wiki gardener and the “openness” of the wikis for everyone does not appeal to me either, so please add comments or direct_message me if you have navigation possibilities that you want to share with the team. If you have other ideas or remarks, feel free to share whatever you have, I welcome that.
An example what is especially welcome could be notes on security -> which navigation possibilities check the authorizations of the user and which perform the jump technically without protecting the jump (many of the examples below set some parameters and then start a transaction, that is a low brainer, but we will find some tricky cases as well). Another example could be that there is a function module that one should use for the navigation instead of some code snippets copied from SCN. Stable interfaces are always the best option if such interfaces exist.
Let’s also maintain a “Challenge” section. If you need to navigate to a certain transaction / screen / tool and you find it tricky and can’t find a way yourself, post it as a comment. I will then add it to the “Challenge” section and we will see if we have enough nut crackers (aka “nuts”) to find out how to do it for you. As the examples I am maintaining below to start the work rolling are not particularly difficult, I can imagine the “Challenge” section will be more fun than using SE93 with WHERE-USED list.
Consider one of these function modules: CK50_COSTCENTER_DISPLAY or CP_08_COSTCENTER_SHOW. There are plenty of others. SE93 -> KS03 will offer you some more options if needed. Does anyone know a simple and stable (BAPI-like) function?
Note: I couldn’t find a nice simple interface function module to do this.
CALL FUNCTION 'K_KOKRS_SET'
EXPORTING
i_kokrs = iv_kokrs
popup = '0'.
SET PARAMETER ID 'PRC' FIELD iv_prctr.
CALL TRANSACTION 'KE53' AND SKIP FIRST SCREEN. “or KE52 if you wish so
Consider function module FI_DOCUMENT_DISPLAY_RFC.
Consider function module BAPI_CUSTOMER_DISPLAY.
Consider function module BAPI_VENDOR_DISPLAY.
Consider function module BAPI_MATERIAL_DISPLAY.
Consider function module K_ORDER_DISPLAY.
Consider function module ME_DISPLAY_PURCHASE_DOCUMENT.
Consider function module MMPUR_REQUISITION_DISPLAY.
No challenges yet. You’re welcome to challenge us…
Hi friends,
The following is the blog that will explains the relationship between data refereneces and field symbols with hands on examples.
Readers will definitely get different view and indepth understanding on feild symbols and data references.
Field Symbols
We all know the standard definition given by SAP about Field symbols as, “Field symbols are placeholders or symbolic names for other fields.
They do not physically reserve space for a field, but points to its contents. A field symbol can point to any data object. The data object to which a field
symbol points is assigned to it after it has been declared in the program”
Let us put the above Definition in more detailed way with
easiest examples as follows
Variable means!
It will have its own address
Work area means!
It will have its own address
Internal table means!
It will have its own address
Field symbol means!
It will not have its own address
But it will point the address of the data object or it
will point to the content of the data object to which it has been assigned.
So performance wise field symbols are powerful when we doing modify and append because the data update is not happening from the external memory,
instead of that it is updating from the same memory. This is how the field symbols are faster when compared to work area.
Note: Field symbols cannot be used without assigning a data object to them. That means either a variable or Structure or internal table
has to be assigned to field symbol before using it. If we remember this thumb rule it will be very easy to work with field symbols
1. Field symbol for a data variable
When we execute this program, the output of no1 is
2. Field symbol for a structure:-
When we execute the above program, it shows the MATNR, MTART as follows
3. Field symbol for an internal table
Suppose I have an internal table as follows
IT_MARA
Matnr Matkl
1000 001 ----------(R1 Address of the record1 in internal table memory)
2000 002 ---------(R2 Address of the record2 in internal table memory)
Suppose we do have a field symbol declared as follows.
Field-symbols: <FS_MARA> TYPE MARA.
When we loop the above internal table by assigning to field
symbol as follows, What happens?
Loop at IT_MARA Assigning <FS_MARA>.
WRITE: / <FS_MARA>-MATNR, <FS_MARA>-MTART.
ENDLOOP.
The memory location of each record is assigned to field symbol, that means when we work with the field symbol like changing any fields
or populating with some values nothing but we are working with the memory location of that particular record in the internal table. It is working like
“Pass by reference” in our subroutines. When we changed something in the field symbol, that means we are directly changing the internal table record.
Whereas when we have work area explicitly, the internal table record is different, and the work area we are using is different, so the
change we did in the work area has to be get modified explicitly in the internal table with the help of keyword ‘MODIFY’ unlike how field symbols
modify directly.
Example to use field symbol with internal table:-
When we execute the above program, the output is
Possible Syntaxes of field symbols:-
Read table <itab> assigning <fs>…
Loop at <itab> assigning <fs>…
Assign <data object> to <fs>
Assign component <component name/component index> to <fs>
Append initial line to <itab> assigning <fs>
DATA REFERENCES
Before understanding Data References, I have a question to you!
Q) What is an object / Class reference? What happens when we create a reference variable to a class?
Ans:- An object is an instance of the class. When we
create instance to the class, memory will be assigned to the components of the
class along with certain values.
Q) What is data reference then?
Ans: - The instance of the data is called ‘Data
reference’. In simple words, memory or data will be created to the data objects
to which we want to create in the runtime.
When we go for data references?
Whenever, we don’t know clearly what data object we want to create specifically then we go for creation of data references. The data object
may be data variable, structure and internal table.
Types of Data References:-
Known Data References: When we know clearly what data type we
need to create in run time, then we go for Known data references.
Un Known Data References: When we don’t know what data type
that we need to create in run time, then we go for Un Known Data References.
Note:- It we know data type, then it doesn’t make sense to
create data reference. But before understanding Unknown data references, it is
must to understand Know creation of Data reference for known data types.
Syntax of Data reference:-
Both the above syntaxes are same. We can go
for any syntax. I will prefer the first syntax in all the coming examples.
Before going to the examples of Known data
references and Unknown data references, let us discuss one small example which
is common to both Known and Unknown data References as follows.
DATA lr_data TYPE REF TO data.
CREATE DATA lr_data TYPE i.
What is ‘DATA’ in the above statement. ‘Data’ also a
predefined data type in ABAP like i, char10 etc but it is of Not Fully data
type which is a generic data type.
Let’s understand the above two program lines in debugging
mode.
Keep the break point in the program and understand what is
what happening with lr_Data variable.
Double click on lr_Data.
If we see the pointed area, the LR_DATA initially not
referring anything.
Now let us take F5, F5 and see the same LR_DATA.
Now if we see the LR_DATA, it is initialized to the initial
value of integer i.
That means through the statement CREATE DATA lr_Data TYPE I,
we are able to initialize the value of LR_DATA to ‘0’ from ‘INITIAL’.
Here LR_DATA is called as “Reference Variable”, not the
normal variable.
Now double click on ‘LR_DATA’ to understand more about
“Reference variable”.
Here LR_DATA, is a Reference variable
Point 1:- We cannot see the value/content of the Reference variable directly with a
double click like normal variable
To see the content/value of the Reference variable, one way is to double click on the Hook symbol.
It will show the value of the reference variable LR_DATA as
follows
Another way is, in debugging mode itself after double
clicking on LR_DATA, put ->* next to the LR_DATA as follows and hit enter,
it will show the value in that variable
By putting ->* next to a reference variable we can see the value of that
variable but we cannot assign any value into that variable
Point 2:- We need to know the meaning of two symbols ->, * .
-> Means Pointing the address
So as per our discussion, now let us try to assign value into the reference variable in the program as follows and see what happens and
why?
What is De REFERENCE means?
Referencing means -> Addressing certain data object by
assigning some memory to it.
De referencing means accessing the address (or) assigning
the value into the content of the reference.
-> This is referencing
->* This is de referencing (or accessing the value at that address)
Here in our example de referencing of variable (or any object) is not possible through by simply adding the symbol ->* next to that
reference variable.
Then, how it is possible to assign the value into the reference variable?
Through Field-symbols only we can access the reference variables.
As field symbols are only things given by SAP, that can point the content of the address of the data
object. (Means field symbols will point to the contend of the data object, explained in the starting of this blog)
Golden Rule to Remember:-
So it is always a thumb rule to remember, to deal with accessing the address or assigning certain value into particular address, it is require to assign that
address to field symbol of that type of data object. If you don’t know the data object of what data reference we are accessing then that field symbols has to
be declared with generic data types which will be discussed later in the same blog.
DATA REFERENCES:-
Known Type
Un Known Type
Let us discuss the examples of Known Type Data references with Hands on examples as follows
Known Data References ( data variable creation )
Now execute the program, we will able to see that we created
an integer type variable and stored a value 10 into that through Known data
reference and a field symbol
2. Known data references(structure creation)
Now execute the program and see the values of the structure
we created through the data references
3. Known data reference(internal table creation)
Now execute the program and see, we could able to create an
internal table through data references and shown as follows. We can write
select query also as well.
Let us discuss the examples for Unknown data references.
Note:- When we working with un known data references, we definitely do not know what data object we are going to create like, we are not
sure whether we are creating an integer or character, we are not sure whether we are creating the data of MARA or VBAK, we are not sure whether we are
creating an internal table of MARA or VBAK. But it is important to know, whether we are going to create a ‘Data variable’ or ‘Structure’ or ‘Internal table’.
Here we need to know few Generic data types given by SAP. The generic data types are also the data types like ‘DDIC’ and ‘ABAP Program
data types’, but which are used when we don’t know the type of the data till run time.
Examples of generic data types:-
Type any (Used for both unknown variable creation, unknown structure creation)
Type any table(Used for creation of unknown table creation)
Type ref to data
Type object
Etc Etc
Note:- Generic data types can only be used with field symbols.
1. Un known data reference(creation of data
variable)
2. Un known data references(creation of structure)
Now let us execute, and give your desired structure
name, our data reference creates a record from that structure and shows as
follows
Enter VBAP and execute, it gives as follows
3. Unknown data references(creation of table):-
*Parameter for user input
PARAMETERS: p_var type string.
data: lr_Data type ref to data.
create data lr_Data type table of (p_var).
"As we dont know what type of structure we have to create, let us declare field symbol dynamically as follows
FIELD-SYMBOLS: <ft_table> type ANY TABLE. "key word any table is used for declaration of unknown field symbol
ASSIGN lr_Data->* to <ft_table>.
if sy-subrc is initial.
select * from (p_var) into table <ft_table> UP TO 5 ROWS.
if sy-subrc = 0.
data: r_Data type REF TO cl_salv_table.
* TRY.
CALL METHOD cl_salv_table=>factory
* EXPORTING
* list_display = IF_SALV_C_BOOL_SAP=>FALSE
* r_container =
* container_name =
IMPORTING
r_salv_table = r_Data
CHANGING
t_table = <ft_table>
.
* CATCH cx_salv_msg .
* ENDTRY.
endif.
r_Data->display( ).
endif.
Now exectute the program and give Any table name that you wish, it will show the records from that table in ALV Report.
This is the brief explanation of Data references with field symbols
The idea behind this blog post is to promote the use of the Badi CTS_REQUEST_CHECK. Managing transports is a vital component of a successful project and often to facilitate this or to allow for traceability of changes back to tickets or projects, naming conventions for transport are mandated. However, in the absence of any systems checks these conventions are often more honoured in the breach than the keeping.
This is where Badi CTS_REQUEST_CHECK comes in extremely useful as it allows for the addition of custom code around the process of creation and release of transports. For example, if we have a naming convention that states that a transport should start with a valid module name, followed by an incident ticket number then we could create a function module that checks that an input string adheres to this convention and would raise an error otherwise. Then we would implement method CHECK_BEFORE_CREATION for badi CTS_REQUEST_CHECK and call this function module from this method displaying an error message if the text was found non compliant.
METHOD if_ex_cts_request_check~check_before_creation.
CALL FUNCTION 'ZABAP_TRANSPORT_TEXT'
EXPORTING
iv_text = text
EXCEPTIONS
naming_convention = 1
OTHERS = 2.
IF sy-subrc <> 0.
MESSAGE e001(ZABAP).
RAISE cancel.
ENDIF.
ENDMETHOD.
This method is called as the name suggests when a new transport is created. Of course, there are other methods of this Badi that allow for other functionality to be developed. For example by using the method CHECK_BEFORE_RELEASE (called when we try to release the transport) we can create a sign off procedure whereby more senior developers would have to sign off for all changes as a form of quality control. For example:
METHOD if_ex_cts_request_check~check_before_release.
DATA: lv_bname TYPE xuser,
lv_password TYPE xubcode,
ls_signoff TYPE zabap_signoff.
CALL FUNCTION 'ZABAP_TRANSPORT_TEXT'
EXPORTING
iv_text = text
EXCEPTIONS
naming_convention = 1
OTHERS = 2.
IF sy-subrc <> 0.
MESSAGE e001(zabap).
RAISE cancel.
ENDIF.
IF type = 'K'.
IF NOT sy-uname = 'F25850A' AND
NOT sy-uname = 'OC1603' AND
NOT sy-uname = 'OC384'.
CALL FUNCTION 'ZPOPUP_GET_USER_PASSWORD'
EXPORTING
iv_user = 'F25850A'
IMPORTING
user = lv_bname
password = lv_password
EXCEPTIONS
cancel_pressed = 1
OTHERS = 2.
IF sy-subrc <> 0 OR lv_password IS INITIAL.
CALL FUNCTION 'ZPOPUP_GET_USER_PASSWORD'
EXPORTING
iv_user = 'OC1603'
IMPORTING
user = lv_bname
password = lv_password
EXCEPTIONS
cancel_pressed = 1
OTHERS = 2.
IF sy-subrc <> 0 OR lv_password IS INITIAL.
CALL FUNCTION 'ZPOPUP_GET_USER_PASSWORD'
EXPORTING
iv_user = 'OC384'
IMPORTING
user = lv_bname
password = lv_password
EXCEPTIONS
cancel_pressed = 1
OTHERS = 2.
IF sy-subrc <> 0 OR lv_password IS INITIAL.
MESSAGE e002(zabap).
RAISE cancel.
ENDIF.
ENDIF.
ENDIF.
CALL FUNCTION 'SUSR_LOGIN_CHECK_RFC'
EXPORTING
bname = lv_bname
password = lv_password
EXCEPTIONS
wait = 1
user_locked = 2
user_not_active = 3
password_expired = 4
wrong_password = 5
no_check_for_this_user = 6
password_attempts_limited = 7
internal_error = 8
OTHERS = 9.
IF sy-subrc <> 0.
MESSAGE e003(zabap).
RAISE cancel.
ENDIF.
ls_signoff-request = request.
ls_signoff-uname = lv_bname.
INSERT into zabap_signoff values ls_signoff.
ENDIF.
ENDIF.
ENDMETHOD.
This also gives us an opportunity to double check the naming convention because some automatically generated transports can slip through the net of the previous check in CHECK_BEFORE_CREATION. We then check is the user releasing is one of the three authorised users and if not we require that one of these users enters a password to sign off on the changes and finally we create a log of these changes in the table zabap_signoff.
Of course may other checks are possible. I was very interested by the idea of triggering the code inspector on release of a transport that I stumbled over while preparing this blog http://scn.sap.com/community/abap/testing-and-troubleshooting/blog/2013/09/19/how-to-trigger-atc-or-code-inspector-checks-during-the-release-of-a-transport-task. As I said at the beginning the goal of this blog is just to hopefully make more people aware of this Badi and the possibilities it presents to improve the management of our transports.
PROJECT LINKS:
For a long time only OLE/DOI-approach was available for creating spreadsheets. As you know, OLE/DOI-approach is quite flexible, but some restrictions. For example, it requires installed MS Excel application (this makes impossible to use background job for generate spreadsheet). Moreover, OLE-approach has low performance (this problem may be partly solved by using VBA, but this requires manually changing of security settings MS-Excel application on each front-end computer).
Since, ZIP-folder processing tools became available in the SAP environment, we are able to generate spreadsheets with new Open XML Format (XLSX). This approach does not have lacks of OLE.
But, in my opinion, the flaw of all existing solutions for generate spreadsheets from ABAP- is many lines of ABAP code required directly for creating and formatting spreadsheet layout. This fact is the cause of that, the same tasks are quite differently implemented by different developers, which complicates further support these developments. My idea is to create a tool (to design spreadsheets) which has graphical user interface, for example such as SMARTFORMS; and resultant spreadsheet would have XLSX format.
WHAT DOES DEVELOPMENT PROCESS LOOK LIKE ?
The development via XLSX Workbench comprises three components:
HOW TO GET RESULTANT XLSX-FILE ?
You run the print program, which prepare a source data (and fill the context) and pass it to F.M.'ZXLWB_CALLFORM'. The F.M. generates the resultant XLSX-file using the form's structure and context data. Everything is processed on the application server, but the result at the developer's decision:
Updating Variant Configuration data for SO item became little tricky for us in an ongoing implementation. After spending some hours investigating the correct combination of data to pass, we were able to post the document correctly. As no detailed documentation is available online for this scenario, I hope this post will help community for similar requirements.
For updating Variant configuration (VC) data for Sales order item, we need to populate below tables of standard FM or BAPI (e.g. SD_SALESDOCUMENT_CREATE).
Normally the standard FM or BAPI does not return any error messages in case configuration data is not updated successfully.
· SALES_SCHEDULES_IN: The required date field should be populated with appropriate value (REQ_DATE).
· SALES_ITEMS_IN: Field PO_ITM_NO should be populated with appropriate value.
· SALES_CFGS_REF Table:
1. This table should have 1 record per item.
2. Combination of CONFIG_ID and ROOT_ID should be unique across line items.
POSEX | 000010 |
CONFIG_ID | 000001 |
ROOT_ID | 00000001 |
SCE | 1 |
COMPLETE | T |
CONSISTENT | T |
CBASE_ID_TYPE | G |
· SALES_CFGS_INST:
1. This table should have 1 record per item.
2. Combination of CONFIG_ID and INST_ID should be unique across line items.
CONFIG_ID | 000001 |
INST_ID | 00000001 |
OBJ_TYPE | MARA |
CLASS_TYPE | 300 |
OBJ_KEY | MATNR value |
QUANTITY | Quantity value |
QUANTITY_UNIT | Quantity Unit |
COMPLETE | T |
CONSISTENT | T |
OBJECT_GUID | MATNR value |
PERSIST_ID_TYPE | G |
· SALES_CFGS_VALUE:
1. Combination of CONFIG_ID and INST_ID should be unique across line items.
2. We can have multiple characteristics for a material. In that case appropriate records should be inserted in this table. Note that CONFIG_ID and INST_ID should be same for all the rows you insert in this table for multiple characteristics for a material.
3. The characteristic value should be in SAP internal format.
CONFIG_ID | 000001 |
INST_ID | 00000001 |
CHARC | Material characteristics |
VALUE | Material characteristics value |
· SALES_CFGS_VK:
1. Combination of CONFIG_ID and INST_ID should be unique across line items.
2. We can have multiple characteristics for a material. In that case appropriate records should be inserted in this table. Note that CONFIG_ID and INST_ID should be same for all the rows you insert in this table for multiple characteristics for a material.
CONFIG_ID | 000001 |
INST_ID | 00000001 |
VKEY | Material characteristics |
In my daily work I like to use Favorite to make my work more efficiently. My personal guideline to management favorite list:
In my opinion, I don't think the Favorite update functionality in SAP gui is convenient to use.
For example if I want to drag one tcode in the bottom area of the favorite tree and drop it to one upper folder,
I need to press the mouse and scroll up the favorite tree until the destination folder appears in the screen, and then drop the tcode to the folder. The scroll speed is quite low. Or I can delete the original tcode in the bottom, and scroll up to the upper folder, and re-add the tcode into that folder.
So I export the favorite list into a local text file and plan to edit that file locally.
Unfortunately the format of the text file is still not straightforward and difficult for manual change:
a. menu type: TR indicates that it is a transaction code, space means it is a folder
b. object ID: each record must have a unique ID. And the hierarchy relationship between a folder and its wrapped tcode are represented by the ID.
c. tcode technical name
d. tcode descripton, or folder name
2. It is necessary to manipulate the object ID on my own if I want to manually change the text file. Special attention must be paid if I need to move a given tcode from one folder to another folder. The corrupt file( wrong object ID ) would prevent you from seeing the favorite list at all. During my attempt, adter I uploaded the manually edited text file, I could not use the system any more since there is dump when SAPGUI tries to render the favorite list with corrupt file:
So I develop a simple tool which will upload a text file with a new format defined by myself. It only has two columns:
Column1: the first level of favorite list tree. It could be a folder, a tcode( wrapped with "[ ]" ), or a webdynpro application( wrapped with "( )" ).
Column2: the second level of favorite list tree. It must be either a tcode or a webdynpro application. No nested folder is allowed since as I said I do not need nested folder in my daily work at all. The hierarchy relationship between a folder and its wrapped tcode are represented by the Tab key.
After I run the tool to upload the text file, my Favorite list is rendered with exactly the same structure defined in text file.
Benefit of using this tool:
I just upload my favorite list which contains 290 entries for your reference.
1. If you would like to know where are these tcode from drop down list stored in your laptop, read this document.
2. Some more detail about SAP GUI settings storage could be found in this blog.
Hi ABAP fans!
Let me do a bit of promotion for ABAP on SAP HANA.
Here's our brand-new ABAP for SAP HANA End-to-End Development example, guiding you the way from HANA via ABAP to a SAP Fiori-like application. Within the guide, we're touching CDS Views as well as ABAP managed database procedures, two of the new features provided with AS ABAP 7.4 SP5, create SAP NetWeaver OData Services, and show the data in a (rather simple) Fiori-like application.
Interested?
Just try it out:Brand-new ABAP 7.4 for SAP HANA End to End Development Guide with Latest ABAP 7.4 SP5 Features
Meet you there,
Jasmin
How to implement:
Create customer function code TR :
If you are not able to activate the program because of nonexistent standard objects please downgrade for earlier SAP versions. If you need help on it, please kept me informed.
Copy past the code bellow or download the attached file:
REPORT znm_objs_dep_trans MESSAGE-ID 00.
*----------------------------------------------------------------------*
* Report ZZS_OBJ_DEP_TRANS - Object Dependencies and Transport by Nuno Morais
*----------------------------------------------------------------------*
* Text Symbols
* B01 Object selection
* B02 Aditional options
* C01 Remote
* C02 Obj. Desc.
* CM1 Cross-system objects version check
* M01 Object not found
* M02 Please fill all required fields
* M03 Critical error
* M04 No objects selected
* M05 Transport not allowed for multiple targets
* M06 Error creating transport request
* M07 Objects added to request (
* M08 Please select a remote system
* M09 RFCs destinations missing
* M10 Request canceled, at least one object $TEMP detected
* M11 Navigation not possible
* M12 Transport canceled
* M13 Object dependencies check not support
* M14 No dependecies found
* O01 Equal
* O02 Different
* O03 New
* O04 No version
* P01 Adding object
* P02 Checking Dependecies
* P03 Checking Remote
* P04 Display objects
* P05 Processing options
* PB1 % Complete
*
* Selection Texts
* P_ERFC Exclude RFCs if exist
* P_ICD Include Tables CDs
* P_ILO Include Tables Locks
* P_ITM Include Tables Maintenances
* P_OBJECT Object Type
* P_OBJ_N Object Name
* P_PGMID Program ID
* P_RFC Remote versions checks
* P_RFC_D System Name
*
* Standard Status GUI function codes: &ALL, &SAL, &OUP, &ODN, &ILT, %PC, &OL0, &OAD and &AVE
* Status GUI function code: TR Create transport
*
*----------------------------------------------------------------------*
* GLOBAL DATA
*----------------------------------------------------------------------*
TYPE-POOLS: abap, icon. "Only for old versions
*----------------------------------------------------------- Constants *
CONSTANTS:
gc_r3tr TYPE pgmid VALUE 'R3TR', "Main object
gc_tobj TYPE trobjtype VALUE 'TOBJ', "Table content in transport
gc_chdo TYPE trobjtype VALUE 'CHDO', "Change documents
gc_fugr TYPE trobjtype VALUE 'FUGR', "Function group
gc_tabl TYPE trobjtype VALUE 'TABL', "Table
gc_temp TYPE developclass VALUE '$TMP'. "Local development class
*---------------------------------------------------------- Structures *
TYPES:
BEGIN OF gty_objects,
status TYPE icon_d, "Check status
pgmid TYPE pgmid, "Program ID in Requests and Tasks
object TYPE trobjtype, "Object Type
obj_name TYPE sobj_name, "Object Name in Object Directory
obj_desc TYPE ddtext, "Object Explanatory short text
devclass TYPE developclass, "Development Package
target TYPE tr_target, "Transport Target of Request
remote TYPE char10, "Remote check status
END OF gty_objects.
SET EXTENDED CHECK OFF.
DATA:
gt_objects TYPE TABLE OF gty_objects, "Objects to transport
gt_objs_desc TYPE TABLE OF ko100, "Objects prograns IDs
gt_e071 TYPE TABLE OF e071,
gt_e071k TYPE TABLE OF e071k. "Change & Transport System: Object Entries of Requests/Tasks
*----------------------------------------------------------- Variables *
DATA gv_percent TYPE i. "Progress bar percentage
*------------------------------------------------------ Class Handler *
DATA go_objects TYPE REF TO cl_salv_table. "Objects ALV
SET EXTENDED CHECK ON.
*----------------------------------------------------------------------*
* CLASS gcl_handle_events DEFINITION
*----------------------------------------------------------------------*
CLASS lcl_handle_events DEFINITION FINAL.
PUBLIC SECTION.
METHODS:
on_user_command FOR EVENT added_function OF cl_salv_events
IMPORTING e_salv_function,
on_double_click FOR EVENT double_click OF cl_salv_events_table
IMPORTING row column. "#EC NEEDED
ENDCLASS. "lcl_handle_events DEFINITION
*----------------------------------------------------------------------*
* SELECTION SCREEN
*----------------------------------------------------------------------*
*---------------------------------------------------- Object selection *
SELECTION-SCREEN BEGIN OF BLOCK b01 WITH FRAME TITLE text-b01.
SELECTION-SCREEN SKIP 1.
SELECTION-SCREEN BEGIN OF LINE.
PARAMETERS:
p_pgmid TYPE pgmid DEFAULT gc_r3tr, "Program ID in Requests and Tasks
p_object TYPE trobjtype, "Object Type
p_obj_n TYPE sobj_name. "Object Name in Object Directory
SELECTION-SCREEN END OF LINE.
SELECTION-SCREEN SKIP 1.
SELECTION-SCREEN BEGIN OF LINE. "Remote versions checks
PARAMETERS: p_rfc AS CHECKBOX.
SELECTION-SCREEN COMMENT (37) com_rfc.
PARAMETERS: p_rfc_d TYPE tmssysnam.
SELECTION-SCREEN END OF LINE.
SELECTION-SCREEN END OF BLOCK b01.
*-------------------------------------------------- Aditional options *
SELECTION-SCREEN BEGIN OF BLOCK b02 WITH FRAME TITLE text-b02.
SELECTION-SCREEN SKIP 1.
PARAMETERS:
p_itm AS CHECKBOX, "Include Tables Maintenance
p_ilo AS CHECKBOX, "Include Lock objects
p_icd AS CHECKBOX, "Include Change documents
p_erfc AS CHECKBOX. "Exclude RFCs if exist
SELECTION-SCREEN END OF BLOCK b02.
*--------------------------------------*
* Selection Screen PAI Helps
*--------------------------------------*
*------------------------------------------------------- Program ID F4 *
AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_pgmid.
PERFORM pgmid_f4.
*------------------------------------------------------ Object Type F4 *
AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_object.
PERFORM object_f4.
*------------------------------------------------------ Object Name F4 *
AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_obj_n.
PERFORM object_name_f4.
*-------------------------------------------------- Systems and RFC F4 *
AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_rfc_d.
PERFORM rfc_f4.
*--------------------------------*
* Selection Screen PAI
*--------------------------------*
AT SELECTION-SCREEN.
PERFORM screen_pai.
*----------------------------------------------------------------------*
* REPORT EVENTS
*----------------------------------------------------------------------*
*---------------------------------*
* Initialization events
*---------------------------------*
INITIALIZATION.
PERFORM load_of_program.
*---------------------------------*
* Executing events
*---------------------------------*
START-OF-SELECTION.
PERFORM run_checks.
END-OF-SELECTION.
PERFORM display_objects.
*----------------------------------------------------------------------*
* CLASS lcl_handle_events IMPLEMENTATION *
*----------------------------------------------------------------------*
CLASS lcl_handle_events IMPLEMENTATION.
*-------------------------------------------------------- User command *
METHOD on_user_command.
CHECK e_salv_function = 'TR'. "Create transport request
DATA lr_selections TYPE REF TO cl_salv_selections. "ALV Selections
DATA:
lt_rows TYPE salv_t_row, "ALV Rows
ls_row TYPE i,
lt_e071_temp TYPE TABLE OF e071, "Change & Transport System: Object Entries of Requests/Tasks
ls_e071 LIKE LINE OF gt_e071,
lt_e071k_temp TYPE TABLE OF e071k,
lt_objects TYPE TABLE OF gty_objects, "Objects to transport
ls_object LIKE LINE OF gt_objects,
lt_targets TYPE TABLE OF tr_target, "Transport Target of Request
ls_target LIKE LINE OF lt_targets.
DATA:
lv_order TYPE trkorr, "Request/Task
lv_task TYPE trkorr.
*---------- Get selected lines ----------*
lr_selections = go_objects->get_selections( ).
lt_rows = lr_selections->get_selected_rows( ).
*---------- Get selected objects to transport ----------*
LOOP AT lt_rows INTO ls_row.
READ TABLE gt_objects INTO ls_object INDEX ls_row.
IF sy-subrc IS INITIAL AND ls_object-status = icon_led_green.
IF ls_object-devclass = gc_temp. "Request canceled, at least one object $TEMP detected
MESSAGE i001 WITH text-m10 space space space DISPLAY LIKE 'E'.
RETURN.
ENDIF.
APPEND ls_object TO lt_objects.
MOVE-CORRESPONDING ls_object TO ls_e071.
APPEND ls_e071 TO gt_e071.
IF ls_object-object = gc_tobj. "Add TABU object directly to the transport
PERFORM add_tobj_content USING ls_object-obj_name.
ENDIF.
ENDIF.
ENDLOOP.
*---------- Get possible target ----------*
LOOP AT lt_objects INTO ls_object.
ls_target = ls_object-target.
APPEND ls_target TO lt_targets.
ENDLOOP.
SORT lt_targets.
DELETE ADJACENT DUPLICATES FROM lt_targets.
*---------- Create transport request and task ----------*
IF lt_objects IS NOT INITIAL. "Objects selected to transport
IF lines( lt_targets ) = 1. "Only one valid target
CALL FUNCTION 'TRINT_ORDER_CHOICE' "Create transport request
EXPORTING
iv_tarsystem = ls_target
IMPORTING
we_order = lv_order
we_task = lv_task
TABLES
wt_e071 = lt_e071_temp
wt_e071k = lt_e071k_temp
EXCEPTIONS
no_correction_selected = 1
display_mode = 2
object_append_error = 3
recursive_call = 4
wrong_order_type = 5
OTHERS = 6.
IF sy-subrc IS INITIAL AND lv_task IS NOT INITIAL.
ls_e071-pgmid = gc_r3tr. "Add objects development class to transport
ls_e071-object = 'DEVC'.
ls_e071-obj_name = ls_object-devclass.
APPEND ls_e071 TO gt_e071.
CALL FUNCTION 'TRINT_APPEND_COMM' "Add object to transport request
EXPORTING
wi_exclusive = abap_false
wi_sel_e071 = abap_true
wi_sel_e071k = abap_true
wi_trkorr = lv_task
TABLES
wt_e071 = gt_e071
wt_e071k = gt_e071k
EXCEPTIONS
e071k_append_error = 1
e071_append_error = 2
trkorr_empty = 3
OTHERS = 4.
IF sy-subrc IS INITIAL. "Added with sucess
*---------- Sort and compress request --------*
CALL FUNCTION 'TR_SORT_AND_COMPRESS_COMM' "#EC FB_RC "#EC CI_SUBRC
EXPORTING
iv_trkorr = lv_task
EXCEPTIONS
trkorr_not_found = 1
order_released = 2
error_while_modifying_obj_list = 3
tr_enqueue_failed = 4
no_authorization = 5
OTHERS = 6.
MESSAGE i001 WITH text-m07 lv_order ')' space. "Objects added to request
ELSE. "Error creating transport request
MESSAGE s001 WITH text-m06 space space space DISPLAY LIKE 'E'.
ENDIF.
ELSE. "Transport canceled
MESSAGE s001 WITH text-m12 space space space DISPLAY LIKE 'W'.
ENDIF.
ELSE. "Transport not allowed for multiple targets
MESSAGE i001 WITH text-m05 space space space.
ENDIF.
ELSE. "No objects selected
MESSAGE i001 WITH text-m04 space space space.
ENDIF.
ENDMETHOD. "on_user_command
*-------------------------------------------------------- Line dbclick *
METHOD on_double_click.
DATA ls_object LIKE LINE OF gt_objects. "Objects to transport
READ TABLE gt_objects INTO ls_object INDEX row.
IF sy-subrc IS INITIAL.
*---------- Display objects ----------*
CASE ls_object-object.
WHEN gc_tobj. "Display Tables Maintenance
SET PARAMETER ID 'DVI' FIELD ls_object-obj_name.
CALL TRANSACTION 'SE54'. "#EC CI_CALLTA
WHEN gc_chdo. "Display change documents
CALL TRANSACTION 'SCDO'. "#EC CI_CALLTA
WHEN OTHERS. "Display all
CALL FUNCTION 'RS_TOOL_ACCESS'
EXPORTING
operation = 'SHOW'
object_name = ls_object-obj_name
object_type = ls_object-object
EXCEPTIONS
not_executed = 1
invalid_object_type = 2
OTHERS = 3.
IF sy-subrc IS NOT INITIAL. "Navigation not possible
MESSAGE s001 WITH text-m11 space space space DISPLAY LIKE 'W'.
ENDIF.
ENDCASE.
ENDIF.
ENDMETHOD. "on_double_click
ENDCLASS. "lcl_handle_events IMPLEMENTATION
*----------------------------------------------------------------------*
* FORMS
*----------------------------------------------------------------------*
*&---------------------------------------------------------------------*
*& Form LOAD_OF_PROGRAM
*&---------------------------------------------------------------------*
FORM load_of_program .
com_rfc = text-cm1. "Cross-system objects versions check
CALL FUNCTION 'TR_OBJECT_TABLE' "Fill Program IDs
TABLES
wt_object_text = gt_objs_desc.
ENDFORM. " LOAD_OF_PROGRAM
*----------------------------------------------------------------------*
* Form PGMID_F4 - Program ID F4
*----------------------------------------------------------------------*
FORM pgmid_f4 .
DATA lt_pgmids TYPE TABLE OF ko101. "Program IDs with Description
*---------- Read PGMID ----------*
CALL FUNCTION 'TR_PGMID_TABLE'
TABLES
wt_pgmid_text = lt_pgmids.
*---------- Set PGMID F4 ----------*
CALL FUNCTION 'F4IF_INT_TABLE_VALUE_REQUEST' "#EC FB_RC
EXPORTING
retfield = 'PGMID'
dynpprog = sy-cprog
value_org = 'S'
dynpnr = '1000'
dynprofield = 'TRE071X-PGMID'
TABLES
value_tab = lt_pgmids
EXCEPTIONS
parameter_error = 1
no_values_found = 2
OTHERS = 3.
ENDFORM. " PGMID_F4
*----------------------------------------------------------------------*
* Form OBJECT_F4 - Object Type F4
*----------------------------------------------------------------------*
FORM object_f4.
DATA:
lt_shlp TYPE shlp_descr, "Description of Search Help
lt_return_values TYPE TABLE OF ddshretval, "Interface Structure Search Help
ls_return_values LIKE LINE OF lt_return_values,
lv_rc TYPE sysubrc. "Return Value of ABAP Statements
FIELD-SYMBOLS <interface> TYPE ddshiface. "Interface description of a F4 help method
*---------- Get search help ----------*
CALL FUNCTION 'F4IF_GET_SHLP_DESCR'
EXPORTING
shlpname = 'SCTSOBJECT'
IMPORTING
shlp = lt_shlp.
*---------- Fill search help ----------*
LOOP AT lt_shlp-interface ASSIGNING <interface>.
IF <interface>-shlpfield = 'OBJECT'.
<interface>-valfield = abap_true.
<interface>-value = p_object.
ENDIF.
IF <interface>-shlpfield = 'PGMID'.
<interface>-valfield = abap_true.
<interface>-value = p_pgmid.
ENDIF.
ENDLOOP.
*---------- Call search help ----------*
CALL FUNCTION 'F4IF_START_VALUE_REQUEST'
EXPORTING
shlp = lt_shlp
IMPORTING
rc = lv_rc
TABLES
return_values = lt_return_values.
*---------- Set search help return ----------*
IF lv_rc IS INITIAL.
READ TABLE lt_return_values INTO ls_return_values WITH KEY fieldname = 'OBJECT'.
IF sy-subrc IS INITIAL.
p_object = ls_return_values-fieldval.
ENDIF.
READ TABLE lt_return_values INTO ls_return_values WITH KEY fieldname = 'PGMID'.
IF sy-subrc IS INITIAL.
p_pgmid = ls_return_values-fieldval.
ENDIF.
ENDIF.
ENDFORM. " OBJECT_F4
*----------------------------------------------------------------------*
* Form OBJECT_NAME_F4 - Object Name F4
*----------------------------------------------------------------------*
FORM object_name_f4.
DATA lv_object_type TYPE seu_obj. "Object type
*---------- Get objects repository information ----------*
lv_object_type = p_object.
CALL FUNCTION 'REPOSITORY_INFO_SYSTEM_F4' "#EC FB_RC
EXPORTING
object_type = lv_object_type
object_name = p_obj_n
IMPORTING
object_name_selected = p_obj_n
EXCEPTIONS
cancel = 1
wrong_type = 2
OTHERS = 3.
ENDFORM. " OBJECT_NAME_F4
*&---------------------------------------------------------------------*
*& Form RFC_F4
*&---------------------------------------------------------------------*
FORM rfc_f4 .
CALL FUNCTION 'TMS_UI_F4_SYSTEMS'
CHANGING
cv_system = p_rfc_d.
ENDFORM. " RFC_F4
*&---------------------------------------------------------------------*
*& Form SCREEN_PAI
*&---------------------------------------------------------------------*
FORM screen_pai .
DATA ls_env_dummy TYPE senvi.
IF sy-ucomm = 'ONLI'.
*---------- Check required data ----------*
IF p_pgmid IS INITIAL OR p_object IS INITIAL OR p_obj_n IS INITIAL OR
( p_rfc IS NOT INITIAL AND p_rfc_d IS INITIAL ).
MESSAGE e001 WITH text-m02 space space space DISPLAY LIKE 'W'. "Please fill all required fields
ENDIF.
IF p_rfc IS NOT INITIAL AND p_rfc_d = sy-sysid.
MESSAGE e001 WITH text-m08 space space space DISPLAY LIKE 'W'. "Please select a remote system
ENDIF.
*---------- Add first object ----------*
PERFORM progress_bar USING text-p01 '10'. "Adding object
PERFORM check_add_object USING p_pgmid p_object p_obj_n ls_env_dummy.
IF gt_objects IS INITIAL.
MESSAGE e001 WITH text-m01 space space space DISPLAY LIKE 'W'. "Object not found
ENDIF.
ENDIF.
ENDFORM. " SCREEN_PAI
*----------------------------------------------------------------------*
* Form PROGRESS_BAR
*----------------------------------------------------------------------*
FORM progress_bar USING i_value TYPE itex132
i_tabix TYPE i.
DATA:
lv_text(40),
lv_percentage TYPE p,
lv_percent_char(3).
lv_percentage = ( i_tabix / 100 ) * 100.
lv_percent_char = lv_percentage.
SHIFT lv_percent_char LEFT DELETING LEADING ' '.
CONCATENATE i_value '...' INTO i_value.
CONCATENATE i_value lv_percent_char text-pb1 INTO lv_text SEPARATED BY space.
IF lv_percentage GT gv_percent OR i_tabix = 1.
CALL FUNCTION 'SAPGUI_PROGRESS_INDICATOR'
EXPORTING
percentage = lv_percentage
text = lv_text.
gv_percent = lv_percentage.
ENDIF.
ENDFORM. " PROGRESS_BAR
*&---------------------------------------------------------------------*
*& Form RUN_CHECKS
*&---------------------------------------------------------------------*
FORM run_checks .
IF gt_objects IS NOT INITIAL.
*---------- Dependecies check ----------*
PERFORM progress_bar USING text-p02 '20'. "Checking Dependecies
PERFORM objects_dependencies_check.
PERFORM progress_bar USING text-p05 '50'. "Processing options
*---------- Include Tables Maintenance ----------*
IF p_itm IS NOT INITIAL.
PERFORM include_maintenances.
PERFORM objects_dependencies_check.
ENDIF.
*---------- Include Lock objects ----------*
IF p_ilo IS NOT INITIAL. PERFORM include_locks. ENDIF.
*---------- Include Change documents ----------*
IF p_icd IS NOT INITIAL. PERFORM include_cds. ENDIF.
*---------- Remote check ----------*
IF p_rfc IS NOT INITIAL.
PERFORM progress_bar USING text-p03 '80'. "Checking Remote
PERFORM remote_objects_check.
ENDIF.
ENDIF.
ENDFORM. " RUN_CHECKS
*----------------------------------------------------------------------*
* Form DISPLAY_OBJECTS
*----------------------------------------------------------------------*
FORM display_objects.
DATA:
lr_events TYPE REF TO cl_salv_events_table, "ALV Events
lr_display TYPE REF TO cl_salv_display_settings, "ALV Output Appearance
lr_columns TYPE REF TO cl_salv_columns_table, "ALV Columns
lr_column TYPE REF TO cl_salv_column_table,
lr_selections TYPE REF TO cl_salv_selections, "ALV Selections
lr_layout TYPE REF TO cl_salv_layout, "ALV Layout
lo_event_handler TYPE REF TO lcl_handle_events. "ALV Events Handler
DATA:
lt_column_ref TYPE salv_t_column_ref, "Columns of ALV List
ls_column_ref TYPE salv_s_column_ref,
ls_key TYPE salv_s_layout_key.
DATA:
lv_title TYPE lvc_title, "ALV title
lv_lines TYPE i, "Number of objects
lv_lines_c TYPE string.
IF gt_objects IS NOT INITIAL.
PERFORM progress_bar USING text-p04 '90'. "Display objects
IF go_objects IS NOT BOUND. "Create ALV
TRY.
IF lines( gt_objects ) = 1. "No dependecies found
MESSAGE s001 WITH text-m14 space space space DISPLAY LIKE 'W'.
ELSE.
SORT gt_objects BY pgmid object obj_name.
ENDIF.
*---------- Create ALV ----------*
cl_salv_table=>factory( IMPORTING r_salv_table = go_objects
CHANGING t_table = gt_objects ).
*---------- Set ALV Functions ----------*
go_objects->set_screen_status(
pfstatus = 'STATUS'
report = sy-cprog
set_functions = go_objects->c_functions_all ).
*---------- Set Layout ----------*
lr_layout = go_objects->get_layout( ).
ls_key-report = sy-repid.
lr_layout->set_key( ls_key ).
lr_layout->set_save_restriction( ).
*---------- Set ALV selections ----------*
lr_selections = go_objects->get_selections( ).
lr_selections->set_selection_mode( if_salv_c_selection_mode=>row_column ).
*---------- Set ALV Display and Title ----------*
lr_display = go_objects->get_display_settings( ).
lr_display->set_striped_pattern( if_salv_c_bool_sap=>true ).
lv_lines = lines( gt_objects ).
lv_lines_c = lv_lines.
CONDENSE lv_lines_c NO-GAPS.
CONCATENATE '(' lv_lines_c ')' INTO lv_lines_c.
CONCATENATE sy-title lv_lines_c INTO lv_title SEPARATED BY space.
lr_display->set_list_header( lv_title ).
*---------- Set ALV Columns ----------*
lr_columns = go_objects->get_columns( ).
lr_columns->set_key_fixation( ).
lr_columns->set_optimize( ).
lt_column_ref = lr_columns->get( ).
LOOP AT lt_column_ref INTO ls_column_ref. "Default format for all columns
lr_column ?= lr_columns->get_column( ls_column_ref-columnname ).
lr_column->set_f4( if_salv_c_bool_sap=>false ).
lr_column->set_alignment( if_salv_c_alignment=>centered ).
IF ls_column_ref-columnname = 'STATUS' OR
ls_column_ref-columnname = 'PGMID' OR
ls_column_ref-columnname = 'OBJECT' OR
ls_column_ref-columnname = 'OBJ_NAME'.
lr_column->set_key( if_salv_c_bool_sap=>true ).
ENDIF.
IF ls_column_ref-columnname = 'OBJ_NAME' OR
ls_column_ref-columnname = 'DEVCLASS'.
lr_column->set_alignment( if_salv_c_alignment=>left ).
ENDIF.
IF ls_column_ref-columnname = 'OBJ_DESC'.
lr_column->set_alignment( if_salv_c_alignment=>left ).
lr_column->set_short_text( text-c02 ).
lr_column->set_medium_text( text-c02 ).
lr_column->set_long_text( text-c02 ).
ENDIF.
IF ls_column_ref-columnname = 'REMOTE'.
IF p_rfc IS INITIAL.
lr_column->set_visible( if_salv_c_bool_sap=>false ).
ELSE.
lr_column->set_short_text( text-c01 ).
lr_column->set_medium_text( text-c01 ).
lr_column->set_long_text( text-c01 ).
ENDIF.
ENDIF.
ENDLOOP.
*---------- Register ALV Events ----------*
lr_events = go_objects->get_event( ).
CREATE OBJECT lo_event_handler.
SET HANDLER lo_event_handler->on_user_command FOR lr_events.
SET HANDLER lo_event_handler->on_double_click FOR lr_events.
*---------- Display Objects ALV ----------*
go_objects->display( ).
CATCH cx_root. "#EC CATCH_ALL
MESSAGE s001 WITH text-m03 space space space DISPLAY LIKE 'E'.
ENDTRY.
ELSE. "Refresh ALV
go_objects->refresh( ).
ENDIF.
ENDIF.
ENDFORM. " DISPLAY_OBJECTS
*----------------------------------------------------------------------*
* FORMS Adds
*----------------------------------------------------------------------*
*----------------------------------------------------------------------*
* Form CHECK_ADD_OBJECT
*----------------------------------------------------------------------*
FORM check_add_object USING value(i_pgmid) TYPE pgmid
i_object TYPE any
i_obj_n TYPE any
is_env_tab TYPE senvi.
DATA lo_wb_object TYPE REF TO cl_wb_object. "Repository Object
DATA:
ls_tadir TYPE tadir, "Directory of Repository Objects
ls_wb_object_type TYPE wbobjtype, "Global WB Type
ls_object LIKE LINE OF gt_objects. "Objects to transport line
DATA:
lv_tr_object TYPE trobjtype, "Object Type
lv_tr_obj_name TYPE trobj_name, "Object Name in Object List
lv_trans_pgmid TYPE pgmid. "Program ID in Requests and Tasks
*-------------------------------------------------- Object convertions *
IF i_pgmid <> gc_r3tr.
SELECT pgmid UP TO 1 ROWS FROM tadir "#EC CI_GENBUFF
INTO i_pgmid
WHERE object = i_object
AND obj_name = i_obj_n.
ENDSELECT.
*---------- Is not a TADIR object and Conversion required ----------*
IF sy-subrc IS NOT INITIAL.
lv_tr_object = i_object.
lv_tr_obj_name = i_obj_n.
cl_wb_object=>create_from_transport_key( EXPORTING p_object = lv_tr_object
p_obj_name = lv_tr_obj_name
RECEIVING p_wb_object = lo_wb_object
EXCEPTIONS objecttype_not_existing = 1
empty_object_key = 2
key_not_available = 3
OTHERS = 4 ).
IF sy-subrc IS INITIAL.
lo_wb_object->get_global_wb_key( IMPORTING p_object_type = ls_wb_object_type
EXCEPTIONS key_not_available = 1
OTHERS = 2 ).
IF sy-subrc IS INITIAL.
lo_wb_object->get_transport_key( IMPORTING p_pgmid = lv_trans_pgmid "#EC CI_SUBRC
EXCEPTIONS key_not_available = 1
OTHERS = 2 ).
*---------- Check Program ID ----------*
CASE lv_trans_pgmid.
WHEN gc_r3tr. "Main objects
i_pgmid = lv_trans_pgmid.
WHEN 'LIMU'. "Sub object
CALL FUNCTION 'GET_R3TR_OBJECT_FROM_LIMU_OBJ'
EXPORTING
p_limu_objtype = lv_tr_object
p_limu_objname = lv_tr_obj_name
IMPORTING
p_r3tr_objtype = lv_tr_object
p_r3tr_objname = lv_tr_obj_name
EXCEPTIONS
no_mapping = 1
OTHERS = 2.
IF sy-subrc IS INITIAL.
ls_object-pgmid = gc_r3tr.
ls_object-object = lv_tr_object.
ls_object-obj_name = lv_tr_obj_name.
PERFORM add_object USING ls_object.
RETURN.
ENDIF.
WHEN OTHERS. "Include objects
i_pgmid = gc_r3tr.
CALL FUNCTION 'GET_TADIR_TYPE_FROM_WB_TYPE'
EXPORTING
wb_objtype = ls_wb_object_type-subtype_wb
IMPORTING
transport_objtype = lv_tr_object
EXCEPTIONS
no_mapping_found = 1
no_unique_mapping = 2
OTHERS = 3.
IF sy-subrc IS INITIAL.
i_object = lv_tr_object.
IF is_env_tab-encl_obj IS NOT INITIAL.
i_obj_n = is_env_tab-encl_obj.
ENDIF.
ENDIF.
ENDCASE.
ENDIF.
ENDIF.
ENDIF.
ENDIF.
*------------------------------------------------------ Check in TADIR *
SELECT SINGLE * FROM tadir
INTO ls_tadir
WHERE pgmid = i_pgmid
AND object = i_object
AND obj_name = i_obj_n.
*---------------------------------------------------------- Add object *
IF ls_tadir IS NOT INITIAL.
MOVE-CORRESPONDING ls_tadir TO ls_object.
*---------- Set SAP Generated object status ----------*
IF ls_tadir-genflag IS NOT INITIAL.
ls_object-status = icon_led_yellow.
ENDIF.
*---------- Add object to be checked ----------*
PERFORM add_object USING ls_object.
*---------- Error Object not valid ----------*
ELSE.
IF lines( gt_objects ) > 0. "Skip first object
ls_object-pgmid = i_pgmid.
ls_object-object = i_object.
ls_object-obj_name = i_obj_n.
ls_object-status = icon_led_red.
PERFORM add_object USING ls_object.
ENDIF.
ENDIF.
ENDFORM. " CHECK_ADD_OBJECT
*&---------------------------------------------------------------------*
*& Form ADD_OBJECT_HEADER
*&---------------------------------------------------------------------*
FORM add_object_header USING i_pgmid TYPE pgmid
i_object TYPE any
i_obj_n TYPE any
i_objfunc TYPE objfunc.
DATA ls_e071 LIKE LINE OF gt_e071.
READ TABLE gt_e071 TRANSPORTING NO FIELDS WITH KEY pgmid = i_pgmid
object = i_object
obj_name = i_obj_n
objfunc = i_objfunc.
IF sy-subrc IS NOT INITIAL.
ls_e071-pgmid = i_pgmid.
ls_e071-object = i_object.
ls_e071-obj_name = i_obj_n.
ls_e071-objfunc = i_objfunc.
APPEND ls_e071 TO gt_e071.
ENDIF.
ENDFORM. " ADD_OBJECT_HEADER
*&---------------------------------------------------------------------*
*& Form ADD_OBJECT_KEYS
*&---------------------------------------------------------------------*
FORM add_object_keys USING i_pgmid TYPE pgmid
i_object TYPE any
i_obj_n TYPE any
i_tabkey TYPE any.
DATA ls_e071k LIKE LINE OF gt_e071k.
ls_e071k-pgmid = i_pgmid.
ls_e071k-object = i_object.
ls_e071k-objname = i_obj_n.
ls_e071k-mastertype = i_object.
ls_e071k-mastername = i_obj_n.
ls_e071k-tabkey = i_tabkey.
APPEND ls_e071k TO gt_e071k.
ENDFORM. " ADD_OBJECT_KEYS
*&---------------------------------------------------------------------*
*& Form ADD_OBJECT
*&---------------------------------------------------------------------*
FORM add_object USING ps_object TYPE gty_objects.
DATA:
ls_objs_desc LIKE LINE OF gt_objs_desc, "Objects prograns ID line"Info Environment
lt_devclass TYPE scts_devclass, "Development Packages
ls_devclass TYPE trdevclass.
DATA:
lv_object TYPE trobjtype, "Object Type
lv_objname TYPE sobj_name, "Object Name in Object Directory
lv_namespace TYPE namespace. "Object Namespace
*---------- Check if already added ----------*
READ TABLE gt_objects TRANSPORTING NO FIELDS WITH KEY pgmid = ps_object-pgmid
object = ps_object-object
obj_name = ps_object-obj_name.
IF sy-subrc IS NOT INITIAL. "New object
*---------------------------------------- Check if is customer objects *
lv_object = ps_object-object.
lv_objname = ps_object-obj_name.
CALL FUNCTION 'TRINT_GET_NAMESPACE' "#EC FB_RC
EXPORTING
iv_pgmid = ps_object-pgmid
iv_object = lv_object
iv_obj_name = lv_objname
IMPORTING
ev_namespace = lv_namespace
EXCEPTIONS
invalid_prefix = 1
invalid_object_type = 2
OTHERS = 3.
IF lv_namespace = '/0CUST/'. "Is customer object
*---------- Read object description ----------*
READ TABLE gt_objs_desc INTO ls_objs_desc WITH KEY object = ps_object-object.
IF sy-subrc IS INITIAL.
ps_object-obj_desc = ls_objs_desc-text. "Object type description
ENDIF.
*---------- Read development class tecnical information ----------*
IF ps_object-devclass IS INITIAL.
SELECT SINGLE devclass FROM tadir
INTO ps_object-devclass
WHERE pgmid = ps_object-pgmid
AND object = ps_object-object
AND obj_name = ps_object-obj_name.
ENDIF.
IF ps_object-devclass IS NOT INITIAL AND ps_object-devclass <> gc_temp.
ls_devclass-devclass = ps_object-devclass.
APPEND ls_devclass TO lt_devclass.
CALL FUNCTION 'TR_READ_DEVCLASSES'
EXPORTING
it_devclass = lt_devclass
IMPORTING
et_devclass = lt_devclass.
READ TABLE lt_devclass INTO ls_devclass INDEX 1.
IF sy-subrc IS INITIAL.
ps_object-target = ls_devclass-target. "Development package target
ENDIF.
ENDIF.
*---------- Add object to transport ----------*
APPEND ps_object TO gt_objects.
ENDIF.
ENDIF.
ENDFORM. " ADD_OBJECT
*&---------------------------------------------------------------------*
*& Form ADD_TOBJ_CONTENT
*&---------------------------------------------------------------------*
FORM add_tobj_content USING p_obj_name TYPE sobj_name.
CONSTANTS:
lc_tabu TYPE trobjtype VALUE 'TABU',
lc_tvdir TYPE sobj_name VALUE 'TVDIR',
lc_tddat TYPE sobj_name VALUE 'TDDAT',
lc_tvimf TYPE sobj_name VALUE 'TVIMF'.
DATA:
lt_tvimf TYPE TABLE OF tvimf, "User routines called from view maintenance
ls_tvimf LIKE LINE OF lt_tvimf.
DATA lv_tabkey TYPE tabkey. "Table Key
*---------- Add table content ----------*
PERFORM add_object_header USING gc_r3tr lc_tabu lc_tvdir 'K'.
PERFORM add_object_keys USING gc_r3tr lc_tabu lc_tvdir p_obj_name.
CLEAR lt_tvimf. "Read User routines called from view maintenance
SELECT * FROM tvimf "#EC CI_GENBUFF
INTO TABLE lt_tvimf
WHERE tabname = p_obj_name.
LOOP AT lt_tvimf INTO ls_tvimf.
AT FIRST.
PERFORM add_object_header USING gc_r3tr lc_tabu lc_tvimf 'K'.
ENDAT.
lv_tabkey = p_obj_name.
lv_tabkey+30 = ls_tvimf-event.
PERFORM add_object_keys USING gc_r3tr lc_tabu lc_tvimf lv_tabkey.
CLEAR lv_tabkey.
ENDLOOP.
PERFORM add_object_header USING gc_r3tr lc_tabu lc_tddat 'K'.
PERFORM add_object_keys USING gc_r3tr lc_tabu lc_tddat p_obj_name.
ENDFORM. " ADD_TOBJ_CONTENT
*----------------------------------------------------------------------*
* FORMS Checks
*----------------------------------------------------------------------*
*----------------------------------------------------------------------*
* Form OBJECTS_DEPENDENCIES_CHECK
*----------------------------------------------------------------------*
FORM objects_dependencies_check .
DATA:
lv_obj_type TYPE seu_obj, "Object type
lt_env_tab TYPE TABLE OF senvi, "Object to check dependencies
ls_env_tab TYPE senvi. "Info Environment
DATA lv_no_rfc TYPE abap_bool.
FIELD-SYMBOLS <ls_object> LIKE LINE OF gt_objects. "Objects to transport
LOOP AT gt_objects ASSIGNING <ls_object> WHERE status IS INITIAL.
*---------- Exclude RFCs if exist ----------*
IF p_erfc IS NOT INITIAL AND <ls_object>-object = gc_fugr.
CLEAR lv_no_rfc.
PERFORM exclude_rfcs USING <ls_object>-obj_name CHANGING lv_no_rfc.
IF lv_no_rfc IS INITIAL.
<ls_object>-status = icon_led_yellow.
CONTINUE.
ENDIF.
ENDIF.
*---------- Get object dependecies ----------*
REFRESH lt_env_tab.
lv_obj_type = <ls_object>-object.
CALL FUNCTION 'REPOSITORY_ENVIRONMENT_RFC'
EXPORTING
obj_type = lv_obj_type
object_name = <ls_object>-obj_name
TABLES
environment_tab = lt_env_tab.
IF lines( lt_env_tab ) IS INITIAL AND lines( gt_objects ) = 1. "Object dependencies check not support
MESSAGE s001 WITH text-m13 space space space DISPLAY LIKE 'E'.
<ls_object>-status = icon_led_red.
ELSE.
DELETE lt_env_tab INDEX 1. "Delete first line
*---------- Add founded dependecies ----------*
LOOP AT lt_env_tab INTO ls_env_tab. "#EC CI_NESTED
PERFORM check_add_object USING space ls_env_tab-type ls_env_tab-object ls_env_tab.
ENDLOOP.
<ls_object>-status = icon_led_green. "Status checked
ENDIF.
ENDLOOP.
ENDFORM. " OBJECTS_DEPENDENCIES_CHECK
*----------------------------------------------------------------------*
* Form REMOTE_OBJECTS_CHECK
*----------------------------------------------------------------------*
FORM remote_objects_check .
FIELD-SYMBOLS <ls_object> LIKE LINE OF gt_objects. "Objects to transport
DATA:
ls_e071 TYPE e071, "Change & Transport System: Object Entries of Requests/Tasks
lt_vrso TYPE TABLE OF vrso, "Version control: Object list (subset of VRSD)
ls_vrso LIKE LINE OF lt_vrso.
DATA:
lv_diagnosis TYPE char20, "Version check result
lv_local_rfc_dest TYPE rfcdest, "Logical Destination
lv_remote_rfc_dest TYPE rfcdest.
*---------- Get local rfc destination ----------*
SELECT desadm FROM tmscsys UP TO 1 ROWS "#EC CI_NOFIRST
INTO lv_local_rfc_dest
WHERE sysnam = sy-sysid.
ENDSELECT.
*---------- Get remote rfc destination ----------*
SELECT desadm FROM tmscsys UP TO 1 ROWS "#EC CI_NOFIRST
INTO lv_remote_rfc_dest
WHERE sysnam = p_rfc_d.
ENDSELECT.
*---------- Check objects versions ----------*
IF lv_local_rfc_dest IS NOT INITIAL AND lv_remote_rfc_dest IS NOT INITIAL.
LOOP AT gt_objects ASSIGNING <ls_object>.
*---------- Get Sub Objects ----------*
ls_e071-object = <ls_object>-object.
ls_e071-obj_name = <ls_object>-obj_name.
REFRESH lt_vrso.
CALL FUNCTION 'TRINT_RESOLVE_OBJ'
EXPORTING
is_e071 = ls_e071
TABLES
et_vrso = lt_vrso
EXCEPTIONS
not_versionable = 1
communication_error = 2
OTHERS = 3.
IF sy-subrc IS INITIAL.
*---------- Remote check all objects and subobjects ----------*
LOOP AT lt_vrso INTO ls_vrso WHERE objtype <> 'DOCU'. "#EC CI_NESTED
CLEAR lv_diagnosis.
CALL FUNCTION 'TRINT_COMP_VERSION'
EXPORTING
is_vrso = ls_vrso
dest1 = lv_local_rfc_dest
dest2 = lv_remote_rfc_dest
IMPORTING
ev_diagnosis = lv_diagnosis
EXCEPTIONS
rfc_error_loc = 1
rfc_error_rem = 2
intern_error_loc = 3
intern_error_rem = 4
OTHERS = 5.
IF sy-subrc IS INITIAL.
CASE lv_diagnosis.
WHEN 0. "Equal
<ls_object>-remote = text-o01.
WHEN 1. "Different
<ls_object>-remote = text-o02.
EXIT.
WHEN 3. "New
<ls_object>-remote = text-o03.
EXIT.
ENDCASE.
ENDIF.
ENDLOOP.
ELSE. "Not versionable
<ls_object>-remote = text-o04.
ENDIF.
ENDLOOP.
ELSE. "RFCs destinations missing
MESSAGE s001 WITH text-m09 space space space DISPLAY LIKE 'W'.
ENDIF.
ENDFORM. " REMOTE_OBJECTS_CHECK
*&---------------------------------------------------------------------*
*& Form INCLUDE_MAINTENANCES
*&---------------------------------------------------------------------*
FORM include_maintenances .
DATA:
ls_tvdir TYPE tvdir, "View Directory
ls_object LIKE LINE OF gt_objects, "Objects to transport line
ls_object_add LIKE LINE OF gt_objects.
DATA:
lv_obj_type TYPE c,
lv_tobj_name TYPE sobj_name, "Object Name in Object Directory
lv_objectname TYPE ob_object. "Object Name
LOOP AT gt_objects INTO ls_object WHERE object = gc_tabl AND status = icon_led_green.
CLEAR ls_tvdir.
SELECT SINGLE * FROM tvdir "#EC CI_SEL_NESTED
INTO ls_tvdir
WHERE tabname = ls_object-obj_name.
IF sy-subrc IS INITIAL.
*---------- Add Function Group if exist ----------*
ls_object_add-pgmid = gc_r3tr.
ls_object_add-object = gc_fugr.
ls_object_add-obj_name = ls_tvdir-area.
PERFORM add_object USING ls_object_add.
IF ls_tvdir-bastab IS INITIAL. lv_obj_type = 'V'. ELSE. lv_obj_type = 'S'. ENDIF.
*---------- Add Definition of a Maintenance and Transport Object ----------*
CLEAR lv_tobj_name.
lv_objectname = ls_object-obj_name.
CALL FUNCTION 'CTO_OBJECT_GET_TADIR_KEY'
EXPORTING
iv_objectname = lv_objectname
iv_objecttype = lv_obj_type
IMPORTING
ev_obj_name = lv_tobj_name.
ls_object_add-pgmid = gc_r3tr.
ls_object_add-object = gc_tobj.
ls_object_add-obj_name = lv_tobj_name.
ls_object_add-status = icon_led_green.
PERFORM add_object USING ls_object_add.
ENDIF.
ENDLOOP.
ENDFORM. " INCLUDE_MAINTENANCES
*&---------------------------------------------------------------------*
*& Form INCLUDE_LOCKS
*&---------------------------------------------------------------------*
FORM include_locks .
DATA:
ls_object LIKE LINE OF gt_objects, "Objects to transport line
ls_object_add LIKE LINE OF gt_objects.
DATA lv_viewname TYPE viewname.
*---------- Add lock objects if exist ----------*
LOOP AT gt_objects INTO ls_object WHERE object = gc_tabl AND status = icon_led_green.
CLEAR lv_viewname.
SELECT viewname FROM dd25l UP TO 1 ROWS "#EC CI_SEL_NESTED "#EC CI_NOFIRST
INTO lv_viewname
WHERE aggtype = 'E'
AND roottab = ls_object-obj_name.
ENDSELECT.
IF sy-subrc IS INITIAL.
ls_object_add-pgmid = gc_r3tr.
ls_object_add-object = 'ENQU'.
ls_object_add-obj_name = lv_viewname.
ls_object_add-status = icon_led_green.
PERFORM add_object USING ls_object_add.
ENDIF.
ENDLOOP.
ENDFORM. " INCLUDE_LOCKS
*&---------------------------------------------------------------------*
*& Form INCLUDE_CDS
*&---------------------------------------------------------------------*
FORM include_cds .
DATA:
ls_object LIKE LINE OF gt_objects, "Objects to transport line
ls_object_add LIKE LINE OF gt_objects.
DATA lv_object TYPE cdobjectcl.
*---------- Add change document object if exist ----------*
LOOP AT gt_objects INTO ls_object WHERE object = gc_tabl AND status = icon_led_green.
CLEAR lv_object.
SELECT object FROM tcdob UP TO 1 ROWS "#EC CI_SEL_NESTED "#EC CI_GENBUFF
INTO lv_object
WHERE tabname = ls_object-obj_name.
ENDSELECT.
IF sy-subrc IS INITIAL.
ls_object_add-pgmid = gc_r3tr.
ls_object_add-object = gc_chdo.
ls_object_add-obj_name = lv_object.
ls_object_add-status = icon_led_green.
PERFORM add_object USING ls_object_add.
ENDIF.
ENDLOOP.
ENDFORM. " INCLUDE_CDS
*&---------------------------------------------------------------------*
*& Form EXCLUDE_RFCS
*&---------------------------------------------------------------------*
FORM exclude_rfcs USING p_obj_name TYPE sobj_name
CHANGING p_no_rfc TYPE abap_bool.
DATA lt_fbinfo_remote TYPE TABLE OF fbinfor. "Function Module Information
DATA lv_complete_area TYPE rs38l_area. "Function group, to which the function module belongs
*---------- Check if all are RFCs ----------*
lv_complete_area = p_obj_name.
CALL FUNCTION 'FUNCTION_SELECT_TFDIR' "#EC FB_RC
EXPORTING
im_complete_area = lv_complete_area
IMPORTING
ex_fbinfo_remote = lt_fbinfo_remote
EXCEPTIONS
include_not_found_trdir = 1
report_source_not_found = 2
permission_failure = 3
OTHERS = 4.
LOOP AT lt_fbinfo_remote TRANSPORTING NO FIELDS WHERE remote <> 'R'.
p_no_rfc = abap_true. "One function found that are not RFCs
EXIT.
ENDLOOP.
ENDFORM. " EXCLUDE_RFCS
Selection screen layout after implementation:
Result objects list layout:
Please consider before using:
How to use:
Example to check dependencies in program ZNM_OBJS_DEP_TRANS:
During my seven years working on SAP China, I have resolved hundreds of internal tickets or customer tickets. Among them there are some kinds of tickets which make me headache:
For example I have ever resolved one customer ticket, I need to (1) create a new sales order (2) create a new customer demand based on sales order (3) create a pick list (3) release the generated delivery note. The issue can only be reproduced by releasing the delivery note. Then I have to repeat the lengthy steps (1) ~ (3) and do debugging in note release.
I bet most of you guys have such feeling: if the issue is purely occuring within your responsibe component, you will always be confident that it could be resolved sooner or later, since you are the owner of your API and quite familar with it. However if your API is called by other software component or from other system with complex context, you have to spend more time to have a basic understanding of the whole story, to find how your API is called, to analyze whether your original design of API could sustain this new challenge you never think about before?
In most of the cases I ever meet, the reason is because of the data setup. For example in customer test system, the test data is not well set up so that the errorous code has no chance to be executed in test system. Sometimes there is technical limitation or whatever other reasons so that it is impossible for you to ask customers to setup exactly the same data in test system as the data they are using in production system. The worst situation is, sometimes the issue occurs during write operation, for example the pricing calculation is wrong when a business document is saved. In this case you can not simply debug the save process, as it will influence customer business. You have to coordinate with customer how to proceed.
The first step to check such issue is trying to find whether there are some FMs or methods which should not be used during background execution when the presentation server is not attached.
Everyday I use debugger to fight against bug. When I found the bug could not be found via debugging, however it does exist in fact, I feel helpless, since this powerful weapean could not help me out this time. Then I have to read and analyze the code, and make them running in my brain. In most cases finally the issue is related to time-dependent processing in the program.
As an ABAPer we are lucky since we do not always have to struggle with such time-dependent issues. When I am developing an Android application for SAP CRM customer briefing in year 2012, I suffer a lot from such kinds of issues. Just two examples:
a. When you touch the Android tablet with single finger and make a slip, there are 5 or 6 different kinds of events triggered sequentially. My event handler registered for these events will handle with the coordinates of events occurred. Those coordinates will become invalid if code stopped in debugger. Then I have to write many System.out.println to print the coordinate in console for analysis.
b. Dead lock in multi-threading. Such issue is hard to reproduce via debugging.
In fact some issue does not simply fall into one or two categories listed above but consists of several of them. I never encounter an issue from customer which contains all the five feature above, and I pray I will NEVER meet with it.
Recently I have been working on one ticket which took me totally almost 10 hours to resolve it. I will share how I analyze this issue step by step.
I am owner of SAP CRM IBASE component CRM-MD-INB, the issue is my Solution management development team colleague complains when they create a new IBASE component and delete it afterwards in the same session and do a save operation, there will be ST22 dump in middleware processing stuff.
I know nothing about solution management development before.
This issue could only be reproduced in background execution. ( The program is designed to only execute in background )
The issue is not always reproducible. 囧
I quickly go through the solution manager program, there are tens of thousands code. I set breakpoint inside my API ( IBASE create, update and delete function module ), then identify all calling space and importing parameter content.
As the scenario is really complex - CRM, SOL and Middleware involved, I spent one hour debugging without any hint found. Purely judgement based on code level, there are too many factors which will impact the program. In order to make me concentrate on my API, I plan to develop a simulation report which also calls IBASE create, update and delete and then perform save. The idea is to make the API call decouple from the solution manager logic. If the issue could then also be reproduced in my simulation report, then life is eaiser - I then only have to work on the simulation report which only contains 200 lines.
I have spent another 1 hour to finish the simulation report. Unfortunately I cannot reproduce the issue with it. After I check again with issue reporter,
I realized that the report does not 100% simulate the real program regarding IBASE operation, and I change it to fix the gap.
The simulation report is uploaded as attachment of this blog.
Since the simulation report is owned by me, it is very convenient to change it for issue analysis.
a. comment out all IBASE related code.
b. uncomment IBASE component creation FM, and execute report - no dump
c. continue to uncomment IBASE component change FM, and execute - no dump
d. continue to uncomment IBASE component deletion FM, and execute - dumps!!!
So now I get to know this issue is related to IBASE deletion.
Now the issue could be reproduced during normal execution of simulation report, but could work perfectly well during debugging.
My previois experience told me that it might be caused by some time dependent processing logic in the code. Then I check the position of code which raises error( line 103 ) and found lots of time operation logic in the same include:
The aim of this include is to find the IBASE and filled it into es_ibinadm. First check in buffer table gt_ibinadm_by_in_guid, if failed then try FM in line 91( in the first screenshot of this blog) as last defence. In normal case, the es_ibinadm is expected to be filled however in this issue, the last defence also fails so the X message is raised. I set breakpoint in this include, however during my debugging, the variable es_ibinadm is successfully filled in line 54, everything works pefectly. However the dump is indeed there when I execute the report directly.
So I run the report once again and go to ST22, this means the dump there is "fresh" and the Debugger button is available only in this fresh state, so that I can observe the variable value in debugger when the dump occurs.
I soon find the root cause: the valfr and valto of the buffer entry is the same,
so during normal execution, the check in line 53 fails, so the code has to try the last defence to call FM CRM_IBASE_COMP_GET_DETAIL. In this case, it is expected behavior to raise an X message since the entry in the buffer table should be returned. When the code is executed in debugger, the valto is always greater than valfr, so the code directly return the entry to its caller without further call on FM CRM_IBASE_COMP_GET_DETAIL.
I will not go deep into IBASE valfr and valto generation logic as it is CRM specific and I am also not expert on it. ( a default creation of IBASE component creation will set its valid to timestamp as a never invalid date( 99991231235959 ). The comparison timestamp is set as valid from timestamp )
After I add the following code to ensure the check in line 53 in above screenshot will always succeed, the issue is resolved - no dump in background job execution any more.
I guess it would also work if the "<" is changed to "<=" in line53. However this code is owned by Middleware software component and I could not change, maybe I can discuss with responsible colleague.
Although it took me 1 hour to develop the simulation report, I think it is definitely worth since it liberates me from spending lots of time and effort to debug the unfamiliar solution management program and enable me to concentrate on the core code which might be related to the dump.
Sometimes if you have some findings and need to make changes on the code which calls your API for verification, you can not really do this since the code is not owned by you. In this case the simulation report plays its role! You can change it at your will for verification.
In early ten years of 21 Century, it is very popular in China to assemble a PC by ourselves via DIY approach. It means we buy CPU, memory chip, hard disk, motherboard and other stuffs from different hardware manufacturers and assemble them. Most common issue is after assembly, the computer cannot boot at all. Then we use "Mini-System" for trouble shooting: as first step we only try to boot computer with LEAST necessary hardwares ( CPU + Power + Motherboard: these three components constitute a so called "Mini-System" ). If the first attempt succeed, we can append additional component, but ensure only ONE new component is added in EACH step. Such iteration could enable us to find which hardware makes the boot failed.
Compared with computer system, our ABAP program is much more complex and issue-isolation is then necessary for root cause investigation.
In my issue processing I used "Mini-System" methodology to finally identify that the dump is related to the incorrect call of IBASE delete function module.
In this issue processing I spent quite a lot of time to debug why function module CRM_IBASE_COMP_GET_DETAIL raises an X message in the beginning.
Inside this FM it calls some deeper APIs which are not owned by me so I waste lots of time to understand the logic. Later after I read the whole source code of includes where the CRM_IBASE_COMP_GET_DETAIL is called, I asked myself: should it be called at all? Why is it called in normal execution to get data from DB, although the entry is already available in the buffer??
It makes sense to spend time and effort to debug the code where the exception is raised to understand why. It makes MORE sense to investigate the code holistically, analyze the callstack and execution context of the code. If the code ( method or function module ) fails to generate the correct output as you expect, ask yourself: should it be called at all?
Hope this blog can help for your issue analysis. And also welcome to share your tip & experience regarding tough issue processing
Hi All,
Here is my code to generate ALV tree with 5 hierarchy dynamically (or less according with your needs and with no change in the code) and changing just a perform parameters to generate it. I don’t know if it have a easier and better way to do but this one is working
If you know another way please share
So follow the code:
Declarations:
DATA: tree1 TYPE REF TO cl_gui_alv_tree.
DATA: v_icon1 TYPE lvc_s_layi,
v_icon2 TYPE lvc_s_layi,
v_icon3 TYPE lvc_s_layi,
v_icon4 TYPE lvc_s_layi,
v_icon5 TYPE lvc_s_layi.
FIELD-SYMBOLS: <field1> TYPE any,
<field2> TYPE any,
<field3> TYPE any,
<field4> TYPE any,
<field5> TYPE any,
<reffield1> TYPE any,
<reffield2> TYPE any,
<reffield3> TYPE any,
<reffield4> TYPE any,
<reffield5> TYPE any.
Logic:
* Hierarchic Field / Ref Tab / Ref Field
PERFORM f_field_symbol USING: 'TYPED' 'T6B1T' 'VTEXT' "1
'DESC' 'TB038B' 'TEXT' "2
'KNUMA' 'KONA' 'KNUMA' "3
'KSCHL' 'VAKEVB' 'KSCHL' "4
'KOTABNR' 'VAKEVB' 'KOTABNR'. "5
*&---------------------------------------------------------------------*
*& Form F_FIELD_SYMBOL
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* -->P_0299 text
* -->P_0300 text
* -->P_0301 text
*----------------------------------------------------------------------*
FORM f_field_symbol USING field1 table1 param1
field2 table2 param2
field3 table3 param3
field4 table4 param4
field5 table5 param5.
DATA r_elemdescr TYPE REF TO cl_abap_elemdescr.
DATA r_field TYPE REF TO data.
DATA: data_element TYPE dd04d-rollname.
IF field1 IS NOT INITIAL.
ASSIGN COMPONENT field1 OF STRUCTURE wa_output TO <field1>.
CHECK sy-subrc = 0.
PERFORM f_fieldinfo USING table1 param1
CHANGING data_element.
r_elemdescr ?= cl_abap_elemdescr=>describe_by_name( data_element ).
CREATE DATA r_field TYPE HANDLE r_elemdescr.
ASSIGN r_field->* TO <reffield1>.
ENDIF.
IF field2 IS NOT INITIAL.
ASSIGN COMPONENT field2 OF STRUCTURE wa_output TO <field2>.
CHECK sy-subrc = 0.
PERFORM f_fieldinfo USING table2 param2
CHANGING data_element.
r_elemdescr ?= cl_abap_elemdescr=>describe_by_name( data_element ).
CREATE DATA r_field TYPE HANDLE r_elemdescr.
ASSIGN r_field->* TO <reffield2>.
ENDIF.
IF field3 IS NOT INITIAL.
ASSIGN COMPONENT field3 OF STRUCTURE wa_output TO <field3>.
CHECK sy-subrc = 0.
PERFORM f_fieldinfo USING table3 param3
CHANGING data_element.
r_elemdescr ?= cl_abap_elemdescr=>describe_by_name( data_element ).
CREATE DATA r_field TYPE HANDLE r_elemdescr.
ASSIGN r_field->* TO <reffield3>.
ENDIF.
IF field4 IS NOT INITIAL.
ASSIGN COMPONENT field4 OF STRUCTURE wa_output TO <field4>.
CHECK sy-subrc = 0.
PERFORM f_fieldinfo USING table4 param4
CHANGING data_element.
r_elemdescr ?= cl_abap_elemdescr=>describe_by_name( data_element ).
CREATE DATA r_field TYPE HANDLE r_elemdescr.
ASSIGN r_field->* TO <reffield4>.
ENDIF.
IF param5 IS NOT INITIAL.
ASSIGN COMPONENT field5 OF STRUCTURE wa_output TO <field5>.
CHECK sy-subrc = 0.
PERFORM f_fieldinfo USING table5 param5
CHANGING data_element.
r_elemdescr ?= cl_abap_elemdescr=>describe_by_name( data_element ).
CREATE DATA r_field TYPE HANDLE r_elemdescr.
ASSIGN r_field->* TO <reffield5>.
ENDIF.
PERFORM build_sort_table USING field1 field2 field3 field4 field5.
ENDFORM. " F_FIELD_SYMBOL
*&---------------------------------------------------------------------*
*& Form F_FIELDINFO
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* -->P_TABLE1 text
* -->P_PARAM1 text
* <--P_DATA_ELEMENT text
*----------------------------------------------------------------------*
FORM f_fieldinfo USING table
param
CHANGING data_element.
DATA: BEGIN OF dfies OCCURS 100.
INCLUDE STRUCTURE dfies.
DATA: END OF dfies.
DATA: tablenm TYPE ddobjname,
fieldnm TYPE dfies-fieldname.
MOVE table TO tablenm.
MOVE param TO fieldnm.
*** Fname Description
IF NOT fieldnm IS INITIAL.
CALL FUNCTION 'DDIF_FIELDINFO_GET'
EXPORTING
tabname = tablenm
fieldname = fieldnm
langu = sy-langu
TABLES
dfies_tab = dfies
EXCEPTIONS
not_found = 1
internal_error = 2
OTHERS = 3.
IF sy-subrc = 0.
READ TABLE dfies INDEX 1.
data_element = dfies-rollname.
ENDIF.
ENDIF.
ENDFORM. " F_FIELDINFO
Creating hierarchies
*&---------------------------------------------------------------------*
*& Form CREATE_HIERARCHY
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* --> p1 text
* <-- p2 text
*----------------------------------------------------------------------*
FORM create_hierarchy .
* add data to tree
DATA: l_last_key TYPE lvc_nkey,
l_kotabnr TYPE vakevb-kotabnr,
l_knuma TYPE vakevb-knuma,
l_desc(100) TYPE c,
l_kschl TYPE vakevb-kschl,
l_add TYPE c.
DATA: l_param_key TYPE lvc_nkey,
l_param2_key TYPE lvc_nkey,
l_param3_key TYPE lvc_nkey,
l_param4_key TYPE lvc_nkey,
l_param5_key TYPE lvc_nkey.
LOOP AT it_output INTO wa_output.
**** LEVEL 1
IF <field1> IS ASSIGNED.
IF <field2> IS ASSIGNED. "Level 2 is empty
IF <field1> IS NOT INITIAL.
IF <reffield1> NE <field1>.
PERFORM level1 USING ''
v_icon1-fieldname
CHANGING l_param_key.
IF <field2> IS ASSIGNED.
CLEAR: <reffield2>.
ENDIF.
IF <field3> IS ASSIGNED.
CLEAR: <reffield3>.
ENDIF.
IF <field4> IS ASSIGNED.
CLEAR: <reffield4>.
ENDIF.
APPEND l_param_key TO it_expand_nodes.
ENDIF.
ENDIF.
ELSE.
"If next level is empty so finish the hierarchy
PERFORM add_complete_line USING '' 2
CHANGING l_last_key.
l_add = 'X'.
ENDIF.
ENDIF.
**** LEVEL 2
IF <field2> IS ASSIGNED.
IF <field3> IS ASSIGNED. "Level 3 is empty
IF <field2> IS NOT INITIAL.
IF <reffield2> NE <field2>.
PERFORM level2 USING l_param_key
2
v_icon2-fieldname
CHANGING l_param2_key.
IF <field3> IS ASSIGNED.
CLEAR: <reffield3>.
ENDIF.
IF <field4> IS ASSIGNED.
CLEAR: <reffield4>.
ENDIF.
APPEND l_param2_key TO it_expand_nodes.
ENDIF.
ENDIF.
ELSE.
"If next level is empty so finish the hierarchy
PERFORM add_complete_line USING L_PARAM_KEY 3
CHANGING l_last_key.
l_add = 'X'.
ENDIF.
ENDIF.
*** LEVEL 3
IF <field3> IS ASSIGNED.
IF <field4> IS ASSIGNED. "Level 4 is empty
IF <field3> IS NOT INITIAL.
IF <reffield3> NE <field3>.
PERFORM level3 USING l_param2_key
3
v_icon3-fieldname
CHANGING l_param3_key .
IF <field4> IS ASSIGNED.
CLEAR: <reffield4>.
ENDIF.
APPEND l_param3_key TO it_expand_nodes.
ENDIF.
ENDIF.
ELSE.
"If next level is empty so finish the hierarchy
PERFORM add_complete_line USING l_param2_key 4
CHANGING l_last_key.
l_add = 'X'.
ENDIF.
ENDIF.
*** LEVEL 4
IF <field4> IS ASSIGNED.
IF <field5> IS ASSIGNED. "Level 4 is empty
IF <field4> IS NOT INITIAL.
IF <reffield4> NE <field4>.
PERFORM level4 USING l_param3_key
3
v_icon3-fieldname
CHANGING l_param4_key .
IF <field5> IS ASSIGNED.
CLEAR: <reffield5>.
ENDIF.
APPEND l_param4_key TO it_expand_nodes.
ENDIF.
ENDIF.
ELSE.
"If next level is empty so finish the hierarchy
PERFORM add_complete_line USING l_param3_key 4
CHANGING l_last_key.
l_add = 'X'.
ENDIF.
ENDIF.
*** LEVEL 5
IF <field5> IS ASSIGNED.
IF <field5> IS NOT INITIAL.
IF <reffield5> NE <field5>.
PERFORM level5 USING l_param4_key
4
v_icon5-fieldname
CHANGING l_param5_key .
APPEND l_param4_key TO it_expand_nodes.
PERFORM add_complete_line USING l_param5_key 6
CHANGING l_last_key.
l_add = 'X'.
ENDIF.
ENDIF.
ENDIF.
IF l_add IS INITIAL.
PERFORM add_complete_line USING l_param5_key 5
CHANGING l_last_key.
ENDIF.
IF <field1> IS ASSIGNED.
<reffield1> = <field1>.
ENDIF.
IF <field2> IS ASSIGNED.
<reffield2> = <field2>.
ENDIF.
IF <field3> IS ASSIGNED.
<reffield3> = <field3>.
ENDIF.
IF <field4> IS ASSIGNED.
<reffield4> = <field4>.
ENDIF.
IF <field5> IS ASSIGNED.
<reffield5> = <field5>.
ENDIF.
CLEAR: l_add.
ENDLOOP.
*&---------------------------------------------------------------------*
*& Form LEVEL1
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* -->P_WA_DATA text
* -->P_L_PARAM2_KEY text
* -->P_3 text
* -->P_1748 text
* <--P_L_PARAM3_KEY text
*----------------------------------------------------------------------*
FORM level1 USING p_relat_key TYPE lvc_nkey
p_icon
CHANGING p_node_key.
DATA: l_node_text TYPE lvc_value,
relat TYPE int4,
wa_refe TYPE tab_type,
wa_level TYPE ty_output.
* set item-layout
DATA: lt_item_layout TYPE lvc_t_layi,
ls_item_layout TYPE lvc_s_layi.
DATA: ls_node TYPE lvc_s_layn.
ls_node-n_image = space.
ls_node-exp_image = space.
ls_item_layout-t_image = p_icon.
ls_item_layout-style = cl_gui_column_tree=>style_intensified.
ls_item_layout-fieldname = tree1->c_hierarchy_column_name.
APPEND ls_item_layout TO lt_item_layout.
* add node
l_node_text = <field1>.
wa_level-level = 1.
ls_node-isfolder = 'X'.
CALL METHOD tree1->add_node
EXPORTING
i_relat_node_key = p_relat_key
i_relationship = cl_gui_column_tree=>relat_last_child
i_node_text = l_node_text
is_outtab_line = wa_level
is_node_layout = ls_node
it_item_layout = lt_item_layout
IMPORTING
e_new_node_key = p_node_key
EXCEPTIONS
relat_node_not_found = 1
node_not_found = 2
OTHERS = 3.
ENDFORM. " LEVEL1
*&---------------------------------------------------------------------*
*& Form LEVEL2
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* -->P_L_PARAM1_KEY text
* -->P_2 text
* -->P_1721 text
* <--P_L_PARAM2_KEY text
*----------------------------------------------------------------------*
FORM level2 USING p_relat_key TYPE lvc_nkey
hierarchy
icon
CHANGING p_node_key TYPE lvc_nkey.
* set item-layout
DATA: lt_item_layout TYPE lvc_t_layi,
l_node_text TYPE lvc_value,
ls_item_layout TYPE lvc_s_layi,
relat TYPE int4,
wa_level TYPE ty_output.
ls_item_layout-t_image = icon.
ls_item_layout-style = cl_gui_column_tree=>style_intensified.
ls_item_layout-fieldname = tree1->c_hierarchy_column_name.
APPEND ls_item_layout TO lt_item_layout.
* add node
l_node_text = <field2>.
wa_level-level = hierarchy.
relat = cl_gui_column_tree=>relat_last_child.
CALL METHOD tree1->add_node
EXPORTING
i_relat_node_key = p_relat_key
i_relationship = relat
i_node_text = l_node_text
is_outtab_line = wa_level
it_item_layout = lt_item_layout
IMPORTING
e_new_node_key = p_node_key.
ENDFORM. "LEVEL2
*&---------------------------------------------------------------------*
*& Form LEVEL3
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* -->P_L_PARAM1_KEY text
* -->P_2 text
* -->P_1721 text
* <--P_L_PARAM2_KEY text
*----------------------------------------------------------------------*
FORM level3 USING p_relat_key TYPE lvc_nkey
hierarchy
icon
CHANGING p_node_key TYPE lvc_nkey.
* set item-layout
DATA: lt_item_layout TYPE lvc_t_layi,
l_node_text TYPE lvc_value,
ls_item_layout TYPE lvc_s_layi,
relat TYPE int4,
wa_level TYPE ty_output.
ls_item_layout-t_image = icon.
ls_item_layout-style = cl_gui_column_tree=>style_intensified.
ls_item_layout-fieldname = tree1->c_hierarchy_column_name.
APPEND ls_item_layout TO lt_item_layout.
* add node
l_node_text = <field3>.
wa_level-knuma = wa_output-knuma.
CONCATENATE wa_output-datab+6(2)
wa_output-datab+4(2)
wa_output-datab(4)
INTO wa_level-zzbrandd
SEPARATED BY '.'.
CONCATENATE wa_output-datbi+6(2)
wa_output-datbi+4(2)
wa_output-datbi(4)
INTO wa_level-kunnr
SEPARATED BY '.'.
wa_level-matnr = wa_output-waers.
wa_level-kondm = wa_output-agnotes.
wa_level-level = hierarchy.
relat = cl_gui_column_tree=>relat_last_child.
CALL METHOD tree1->add_node
EXPORTING
i_relat_node_key = p_relat_key
i_relationship = relat
i_node_text = l_node_text
is_outtab_line = wa_level
it_item_layout = lt_item_layout
IMPORTING
e_new_node_key = p_node_key.
ENDFORM. " LEVEL3
*&---------------------------------------------------------------------*
*& Form LEVEL4
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* -->P_L_PARAM1_KEY text
* -->P_2 text
* -->P_1721 text
* <--P_L_PARAM2_KEY text
*----------------------------------------------------------------------*
FORM level4 USING p_relat_key TYPE lvc_nkey
hierarchy
icon
CHANGING p_node_key TYPE lvc_nkey.
* set item-layout
DATA: lt_item_layout TYPE lvc_t_layi,
l_node_text TYPE lvc_value,
ls_item_layout TYPE lvc_s_layi,
relat TYPE int4,
wa_level TYPE ty_output.
ls_item_layout-t_image = icon.
ls_item_layout-style = cl_gui_column_tree=>style_intensified.
ls_item_layout-fieldname = tree1->c_hierarchy_column_name.
APPEND ls_item_layout TO lt_item_layout.
* add node
l_node_text = <field4>.
wa_level-zzbrandd = wa_output-combin.
wa_level-level = hierarchy.
wa_level-knuma = wa_output-knuma.
relat = cl_gui_column_tree=>relat_last_child.
CALL METHOD tree1->add_node
EXPORTING
i_relat_node_key = p_relat_key
i_relationship = relat
i_node_text = l_node_text
is_outtab_line = wa_level
it_item_layout = lt_item_layout
IMPORTING
e_new_node_key = p_node_key.
ENDFORM. "LEVEL4
*&---------------------------------------------------------------------*
*& Form LEVEL5
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* -->P_L_PARAM1_KEY text
* -->P_2 text
* -->P_1721 text
* <--P_L_PARAM2_KEY text
*----------------------------------------------------------------------*
FORM level5 USING p_relat_key TYPE lvc_nkey
hierarchy
icon
CHANGING p_node_key TYPE lvc_nkey.
* set item-layout
DATA: lt_item_layout TYPE lvc_t_layi,
l_node_text TYPE lvc_value,
ls_item_layout TYPE lvc_s_layi,
relat TYPE int4,
wa_level TYPE ty_output.
ls_item_layout-t_image = icon.
ls_item_layout-style = cl_gui_column_tree=>style_intensified.
ls_item_layout-fieldname = tree1->c_hierarchy_column_name.
APPEND ls_item_layout TO lt_item_layout.
* add node
l_node_text = <field5>.
wa_level-zzbrandd = wa_output-combin.
wa_level-level = hierarchy.
wa_level-knuma = wa_output-knuma.
relat = cl_gui_column_tree=>relat_last_child.
CALL METHOD tree1->add_node
EXPORTING
i_relat_node_key = p_relat_key
i_relationship = relat
i_node_text = l_node_text
is_outtab_line = wa_level
it_item_layout = lt_item_layout
IMPORTING
e_new_node_key = p_node_key.
ENDFORM. "LEVEL5
*&---------------------------------------------------------------------*
*& Form add_cmplete_line
*&---------------------------------------------------------------------*
* add hierarchy-level 3 to tree
*----------------------------------------------------------------------*
* -->P_LS_SFLIGHT sflight
* -->P_RELEATKEY relatkey
* <-->p_node_key new node-key
*----------------------------------------------------------------------*
FORM add_complete_line USING p_relat_key TYPE lvc_nkey
hierarchy
CHANGING p_node_key TYPE lvc_nkey.
DATA: l_node_text TYPE lvc_value.
* set item-layout
DATA: lt_item_layout TYPE lvc_t_layi,
ls_item_layout TYPE lvc_s_layi.
ls_item_layout-fieldname = tree1->c_hierarchy_column_name.
APPEND ls_item_layout TO lt_item_layout.
l_node_text = wa_output-bonem.
IF l_node_text IS INITIAL.
MESSAGE s021(zgeral) DISPLAY LIKE 'E'.
LEAVE LIST-PROCESSING.
ENDIF.
DATA: ls_node TYPE lvc_s_layn.
ls_node-n_image = space.
ls_node-exp_image = space.
wa_output-level = hierarchy.
CALL METHOD tree1->add_node
EXPORTING
i_relat_node_key = p_relat_key
i_relationship = cl_gui_column_tree=>relat_last_child
is_outtab_line = wa_output
i_node_text = l_node_text
is_node_layout = ls_node
it_item_layout = lt_item_layout
IMPORTING
e_new_node_key = p_node_key.
ENDFORM. " add_complete_line
I think that is everything here. Let me know if I missed something or someone need help to understand it.
Hope it helps.
Regards,
Andréa