Quelquepart

Blog d'un développeur ABAP

Vous êtes ici : Accueil>Show code in Nugget

Show code in Nugget ZRSPC.nugg

Table of content

Program ZRSPC: Chain BW Process

Text Elements

Text symbols

Text symbolLanguageTextLength
T01EFile information50
T02EBatch information50
T03EDirect input for Process chain scheduling50

Selection texts

NameLanguageText
P_FILEEFile name
P_HEADEREHeader line
P_JOBNMEJob name
P_MAILESend mail at end of job
P_MAILTMEPeriodic mail status (minuts)
P_NOSTOPEDo not stop on error
P_STARTEStart Step
P_TESTECheck file only
SO_LINESEAction

GUI Status

GUI Status

CodeModalTitle
LOGDStandard ALV Log display

Function code

CodeTextIcon
%MLFolder
%PCLocal file...@49@
%SCFind@13@
%SC+Find next@4E@
%SLMail Recipient@1S@
&ABCABC Analysis@DL@
&ALLSelect all@4B@
&AQWWord processing...@DK@
&AUFDefine totals drilldown...
&AVESaving...
&AVESave layout...@DN@
&AVRMean value
&CDFUnfreeze
&CFIFreeze to column
&COUNTCount
&DATA_SAVESave@2L@
&EB9Call Up Report@36@
&ELPHelp@35@
&ERWLayout Management
&ETADetails@16@
&F03Back
&F12Cancel@0W@
&F15Exit
&F4Possible entries
&GRAPHGraphic@0N@
&IC1Choose@16@
&ILDDelete Filter@GD@
&ILTSet filter@4G@
&INFOInformation@0S@
&MAXMaximum
&MINMinimum
&OADChoose...
&OADSelect layout...@DM@
&ODNSort in descending order@3F@
&OL0Change layout...@LZ@
&OLXChange...@0R@
&OPTOptimize width
&OUPSort in Ascending Order@3E@
&REFRESHRefresh@42@
&RNTPrint@0X@
&RNT_PREVPrint preview@3G@
&SALDeselect all@4D@
&SUMSubtotals...@5V@
&UMCTotal@3Z@
&VCRYSTALCrystal Reports
&VEXCELMicrosoft Excel@J2@
&VGRIDSAP List Viewer
&VLOTUSLotus 1-2-3
&XINTAdditional Functions of SAP Query
&XXLSpreadsheet...@DJ@
CALCSum@3Z@
CHANGELOGDisplay other log@2Q@
DELETEDelete@11@
DETAILJobs@M5@
FOCUSGoto active@3Y@
JOBSDisplay job@M4@
REFRESHRefresh@42@
RESTARTRestart from step@8W@
STOPStop@3U@

Title bar

CodeText

ABAP Code

*&---------------------------------------------------------------------*
*& Program : ZRSPC
*& Author  : S. HERMANN
*& Date    : 25.06.2015
*& Version : 1.7.1
*& Required: Function ZRSPC_SEND_MAIL (see code at end of this program)
*&---------------------------------------------------------------------*
*& This program allow you to execute process listed in a CSV file
*& The main purpose is to automate process that are not handled by RSPC
*& Based on ZQW_AUTOMATE_ACTION (by C. Cabrita)
*&
*& You can execute process of theses type :
*&  DEL_DELTA_INIT : Delete the delta init flag based on infopackage
*&  DEL_DSO : Delete data selection which is in active table of a DSO
*&            or complete deletion
*&  DEL_CUBE : Delete data selection which is in a cube
*&            or complete deletion with dimension table
*&  CHANGE_IP_MODE : Change infopackage mode (full / delta / init)
*&                   and manage "autoswitch flag"
*&  CHANGE_IP_SEL : Change infopackage selection
*&  TRIG_IP : Triggers infopackage - parallel process managed
*&  TRIG_DTP : Triggers DTP - parallel process managed
*&  TRIG_DTP_NODATA : triggers DTP without data transfer
*&  TRIG_CHAIN : Triggers process chain - parallel process managed
*&  ACT_DSO : Activation of unactivated requests in DSO
*&  DEL_UNUSED_DIM : Deletion of unused values in dimension table
*&  DEL_UNUSED_IOBJ : Deletion of unused values in info object tables
*&  DEL_INDEX : Delete index for cube
*&  DBSTAT : Index/Stat generation for cubes and tables
*&  CALL_ABAP : Execute ABAP program with variant
*&  PROCESS_PSA : Load data from PSA to targets
*&               (using the most recent request from given infopackage)
*&  EXPORT_DS : Generate export datasource (3.x flow)
*&  REPLICATE_DS : Replicate a datasource
*&  ACTIVATE_OBJECT : Re-activate BW Object (Cube, rules, ...)
*&  STOP : Interrupt the treatment
*&  WAIT : Wait a given time or amount of seconds before continue
*&
*& You can desactivate line of the file by add an * at the begin of the
*& process type
*&
*& You can schedule the batch process with a file, or directly by set up
*& list of actions in the selection screen (use same syntax as for CSV
*& file)
*&
*& CSV file has 4 columns :
*&   - PROCESS : process type listed above
*&   - OBJECT : object on which apply the process
*&   - PARAM : parameters for the process
*&   - COMMENT : You can add free text in the 4th column
*&
*&---------------------------------------------------------------------*
*&
*& Here are the following values of OBJECT/PARAM for each process :
*&
*&  Delete the delta init flag based on infopackage
*&  PROCESS = DEL_DELTA_INIT
*&  OBJECT  = Tech name of infopackage
*&  PARAM   = Empty
*&  Example : DEL_DELTA_INIT;ZPAK_4ACUACE06UC6VKRWXUQFKRU3V
*&
*&  Selective/complete deletion of data in DSO (active table)
*&  PROCESS = DEL_DSO
*&  OBJECT  = Name of DSO
*&  PARAM   = Where clause for deletion or null for complete deletion
*&            For the where clause you must set fieldname in upper case
*&            and inside " " and values inside ' '
*&            Be carefull Value must be in internal format
*&  Examples:
*&  DEL_DSO;Z41V_O10;;Complete deletion deletion
*&  DEL_DSO;Z41V_O10;"/BIC/ZMATNR" = 'A23R4E';Selective deletion
*&
*&  Selective/complete deletion in a cube
*&  PROCESS = DEL_CUBE
*&  OBJECT  = Name of cube
*&  PARAM   = Line at the following format :
*&            condition1|condition2|...|condition_n
*&            each condition has the following structure :
*&            Infoobject@@Operator@@Value low@@Value high
*&            or null for complete deletion
*&            Be carefull Value must be in internal format
*&            Operator can be EQ, NE, LT, LE, GT, GE, BT
*&            (standard abap select-option operator)
*&  Examples:
*&  DEL_CUBE;Z41V_C01;;Complete deletion deletion
*&  DEL_CUBE;Z41V_C01;0MATERIAL@@EQ@@A23R4E;Selective deletion
*&
*&  Modify infopackage mode and/or autoswitch (AS) flag
*&  PROCESS = CHANGE_IP_MODE
*&  OBJECT  = Tech name of infopackage
*&  PARAM   = You can add many of theses param, separated by |
*&            FULL : IP mode is set to Full
*&            REPAIR : Flag REPAIR is activated
*&            NOREPAIR : Flag REPAIR is desactivated
*&            DELTA : IP mode is set to Delta
*&            INIT : IP mode is set to Init with data transfert
*&            INITNODT : IP mode is set to Init without data transfert
*&            AUTOSWITCH : Flag Autoswitch is activated
*&            NOSWITCH : Flag Autoswitch is desactivated
*&  Examples:
*&  CHANGE_IP_MODE;ZPAK_4ACUACE06UC6VKR;INIT|NOSWITCH;init with DT without AS
*&  CHANGE_IP_MODE;ZPAK_4ACUACE06UC6VKR;FULL;full, no change AS
*&  CHANGE_IP_MODE;ZPAK_4ACUACE06UC6VKR;AUTOSWITCH;flag AS, load mode unchanged
*&
*&  Modify infopackage selection
*&  PROCESS = CHANGE_IP_SEL
*&  OBJECT  = Tech name of infopackage
*&  PARAM   = Selection use this syntax : InfoObject@@Technical Name@@From@@To
*&            You can add as many selection as you want.
*&            Each selection is separated by |
*&  Examples:
*&  CHANGE_IP_SEL;ZPAK_4ACUACE06UC6VKR;0PLANT@@WERKS@@123@@127;Select all plant between 123 and 127
*&  CHANGE_IP_SEL;ZPAK_4ACUACE06UC6VKR;0PLANT@@WERKS@@123@@127|0PLANT@@WERKS@@130;Select all plant between 123 and 127 and plant 130
*&  CHANGE_IP_SEL;ZPAK_4ACUACE06UC6VKR;0PLANT@@WERKS@@130|ZLOEKZ@@ZZLOEKZ@@X;Select plant 130 and loekz X
*&
*&  Start infopackage
*&  PROCESS = TRIG_IP
*&  OBJECT  = Tech name of infopackage
*&            if IP need to be triggered in parallel we just have to
*&            put a list of IP separated by |
*&  PARAM   = Empty to run the IP like in process chain
*&            - No process psa
*&            - No activation
*&            - Autoswitch init/delta
*&            X to run like a manual run
*&            It means that process psa is done automatically if
*&            required and activation can be started.
*&  Example : TRIG_IP;ZPAK_4ACUACE06UC6VKR5F3O1UHDM3
*&
*&  Start a DTP
*&  PROCESS = TRIG_DTP
*&  OBJECT  = Tech name of DTP
*&            if DTP need to be triggered in parallel we just have to
*&            put a list of DTP separated by |
*&  PARAM   = Empty
*&  Example : TRIG_DTP;DTP_4XH0MOXLDP7HPGQ5F3O1UHDM3
*&
*&  Start a DTP without data transfer
*&  PROCESS = TRIG_DTP_NODATA
*&  OBJECT  = Tech name of DTP
*&  PARAM   = Empty
*&  Example : TRIG_DTP_NODATA;DTP_4XH0MOXLDP7HPGQ5F3O1UHDM3
*&
*&  Activation of unactivated requests in DSO
*&  PROCESS = ACT_DSO
*&  OBJECT  = Name of DSO
*&  PARAM   = X to not condenses all request when activate
*&  Example : ACT_DSO;Z41V_O01
*&
*&  Deletion of dimension that are not used
*&  PROCESS = DEL_UNUSED_DIM
*&  OBJECT  = Name of a Cube
*&  PARAM   = Empty
*&  Example : DEL_UNUSED_DIM;Z41V_C01
*&
*&  Deletion of unused masterdata content
*&  PROCESS = DEL_UNUSED_IOBJ
*&  OBJECT  = Name of an Info Object
*&  PARAM   = Empty
*&  Example : DEL_UNUSED_IOBJ;0MATERIAL
*&
*&  Start a process chain
*&  PROCESS = TRIG_CHAIN
*&  OBJECT  = Tech name of process chain
*&            if chain need to be triggered in parallel we just have to
*&            put a list of chains separated by |
*&  PARAM   = Empty
*&  Example : TRIG_CHAIN;ZTRANSAC_SD
*&
*&  Index deletion for cube
*&  PROCESS = DEL_INDEX
*&  OBJECT  = Name of a Cube
*&  PARAM   = Empty
*&  Example : DEL_INDEX;Z41V_C01
*&
*&  Index/stat generation
*&  PROCESS = DBSTAT
*&  OBJECT  = Name of a cube or table
*&  PARAM   = You can add many of theses param, separated by |
*&            STAT to generate Statistics
*&            INDEX to generate index,
*&  Examples:
*&  DBSTAT;Z41V_C01;INDEX;generate index for cube Z41V_C01
*&  DBSTAT;/BI0/SMATERIAL;STAT;generate statistics for sid table of 0MATERIAL
*&  DBSTAT;Z41V_C01;STAT INDEX;generate index & statistics for cube Z41V_C01
*&
*&  ABAP program execition with variant
*&  PROCESS = CALL_ABAP
*&  OBJECT  = Name of an ABAP Program
*&  PARAM   = Name of Variant to execute
*&  Example : CALL_ABAP;ZDELETE_GENERIC;ZVARDEL_C01
*&
*&  Load data from PSA to targets
*&  PROCESS = PROCESS_PSA
*&  OBJECT  = Name of an Infopackage in "PSA only" mode
*&  PARAM   = Empty
*&            Infopackage monitoring may remain in "yellow" until
*&            all targets has been activated
*&  Example : PROCESS_PSA;ZPAK_4XH0MOXLDP7HPGQ5F3O1UHDM3
*&
*&  Generate export datasource (3.x flow)
*&  PROCESS = EXPORT_DS
*&  OBJECT  = Name of a cube/dso
*&  PARAM   = Empty
*&  Example : EXPORT_DS;Z41V_C01
*&
*&  Replicate a datasource
*&  PROCESS = REPLICATE_DS
*&  OBJECT  = Name of a datasource
*&  PARAM   = source system + datasource version separated by |
*&            DS version = ISFS for a 3.x datasource, RSDS for a 7.x
*&  Example : REPLICATE_DS;0MATERIAL_ATTR;DEVCLNT100|ISFS
*&
*&  Re-activate BW object (Cube, DSO, rules, ...)
*&  PROCESS = ACTIVATE_OBJECT
*&  OBJECT  = Object name
*&  PARAM   = Object type (Field RSTLOGOPROP-TLOGO)
*&  Tested successfully with :
*&   - Cube (CUBE)
*&   - DSO (ODSO)
*&   - DTP (DTPA)
*&   - Infoset (ISET)
*&   - Multiprovider (MPRO)
*&   - Process chain (RSPC)
*&   - Transformation (TRFN)
*&   - Updates rules 3.x (UPDR)
*&  Example : ACTIVATE_OBJECT;Z41V_C01;CUBE
*&
*&  Process interruption.
*&  This process could be cancelled until it occurs
*&  PROCESS = STOP
*&  OBJECT  = Empty
*&  PARAM   = Empty
*&  Example : STOP;;;Interrupt process
*&
*&  Wait a given time or an amount of seconds before continue
*&  PROCESS = WAIT
*&  OBJECT  = Empty
*&  PARAM   = Number of seconds to wait
*&            or calendar to wait (prefix with T)
*&            Be carefull, time to wait is local time
*&            Your current local time is given on selection screen
*&  Example : WAIT;;30;Wait 30s to let system finish updates
*&            WAIT;;T20150517060000;Wait until 17.05.2015 at 06:00:00
*&
*&  Index creation for cube (obsolete, please use DBSTAT)
*&  PROCESS = INDEX
*&  OBJECT  = Name of a Cube
*&  PARAM   = Empty
*&  Example : INDEX;Z41V_C01
*&---------------------------------------------------------------------*
*& TECHNICAL PURPOSE :
*& This program have 3 call mode :
*& - First online mode to load a process file and start the batch
*& - batch mode (called at the end of the first online mode)
*& - Next online mode to display the log of the process
*&
*& Data is saved into shared buffer.
*& You can easilly change the storage space by modification of the
*& 2 subroutines "import_process_list" and "export_process_list"
*&
*& Please Send comment & improvements to http://quelquepart.biz
*&---------------------------------------------------------------------*
*& History :
*& 2015.06.25 v1.7.1: Add mail compression (divide by 4 the mail size)
*& 2015.05.25 v1.7  : Add process CHANGE_IP_SEL to modify IP selection
*&                    Add cancellation of STOP process
*&                    Add wait a given hour on the WAIT process
*&                    Add nb lines on sum selected time function
*&                    Fix bug on DBSTAT checks
*& 2014.12.07 v1.6.1: Fix bug ST13 log dummy entries (delete log)
*& 2014.06.15 v1.6  : Changes in documentation
*&                    Add process DBSTAT (replace process INDEX)
*&                    Changes in parameters of process CHANGE_IP_MODE
*& 2014.04.29 v1.5  : Add process CHANGE_IP_MODE
*&                    Add periodic status by email
*&                    Changes : Ignore case for field PROCESS
*& 2014.03.06 v1.4.1: Changes in documentation
*&                    Add option on DSO activation to not condense req
*&                    Changes : Allow to choose many objects to display
*& 2014.02.28 v1.4  : Add process ACTIVATE_OBJECT
*&                    Add process REPLICATE_DS
*&                    Add process EXPORT_DS
*& 2014.02.12 v1.3.3: Add Focus on active step at first display
*& 2014.02.04 v1.3.2: Add server prefix in end mail
*&                    Add Display days in time count
*&                    Add button to focus on active step
*& 2014.01.21 v1.3.1: Changes in documentation
*& 2013.12.10 v1.3  : Add process WAIT
*& 2013.10.24 v1.2  : Add option to start without file
*&                    Add process TRIG_DTP_NODATA
*& 2013.10.15 v1.1.1: Fix bug on restart
*& 2013.10.01 v1.1  : Add icon in the display report
*&                    Add "online mode" on process TRIG_IP
*&                    Add jump to objects
*&                    Add button to calculate exec time of selection
*&                    Add button to stop job process
*&                    Add option to restart selection only
*&                    Change DEL_DELTA_INIT from export datasource to
*&                    Infopackage to manage also external datasource
*&                    Minor change on mail report
*&                    Ignore blank lines in input file
*&                    Send end mail also on manual stop/restart
*&                    Fix init deletion in case of init during same day
*& 2013.07.01 v1.0  : Initial release
*&---------------------------------------------------------------------*
* TODO :
* - Use db table to store log instead of shared buffer


PROGRAM zrspc.

*######################################################################*
*
*                             DATA SECTION
*
*######################################################################*
TABLES sscrfields. "for button on selection screen

DATA : BEGIN OF s_param,
         process TYPE string,
         object TYPE string,
         param  TYPE string,
         comment TYPE string,
         state(4) TYPE c,
         line TYPE i,
         start_date TYPE d,
         start_time TYPE t,
         end_date TYPE d,
         end_time TYPE t,
         exec_time TYPE t,
         selkz(1) TYPE c,
       END OF s_param,
       BEGIN OF s_shared,
         param LIKE TABLE OF s_param,
         jobname TYPE tbtcjob-jobname,
         jobcount TYPE tbtcm-jobcount,
         mail(1) TYPE c,
         nostop(1) TYPE c,
         mail_time TYPE i,
         runid(14) TYPE c,
       END OF s_shared,
       w_shared_param(30) TYPE c,
       w_continue(1) TYPE c,
       w_display_only(1) TYPE c, "true if display log for other user
       BEGIN OF s_select,
         chosen(1) TYPE c,
         object TYPE string,
       END OF s_select,
       t_select LIKE TABLE OF s_select,
       w_so_line(255) TYPE c,
       o_grid TYPE REF TO cl_gui_alv_grid.

* Program execution mode
CONSTANTS : c_mode_start(1) TYPE c VALUE '1', "schedule mode
            c_mode_batch(1) TYPE c VALUE '2', "batch mode
            c_mode_log(1) TYPE c VALUE '3',   "log mode

* Authorized process type
            c_action_del_init TYPE string VALUE 'DEL_DELTA_INIT',
            c_action_del_dso TYPE string VALUE 'DEL_DSO',
            c_action_del_cube TYPE string VALUE 'DEL_CUBE',
            c_action_ip_mode TYPE string VALUE 'CHANGE_IP_MODE',
            c_action_ip_sel TYPE string VALUE 'CHANGE_IP_SEL',
            c_action_trig_ip TYPE string VALUE 'TRIG_IP',
            c_action_trig_dtp TYPE string VALUE 'TRIG_DTP',
            c_action_trig_dtp_nodata TYPE string VALUE 'TRIG_DTP_NODATA',
            c_action_chain TYPE string VALUE 'TRIG_CHAIN',
            c_action_activ_dso TYPE string VALUE 'ACT_DSO',
            c_action_del_dim TYPE string VALUE 'DEL_UNUSED_DIM',
            c_action_del_iobj TYPE string VALUE 'DEL_UNUSED_IOBJ',
            c_action_del_index TYPE string VALUE 'DEL_INDEX',
            c_action_index TYPE string VALUE 'INDEX',
            c_action_dbstat TYPE string VALUE 'DBSTAT',
            c_action_abap TYPE string VALUE 'CALL_ABAP',
            c_action_process_psa TYPE string VALUE 'PROCESS_PSA',
            c_action_export_ds TYPE string VALUE 'EXPORT_DS',
            c_action_replicate_ds TYPE string VALUE 'REPLICATE_DS',
            c_action_activate_obj TYPE string VALUE 'ACTIVATE_OBJECT',
            c_action_stop TYPE string VALUE 'STOP',
            c_action_wait TYPE string VALUE 'WAIT',

* Message type
            c_msg_error(1) TYPE c VALUE 'E',
            c_msg_success(1) TYPE c VALUE 'S',
            c_msg_abort(1) TYPE c VALUE 'A',
            c_msg_info(1) TYPE c VALUE 'I',

* Misc. constants
            c_version_active TYPE rsobjvers VALUE 'A',
            c_true(1) TYPE c VALUE 'X',
            c_comment(1) TYPE c VALUE '*',
            c_nogui(1) TYPE c VALUE 'N',
            c_stop_cancel(12) TYPE c VALUE 'CANCEL STOP',

* Separator in file
            c_separator(1) TYPE c VALUE ';',
            c_separator_param(1) TYPE c VALUE '|',
            c_separator_cond(2) TYPE c VALUE '@@',

* State in table monitoring
            c_state_skip LIKE s_param-state VALUE '@03@',
            c_state_ok  LIKE s_param-state VALUE '@5B@',
            c_state_ko  LIKE s_param-state VALUE '@5C@',
            c_state_run LIKE s_param-state VALUE '@5D@',
            c_state_abort LIKE s_param-state VALUE '@8N@',

* Used only in detailed log
            c_state_info LIKE s_param-state VALUE '@0S@',

* Stantard ip status
            c_ipstatus_ok TYPE rsstatus VALUE '@08@',
            c_ipstatus_ko TYPE rsstatus VALUE '@0A@',

* Standard chain status
            c_chainstatus_ok TYPE rspc_state VALUE 'G',
            c_chainstatus_ko TYPE rspc_state VALUE 'R',

* Time to wait between 2 status check
            c_check_wait TYPE i VALUE 5.


*######################################################################*
*
*                             SELECTION-SCREEN
*
*######################################################################*

SELECTION-SCREEN BEGIN OF SCREEN 900.
SELECTION-SCREEN FUNCTION KEY 1.
SELECTION-SCREEN COMMENT /1(50) w_time.
SELECTION-SCREEN BEGIN OF BLOCK one WITH FRAME TITLE text-t01.
PARAMETERS p_file TYPE string LOWER CASE.
PARAMETERS p_header AS CHECKBOX DEFAULT c_true.
PARAMETERS p_start TYPE i DEFAULT 1.
PARAMETERS p_test AS CHECKBOX.
SELECTION-SCREEN END OF BLOCK one.

SELECTION-SCREEN BEGIN OF BLOCK two WITH FRAME TITLE text-t02.
PARAMETERS p_jobnm TYPE tbtcjob-jobname DEFAULT 'ZRSPC' OBLIGATORY.
PARAMETERS p_mail AS CHECKBOX TYPE c DEFAULT c_true.
PARAMETERS p_mailtm TYPE i DEFAULT 60.
PARAMETERS p_nostop AS CHECKBOX TYPE c DEFAULT space.
SELECTION-SCREEN END OF BLOCK two.

SELECTION-SCREEN BEGIN OF BLOCK tri WITH FRAME TITLE text-t03.
SELECT-OPTIONS so_lines FOR w_so_line NO INTERVALS LOWER CASE.
SELECTION-SCREEN END OF BLOCK tri.
SELECTION-SCREEN END OF SCREEN 900.

AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_file.
  PERFORM prompt_for_file USING 'Choose process file'
                          CHANGING p_file.

AT SELECTION-SCREEN.
* Keep information that user validate the selection screen (F8)
  IF sy-dynnr = 900 AND sy-ucomm = 'CRET'.
    w_continue = c_true.
  ELSEIF sy-dynnr = 900 AND sy-ucomm = 'FC01'.
    PERFORM ask_log.
    PERFORM main USING c_mode_log.
  ENDIF.

*######################################################################*
*
*                             INITIALIZATION
*
*######################################################################*
INITIALIZATION.
* Buld default shared buffer id
  PERFORM build_shared_id USING sy-uname.

* allow to clear buffer with debug change
  IF sy-ucomm = 'SHN_CLEAR'.
    PERFORM export_process_list USING s_shared.
  ENDIF.

* Define text of button on selection-screen
  MOVE '@2Q@ Display Log' TO sscrfields-functxt_01.

  CONCATENATE 'Current time :' sy-timlo(2) ':' sy-timlo+2(2) ':'
              sy-timlo+4 INTO w_time.
*######################################################################*
*
*                             MAIN SECTION
*
*######################################################################*

START-OF-SELECTION.
  PERFORM main USING space.



*######################################################################*
*
*                          SUBROUTINE SECTION
*
*######################################################################*

*&---------------------------------------------------------------------*
*&      Form  MAIN
*&---------------------------------------------------------------------*
*       Main program
*       Define which action to do regarding which mode is used
*       - Load a new file
*       - Batch mode (run the loaded file)
*       - Report mode
*----------------------------------------------------------------------*
*      -->FP_MODE Program execution mode
*----------------------------------------------------------------------*
FORM main USING fp_mode TYPE c.
  DATA lw_mode(1) TYPE c.

  IF fp_mode IS INITIAL.
* First call, determine mode automatically
    PERFORM get_mode CHANGING lw_mode.
*    lw_mode = 2. "shn for batch mode debug
  ELSE.
    lw_mode = fp_mode.
  ENDIF.

  CASE lw_mode.
    WHEN c_mode_start.
* If mode = schedule new file, display selection screen
      CLEAR w_continue.
      PERFORM build_shared_id USING sy-uname.
      CALL SELECTION-SCREEN 900.
      IF NOT w_continue = c_true.
        RETURN.
      ENDIF.
      CLEAR s_shared.
      s_shared-jobname = p_jobnm.
      s_shared-mail = p_mail.
      s_shared-nostop = p_nostop.
      s_shared-mail_time = p_mailtm * 60.
      s_shared-runid = sy-datum && sy-uzeit.
* Load file and check file content
      PERFORM load_file_in_memory.

* File loaded, start the batch
      IF NOT s_shared-param IS INITIAL.
* Start the batch
        PERFORM start_batch.
* Switch to display mode
        PERFORM main USING c_mode_log.
        RETURN.
* File not loaded (error or check only), display selection screen again
      ELSE.
        PERFORM main USING c_mode_start.
        RETURN.
      ENDIF.
    WHEN c_mode_batch.
* In case of direct input, load the file
      IF NOT so_lines[] IS INITIAL.
        CLEAR s_shared.
        s_shared-jobname = p_jobnm.
        s_shared-mail = p_mail.
        s_shared-nostop = p_nostop.
        s_shared-mail_time = p_mailtm * 60.
        s_shared-runid = sy-datum && sy-uzeit.
        IF NOT p_file IS INITIAL.
          MESSAGE 'Cannot run in background with desktop file input'
                  TYPE c_msg_error.
        ENDIF.
* Load file and check file content
        PERFORM load_file_in_memory.
      ELSE.
* Get process to execute
        PERFORM import_process_list CHANGING s_shared.
      ENDIF.
* Schedule periodic mail
      IF s_shared-mail_time GT 0.
        CALL FUNCTION 'ZRSPC_SEND_MAIL' STARTING NEW TASK 'SENDMAIL'
          EXPORTING
            i_shared = w_shared_param
            i_runid  = s_shared-runid.
      ENDIF.
      PERFORM process_file.
      IF s_shared-mail = c_true.
        PERFORM send_mail.
      ENDIF.

    WHEN c_mode_log.
      PERFORM display_log.

  ENDCASE.
ENDFORM.                    " MAIN

*&---------------------------------------------------------------------*
*&      Form  prompt_for_file
*&---------------------------------------------------------------------*
*       Searchhelp for input file
*----------------------------------------------------------------------*
*      -->FP_TITLE     Title of the search-help
*      -->FP_FILENAME  Returning path+filename
*----------------------------------------------------------------------*
FORM prompt_for_file  USING fp_title TYPE string
                      CHANGING fp_filename TYPE string.
  DATA : lt_file_f4 TYPE filetable,
         ls_file_f4 LIKE LINE OF lt_file_f4,
         l_rc TYPE i,
         l_filter TYPE string.
  l_filter = 'CSV File (*.csv)|*.csv'.
  CALL METHOD cl_gui_frontend_services=>file_open_dialog
    EXPORTING
      window_title = fp_title
      file_filter  = l_filter
    CHANGING
      file_table   = lt_file_f4
      rc           = l_rc
    EXCEPTIONS
      OTHERS       = 0.
  READ TABLE lt_file_f4 INTO ls_file_f4 INDEX 1.
  IF sy-subrc = 0.
    fp_filename = ls_file_f4.
  ENDIF.
ENDFORM.                    " PROMPT_FOR_FILE

*&---------------------------------------------------------------------*
*&      Form  LOAD_FILE_IN_MEMORY
*&---------------------------------------------------------------------*
*       Load file from local pc
*----------------------------------------------------------------------*
FORM load_file_in_memory .
  DATA : lw_file TYPE string,
         lt_file LIKE TABLE OF lw_file,
         lt_string_param TYPE STANDARD TABLE OF string,
         ls_string_param LIKE LINE OF lt_string_param.
  DATA : ls_log_hdr TYPE bal_s_log,
         lw_log_hnd TYPE balloghndl,
         lt_log_hnd TYPE bal_t_logh,
         ls_log_msg TYPE bal_s_msg,
         lt_log_msg LIKE TABLE OF ls_log_msg,
         lw_preftype TYPE rstlogo,
         lw_logsys TYPE rsds-logsys,
         BEGIN OF ls_tlogo,
           tlogo TYPE rstlogoprop-tlogo,
           modversfl TYPE rstlogoprop-modversfl,
           class TYPE rstlogoprop-class,
         END OF ls_tlogo,
         lw_mode TYPE c,
         lw_switch TYPE c,
         lw_param LIKE s_param-param,
         lw_length TYPE i,
         lw_date(8) TYPE c,
         lw_time(6) TYPE c.

  DEFINE write_log.
    clear ls_log_msg.
    ls_log_msg-msgty = c_msg_error.
    ls_log_msg-msgid = '00'.
    ls_log_msg-msgno = '001'.
    ls_log_msg-msgv1 = ' Line:'.
    ls_log_msg-msgv2 = &1.
    condense ls_log_msg-msgv2.
    ls_log_msg-msgv3 = &2.
    ls_log_msg-msgv4 = &3.
    ls_log_msg-probclass = &4.
    append ls_log_msg to lt_log_msg.
  END-OF-DEFINITION.

* Read local file
  IF NOT p_file IS INITIAL.
    CALL METHOD cl_gui_frontend_services=>gui_upload
      EXPORTING
        filename = p_file
        filetype = 'ASC'
      CHANGING
        data_tab = lt_file
      EXCEPTIONS
        OTHERS   = 8.
    IF sy-subrc NE 0.
      MESSAGE 'Cannot open the file'
              TYPE c_msg_success DISPLAY LIKE c_msg_error.
      RETURN.
    ENDIF.

* If header line, delete it
    IF p_header = c_true.
      DELETE lt_file INDEX 1.
    ENDIF.
  ELSEIF NOT so_lines[] IS INITIAL.
    LOOP AT so_lines.
      lw_file = so_lines-low.
      APPEND lw_file TO lt_file.
    ENDLOOP.
  ELSE.
    MESSAGE 'Fill file name or list of actions'
             TYPE c_msg_success DISPLAY LIKE c_msg_error.
    RETURN.
  ENDIF.

* Check the file content
  REFRESH lt_log_msg.
  LOOP AT lt_file INTO lw_file.
* Skip blank lines
    IF lw_file IS INITIAL OR lw_file CO '; '.
      DELETE lt_file.
      CONTINUE.
    ENDIF.

    CLEAR s_param.
    s_param-line = sy-tabix.
    IF p_start GT sy-tabix.
      s_param-state = c_state_skip.
    ENDIF.
    SPLIT lw_file AT c_separator
          INTO s_param-process
               s_param-object
               s_param-param
               s_param-comment.
    TRANSLATE s_param-process TO UPPER CASE.

    CASE s_param-process.
      WHEN c_action_activate_obj.
* Check object type
        SELECT SINGLE tlogo modversfl class INTO ls_tlogo
               FROM rstlogoprop
               WHERE tlogo = s_param-param.
        IF sy-subrc NE 0.
          write_log s_param-line ' Object type does not exist:'
                    s_param-param 2.
        ELSEIF ls_tlogo-modversfl = space.
          write_log s_param-line ' Object type does not support activation:'
                    s_param-param 3.
        ELSEIF ls_tlogo-class = space.
          write_log s_param-line ' Object type is not yet managed:'
                    s_param-param 3.
        ENDIF.

      WHEN c_action_del_dso OR c_action_activ_dso.
        SELECT SINGLE odsobject
               INTO s_param-object
               FROM rsdodso
               WHERE odsobject = s_param-object
               AND objvers = c_version_active.
        IF sy-subrc NE 0.
          write_log s_param-line ' DSO does not exist:'
                    s_param-object 2.
        ENDIF.

      WHEN c_action_del_cube OR c_action_del_dim
      OR c_action_del_index OR c_action_index.
        SELECT SINGLE infocube
               INTO s_param-object
               FROM rsdcube
               WHERE infocube = s_param-object
               AND objvers = c_version_active
               AND ( cubetype = 'A' OR cubetype = 'B' ).
        IF sy-subrc NE 0.
          write_log s_param-line ' Cube does not exist:'
                    s_param-object 2.
        ENDIF.
      WHEN c_action_dbstat.
        SELECT SINGLE infocube
               INTO s_param-object
               FROM rsdcube
               WHERE infocube = s_param-object
               AND objvers = c_version_active
               AND ( cubetype = 'A' OR cubetype = 'B' ).
        IF sy-subrc NE 0.
          SELECT SINGLE tabname
               INTO s_param-object
               FROM dd02l
               WHERE tabname = s_param-object
               AND as4vers = c_version_active.
          IF sy-subrc NE 0.
            write_log s_param-line ' Cube/Table does not exist:'
                      s_param-object 2.
          ENDIF.
* For table, INDEX not managed
          FIND FIRST OCCURRENCE OF 'INDEX' IN s_param-param.
          IF sy-subrc = 0.
            write_log s_param-line ' INDEX not managed for table:'
                      s_param-object 3.
          ENDIF.
        ENDIF.
        lw_param = s_param-param.
        REPLACE 'STAT' IN lw_param WITH space.
        REPLACE 'INDEX' IN lw_param WITH space.
        REPLACE ALL OCCURRENCES OF c_separator_param IN lw_param WITH space.
        IF NOT lw_param CO space.
          CONDENSE lw_param.
          write_log s_param-line ' Use only INDEX / STAT as parameter:'
                    lw_param 4.
        ENDIF.
      WHEN c_action_export_ds.
        SELECT SINGLE odsobject
               INTO s_param-object
               FROM rsdodso
               WHERE odsobject = s_param-object
               AND objvers = c_version_active.
        IF sy-subrc NE 0.
          SELECT SINGLE infocube
                 INTO s_param-object
                 FROM rsdcube
                 WHERE infocube = s_param-object
                 AND objvers = c_version_active
                 AND ( cubetype = 'A' OR cubetype = 'B' ).
          IF sy-subrc NE 0.
            write_log s_param-line ' Cube/DSO does not exist:'
                      s_param-object 2.
          ENDIF.
        ENDIF.

      WHEN c_action_process_psa.
        SELECT SINGLE logdpid
               INTO s_param-object
               FROM rsldpio
               WHERE logdpid = s_param-object
               AND objvers = c_version_active.
        IF sy-subrc NE 0.
          write_log s_param-line ' Infopackage does not exist:'
                    s_param-object 2.
        ENDIF.

        SELECT SINGLE logdpid INTO s_param-object
               FROM rsldpsel
               WHERE logdpid = s_param-object
               AND   objvers = c_version_active
               AND   ziel    = 1.
        IF sy-subrc NE 0.
          write_log s_param-line ' Infopackage is not in mode PSA only:'
                    s_param-object 3.
        ENDIF.

      WHEN c_action_trig_ip
      OR c_action_del_init
      OR c_action_ip_mode
      OR c_action_ip_sel.
* Split different conditions into an internal table
        SPLIT s_param-object AT c_separator_param
                        INTO TABLE lt_string_param.
        LOOP AT lt_string_param INTO ls_string_param.
          SELECT SINGLE logdpid
                 INTO ls_string_param
                 FROM rsldpio
                 WHERE logdpid = ls_string_param
                 AND objvers = c_version_active.
          IF sy-subrc NE 0.
            write_log s_param-line ' Infopackage does not exist:'
                      ls_string_param 2.
          ENDIF.
        ENDLOOP.
        IF s_param-process = c_action_ip_mode.
          lw_param = s_param-param.
          TRANSLATE lw_param TO UPPER CASE.
          REPLACE FIRST OCCURRENCE OF 'FULL' IN lw_param WITH ''.
          REPLACE FIRST OCCURRENCE OF 'NOREPAIR' IN lw_param WITH ''.
          REPLACE FIRST OCCURRENCE OF 'REPAIR' IN lw_param WITH ''.
          REPLACE FIRST OCCURRENCE OF 'DELTA' IN lw_param WITH ''.
          REPLACE FIRST OCCURRENCE OF 'INITNODT' IN lw_param WITH ''.
          REPLACE FIRST OCCURRENCE OF 'INIT' IN lw_param WITH ''.
          REPLACE FIRST OCCURRENCE OF 'AUTOSWITCH' IN lw_param WITH ''.
          REPLACE FIRST OCCURRENCE OF 'NOSWITCH' IN lw_param WITH ''.
          REPLACE ALL OCCURRENCES OF c_separator_param IN lw_param WITH space.
          IF NOT ls_string_param CO space.
            write_log s_param-line ' Invalid or duplicated parameters :'
                      ls_string_param 3.
          ENDIF.
        ENDIF.

      WHEN c_action_trig_dtp
      OR c_action_trig_dtp_nodata.
* Split different conditions into an internal table
        SPLIT s_param-object AT c_separator_param
                        INTO TABLE lt_string_param.
        LOOP AT lt_string_param INTO ls_string_param.
          SELECT SINGLE dtp
                 INTO ls_string_param
                 FROM rsbkdtp
                 WHERE dtp = ls_string_param
                 AND objvers = c_version_active.
          IF sy-subrc NE 0.
            write_log s_param-line ' DTP does not exist:'
                      ls_string_param 2.
          ENDIF.
        ENDLOOP.

      WHEN c_action_del_iobj.
        SELECT SINGLE iobjnm
               INTO s_param-object
               FROM rsdiobj
               WHERE iobjnm = s_param-object
               AND objvers = c_version_active.
        IF sy-subrc NE 0.
          write_log s_param-line ' Info object does not exist:'
                    s_param-object 2.
        ENDIF.

      WHEN c_action_chain.
* Split different conditions into an internal table
        SPLIT s_param-object AT c_separator_param
                        INTO TABLE lt_string_param.
        LOOP AT lt_string_param INTO ls_string_param.
          SELECT SINGLE chain_id
                 INTO ls_string_param
                 FROM rspcchainattr
                 WHERE chain_id = ls_string_param
                 AND objvers = c_version_active.
          IF sy-subrc NE 0.
            write_log s_param-line ' Process chain does not exist:'
                      ls_string_param 2.
          ENDIF.
        ENDLOOP.

      WHEN c_action_abap.
        SELECT SINGLE progname
               INTO s_param-object
               FROM reposrc
               WHERE progname = s_param-object
               AND r3state = c_version_active.
        IF sy-subrc NE 0.
          write_log s_param-line ' ABAP Program does not exist:'
                    s_param-object 2.
        ENDIF.
        SELECT SINGLE variant
               INTO s_param-param
               FROM vari
               WHERE report = s_param-object
               AND variant = s_param-param.
        IF sy-subrc NE 0.
          write_log s_param-line ' Variant does not exist:'
                    s_param-param 3.
        ENDIF.

      WHEN c_action_replicate_ds.
        SPLIT s_param-param AT c_separator_param INTO lw_logsys lw_preftype.
        SELECT SINGLE logsys
               INTO lw_logsys
               FROM tbdls
               WHERE logsys = lw_logsys.
        IF sy-subrc NE 0.
          write_log s_param-line ' Source system does not exist:'
                    lw_logsys 2.
        ENDIF.
        IF lw_preftype NE 'ISFS' AND lw_preftype NE 'RSDS'.
          write_log s_param-line ' Use only ISFS & RSDS as parameter:'
                    lw_preftype 3.
        ENDIF.
      WHEN c_action_wait.
* Check that parameter is integer of date/time prefixed by T
* Check that given date/time is not in the past
        IF s_param-param(1) = 'T'.
          lw_length = strlen( s_param-param+1 ).
          IF NOT lw_length = 14 OR NOT s_param-param+1(14) CO '0123456789'.
            write_log s_param-line ' Date/time not valid. Please use AAAAMMJJHHMMSS:'
                      s_param-param+1 2.
          ELSE.
            lw_date = s_param-param+1(8).
            CALL FUNCTION 'RP_CHECK_DATE'
              EXPORTING
                date         = lw_date
              EXCEPTIONS
                date_invalid = 1
                OTHERS       = 2.
            IF sy-subrc <> 0.
              write_log s_param-line ' Date invalid:'
                        lw_date 3.
            ELSEIF lw_date LT sy-datlo.
              write_log s_param-line ' Date in the past:'
                        lw_date 3.
            ENDIF.
            lw_time = s_param-param+9(6).
            IF lw_time(2) GT 23 OR lw_time+2(2) GT 59 OR lw_time+4(2) GT 59.
              write_log s_param-line ' Time invalid:'
                      lw_time 3.
            ELSEIF lw_date = sy-datlo AND lw_time LT sy-timlo.
              write_log s_param-line ' Time in the past:'
                        lw_time 3.
            ENDIF.
          ENDIF.
        ELSE.
          IF NOT s_param-param CO '0123456789'.
            write_log s_param-line ' Enter a number of seconds:'
                      s_param-param 2.
          ENDIF.
        ENDIF.
      WHEN c_action_stop.
* No control for stop process



      WHEN OTHERS.
* Do not write error for line desactivated
        IF s_param-process(1) NE c_comment.
          write_log s_param-line ' Process type does not exist:'
                    s_param-process 1.
        ENDIF.
    ENDCASE.
    APPEND s_param TO s_shared-param.
  ENDLOOP.

* If error found, display error log, delete memory file and exit
  IF NOT lt_log_msg IS INITIAL.

* Write header log
    CLEAR ls_log_hdr.
    ls_log_hdr-aldate_del    = sy-datum. "effacement apres 0j
    ls_log_hdr-aluser        = sy-uname.
    ls_log_hdr-alprog        = sy-repid.
    ls_log_hdr-altcode       = sy-tcode.
    ls_log_hdr-del_before    = c_true.
    CALL FUNCTION 'BAL_LOG_CREATE'
      EXPORTING
        i_s_log      = ls_log_hdr
      IMPORTING
        e_log_handle = lw_log_hnd
      EXCEPTIONS
        OTHERS       = 2.
    IF sy-subrc <> 0.
      MESSAGE 'Cannot initialize error log' TYPE c_msg_error.
    ENDIF.

* Write error msg
    LOOP AT lt_log_msg INTO ls_log_msg.
      CALL FUNCTION 'BAL_LOG_MSG_ADD'
        EXPORTING
          i_log_handle = lw_log_hnd
          i_s_msg      = ls_log_msg
        EXCEPTIONS
          OTHERS       = 4.
      IF sy-subrc <> 0.
        MESSAGE 'Cannot append error log' TYPE c_msg_error.
      ENDIF.
    ENDLOOP.

    APPEND lw_log_hnd TO lt_log_hnd.

* Affichage du log
    CALL FUNCTION 'BAL_DSP_LOG_DISPLAY'
      EXPORTING
        i_t_log_handle = lt_log_hnd
      EXCEPTIONS
        OTHERS         = 5.
    IF sy-subrc <> 0.
      MESSAGE 'Cannot display error log' TYPE c_msg_error.
    ENDIF.
    CLEAR s_shared.
  ELSEIF p_test = c_true.
    CLEAR s_shared.
    MESSAGE 'No error found' TYPE c_msg_success.
  ENDIF.
ENDFORM.                    " LOAD_FILE_IN_MEMORY

*&---------------------------------------------------------------------*
*&      Form  START_BATCH
*&---------------------------------------------------------------------*
*       Submit ZRSPC in background to start mode 2
*----------------------------------------------------------------------*
FORM start_batch.
  CALL FUNCTION 'JOB_OPEN'
    EXPORTING
      jobname  = s_shared-jobname
    IMPORTING
      jobcount = s_shared-jobcount
    EXCEPTIONS
      OTHERS   = 4.
  IF sy-subrc NE 0.
    MESSAGE 'Cannot create job to start the batch'
            TYPE c_msg_error.
    RETURN.
  ENDIF.

  PERFORM export_process_list USING s_shared.

* Insert process into job
  SUBMIT zrspc AND RETURN
               USER sy-uname
               VIA JOB s_shared-jobname
               NUMBER s_shared-jobcount.
  IF sy-subrc NE 0.
    MESSAGE 'Cannot submit job to start the batch'
            TYPE c_msg_error.
    RETURN.
  ENDIF.

* Close job
  CALL FUNCTION 'JOB_CLOSE'
    EXPORTING
      jobcount  = s_shared-jobcount
      jobname   = s_shared-jobname
      sdlstrtdt = sy-datum
      sdlstrttm = sy-uzeit
    EXCEPTIONS
      OTHERS    = 9.
  IF sy-subrc <> 0.
    MESSAGE 'Cannot close job to start the batch'
            TYPE c_msg_error.
    RETURN.
  ENDIF.
  MESSAGE 'Job started' TYPE c_msg_success.

ENDFORM.                    " START_BATCH

*&---------------------------------------------------------------------*
*&      Form  PROCESS_FILE
*&---------------------------------------------------------------------*
*       Execute all process from table s_shared-param
*----------------------------------------------------------------------*
FORM process_file .
  DATA : lw_message TYPE string,
         lw_subrc TYPE i,
         ls_shared LIKE s_shared,
         ls_param LIKE s_param.

  IF s_shared-param IS INITIAL.
    RETURN.
  ENDIF.

  LOOP AT s_shared-param INTO s_param.
* Do not execute line marked as skip
    CHECK s_param-state NE c_state_skip.

    CLEAR lw_subrc.

* Skip desactivated lines
    IF s_param-process(1) = c_comment.
      lw_message = sy-tabix.
      CONCATENATE '*** Skip process ' lw_message ':'
                  s_param-process 'on object' s_param-object
                  INTO lw_message
                  SEPARATED BY space.
      s_param-state = c_state_skip.
      s_param-start_date = sy-datum.
      s_param-start_time = sy-uzeit.
      s_param-end_date = sy-datum.
      s_param-end_time = sy-uzeit.
      s_param-exec_time = 0.
      MODIFY s_shared-param FROM s_param.
      PERFORM export_process_list USING s_shared.
      CONTINUE.
    ENDIF.

* Log the start
    lw_message = sy-tabix.
    CONCATENATE '*** Triggering process ' lw_message ':'
                s_param-process 'on object' s_param-object
                INTO lw_message
                SEPARATED BY space.
    CONDENSE lw_message.
    MESSAGE lw_message TYPE c_msg_success.

    s_param-start_date = sy-datum.
    s_param-start_time = sy-uzeit.
    s_param-state = c_state_run.
    MODIFY s_shared-param FROM s_param.
    PERFORM export_process_list USING s_shared.

* Execute process
    PERFORM (s_param-process) IN PROGRAM (sy-repid) "IF FOUND
            USING s_param
            CHANGING lw_subrc.

* Get process list to check if STOP must be cancelled
    PERFORM import_process_list CHANGING ls_shared.

* Log the process result (success/error)
    IF lw_subrc NE 0.
      s_param-end_date = sy-datum.
      s_param-end_time = sy-uzeit.
      s_param-exec_time = ( s_param-end_date - s_param-start_date )
                          *  86400
                          + s_param-end_time - s_param-start_time.
      s_param-state = c_state_ko.
      MODIFY s_shared-param FROM s_param.
      PERFORM export_process_list USING s_shared.
* Stop on error
      IF s_shared-nostop = space OR s_param-process = c_action_stop.
        EXIT.
      ENDIF.
    ELSE.
      s_param-end_date = sy-datum.
      s_param-end_time = sy-uzeit.
      s_param-exec_time = ( s_param-end_date - s_param-start_date )
                          *  86400
                          + s_param-end_time - s_param-start_time.
      s_param-state = c_state_ok.
      MODIFY s_shared-param FROM s_param.
      PERFORM export_process_list USING s_shared.
    ENDIF.

* Check if a STOP process must be cancelled
    LOOP AT ls_shared-param INTO ls_param WHERE process = c_action_stop
                                            AND param = c_stop_cancel.
      CONCATENATE '*' ls_param-process INTO ls_param-process.
      MODIFY s_shared-param INDEX sy-tabix FROM ls_param TRANSPORTING process.
    ENDLOOP.
  ENDLOOP.
  PERFORM export_process_list USING s_shared.
ENDFORM.                    " PROCESS_FILE

*&---------------------------------------------------------------------*
*&      Form  DEL_DTA_COMPLETE
*&---------------------------------------------------------------------*
*       Complete data deletion (with dimensions in case of Cube)
*----------------------------------------------------------------------*
*      -->FP_IPROV  Infoprovider to delete
*      <--FP_SUBRC  Return code (<> 0 if error during process)
*----------------------------------------------------------------------*
FORM del_dta_complete  USING    fp_iprov TYPE string
                       CHANGING fp_subrc TYPE i.
  TYPE-POOLS rsenq.

  DATA : lo_dta  TYPE REF TO cl_rsd_dta,
         lo_error TYPE REF TO cx_root,
         lt_object TYPE rsenq_t_object,
         ls_object TYPE rsenq_s_object,
         lt_msg TYPE rs_t_msg,
         lw_lockid TYPE rsenq_lockid,
         lw_dta TYPE rsinfocube.

  CLEAR fp_subrc.
  lw_dta = fp_iprov.

* Create Cube Object
  TRY.
      CREATE OBJECT lo_dta
        EXPORTING
          i_infoprov    = lw_dta
        EXCEPTIONS
          input_invalid = 1
          not_found     = 2
          OTHERS        = 3.
    CATCH cx_root INTO lo_error.                         "#EC CATCH_ALL
      fp_subrc = 1.
  ENDTRY.
  IF fp_subrc NE 0.
    RETURN.
  ENDIF.

* Lock cube
  ls_object-object = 'DATATARGET'.
  ls_object-value  = lw_dta.
  APPEND ls_object TO lt_object.
  REFRESH lt_msg.
  CALL FUNCTION 'RSENQ_ENQUEUE'
    EXPORTING
      i_action   = rsenq_c_refresh_datatarget
      i_t_object = lt_object
    IMPORTING
      e_lockid   = lw_lockid
    CHANGING
      c_t_msg    = lt_msg
    EXCEPTIONS
      locked     = 1
      OTHERS     = 2.
  IF sy-subrc <> 0.
    fp_subrc = 8.
    RETURN.
  ENDIF.

* Delete cube content
  TRY.
      CALL METHOD lo_dta->delete_data
        EXPORTING
          i_incl_dime   = c_true
          i_with_dialog = space
        EXCEPTIONS
          cancelled     = 1
          not_found     = 2
          OTHERS        = 3.
    CATCH cx_root INTO lo_error.                         "#EC CATCH_ALL
      fp_subrc = 8.
  ENDTRY.

* Unlock cube
  IF fp_subrc NE 0.
    IF NOT lw_lockid IS INITIAL.
      CALL FUNCTION 'RSENQ_DEQUEUE'
        EXPORTING
          i_lockid = lw_lockid
        CHANGING
          c_t_msg  = lt_msg
        EXCEPTIONS
          OTHERS   = 0.
    ENDIF.
    RETURN.
  ELSE.
    MESSAGE s095(rsmpc) WITH lw_dta.
    IF NOT lw_lockid IS INITIAL.
      CALL FUNCTION 'RSENQ_DEQUEUE'
        EXPORTING
          i_lockid = lw_lockid
        CHANGING
          c_t_msg  = lt_msg
        EXCEPTIONS
          OTHERS   = 0.
    ENDIF.
  ENDIF.
ENDFORM.                    " DEL_DTA_COMPLETE

*&---------------------------------------------------------------------*
*&      Form  execute_process
*&---------------------------------------------------------------------*
*       Start a process
*       Could be used with infopackage, process chain,
*       or any process chain type
*----------------------------------------------------------------------*
*      -->FP_TYPE      Type of process to start
*      -->FP_VARIANT   Name of the process
*      -->FP_INSTANCE  Name of the started instance
*----------------------------------------------------------------------*
FORM execute_process USING fp_type TYPE rspc_type
                           fp_variant TYPE rspc_variant
                     CHANGING fp_instance TYPE rspc_instance.

  DATA : lw_object TYPE seoclsname,
         lw_logid TYPE rspc_logid,
         lw_state TYPE rspc_state,
         lw_eventno TYPE rspc_eventno,
         lw_hold TYPE rspc_hold,
         lw_chain TYPE rspc_chain.

  IF fp_type = 'CHAIN'.
    lw_chain = fp_variant.
  ELSE.
    CLEAR lw_chain.
  ENDIF.

* Get required information
  CALL FUNCTION 'RSPC_PROCESS_GET_INFO'
    EXPORTING
      i_type    = fp_type
      i_variant = fp_variant
    IMPORTING
      e_object  = lw_object
      e_logid   = lw_logid.

* Execute process
  CALL METHOD (lw_object)=>if_rspc_execute~execute
    EXPORTING
      i_variant  = fp_variant
      i_logid    = lw_logid
    IMPORTING
      e_instance = fp_instance
      e_state    = lw_state
      e_eventno  = lw_eventno
      e_hold     = lw_hold.

* Terminate properly to avoid dump
  CALL FUNCTION 'RSPC_PROCESS_FINISH'
    EXPORTING
      i_logid    = lw_logid
      i_type     = fp_type
      i_variant  = fp_variant
      i_instance = fp_instance
      i_state    = lw_state
      i_eventno  = lw_eventno
      i_hold     = lw_hold.

* Clean ST13 log from crap entry created by the 3 previous functions
  DELETE FROM rspcprocesslog WHERE log_id = lw_logid AND type = fp_type.

ENDFORM.                    "execute_process

*&---------------------------------------------------------------------*
*&      Form  trig_process
*&---------------------------------------------------------------------*
*       Triggers Load process in asynchronous mode :
*       - Infopackages
*       - DTP
*----------------------------------------------------------------------*
*      -->FP_PARAM   Line of the file
*      <--FP_SUBRC   Return code (<> 0 if error during process)
*----------------------------------------------------------------------*
FORM trig_process USING fp_param LIKE s_param
                  CHANGING fp_subrc TYPE i.
  DATA : lt_string_param TYPE STANDARD TABLE OF string,
         ls_string_param LIKE LINE OF lt_string_param,
         lw_variant TYPE rspc_variant,
         lw_request TYPE rspc_instance,
         lw_message TYPE string,
         BEGIN OF ls_run,
           req TYPE bapi6107dr-request,
         END OF ls_run,
         lt_run LIKE TABLE OF ls_run,
         ls_reqdone TYPE rsreqdone,
         lw_count TYPE i,
         lw_type TYPE rspc_type,
         lo_dtp TYPE REF TO cl_rsbk_dtp,
         lo_request TYPE REF TO cl_rsbk_request,
         lw_dtp TYPE rsbkdtpnm.

* Split different process to start into an internal table
  SPLIT fp_param-object AT c_separator_param
                       INTO TABLE lt_string_param.

* Infopackage
  IF fp_param-process = c_action_trig_ip.
    lw_type = 'LOADING'.
* DTP
  ELSEIF fp_param-process = c_action_trig_dtp.
    lw_type = 'DTP_LOAD'.
* DTOP without datatransfer
  ELSEIF fp_param-process = c_action_trig_dtp_nodata.
    lw_type = space.
* Exit on error in other case.
  ELSE.
    fp_subrc = 8.
    RETURN.
  ENDIF.

* Start all infopackage/dtp requested
  IF NOT lw_type IS INITIAL.
    LOOP AT lt_string_param INTO ls_string_param.
      lw_variant = ls_string_param.

* Trigger the process
      PERFORM execute_process USING lw_type lw_variant
                              CHANGING lw_request.
* Exit on error
      IF lw_request IS INITIAL OR lw_request(4) = 'ERRO'.
        fp_subrc = 8.
        RETURN.
      ENDIF.

* Remember request number to check completion
      ls_run-req = lw_request.
      APPEND ls_run TO lt_run.
    ENDLOOP.
  ELSE.
* Start DTP without data transfer
    LOOP AT lt_string_param INTO ls_string_param.
      TRY.
          lw_dtp = ls_string_param.
          lo_dtp = cl_rsbk_dtp=>factory( lw_dtp ).
          CALL METHOD lo_dtp->if_rsbk_dtp_execute~create_request
            RECEIVING
              r_r_request = lo_request.
          lo_request->set_ctype( 'NODATA' ).

          CALL METHOD lo_request->if_rsbk_request~doit
            EXPORTING
              i_no_commit = rs_c_false.
          lw_request = lo_request->if_rsbk_request~get_requid30( ).
* Remember request number to check completion
          ls_run-req = lw_request.
          APPEND ls_run TO lt_run.
        CATCH cx_rs_failed cx_rs_not_found cx_rs_foreign_lock.
          fp_subrc = 8.
          RETURN.
      ENDTRY.
    ENDLOOP.
  ENDIF.

* Check all started process
  DESCRIBE TABLE lt_run LINES lw_count.
  WHILE lw_count > 0.
* Wait some times between checks to let the server work
    WAIT UP TO c_check_wait SECONDS.

* Check each request
    LOOP AT lt_run INTO ls_run.
      CALL FUNCTION 'RSSM_RSREQDONE_READ'
        EXPORTING
          i_rnr         = ls_run-req
        IMPORTING
          e_s_rsreqdone = ls_reqdone.

      IF ls_reqdone-tstatus = c_ipstatus_ok.
        CONCATENATE 'Request' ls_run-req 'finished'
                     INTO lw_message SEPARATED BY space.
        MESSAGE lw_message TYPE c_msg_success.
        DELETE lt_run.
        lw_count = lw_count - 1.
        CONTINUE.
      ELSEIF ls_reqdone-tstatus = c_ipstatus_ko.
        fp_subrc = 8.
        RETURN.
      ENDIF.
    ENDLOOP.
    IF sy-subrc NE 0. "to avoid infinite loop
      EXIT.
    ENDIF.
  ENDWHILE.
ENDFORM.                    " trig_process

*&---------------------------------------------------------------------*
*&      Form  trig_ip_online                                   @Cabrita
*&---------------------------------------------------------------------*
*       Triggers Infopackage in asynchronous mode like online schedule
*----------------------------------------------------------------------*
*      -->FP_PARAM   Line of the file
*      <--FP_SUBRC   Return code (<> 0 if error during process)
*----------------------------------------------------------------------*
FORM trig_ip_online USING fp_param LIKE s_param
                    CHANGING fp_subrc TYPE i.
  DATA : lt_return TYPE STANDARD TABLE OF bapiret2,
         l_requestid TYPE rsrequnr,
         l_infopackage LIKE bapi6109-infopackage,
         lt_string_param TYPE STANDARD TABLE OF string,
         ls_string_param LIKE LINE OF lt_string_param,
         BEGIN OF ls_run,
           req TYPE bapi6107dr-request,
         END OF ls_run,
         lt_run LIKE TABLE OF ls_run,
         ls_reqdone TYPE rsreqdone,
         lw_count TYPE i,
         lw_type TYPE rspc_type,
         lw_message TYPE string.

* Split different process to start into an internal table
  SPLIT fp_param-object AT c_separator_param
                       INTO TABLE lt_string_param.

  LOOP AT lt_string_param INTO ls_string_param.
    l_infopackage = ls_string_param.

* Trigger infopackage
    CALL FUNCTION 'BAPI_IPAK_START'
      EXPORTING
        infopackage = l_infopackage
      IMPORTING
        requestid   = l_requestid
      TABLES
        return      = lt_return.

    READ TABLE lt_return WITH KEY type = c_msg_error
               TRANSPORTING NO FIELDS.
    IF sy-subrc = 0.
      fp_subrc = 8.
      RETURN.
    ENDIF.

* Remember request number to check completion
    ls_run-req = l_requestid.
    APPEND ls_run TO lt_run.
  ENDLOOP.

* Check all started process
  DESCRIBE TABLE lt_run LINES lw_count.
  WHILE lw_count > 0.
* Wait some times between checks to let the server work
    WAIT UP TO c_check_wait SECONDS.

* Check each request
    LOOP AT lt_run INTO ls_run.
      CALL FUNCTION 'RSSM_RSREQDONE_READ'
        EXPORTING
          i_rnr         = ls_run-req
        IMPORTING
          e_s_rsreqdone = ls_reqdone.

      IF ls_reqdone-tstatus = c_ipstatus_ok.
        CONCATENATE 'Request' ls_run-req 'finished'
                     INTO lw_message SEPARATED BY space.
        MESSAGE lw_message TYPE c_msg_success.
        DELETE lt_run.
        lw_count = lw_count - 1.
        CONTINUE.
      ELSEIF ls_reqdone-tstatus = c_ipstatus_ko.
        fp_subrc = 8.
        RETURN.
      ENDIF.
    ENDLOOP.
    IF sy-subrc NE 0. "to avoid infinite loop
      EXIT.
    ENDIF.
  ENDWHILE.
ENDFORM.                    "trig_ip_online

*&---------------------------------------------------------------------*
*&      Form  GET_MODE
*&---------------------------------------------------------------------*
*       Determine run mode for the program
*----------------------------------------------------------------------*
*      -->FP_MODE Program execution mode
*----------------------------------------------------------------------*
FORM get_mode CHANGING fp_mode TYPE c.
  DATA lw_answer(1) TYPE c.

* If program is running in batch => mode = batch mode
  IF sy-batch NE space.
    fp_mode = c_mode_batch.
    RETURN.
  ENDIF.

* If program is online, it could be for schedule a batch mode
* or display log of last schedule

* check if a batch mode is running
  PERFORM import_process_list CHANGING s_shared.
* If no previous file loaded, mode => schedule mode
  IF s_shared-param IS INITIAL.
    fp_mode = c_mode_start.
    RETURN.
  ENDIF.

* If previous file loaded, check status of loads
  LOOP AT s_shared-param INTO s_param
       WHERE state = c_state_run OR state = space.
    EXIT.
  ENDLOOP.
* If previous file is running, mode => display log
  IF sy-subrc = 0.
    fp_mode = c_mode_log.
    RETURN.
  ENDIF.

* If previous file is not running (finished/error)
* Ask for display log or deletion
  CALL FUNCTION 'POPUP_TO_CONFIRM'
    EXPORTING
      titlebar              = 'Log found'
      text_question         = 'Last run is stopped. Do you want to display log or load a new file (last log will be lost) ?'
      text_button_1         = 'Display'
      icon_button_1         = 'ICON_DISPLAY'
      text_button_2         = 'Start'
      icon_button_2         = 'ICON_IMPORT'
      default_button        = '1'
      display_cancel_button = c_true
    IMPORTING
      answer                = lw_answer
    EXCEPTIONS
      OTHERS                = 2.
  IF sy-subrc NE 0 OR lw_answer = '1'. "Display
    fp_mode = c_mode_log.
  ELSEIF lw_answer = '2'. "Start
    fp_mode = c_mode_start.
  ELSE.
    MESSAGE 'Cancelled by user action' TYPE c_msg_success.
    LEAVE TO SCREEN  0.
  ENDIF.
ENDFORM.                    " GET_MODE

*&---------------------------------------------------------------------*
*&      Form  DISPLAY_LOG
*&---------------------------------------------------------------------*
*       Display log in ALV
*----------------------------------------------------------------------*
FORM display_log .

  DATA : lt_fieldcat TYPE slis_t_fieldcat_alv,
         ls_fieldcat LIKE LINE OF lt_fieldcat,
         ls_layout TYPE slis_layout_alv.

  PERFORM import_process_list CHANGING s_shared.
  IF s_shared-param IS INITIAL.
    MESSAGE 'No log found' TYPE c_msg_error.
  ENDIF.
  PERFORM update_exec_time.
  PERFORM update_log_title.

* Define layout
  ls_layout-zebra = c_true.
  ls_layout-colwidth_optimize = c_true.
  ls_layout-box_fieldname = 'SELKZ'.
  ls_layout-box_tabname = 'S_SHARED-PARAM'.

* Define field catalog
  ls_fieldcat-fieldname = 'LINE'.
  ls_fieldcat-seltext_m = 'Step'.
  APPEND ls_fieldcat TO lt_fieldcat.
  ls_fieldcat-fieldname = 'PROCESS'.
  ls_fieldcat-seltext_m = 'Process'.
  APPEND ls_fieldcat TO lt_fieldcat.
  ls_fieldcat-fieldname = 'OBJECT'.
  ls_fieldcat-seltext_m = 'Object'.
  ls_fieldcat-hotspot = c_true.
  APPEND ls_fieldcat TO lt_fieldcat.
  ls_fieldcat-fieldname = 'PARAM'.
  ls_fieldcat-seltext_m = 'Parameters'.
  ls_fieldcat-hotspot = space.
  APPEND ls_fieldcat TO lt_fieldcat.
  ls_fieldcat-fieldname = 'COMMENT'.
  ls_fieldcat-seltext_m = 'Comment'.
  APPEND ls_fieldcat TO lt_fieldcat.
  ls_fieldcat-fieldname = 'EXEC_TIME'.
  ls_fieldcat-seltext_m = 'Exec. Time'.
  ls_fieldcat-do_sum = c_true.
  APPEND ls_fieldcat TO lt_fieldcat.
  ls_fieldcat-fieldname = 'STATE'.
  ls_fieldcat-seltext_m = 'State'.
  ls_fieldcat-do_sum = space.
  ls_fieldcat-icon = c_true.
  APPEND ls_fieldcat TO lt_fieldcat.

* Search line to focus
* Try to find the active line
  READ TABLE s_shared-param INTO s_param WITH KEY state = c_state_run.
* If no active line, try to find the aborted line
  IF sy-subrc NE 0.
    READ TABLE s_shared-param INTO s_param WITH KEY state = c_state_abort.
* If no aborted, try to find the first error line
    IF sy-subrc NE 0.
      READ TABLE s_shared-param INTO s_param WITH KEY state = c_state_ko.
    ENDIF.
  ENDIF.
* Line found, select it (will be focused on first display)
  IF sy-subrc = 0.
    s_param-selkz = 'X'.
    MODIFY s_shared-param FROM s_param INDEX sy-tabix.
  ENDIF.

* Display popup ALV
  CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY'
    EXPORTING
      is_layout                = ls_layout
      it_fieldcat              = lt_fieldcat
      i_save                   = 'A'
      i_callback_program       = sy-cprog
      i_callback_user_command  = 'ALV_USER_COMMAND'
      i_callback_pf_status_set = 'ALV_SET_STATUS'
    TABLES
      t_outtab                 = s_shared-param
    EXCEPTIONS
      program_error            = 1
      OTHERS                   = 2.
  IF sy-subrc <> 0.
    MESSAGE 'Cannot display process log' TYPE c_msg_error.
  ENDIF.

ENDFORM.                    " DISPLAY_LOG

*&---------------------------------------------------------------------*
*&      Form  alv_user_command
*&---------------------------------------------------------------------*
*       Specific User command for ALV log display
*       Called by REUSE_ALV_GRID_DISPLAY
*----------------------------------------------------------------------*
*      -->FP_UCOMM     Function code
*      -->FP_SELFIELD  Selected line
*----------------------------------------------------------------------*
FORM alv_user_command USING fp_ucomm TYPE sy-ucomm          "#EC CALLED
                            fp_selfield TYPE slis_selfield.
  DATA : lt_joblog TYPE TABLE OF tbtc5,
         ls_joblog LIKE LINE OF lt_joblog,
         lw_found(1) TYPE c,
         lw_dummy(1) TYPE c,                                "#EC NEEDED
         lw_step TYPE string,
         lw_button_2(30) TYPE c,
         lw_string(10) TYPE c,
         lw_start_line TYPE i,
         lw_answer(1) TYPE c,
         lt_report TYPE TABLE OF string,
         lt_joblist TYPE tbtcjob_ttyp,
         ls_jobparam TYPE btcselect,
         lt_icubes TYPE rssm_t_icube,
         lw_table TYPE tabname,
         lt_string TYPE TABLE OF string,
         lw_type TYPE e071-object,
         lw_object TYPE e071-obj_name,
         lw_count TYPE i,
         lt_fieldcat TYPE slis_t_fieldcat_alv,
         ls_fieldcat LIKE LINE OF lt_fieldcat,
         lt_param_bkp LIKE s_shared-param,
         ls_param_bkp LIKE s_param,
         lw_total TYPE t,
         lw_total_last TYPE t,
         lw_days TYPE i,
         lw_days_char(10) TYPE c,
         lw_message(100) TYPE c.
  DATA : lt_rows TYPE lvc_t_row,
         ls_rows LIKE LINE OF lt_rows.

  CASE fp_ucomm.
* On dbl click on a line, display SM37 log related to this step
    WHEN '&IC1' OR 'DETAIL'.
      IF fp_selfield-tabindex IS INITIAL.
        RETURN.
      ENDIF.
      READ TABLE s_shared-param INTO s_param INDEX fp_selfield-tabindex.
      IF sy-subrc NE 0.
        RETURN.
      ENDIF.
* Click on an object, display object instead of SM37
      IF fp_selfield-fieldname = 'OBJECT' AND fp_ucomm = '&IC1'.
        IF s_param-process(1) = '@'.
          s_param-process = s_param-process+5.
        ENDIF.
        CASE s_param-process.
          WHEN c_action_del_dso
          OR c_action_del_cube
          OR c_action_activ_dso
          OR c_action_del_dim
          OR c_action_del_index
          OR c_action_index.
            SPLIT s_param-object AT c_separator_param INTO TABLE lt_icubes.
            CALL FUNCTION 'RSSM_CALL_ICUBE_PFLEGE'
              EXPORTING
                e_content_first = c_true
              TABLES
                e_t_icube       = lt_icubes
              EXCEPTIONS
                OTHERS          = 2.
            IF sy-subrc <> 0.
              RETURN.
            ENDIF.
          WHEN c_action_dbstat.
* search if object is cube or table
            SELECT SINGLE infocube
                   INTO s_param-object
                   FROM rsdcube
                   WHERE infocube = s_param-object
                   AND objvers = c_version_active
                   AND ( cubetype = 'A' OR cubetype = 'B' ).
            IF sy-subrc = 0. "cube, goto manage
              SPLIT s_param-object AT c_separator_param INTO TABLE lt_icubes.
              CALL FUNCTION 'RSSM_CALL_ICUBE_PFLEGE'
                EXPORTING
                  e_content_first = c_true
                TABLES
                  e_t_icube       = lt_icubes
                EXCEPTIONS
                  OTHERS          = 2.
              IF sy-subrc <> 0.
                RETURN.
              ENDIF.
            ELSE. "table, goto SE11
              lw_table = s_param-object.
              CALL METHOD cl_wb_ddic=>access_ddic_via_manager
                EXPORTING
                  p_obj_name  = lw_table
                  p_obj_type  = 'TABL'
                  p_operation = 'S'. "display
            ENDIF.
          WHEN c_action_abap.
* Display code in SE38
            EDITOR-CALL FOR REPORT s_param-object DISPLAY-MODE.
          WHEN c_action_chain
          OR c_action_trig_ip
          OR c_action_trig_dtp
          OR c_action_trig_dtp_nodata
          OR c_action_process_psa
          OR c_action_del_init
          OR c_action_ip_mode
          OR c_action_ip_sel.
            CASE s_param-process.
              WHEN c_action_chain.
                lw_type = 'RSPC'.
              WHEN c_action_trig_ip
              OR c_action_process_psa
              OR c_action_del_init
              OR c_action_ip_mode
              OR c_action_ip_sel.
                lw_type = 'ISIP'.
              WHEN c_action_trig_dtp
              OR c_action_trig_dtp_nodata.
                lw_type = 'DTPA'.
              WHEN c_action_del_iobj.
                lw_type = 'IOBJ'.
            ENDCASE.

            SPLIT s_param-object AT c_separator_param INTO TABLE lt_string.
            DESCRIBE TABLE lt_string LINES lw_count.
* If more than 1 object on the line, display popup to ask which object display
            IF lw_count > 1.
              REFRESH t_select.
              LOOP AT lt_string INTO s_param-object.
                CLEAR s_select.
                s_select-object = s_param-object.
                APPEND s_select TO t_select.
              ENDLOOP.

* Define field catalog
              REFRESH lt_fieldcat.
              ls_fieldcat-fieldname = 'OBJECT'.
              ls_fieldcat-seltext_m = 'Object'.
              ls_fieldcat-outputlen = 30.
              ls_fieldcat-datatype = 'CHAR'.
              APPEND ls_fieldcat TO lt_fieldcat.

              CALL FUNCTION 'REUSE_ALV_POPUP_TO_SELECT'
                EXPORTING
                  i_checkbox_fieldname = 'CHOSEN'
                  i_tabname            = 'T_SELECT'
                  i_title              = 'Choose obect to display'
                  it_fieldcat          = lt_fieldcat
                TABLES
                  t_outtab             = t_select.
              IF sy-subrc =  0.
                LOOP AT t_select INTO s_select WHERE chosen = c_true.
                  lw_object = s_select-object.
                  IF NOT lw_object IS INITIAL.
                    CALL FUNCTION 'TR_OBJECT_JUMP_TO_TOOL'
                      EXPORTING
                        iv_pgmid    = 'R3TR'
                        iv_object   = lw_type
                        iv_obj_name = lw_object
                        iv_action   = 'SHOW'
                      EXCEPTIONS
                        OTHERS      = 1.
                    IF sy-subrc <> 0.
                      RETURN.
                    ENDIF.
                  ENDIF.
                ENDLOOP.
              ENDIF.
            ELSE.
              READ TABLE lt_string INTO s_param-object INDEX 1.
              lw_object = s_param-object.
              IF NOT lw_object IS INITIAL.
                CALL FUNCTION 'TR_OBJECT_JUMP_TO_TOOL'
                  EXPORTING
                    iv_pgmid    = 'R3TR'
                    iv_object   = lw_type
                    iv_obj_name = lw_object
                    iv_action   = 'SHOW'
                  EXCEPTIONS
                    OTHERS      = 1.
                IF sy-subrc <> 0.
                  RETURN.
                ENDIF.
              ENDIF.
            ENDIF.

* For STOP, clic on object ask to cancel
          WHEN c_action_stop.
* Do not try to cancel if cancel is already asked
            IF NOT s_param-param IS INITIAL.
              RETURN.
            ENDIF.
* Confirm action
            CALL FUNCTION 'POPUP_TO_CONFIRM'
              EXPORTING
                titlebar              = 'Cancel STOP process'
                text_question         = 'Are you sure you want to cancel this STOP process ?'
                default_button        = '2'
                display_cancel_button = space
              IMPORTING
                answer                = lw_answer
              EXCEPTIONS
                OTHERS                = 2.
            IF sy-subrc = 0 AND lw_answer = '1'.
* Get list of process
              PERFORM import_process_list CHANGING s_shared.
              READ TABLE s_shared-param INTO s_param INDEX fp_selfield-tabindex.
* Ask background process to cancel stop
              s_param-param = c_stop_cancel.
              MODIFY s_shared-param FROM s_param INDEX fp_selfield-tabindex
                     TRANSPORTING param.
              PERFORM export_process_list USING s_shared.
* Then refresh display
              PERFORM update_exec_time.
              PERFORM update_log_title.
              fp_selfield-refresh = c_true.
              fp_selfield-row_stable = c_true.
              fp_selfield-col_stable = c_true.
            ENDIF.
            RETURN.
          WHEN OTHERS.
            MESSAGE 'Cannot display this object' TYPE c_msg_error.
        ENDCASE.
        RETURN.
      ENDIF.

* On dbl click on a line, display SM37 log related to this step
      IF s_param-state NE c_state_ok
      AND s_param-state NE c_state_ko
      AND s_param-state NE c_state_run
      AND s_param-state NE c_state_abort.
        MESSAGE 'No log to display for this step' TYPE c_msg_error.
      ENDIF.

* Get logs from job number/name
      CALL FUNCTION 'BP_JOBLOG_READ'
        EXPORTING
          jobcount  = s_shared-jobcount
          jobname   = s_shared-jobname
        TABLES
          joblogtbl = lt_joblog
        EXCEPTIONS
          OTHERS    = 0.

* Delete the "Job finish" end message
      DELETE lt_joblog WHERE msgid = '00' AND msgno = '517'.

* Scan all message to keep only current step lines
* Step begin by a message like this :
* *** Triggering process <process number> : <process type > or <object>
      lw_found = space.
      LOOP AT lt_joblog INTO ls_joblog.
* Search the good process
        IF lw_found = space.
* Not a step, delete
          IF ls_joblog-text(3) NE '***'.
            DELETE lt_joblog.
            CONTINUE.
          ENDIF.
* A step line, the good ?
          SPLIT ls_joblog-text AT space
                INTO lw_dummy lw_dummy lw_dummy lw_step lw_dummy.
          IF lw_step = s_param-line.
* Found !
            lw_found = c_true.
          ELSE.
* Not the good process, delete
            DELETE lt_joblog.
            CONTINUE.
          ENDIF.

        ELSE.
* Search if again on the good process
          IF ls_joblog-text(3) = '***'.
            DELETE lt_joblog FROM sy-tabix.
            EXIT.
          ENDIF.
        ENDIF.
      ENDLOOP.
      IF lt_joblog IS INITIAL.
        MESSAGE 'No log to display for this step' TYPE c_msg_error.
      ENDIF.

      LOOP AT lt_joblog INTO ls_joblog.
* Display icon for the message type
        IF ls_joblog-msgtype = c_msg_success.
          lw_step = c_state_ok.
        ELSEIF ls_joblog-msgtype = c_msg_error
        OR ls_joblog-msgtype = c_msg_abort.
          lw_step = c_state_ko.
        ELSE.
          lw_step = c_state_info.
        ENDIF.
* Display date of msg
        WRITE ls_joblog-enterdate TO lw_string.
        CONCATENATE lw_step lw_string INTO lw_step
                    SEPARATED BY space.
* Display time of message
        WRITE ls_joblog-entertime TO lw_string.
        CONCATENATE lw_step lw_string INTO lw_step
                    SEPARATED BY space.
* Display text of message
        CONCATENATE lw_step ls_joblog-text INTO lw_step
                    SEPARATED BY space.
        APPEND lw_step TO lt_report.
      ENDLOOP.

* Display log in popup
      lw_step = s_param-line.
      CONCATENATE 'Display detailed log for step' lw_step
                  INTO lw_step SEPARATED BY space.
      CALL FUNCTION 'C_POPUP_WITH_TABLE_DISPLAY'
        EXPORTING
          endpos_col   = 150
          endpos_row   = 20
          startpos_col = 5
          startpos_row = 5
          titletext    = lw_step
        TABLES
          valuetab     = lt_report.

* Refresh the display
    WHEN 'REFRESH'.
      PERFORM import_process_list CHANGING s_shared.
      PERFORM update_exec_time.
      PERFORM update_log_title.
      fp_selfield-refresh = c_true.
      fp_selfield-row_stable = c_true.
      fp_selfield-col_stable = c_true.

* Delete the log
    WHEN 'DELETE'.
* Cannot delete log for other users
      IF w_display_only = c_true.
        RETURN.
      ENDIF.

* If job is running, stop it before delete the log
      PERFORM check_job_active CHANGING lw_found.
      IF lw_found NE space.
        RETURN.
      ENDIF.

      CLEAR s_shared.
      PERFORM export_process_list USING s_shared.

* Go back to selection screen
* Submit is equivalent of PERFORM main USING c_mode_start
* but avoid screen stack overflow
      SUBMIT zrspc.

* Restart the job
    WHEN 'RESTART'.
* Cannot restart job for other users
      IF w_display_only = c_true.
        RETURN.
      ENDIF.

* Check a step is selected
      IF fp_selfield-tabindex IS INITIAL.
        MESSAGE 'Please select step to restart' TYPE c_msg_error.
        RETURN.
      ENDIF.
      READ TABLE s_shared-param INTO s_param WITH KEY selkz = c_true.
      IF sy-subrc NE 0.
        READ TABLE s_shared-param INTO s_param INDEX fp_selfield-tabindex.
      ENDIF.
      IF sy-subrc NE 0.
        RETURN.
      ENDIF.
      lw_start_line = s_param-line.

      PERFORM check_job_active CHANGING lw_found.
      IF lw_found NE space.
        RETURN.
      ENDIF.

* Ask for restart process from selected step
      lw_button_2 = lw_step = lw_start_line.
      CONCATENATE 'Do you want to restart only selected step(s) or all process from step'
                  lw_step '?' INTO lw_step SEPARATED BY space.
      CONCATENATE 'All from' lw_button_2 INTO lw_button_2
                  SEPARATED BY space.

      CALL FUNCTION 'POPUP_TO_CONFIRM'
        EXPORTING
          titlebar              = 'Restart process'
          text_question         = lw_step
          default_button        = '2'
          text_button_1         = 'Only Select.'
          text_button_2         = lw_button_2
          display_cancel_button = c_true
        IMPORTING
          answer                = lw_answer
        EXCEPTIONS
          OTHERS                = 2.
* Restart all from selected step
      IF sy-subrc = 0 AND lw_answer = '2'.
        PERFORM import_process_list CHANGING s_shared.
        LOOP AT s_shared-param INTO s_param.
          IF s_param-line LT lw_start_line.
            s_param-state = c_state_skip.
          ELSE.
            CLEAR : s_param-start_time, s_param-start_date,
                    s_param-end_date, s_param-end_time,
                    s_param-exec_time, s_param-state.
          ENDIF.
          MODIFY s_shared-param FROM s_param.
        ENDLOOP.
        PERFORM start_batch.
        PERFORM update_log_title.
        fp_selfield-refresh = c_true.
        fp_selfield-row_stable = c_true.
        fp_selfield-col_stable = c_true.
* Restart only selected steps
      ELSEIF sy-subrc = 0 AND lw_answer = '1'.
        lt_param_bkp = s_shared-param.
        PERFORM import_process_list CHANGING s_shared.
        LOOP AT s_shared-param INTO s_param.
          READ TABLE lt_param_bkp INTO ls_param_bkp INDEX sy-tabix.
          IF ls_param_bkp-selkz = space.
            s_param-state = c_state_skip.
          ELSE.
            CLEAR : s_param-start_time, s_param-start_date,
                    s_param-end_date, s_param-end_time,
                    s_param-exec_time, s_param-state.
          ENDIF.
          MODIFY s_shared-param FROM s_param.
        ENDLOOP.
        PERFORM start_batch.
        PERFORM update_log_title.
        fp_selfield-refresh = c_true.
        fp_selfield-row_stable = c_true.
        fp_selfield-col_stable = c_true.
      ELSE.
* Cancel
        MESSAGE 'Cancelled by user action' TYPE c_msg_success.
      ENDIF.

* Start SM37 on current job
    WHEN 'JOBS'.

* Get job detail
      ls_jobparam-jobname   = s_shared-jobname.
      ls_jobparam-jobcount  = s_shared-jobcount.
      CALL FUNCTION 'BP_JOB_SELECT'
        EXPORTING
          jobselect_dialog  = 'N'
          jobsel_param_in   = ls_jobparam
        IMPORTING
          jobsel_param_out  = ls_jobparam
        TABLES
          jobselect_joblist = lt_joblist
        EXCEPTIONS
          OTHERS            = 8.

* Display job in SM37
      IF sy-subrc = 0.
        CALL FUNCTION 'BP_JOBLIST_PROCESSOR_SM37B'
          EXPORTING
            joblist_opcode = 22 "btc_joblist_show
          TABLES
            joblist        = lt_joblist
          EXCEPTIONS
            OTHERS         = 4.
      ENDIF.
      IF sy-subrc <> 0.
        MESSAGE 'Cannot display SM37' TYPE c_msg_error.
      ENDIF.
    WHEN 'CHANGELOG'.
      PERFORM ask_log.
      PERFORM import_process_list CHANGING s_shared.
      PERFORM update_exec_time.
      PERFORM update_log_title.
      fp_selfield-refresh = c_true.
    WHEN 'CALC'.
      PERFORM get_exec_time USING c_true CHANGING lw_message lw_count.
      lw_string = lw_count.
      CONDENSE lw_string.
      CONCATENATE 'Total execution time of selection (' lw_string 'lines) :'
                  lw_message INTO lw_message SEPARATED BY space.
      MESSAGE lw_message TYPE c_msg_info.
    WHEN 'STOP'.
      PERFORM check_job_active CHANGING lw_found.
      IF lw_found = space.
        MESSAGE 'Job stopped' TYPE c_msg_success.
      ENDIF.
    WHEN 'FOCUS'.
      CLEAR ls_rows-index.
* Try to find the active line
      READ TABLE s_shared-param INTO s_param WITH KEY state = c_state_run.
* If no active line, try to find the aborted line
      IF sy-subrc NE 0.
        READ TABLE s_shared-param INTO s_param WITH KEY state = c_state_abort.
* If no aborted, try to find the first error line
        IF sy-subrc NE 0.
          READ TABLE s_shared-param INTO s_param WITH KEY state = c_state_ko.
        ENDIF.
      ENDIF.
      IF sy-subrc = 0.
        ls_rows-index = sy-tabix.
        REFRESH lt_rows.
        APPEND ls_rows TO lt_rows.
        CALL METHOD o_grid->set_selected_rows
          EXPORTING
            it_index_rows = lt_rows.
      ENDIF.
  ENDCASE.

ENDFORM.                    "alv_user_command

*&---------------------------------------------------------------------*
*&      Form  alv_set_status
*&---------------------------------------------------------------------*
*       Set pf status for alv display
*       Like original  with new focde :
*       DELETE, REFRESH, RESTART, STOP, JOB, FOCUS
*       Called by REUSE_ALV_GRID_DISPLAY
*----------------------------------------------------------------------*
*      -->RT_EXTAB   Fcode Exclusion List
*----------------------------------------------------------------------*
FORM alv_set_status USING rt_extab TYPE slis_t_extab .      "#EC CALLED
  IF w_display_only = c_true.
* Cannot delete log for other users
    APPEND 'DELETE' TO rt_extab.
* Cannot restart job for other users
    APPEND 'RESTART' TO rt_extab.
  ENDIF.
  SET PF-STATUS 'LOG' EXCLUDING rt_extab[].

* Get the grid object
  IF o_grid IS INITIAL.
    CALL FUNCTION 'GET_GLOBALS_FROM_SLVC_FULLSCR'
      IMPORTING
        e_grid = o_grid.
  ENDIF.

ENDFORM.                    "set_status

*&---------------------------------------------------------------------*
*&      Form  ASK_LOG
*&---------------------------------------------------------------------*
*       Get list of log recorded in shared buffer
*       - Display error if no log
*       - Use log if only one
*       - Ask which log to use if many
*----------------------------------------------------------------------*
FORM ask_log.
  DATA : lo_shbuff TYPE REF TO cl_abap_expimp_shbuf,
         lt_keytab TYPE TABLE OF string,
         lw_lines TYPE i,
         lw_key TYPE string,
         lw_user TYPE sy-uname,
         lt_values TYPE TABLE OF seahlpres,
         ls_value LIKE LINE OF lt_values,
         lt_fields TYPE TABLE OF dfies,
         ls_field LIKE LINE OF lt_fields,
         lt_result TYPE TABLE OF ddshretval,
         ls_result LIKE LINE OF lt_result.

  CREATE OBJECT lo_shbuff.

  CALL METHOD lo_shbuff->get_keys
    EXPORTING
      tabname     = 'INDX'
      area        = 'ST'
      id          = 'ZRSPC_'
      generic_key = c_true
    IMPORTING
      keytab      = lt_keytab.

* If no log available, display error
  IF lt_keytab[] IS INITIAL.
    MESSAGE 'No log available' TYPE c_msg_error.
  ENDIF.
  DESCRIBE TABLE lt_keytab LINES lw_lines.

* If only 1 log available, display it
  IF lw_lines = 1.
    READ TABLE lt_keytab INTO lw_key INDEX 1.
    lw_user = lw_key+43.
    PERFORM build_shared_id USING lw_user.
    RETURN.
  ENDIF.

* If many logs available, ask which one to display
  LOOP AT lt_keytab INTO lw_key.
    lw_user = lw_key+43.
    APPEND lw_user TO lt_values.
    CLEAR ls_value.
    SELECT SINGLE name_text INTO ls_value
           FROM v_username
           WHERE bname = lw_user.
    APPEND ls_value TO lt_values.
  ENDLOOP.

  CALL FUNCTION 'DDIF_FIELDINFO_GET'
    EXPORTING
      tabname    = 'SYST'
      lfieldname = 'UNAME'
    IMPORTING
      dfies_wa   = ls_field.
  APPEND ls_field TO lt_fields.
  CALL FUNCTION 'DDIF_FIELDINFO_GET'
    EXPORTING
      tabname    = 'ADRP'
      lfieldname = 'NAME_TEXT'
    IMPORTING
      dfies_wa   = ls_field.
  APPEND ls_field TO lt_fields.

  CALL FUNCTION 'F4IF_INT_TABLE_VALUE_REQUEST'
    EXPORTING
      retfield     = 'UNAME'
      window_title = 'Log list'
    TABLES
      value_tab    = lt_values
      field_tab    = lt_fields
      return_tab   = lt_result.

  READ TABLE lt_result INTO ls_result INDEX 1.
  IF sy-subrc NE 0.
    MESSAGE 'Action cancelled' TYPE c_msg_error.
    RETURN.
  ENDIF.
  lw_user = ls_result-fieldval.
  PERFORM build_shared_id USING lw_user.
  RETURN.
ENDFORM.                    " ASK_LOG

*&---------------------------------------------------------------------*
*&      Form  SEND_MAIL
*&---------------------------------------------------------------------*
*       Send report by email
*----------------------------------------------------------------------*
FORM send_mail .
  DATA : lt_content TYPE soli_tab,
         ls_userdet TYPE rsplppm_s_userdetails,
         lw_state(8) TYPE c,
         lw_subject TYPE so_obj_des,
         lo_mail TYPE REF TO cl_bcs, "Mail object
         lo_content TYPE REF TO cl_document_bcs, "Mail content
         lo_sender TYPE REF TO cl_sapuser_bcs, "Mail sender
         lo_recipient TYPE REF TO if_recipient_bcs, "Mail recipient
         lo_bcs TYPE REF TO cx_bcs, "Mail exception
         lw_message(100) TYPE c,
         lw_count TYPE i.

* Macro to write HTML
  DEFINE c.
    append &1 to lt_content.
  END-OF-DEFINITION.

  MESSAGE '***Mail report generation' TYPE c_msg_success.

* Write mail content
  c '<html>'.
  c '<head>'.
  c '<meta http-equiv="content-type"'.
  c ' content="text/html; charset=utf-8">'.
  c '<title>Automate action - LOG</title>'.
  c '<style type="text/css">'.
  c 'table{padding:0;margin:0;}'.
  c 'strong{font-weight:bold;color:#FF6600;}'.
  c '</style>'.
  c '</head>'.
  c '<body>'.
  c '<p>Log for job <strong>'.
  c s_shared-jobname.
  c '</strong></p><table cellpadding=0 cellspacing=0 border=0 width=100%>'.
  c '<tr><th>Step</th><th>Process</th><th>Object</th>'.
  c '<th>Parameters</th><th>Comment</th><th>State</th>'.
  c '<th>Exec Time</th></tr>'.
  LOOP AT s_shared-param INTO s_param.
* Process Success
    IF s_param-state = c_state_ok. "green
      c '<tr bgcolor=#66CC66><td>&nbsp;'.
      lw_state = 'OK'.
* Process skiped
    ELSEIF s_param-state = c_state_skip.
      c '<tr bgcolor=#66CCFF><td>&nbsp;'. "blue
      lw_state = 'SKIP'.
* Process in error
    ELSEIF s_param-state = c_state_ko
        OR s_param-state = c_state_abort
        OR s_param-state = c_state_run.
      c '<tr bgcolor=#FF6666><td>&nbsp;'. "red
      lw_state = 'KO'.
* Not processed - Append for process after a process in error
    ELSE.
      c '<tr><td>&nbsp;'.
      lw_state = ''.
    ENDIF.
    c s_param-line.
    c '</td><td>'.
    IF s_param-process(1) = '@'.
      s_param-process = s_param-process+5.
    ENDIF.
    c s_param-process.
    c '</td><td>&nbsp;'.
    c s_param-object.
    c '</td><td>&nbsp;'.
    c s_param-param.
    c '</td><td>&nbsp;'.
    c s_param-comment.
    c '</td><td>&nbsp;'.
    c lw_state.
    c '</td><td>&nbsp;'.
    WRITE s_param-exec_time TO lw_state.
    c lw_state.
    c '</td></tr>'.
  ENDLOOP.
* Add a total line
  c '<tr bgcolor=#FFFF66 style="padding-top:10px;"><td>&nbsp;</td>'.
  c '<td colspan=5><b>Total execution time</b></td><td>&nbsp;<b>'.
  PERFORM get_exec_time USING space CHANGING lw_message lw_count.
  c lw_message.
  c '</b></td></tr>'.
  c '</table>'.

* Get the email of current user
  CLEAR ls_userdet.
  CALL FUNCTION 'RSPLPPM_GET_USERDETAILS'
    EXPORTING
      i_user          = sy-uname
    IMPORTING
      e_s_userdetails = ls_userdet.
  IF ls_userdet-email IS INITIAL.
    MESSAGE 'Cannot send email as recipient have not email defined'
             TYPE c_msg_error.
  ENDIF.

* Remove all unused spaces
  PERFORM compress_email CHANGING lt_content.

* Catch object errors
  TRY.
* Create mail object
      lo_mail = cl_bcs=>create_persistent( ).
      lw_subject = '[' && sy-sysid && ']' && ' Chain BW Process - Log'.

* Create mail content object
      CALL METHOD cl_document_bcs=>create_document
        EXPORTING
          i_type    = 'HTM'
          i_subject = lw_subject
          i_text    = lt_content
        RECEIVING
          result    = lo_content.

* Link the mail content object to the mail object
      CALL METHOD lo_mail->set_document
        EXPORTING
          i_document = lo_content.

* Define sender as current user
* It require that current user have an email defined
      lo_sender = cl_sapuser_bcs=>create( sy-uname ).
      CALL METHOD lo_mail->set_sender
        EXPORTING
          i_sender = lo_sender.

* Define receiver list
      lo_recipient =
      cl_cam_address_bcs=>create_internet_address( ls_userdet-email ).

* Add receiver to the receiver list
      CALL METHOD lo_mail->add_recipient
        EXPORTING
          i_recipient = lo_recipient.

* Define mail attributes
      CALL METHOD lo_mail->set_status_attributes
        EXPORTING
          i_requested_status = 'N'
          i_status_mail      = 'N'.

* Set mail to be immediatly send (no batch wait)
      lo_mail->set_send_immediately( c_true ).

* Send the mail
      CALL METHOD lo_mail->send( ).
      COMMIT WORK.
      MESSAGE 'Mail sent' TYPE c_msg_success.

* Any Exception during process ?
    CATCH cx_bcs INTO lo_bcs.
      lw_message = lo_bcs->get_text( ).
      MESSAGE lw_message TYPE c_msg_error.
  ENDTRY.

ENDFORM.                    " SEND_MAIL

*&---------------------------------------------------------------------*
*&      Form  IMPORT_PROCESS_LIST
*&---------------------------------------------------------------------*
*       Import the process list from memory
*----------------------------------------------------------------------*
FORM import_process_list CHANGING fs_shared LIKE s_shared.
  IMPORT fs_shared FROM SHARED BUFFER indx(st) ID w_shared_param.
ENDFORM.                    " IMPORT_PROCESS_LIST

*&---------------------------------------------------------------------*
*&      Form  EXPORT_PROCESS_LIST
*&---------------------------------------------------------------------*
*       Export the process list to memory
*----------------------------------------------------------------------*
FORM export_process_list USING fs_shared LIKE s_shared.
  EXPORT fs_shared TO SHARED BUFFER indx(st) ID w_shared_param.
ENDFORM.                    " EXPORT_PROCESS_LIST

*&---------------------------------------------------------------------*
*&      Form  UPDATE_EXEC_TIME
*&---------------------------------------------------------------------*
*       Check if job is cancelled to update the "running" status
*       Update execution time for process not finished
*----------------------------------------------------------------------*
FORM update_exec_time .
  DATA lw_status TYPE tbtcjob-status.

  CALL FUNCTION 'BP_JOB_STATUS_GET'
    EXPORTING
      jobcount = s_shared-jobcount
      jobname  = s_shared-jobname
    IMPORTING
      status   = lw_status
    EXCEPTIONS
      OTHERS   = 4.
  IF sy-subrc = 0 AND lw_status = 'A'.
    LOOP AT s_shared-param INTO s_param WHERE state = c_state_run.
      s_param-state = c_state_abort.
      MODIFY s_shared-param FROM s_param.
    ENDLOOP.
    RETURN.
  ENDIF.

  LOOP AT s_shared-param INTO s_param WHERE start_date IS NOT INITIAL
                                      AND end_date IS INITIAL.

    s_param-exec_time = ( sy-datum - s_param-start_date ) *  86400
                        + sy-uzeit - s_param-start_time.
    MODIFY s_shared-param FROM s_param.
  ENDLOOP.
ENDFORM.                    " UPDATE_EXEC_TIME

*&---------------------------------------------------------------------*
*&      Form  update_log_title
*&---------------------------------------------------------------------*
*       Set how many process remain to process
*       and total exec time in the title
*----------------------------------------------------------------------*
FORM update_log_title.
  DATA : lw_remain TYPE i,
         lw_total TYPE i,
         lw_msg(15) TYPE c.
  CLEAR : lw_remain, lw_total.

  DESCRIBE TABLE s_shared-param LINES lw_total.

  LOOP AT s_shared-param INTO s_param.
* Count how many process remain to execute
    IF s_param-state = c_state_ko
    OR s_param-state = c_state_run
    OR s_param-state = c_state_abort
    OR s_param-state = space.
      lw_remain = lw_remain + 1.
    ENDIF.

* Update Process type field to add icon
    CASE s_param-process.
      WHEN c_action_del_dim
        OR c_action_del_iobj
        OR c_action_del_dso
        OR c_action_del_cube
        OR c_action_del_index
        OR c_action_del_init.
        CONCATENATE '@11@' s_param-process "icon delete
                    INTO s_param-process SEPARATED BY space.
      WHEN c_action_trig_ip.
        CONCATENATE '@9N@' s_param-process "icon IP
                    INTO s_param-process SEPARATED BY space.
      WHEN c_action_ip_mode OR c_action_ip_sel.
        CONCATENATE '@8W@' s_param-process "icon play/param
                    INTO s_param-process SEPARATED BY space.
      WHEN c_action_trig_dtp "icon DTP
        OR c_action_trig_dtp_nodata.
        CONCATENATE '@VK@' s_param-process
                    INTO s_param-process SEPARATED BY space.
      WHEN c_action_chain. "icon chain
        CONCATENATE '@CQ@' s_param-process
                    INTO s_param-process SEPARATED BY space.
      WHEN c_action_activ_dso "icon activation
        OR c_action_activate_obj.
        CONCATENATE '@3C@' s_param-process
                    INTO s_param-process SEPARATED BY space.
      WHEN c_action_index "icon index
        OR c_action_dbstat.
        CONCATENATE '@JH@' s_param-process
                    INTO s_param-process SEPARATED BY space.
      WHEN c_action_abap. "icon abap
        CONCATENATE '@9U@' s_param-process
                    INTO s_param-process SEPARATED BY space.
      WHEN c_action_process_psa. "icon process psa
        CONCATENATE '@9P@' s_param-process
                    INTO s_param-process SEPARATED BY space.
      WHEN c_action_stop. "icon stop
        CONCATENATE '@8N@' s_param-process
                    INTO s_param-process SEPARATED BY space.
        IF s_param-param = c_stop_cancel.
          s_param-param = 'Cancel is on going. Please wait...'.
        ELSE.
          s_param-object = 'Clic to cancel STOP'.
        ENDIF.
      WHEN c_action_wait. "icon clock
        CONCATENATE '@1T@' s_param-process
                    INTO s_param-process SEPARATED BY space.
      WHEN c_action_export_ds. "icon loop arrow
        CONCATENATE '@5U@' s_param-process
                    INTO s_param-process SEPARATED BY space.
      WHEN c_action_replicate_ds. "icon source system
        CONCATENATE '@6K@' s_param-process
                    INTO s_param-process SEPARATED BY space.
      WHEN OTHERS. "desactivated process
        CONCATENATE '@00@' s_param-process
                    INTO s_param-process SEPARATED BY space.
    ENDCASE.
    MODIFY s_shared-param FROM s_param.
  ENDLOOP.

* Display how many steps stay to process
* except if all process is finished
  IF lw_remain NE 0.
    lw_msg = lw_remain.
    CONDENSE lw_msg NO-GAPS.
    CONCATENATE 'Remaining steps:' lw_msg
                INTO sy-title
                SEPARATED BY space.
    lw_msg = lw_total.
    CONDENSE lw_msg NO-GAPS.
    CONCATENATE sy-title '/' lw_msg
                INTO sy-title.
  ELSE.
    sy-title = 'Chain BW Process finished'.
  ENDIF.

* Display total execution time
  PERFORM get_exec_time USING space CHANGING lw_msg lw_total.
  CONCATENATE sy-title '- Total exec time:' lw_msg
              INTO sy-title
              SEPARATED BY space.
ENDFORM.                    "update_log_title

*&---------------------------------------------------------------------*
*&      Form  CHECK_JOB_ACTIVE
*&---------------------------------------------------------------------*
*       Check if job is running and ask to stop it
*----------------------------------------------------------------------*
*      <--FP_CANCEL  =X if user cancel action
*----------------------------------------------------------------------*
FORM check_job_active  CHANGING fp_cancel TYPE c.
  DATA : lw_found(1) TYPE c,
         lw_answer(1) TYPE c.

* Reset output flag
  CLEAR fp_cancel.

* Check if job is running
  CALL FUNCTION 'SHOW_JOBSTATE'
    EXPORTING
      jobcount = s_shared-jobcount
      jobname  = s_shared-jobname
    IMPORTING
      running  = lw_found
    EXCEPTIONS
      OTHERS   = 4.
* If job run, ask for cancel active job or cancel action
  IF sy-subrc = 0 AND lw_found NE space.
    CALL FUNCTION 'POPUP_TO_CONFIRM'
      EXPORTING
        titlebar              = 'Job jound'
        text_question         = 'There is a job running for this process list. Abort this job or cancel operation ?'
        text_button_1         = 'Abort job'
        icon_button_1         = 'ICON_STOP'
        text_button_2         = 'Cancel'
        icon_button_2         = 'ICON_BACK'
        default_button        = '2'
        display_cancel_button = space
      IMPORTING
        answer                = lw_answer
      EXCEPTIONS
        OTHERS                = 2.
    IF sy-subrc = 0 AND lw_answer = '1'.
* Cancel active job
      CALL FUNCTION 'BP_JOB_ABORT'
        EXPORTING
          jobcount = s_shared-jobcount
          jobname  = s_shared-jobname
        EXCEPTIONS
          OTHERS   = 6.
      IF sy-subrc <> 0.
        fp_cancel = c_true.
        MESSAGE 'Job cancellation failled' TYPE c_msg_error.
      ELSE.
* On job cancellation, send end mail.
        IF s_shared-mail = c_true.
          PERFORM send_mail.
        ENDIF.
      ENDIF.
    ELSE.
* Cancel action
      MESSAGE 'Cancelled by user action' TYPE c_msg_success.
      fp_cancel = c_true.
      RETURN.
    ENDIF.
  ENDIF.
ENDFORM.                    " CHECK_JOB_ACTIVE

*&---------------------------------------------------------------------*
*&      Form  BUILD_SHARED_ID
*&---------------------------------------------------------------------*
*       Build ID for shared buffer
*----------------------------------------------------------------------*
*      -->FP_UNAME  Username
*----------------------------------------------------------------------*
FORM build_shared_id USING fp_uname TYPE sy-uname.

  CONCATENATE 'ZRSPC_' fp_uname INTO w_shared_param.
  IF fp_uname = sy-uname.
    w_display_only = space.
  ELSE.
    w_display_only = c_true.
  ENDIF.
ENDFORM.                    " BUILD_SHARED_ID

*&---------------------------------------------------------------------*
*&      Form  get_exec_time
*&---------------------------------------------------------------------*
*       Calculate total execution time
*----------------------------------------------------------------------*
*      -->FP_FILTER  Calculate the time only for selected lines
*      <--FP_TIME    Total execution time
*      <--FP_SEL     Number of lines selected
*----------------------------------------------------------------------*
FORM get_exec_time USING fp_filter
                   CHANGING fp_time TYPE c
                            fp_sel TYPE i.
  DATA : lw_count TYPE i,
         lw_time TYPE t.
  CLEAR fp_sel.
  LOOP AT s_shared-param INTO s_param.
    IF fp_filter NE space.
      CHECK s_param-selkz = c_true.
    ENDIF.
    lw_count = lw_count + s_param-exec_time.
    fp_sel = fp_sel + 1.
  ENDLOOP.
  CLEAR fp_time.
  lw_time = lw_count.
  IF lw_count GE 86400.
    lw_count = lw_count DIV 86400.
    fp_time = lw_count.
    CONCATENATE fp_time 'd' INTO fp_time.
    CONDENSE fp_time NO-GAPS.
    WRITE lw_time TO fp_time+3.
  ELSE.
    WRITE lw_time TO fp_time.
  ENDIF.
ENDFORM.                    "get_exec_time

*######################################################################*
*
*                     FILE ACTION SUBROUTINE SECTION
*
*######################################################################*

*&---------------------------------------------------------------------*
*&      Form  ACT_DSO                                          @Cabrita
*&---------------------------------------------------------------------*
*       Subroutine to perform process ACT_DSO
*       Activation of datastore object
*----------------------------------------------------------------------*
*      -->FP_PARAM   Line of the file
*      <--FP_SUBRC   Return code (<> 0 if error during process)
*----------------------------------------------------------------------*
FORM act_dso USING fp_param LIKE s_param                    "#EC CALLED
             CHANGING fp_subrc TYPE i.
  TYPE-POOLS rssm. "no more required in BI7.3

  DATA : lw_error TYPE  rs_bool,
         lw_dso(30) TYPE c,
         lw_nocondense TYPE rsodsnocondense.

  lw_dso = fp_param-object.
  IF fp_param-param IS INITIAL.
    lw_nocondense = space.
  ELSE.
    lw_nocondense = c_true.
  ENDIF.
* Call activation
  CALL FUNCTION 'RSSM_PROCESS_ODSACTIVATE'
    EXPORTING
      i_odsobject   = lw_dso
      i_jobname     = space
      i_no_condense = lw_nocondense
    IMPORTING
      e_error       = lw_error.

  IF NOT lw_error IS INITIAL.
    fp_subrc = 8.
    RETURN.
  ENDIF.

ENDFORM. " act_dso

*&---------------------------------------------------------------------*
*&      Form CALL_ABAP
*&---------------------------------------------------------------------*
*       Subroutine to perform process CALL_ABAP
*       Execute ABAP Program with variant
*----------------------------------------------------------------------*
*      -->FP_PARAM   Line of the file
*      <--FP_SUBRC   Return code (<> 0 if error during process)
*----------------------------------------------------------------------*
FORM call_abap USING fp_param LIKE s_param                  "#EC CALLED
               CHANGING fp_subrc TYPE i.

  DATA : lw_program TYPE sobj_name,
         lw_variant TYPE variant.

  lw_program = fp_param-object.
  lw_variant = fp_param-param.
  SUBMIT (lw_program) USING SELECTION-SET lw_variant AND RETURN.

  IF NOT sy-subrc = 0.
    fp_subrc = 8.
  ENDIF.
ENDFORM.                    "CALL_ABAP

*&---------------------------------------------------------------------*
*&      Form  del_cube                                         @Cabrita
*&---------------------------------------------------------------------*
*       Subroutine to perform process DEL_CUBE
*       Deletes records in infocube according to a where clause
*       Or complete deletion if where clause is missing
*
*       Param field for DEL_CUBE process is made like this :
*       INFOOBJECT@@OPERATOR@@VALUE|INFOOBJECT@@OPERATOR@@VALUE
*----------------------------------------------------------------------*
*      -->FP_PARAM   Line of the file
*      <--FP_SUBRC   Return code (<> 0 if error during process)
*----------------------------------------------------------------------*
FORM del_cube USING fp_param LIKE s_param                   "#EC CALLED
              CHANGING fp_subrc TYPE i.

* Splitted parameters of a condition (@@ as separator)
  DATA : BEGIN OF ls_param_split,
           infoobject TYPE rsiobjnm,
           option   TYPE rsz_operator,
           low      TYPE rschavl,
           high     TYPE rschavl,
          END OF ls_param_split,
         lt_param_split LIKE STANDARD TABLE OF ls_param_split,
* Splitted condition
         lt_string_param TYPE STANDARD TABLE OF string,
         ls_string_param LIKE LINE OF lt_string_param,

         ls_sel   TYPE rsdrd_sx_sel,  "contains infoobject name + range
         lt_sel   TYPE rsdrd_thx_sel, "parameters of selection
         ls_range TYPE rsdrd_s_range, "range of selections
         lw_target TYPE rsddatatarget, "target in which we delete
         lt_msg   TYPE  rs_t_msg,     "return messages of MF delet. Cube
         lw_count  TYPE f,             "number of lines deleted
         lw_count_int  TYPE integer,   "number of lines deleted
         lw_message TYPE string.

* Complete deletion
  IF fp_param-param IS INITIAL.
    PERFORM del_dta_complete USING fp_param-object
                             CHANGING fp_subrc.
    RETURN.
  ENDIF.

* Selective deletion

* Split different conditions into an internal table
  SPLIT fp_param-param AT c_separator_param INTO TABLE lt_string_param.

* Loop at all the conditions
  LOOP AT lt_string_param INTO ls_string_param.
* Split the parameters of the condition
    SPLIT ls_string_param AT c_separator_cond
                          INTO ls_param_split-infoobject
                               ls_param_split-option
                               ls_param_split-low
                               ls_param_split-high.

    APPEND ls_param_split TO lt_param_split.
  ENDLOOP.

* In the next loop there will be ruptures on infoobject
  SORT lt_param_split BY infoobject.
  REFRESH lt_sel.
* Fill internal table used for data selection to delete
  LOOP AT lt_param_split INTO ls_param_split.
    AT NEW infoobject.
      CLEAR ls_sel.
      ls_sel-iobjnm = ls_param_split-infoobject.
    ENDAT.

    CLEAR ls_range.
    ls_range-sign = 'I'.
    ls_range-option = ls_param_split-option.
    ls_range-low = ls_param_split-low.
    ls_range-high = ls_param_split-high.
    ls_range-keyfl = c_true.
    APPEND ls_range TO ls_sel-t_range.

    AT END OF infoobject.
      INSERT ls_sel INTO TABLE lt_sel.
    ENDAT.
  ENDLOOP.

  lw_target = fp_param-object.

* Deletion of data intoinfocube
  CALL FUNCTION 'RSDRD_SEL_DELETION'
    EXPORTING
      i_datatarget = lw_target
      i_thx_sel    = lt_sel
    IMPORTING
      e_cnt        = lw_count
    CHANGING
      c_t_msg      = lt_msg
    EXCEPTIONS
      OTHERS       = 4.
  IF sy-subrc <> 0.
    fp_subrc = sy-subrc.
    RETURN.
  ENDIF.

  lw_count_int = lw_count.
  lw_message = lw_count_int.
  CONCATENATE lw_message 'lines deleted in cube' fp_param-object
              INTO lw_message SEPARATED BY space.
  CONDENSE lw_message.
  MESSAGE lw_message TYPE c_msg_success.
ENDFORM.                    " del_cube

*&---------------------------------------------------------------------*
*&      Form del_delta_init
*&---------------------------------------------------------------------*
*       Subroutine to perform process DEL_DELTA_INIT
*       Deletes delta init of datasource
*----------------------------------------------------------------------*
*      -->FP_PARAM   Line of the file
*      <--FP_SUBRC   Return code (<> 0 if error during process)
*----------------------------------------------------------------------*
FORM del_delta_init USING fp_param LIKE s_param             "#EC CALLED
                    CHANGING fp_subrc TYPE i.
  TYPE-POOLS sbiwm. "no more required in BI7.3

  DATA : lw_logsys TYPE sbiwm_logsys,
         lw_oltpsource TYPE roosourcer,
         lt_rssdlinit TYPE TABLE OF rssdlinit.

  SELECT SINGLE oltpsource logsys
         INTO (lw_oltpsource, lw_logsys )
         FROM rsldpio
         WHERE logdpid = fp_param-object
         AND objvers = c_version_active.

* Force the init reccord if not already recorded
  PERFORM fill_init_sel IN PROGRAM saplrss1
          USING lw_oltpsource lw_logsys space
          CHANGING fp_subrc.
  CLEAR fp_subrc.
  COMMIT WORK AND WAIT.

* Get list of inits to delete
  SELECT * FROM rssdlinit INTO TABLE lt_rssdlinit WHERE
         oltpsource = lw_oltpsource AND
         logsys     = lw_logsys.

* If found, delete init
  IF NOT lt_rssdlinit[] IS INITIAL.
* Delete init - step 1
    PERFORM del_source_system_init IN PROGRAM saplrssm
                                   TABLES lt_rssdlinit
                                   USING  lw_logsys
                                          lw_oltpsource
                                          space
                                          space
                                   CHANGING fp_subrc.
    IF fp_subrc NE 0.
      RETURN.
    ENDIF.
  ENDIF.

* Delete init - step 2
  CALL FUNCTION 'RSS1_QUEUE_DELETED_IN_OLTP'
    EXPORTING
      i_oltpsource = lw_oltpsource
      i_logsys     = lw_logsys
    EXCEPTIONS
      failed       = 1
      OTHERS       = 2.
  IF sy-subrc NE 0.
    fp_subrc = 8.
    RETURN.
  ENDIF.
ENDFORM.                    " del_delta_init

*&---------------------------------------------------------------------*
*&      Form  del_dso                                          @Cabrita
*&---------------------------------------------------------------------*
*       Subroutine to perform process DEL_DSO
*       Deletes records in active table of a DSO according to
*       a where-clause
*       Or complete deletion if where clause is missing
*----------------------------------------------------------------------*
*      -->FP_PARAM   Line of the file
*      <--FP_SUBRC   Return code (<> 0 if error during process)
*----------------------------------------------------------------------*
FORM del_dso USING fp_param LIKE s_param                    "#EC CALLED
             CHANGING fp_subrc TYPE i.

  DATA : lw_active_table TYPE tabname,
         lw_tabname      TYPE tabname.

  CLEAR : lw_active_table, lw_tabname.

* Complete deletion
  IF fp_param-param IS INITIAL.

    PERFORM del_dta_complete USING fp_param-object
                             CHANGING fp_subrc.
    RETURN.
  ENDIF.

* Selective deletion
* Find the name of active table of the DSO
  CONCATENATE '/BIC/A' fp_param-object '00' INTO lw_active_table.

* Check if the active table exists in ddic
  SELECT SINGLE tabname
    INTO lw_tabname
    FROM dd02l
    WHERE tabname = lw_active_table
    AND as4local = c_version_active.

  IF sy-subrc IS INITIAL.
    SUBMIT z_delete_generic WITH p_table EQ lw_active_table
                            WITH p_where = fp_param-param
                            AND RETURN.
  ELSE.
    fp_subrc = 8.
    RETURN.
  ENDIF.
ENDFORM.                    " del_dso

*&---------------------------------------------------------------------*
*&      Form  DEL_INDEX
*&---------------------------------------------------------------------*
*       Subroutine to perform process DEL_INDEX
*       Delete index for cube
*----------------------------------------------------------------------*
*      -->FP_PARAM   Line of the file
*      <--FP_SUBRC   Return code (<> 0 if error during process)
*----------------------------------------------------------------------*
FORM del_index  USING fp_param LIKE s_param                 "#EC CALLED
                CHANGING fp_subrc TYPE i.

  DATA : lw_cube TYPE rsiccont-icube,
         lt_msg TYPE rs_t_msg.

  lw_cube = fp_param-object.
  PERFORM drop_indexes_from_cube IN PROGRAM saplrsm1
          USING    lw_cube
                   c_true
                   c_true
                   space
          CHANGING lt_msg
                   fp_subrc.

ENDFORM.                    "DEL_INDEX

*&---------------------------------------------------------------------*
*&      Form  DEL_UNUSED_DIM
*&---------------------------------------------------------------------*
*       Subroutine to perform process DEL_UNUSED_DIM
*       Rebuild each dimension in cube to delete non used entries
*----------------------------------------------------------------------*
*      -->FP_PARAM   Line of the file
*      <--FP_SUBRC   Return code (<> 0 if error during process)
*----------------------------------------------------------------------*
FORM del_unused_dim  USING fp_param LIKE s_param            "#EC CALLED
                     CHANGING fp_subrc TYPE i.
  DATA lw_cube TYPE rsdcubev-infocube.

  lw_cube = fp_param-object.
  CALL FUNCTION 'RSDRD_DIM_REMOVE_UNUSED'
    EXPORTING
      i_infocube   = lw_cube
      i_check_only = space
    EXCEPTIONS
      x_message    = 1
      OTHERS       = 2.
  fp_subrc = sy-subrc.
  IF fp_subrc = 0.
    MESSAGE 'Unused dimension values removed' TYPE c_msg_success.
  ENDIF.
ENDFORM.                    "DEL_UNUSED_DIM

*&---------------------------------------------------------------------*
*&      Form  del_unused_iobj
*&---------------------------------------------------------------------*
*       Subroutine to perform process DEL_UNUSED_IOBJ
*       Delete info object values that are not used
*----------------------------------------------------------------------*
*      -->FP_PARAM   Line of the file
*      <--FP_SUBRC   Return code (<> 0 if error during process)
*----------------------------------------------------------------------*
FORM del_unused_iobj USING fp_param LIKE s_param            "#EC CALLED
                     CHANGING fp_subrc TYPE i.
  DATA : lw_iobj TYPE rsdiobjnm,
         lw_result TYPE i.

  lw_iobj = fp_param-object.

  CALL FUNCTION 'RSDMDD_DELETE_MASTER_DATA'
    EXPORTING
      i_iobjnm            = lw_iobj
      i_flag_delete_sids  = c_true
      i_flag_delete_texts = c_true
      i_flag_dialog       = space
      i_flag_force_delete = space
      i_flag_delete_all   = c_true
      i_flag_simulation   = space
    IMPORTING
      e_result            = lw_result.
  CASE lw_result.
    WHEN rsdmd_c_all_deleted.
      MESSAGE s127(rsdmd).
    WHEN rsdmd_c_parts_deleted.
      MESSAGE s128(rsdmd).
    WHEN rsdmd_c_bg_started.
      MESSAGE s114(rsdmd).
    WHEN rsdmd_c_no_data.
      MESSAGE s106(rsdmd) WITH lw_iobj.
    WHEN rsdmd_c_none_deleted.
      MESSAGE s129(rsdmd).
    WHEN rsdmd_c_error.
      fp_subrc = 8.
      RETURN.
  ENDCASE.
ENDFORM.                    "del_unused_iobj

*&---------------------------------------------------------------------*
*&      Form  INDEX
*&---------------------------------------------------------------------*
*       Subroutine to perform process INDEX
*       Create index for cube
*----------------------------------------------------------------------*
*      -->FP_PARAM   Line of the file
*      <--FP_SUBRC   Return code (<> 0 if error during process)
*----------------------------------------------------------------------*
FORM index USING fp_param LIKE s_param                      "#EC CALLED
           CHANGING fp_subrc TYPE i.

  DATA : lw_cube TYPE rsinfocube,
         lw_error(1) TYPE c.

  lw_cube = fp_param-object.
  CALL FUNCTION 'RSSM_PROCESS_INDEX'
    EXPORTING
      i_cube  = lw_cube
    IMPORTING
      e_error = lw_error.
  IF NOT lw_error IS INITIAL.
    fp_subrc = 8.
  ENDIF.
ENDFORM.                    "INDEX

*&---------------------------------------------------------------------*
*&      Form  trig_chain
*&---------------------------------------------------------------------*
*       Subroutine to perform process TRIG_CHAIN
*       Triggers chain process in asynchronous mode
*----------------------------------------------------------------------*
*      -->FP_PARAM   Line of the file
*      <--FP_SUBRC   Return code (<> 0 if error during process)
*----------------------------------------------------------------------*
FORM trig_chain USING fp_param LIKE s_param                 "#EC CALLED
                CHANGING fp_subrc TYPE i.
  DATA : lt_string_param TYPE STANDARD TABLE OF string,
         ls_string_param LIKE LINE OF lt_string_param,
         lw_variant TYPE rspc_variant,
         BEGIN OF ls_run,
           log TYPE rspc_logid,
         END OF ls_run,
         lw_request TYPE rspc_instance,
         lt_run LIKE TABLE OF ls_run,
         lw_count TYPE i,
         lw_message TYPE string,
         lw_chain_status TYPE rspc_state.

* Split different process to start into an internal table
  SPLIT fp_param-object AT c_separator_param
                        INTO TABLE lt_string_param.

* Start all infopackage requested
  LOOP AT lt_string_param INTO ls_string_param.
* Trigger the process
    lw_variant = ls_string_param.
    PERFORM execute_process USING 'CHAIN' lw_variant
                            CHANGING lw_request.

* Exit on error
    IF lw_request IS INITIAL OR sy-subrc NE 0.
      fp_subrc = 8.
      RETURN.
    ENDIF.

* Remember logid to check completion
    ls_run-log = lw_request.
    APPEND ls_run TO lt_run.
  ENDLOOP.

* Check all started chain
  DESCRIBE TABLE lt_run LINES lw_count.
  WHILE lw_count > 0.
* Wait some times between checks to let the server work
    WAIT UP TO c_check_wait SECONDS.

* Check each request
    LOOP AT lt_run INTO ls_run.
      CALL FUNCTION 'RSPC_API_CHAIN_GET_STATUS'
        EXPORTING
          i_chain  = space
          i_logid  = ls_run-log
        IMPORTING
          e_status = lw_chain_status.

      IF lw_chain_status = c_chainstatus_ok.
        CONCATENATE 'Chain run ' ls_run-log 'finished'
                     INTO lw_message SEPARATED BY space.
        MESSAGE lw_message TYPE c_msg_success.

        DELETE lt_run.
        lw_count = lw_count - 1.
        CONTINUE.
      ELSEIF lw_chain_status = c_chainstatus_ko.
        fp_subrc = 8.
        RETURN.
      ENDIF.
    ENDLOOP.
    IF sy-subrc NE 0. "to avoid infinite loop
      EXIT.
    ENDIF.
  ENDWHILE.
ENDFORM.                    " trig_chain

*&---------------------------------------------------------------------*
*&      Form  trig_dtp
*&---------------------------------------------------------------------*
*       Subroutine to perform process TRIG_DTP
*       Triggers DTP in asynchronous mode
*----------------------------------------------------------------------*
*      -->FP_PARAM   Line of the file
*      <--FP_SUBRC   Return code (<> 0 if error during process)
*----------------------------------------------------------------------*
FORM trig_dtp USING fp_param LIKE s_param                   "#EC CALLED
              CHANGING fp_subrc TYPE i.
  PERFORM trig_process USING fp_param
                       CHANGING fp_subrc.
ENDFORM.                    "trig_dtp

*&---------------------------------------------------------------------*
*&      Form  trig_dtp_nodata
*&---------------------------------------------------------------------*
*       Subroutine to perform process TRIG_DTP_NODATA
*       Triggers DTP in asynchronous mode
*----------------------------------------------------------------------*
*      -->FP_PARAM   Line of the file
*      <--FP_SUBRC   Return code (<> 0 if error during process)
*----------------------------------------------------------------------*
FORM trig_dtp_nodata USING fp_param LIKE s_param            "#EC CALLED
                     CHANGING fp_subrc TYPE i.
  PERFORM trig_process USING fp_param
                       CHANGING fp_subrc.
ENDFORM.                    "trig_dtp_nodata

*&---------------------------------------------------------------------*
*&      Form  trig_ip
*&---------------------------------------------------------------------*
*       Subroutine to perform process TRIG_IP
*       Triggers Infopackage in asynchronous mode
*----------------------------------------------------------------------*
*      -->FP_PARAM   Line of the file
*      <--FP_SUBRC   Return code (<> 0 if error during process)
*----------------------------------------------------------------------*
FORM trig_ip USING fp_param LIKE s_param                    "#EC CALLED
             CHANGING fp_subrc TYPE i.
* Default mode : like a process chain
  IF fp_param-param IS INITIAL.
    MESSAGE 'Start infopackage in background mode' TYPE c_msg_info.
    PERFORM trig_process USING fp_param
                         CHANGING fp_subrc.
* Online mode
  ELSE.
    MESSAGE 'Start infopackage in online mode' TYPE c_msg_info.
    PERFORM trig_ip_online USING fp_param
                           CHANGING fp_subrc.
  ENDIF.
ENDFORM.                    "trig_ip

*&---------------------------------------------------------------------*
*&      Form  process_psa
*&---------------------------------------------------------------------*
*       Subroutine to perform process PROCESS_PSA
*       Load data from infopackage to targets
*       Note that infopackage monitoring may remain in "yellow" until
*       all targets has been activated
*----------------------------------------------------------------------*
*      -->FP_PARAM   Line of the file
*      <--FP_SUBRC   Return code (<> 0 if error during process)
*----------------------------------------------------------------------*
FORM process_psa USING fp_param LIKE s_param                "#EC CALLED
                 CHANGING fp_subrc TYPE i.
  DATA : lw_error_proc TYPE  rs_bool,
         lw_rnr TYPE rsreqdone-rnr.

* Search most recent request ready to udpate from PSA
* Assistant is the msg number from msg class RSM2
* 44 => Request successfully loaded into PSA - start further update
  SELECT MAX( rnr ) INTO lw_rnr
         FROM rsreqdone
         WHERE logdpid = fp_param-object
         AND assistant = 44.
  IF sy-subrc NE 0 OR lw_rnr IS INITIAL.
    MESSAGE 'No relevant request found' TYPE c_msg_info.
    fp_subrc = 8.
    RETURN.
  ENDIF.

  CALL FUNCTION 'RSSM_PROCESS_PSAPROCESS'
    EXPORTING
      i_dta     = space
      i_rnr     = lw_rnr
      i_type    = 'PSAPROCESS'
      i_jobname = 'PSAPROCESS'
    IMPORTING
      e_error   = lw_error_proc.
  IF NOT lw_error_proc IS INITIAL.
    fp_subrc = 8.
    RETURN.
  ENDIF.
ENDFORM.                    "process_psa

*&---------------------------------------------------------------------*
*&      Form  stop
*&---------------------------------------------------------------------*
*       Subroutine to perform process STOP
*       Return subrc <> 0 to stop the program execution
*----------------------------------------------------------------------*
*      -->FP_PARAM   Line of the file
*      <--FP_SUBRC   Return code (<> 0 if error during process)
*----------------------------------------------------------------------*
FORM stop USING fp_param LIKE s_param                       "#EC CALLED
          CHANGING fp_subrc TYPE i.
  fp_subrc = 8.
  MESSAGE 'Stop program execution' TYPE c_msg_info.

ENDFORM.                    "stop

*&---------------------------------------------------------------------*
*&      Form wait
*&---------------------------------------------------------------------*
*       Subroutine to perform process WAIT
*       Wait given time or number of seconds then continue
*----------------------------------------------------------------------*
*      -->FP_PARAM   Line of the file
*      <--FP_SUBRC   Return code (<> 0 if error during process)
*----------------------------------------------------------------------*
FORM wait USING fp_param LIKE s_param                       "#EC CALLED
          CHANGING fp_subrc TYPE i.
  DATA : lw_message TYPE string,
         lw_date TYPE d,
         lw_time TYPE t,
         lw_seconds TYPE i.
  IF fp_param-param(1) = 'T'.
    lw_date = fp_param-param+1(8).
    lw_time = fp_param-param+9(6).
    lw_seconds = ( lw_date - sy-datlo ) * 86400 + lw_time - sy-timlo.
  ELSE.
    lw_seconds = fp_param-param.
  ENDIF.
  lw_message = lw_seconds.
  CONDENSE lw_message.
  CONCATENATE 'Wait up to' lw_message 'seconds' INTO lw_message
              SEPARATED BY space.
  MESSAGE lw_message TYPE c_msg_info.
  WAIT UP TO lw_seconds SECONDS.
ENDFORM.                    "wait

*&---------------------------------------------------------------------*
*&      Form  EXPORT_DS
*&---------------------------------------------------------------------*
*       Subroutine to perform process EXPORT_DS
*       Generate export datasource/infosource for a given infoprovider
*----------------------------------------------------------------------*
*      -->FP_PARAM   Line of the file
*      <--FP_SUBRC   Return code (<> 0 if error during process)
*----------------------------------------------------------------------*
FORM export_ds USING fp_param LIKE s_param                  "#EC CALLED
               CHANGING fp_subrc TYPE i.
  DATA : l_cube TYPE rsdcube-infocube,
         l_ods TYPE rsdodso-odsobject.

* Generation for infocube
  SELECT SINGLE infocube INTO l_cube
         FROM rsdcube
         WHERE infocube = fp_param-object
         AND objvers = rs_c_objvers-active.
  IF sy-subrc = 0.
    CALL FUNCTION 'RSB1_GEN_METADATA_TO_CUBE'
      EXPORTING
        i_infocubename       = l_cube
        i_onlymyself         = c_true
        i_quiet              = c_true
      EXCEPTIONS
        generation_failed    = 1
        authorization_failed = 2
        OTHERS               = 3.
    IF sy-subrc <> 0.
      MESSAGE ID sy-msgid TYPE c_msg_info NUMBER sy-msgno
                 WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
      fp_subrc = sy-subrc.
    ENDIF.
    RETURN.
  ENDIF.

* Generation for DSO
  SELECT SINGLE odsobject INTO l_ods
         FROM rsdodso
         WHERE odsobject = fp_param-object
         AND objvers = rs_c_objvers-active.
  IF sy-subrc = 0.
    CALL FUNCTION 'RSAR_EXPORT_METADATA_GEN'
      EXPORTING
        i_dtanm = l_ods
      EXCEPTIONS
        OTHERS  = 1.
    IF sy-subrc <> 0.
      MESSAGE ID sy-msgid TYPE c_msg_info NUMBER sy-msgno
                 WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
      fp_subrc = sy-subrc.
    ENDIF.
  ENDIF.
ENDFORM.                    " EXPORT_DS

*&---------------------------------------------------------------------*
*&      Form  REPLICATE_DS
*&---------------------------------------------------------------------*
*       Subroutine to perform process REPLICATE_DS
*       Replicate a given datasource
*----------------------------------------------------------------------*
*      -->FP_PARAM   Line of the file
*      <--FP_SUBRC   Return code (<> 0 if error during process)
*----------------------------------------------------------------------*
FORM replicate_ds USING fp_param LIKE s_param               "#EC CALLED
                  CHANGING fp_subrc TYPE i.
  DATA : l_oltpsource TYPE rsds-datasource,
         l_logsys TYPE rsds-logsys,
         l_preftype TYPE rstlogo,
         l_message TYPE string.

  l_oltpsource = fp_param-object.
  SPLIT fp_param-param AT c_separator_param INTO l_logsys l_preftype.

  CALL FUNCTION 'RSDS_DATASOURCE_REPLICATE'
    EXPORTING
      i_datasource = l_oltpsource
      i_logsys     = l_logsys
      i_preftype   = l_preftype
    EXCEPTIONS
      failed       = 1
      OTHERS       = 2.
  IF sy-subrc <> 0.
    l_message = 'Cannot replicate datasource' && fp_param-object.
    MESSAGE l_message TYPE c_msg_info.
    fp_subrc = sy-subrc.
  ENDIF.
ENDFORM.                    " REPLICATE_DS


*&---------------------------------------------------------------------*
*&      Form  ACTIVATE_OBJECT
*&---------------------------------------------------------------------*
*       Subroutine to perform process ACTIVATE_OBJECT
*       Activate object
*----------------------------------------------------------------------*
*      -->FP_PARAM   Line of the file
*      <--FP_SUBRC   Return code (<> 0 if error during process)
*----------------------------------------------------------------------*
FORM activate_object USING fp_param LIKE s_param            "#EC CALLED
                     CHANGING fp_subrc TYPE i.
  DATA : lo_tlogo TYPE REF TO if_rso_tlogo_maintain,
         l_tlogo TYPE rstlogo,
         l_objnm TYPE sobj_name,
         lo_updr TYPE REF TO cl_rsau_updr,
         lo_chain TYPE REF TO cl_rspc_chain,
         lo_iset TYPE REF TO cl_rsq_iset,
         l_result_ok(1) TYPE c.
  CLEAR fp_subrc.
  l_tlogo = fp_param-param.
  l_objnm = fp_param-object.

* Get object
  TRY.
      lo_tlogo = cl_rso_tlogo_utilities=>create_tlogo_instance( i_tlogo = l_tlogo
                                                                 i_objnm = l_objnm ).
    CATCH cx_rs_not_found.
* Object not managed
  ENDTRY.
  IF NOT lo_tlogo IS BOUND.
    MESSAGE 'Error before object preparation' TYPE c_msg_info.
    fp_subrc = 8.
    RETURN.
  ENDIF.

* Specific process for Update rules activation
  IF l_tlogo = 'UPDR'.
    lo_updr ?= lo_tlogo.

    CALL FUNCTION 'RSAU_UPDR_ACTIVATE'
      EXPORTING
        i_objvers = rs_c_objvers-modified
        i_r_updr  = lo_updr
      IMPORTING
        e_ok      = l_result_ok.
    IF l_result_ok = space. "Activation NOK
      fp_subrc = 4.
    ENDIF.

* Specific process for Process chain
  ELSEIF l_tlogo = 'RSPC'.
    lo_chain ?= lo_tlogo.
    CALL METHOD lo_chain->activate
      EXPORTING
        i_gui = c_nogui.
    fp_subrc = sy-subrc.

* Specific process for Infoset
  ELSEIF l_tlogo = 'ISET'.
    lo_iset ?= lo_tlogo.
* Prepare object activation
    TRY.
        CALL METHOD lo_tlogo->prepare
          EXPORTING
            i_with_cto_check = space.
      CATCH cx_rs_not_authorized.
        fp_subrc = 1.
      CATCH cx_rs_cancelled.
        fp_subrc = 2.
      CATCH cx_rs_display_only.
        fp_subrc = 3.
    ENDTRY.
    IF fp_subrc NE 0.
      MESSAGE 'Error during object preparation' TYPE c_msg_info.
      RETURN.
    ENDIF.
* Activate
    IF fp_subrc = 0.
      l_result_ok = lo_iset->activate_infoset( i_gui = c_nogui ).
    ENDIF.
* Unlock object
    CALL METHOD lo_tlogo->dequeue.
    IF l_result_ok = space. "Activation NOK
      fp_subrc = 4.
    ENDIF.

* Default standard process
  ELSE.
* Prepare object activation
    TRY.
        CALL METHOD lo_tlogo->prepare
          EXPORTING
            i_with_cto_check = space.
      CATCH cx_rs_not_authorized.
        fp_subrc = 1.
      CATCH cx_rs_cancelled.
        fp_subrc = 2.
      CATCH cx_rs_display_only.
        fp_subrc = 3.
    ENDTRY.
    IF fp_subrc NE 0.
      MESSAGE 'Error during object preparation' TYPE c_msg_info.
      RETURN.
    ENDIF.
* Activate
    IF fp_subrc = 0.
      CALL METHOD lo_tlogo->activate
        EXPORTING
          i_with_cto         = space
          i_force_activation = c_true
        IMPORTING
          e_subrc            = fp_subrc.
    ENDIF.
* Unlock object
    CALL METHOD lo_tlogo->dequeue.
  ENDIF.
  IF fp_subrc NE 0.
    MESSAGE 'Error during object activation' TYPE c_msg_info.
    RETURN.
  ELSE.
    MESSAGE 'Activation completed' TYPE c_msg_success.
  ENDIF.

ENDFORM.                    " ACTIVATE_OBJECT

*&---------------------------------------------------------------------*
*&      Form  CHANGE_IP_MODE
*&---------------------------------------------------------------------*
*       Subroutine to perform process CHANGE_IP_MODE
*       Modify infopackage load mode and/or autoswitch flag
*----------------------------------------------------------------------*
*      -->FP_PARAM   Line of the file
*      <--FP_SUBRC   Return code (<> 0 if error during process)
*----------------------------------------------------------------------*
FORM change_ip_mode USING fp_param LIKE s_param             "#EC CALLED
                    CHANGING fp_subrc TYPE i.
  DATA : l_param TYPE string,
         lt_param TYPE TABLE OF string.

  l_param = fp_param-param.
  TRANSLATE l_param TO UPPER CASE.
  SPLIT l_param AT c_separator_param INTO TABLE lt_param.

* Set update mode (full)
  READ TABLE lt_param WITH KEY = 'FULL' TRANSPORTING NO FIELDS.
  IF sy-subrc = 0.
    UPDATE rssdbatch SET updmode = 'F'
                     WHERE logid = fp_param-object.
    COMMIT WORK.
  ELSE.
* Set update mode (delta)
    READ TABLE lt_param WITH KEY = 'DELTA' TRANSPORTING NO FIELDS.
    IF sy-subrc = 0.
      UPDATE rssdbatch SET updmode = 'D'
                       WHERE logid = fp_param-object.
      COMMIT WORK.
    ELSE.
* Set update mode (init with DT)
      READ TABLE lt_param WITH KEY = 'INIT' TRANSPORTING NO FIELDS.
      IF sy-subrc = 0.
        UPDATE rssdbatch SET updmode = 'C'
                         WHERE logid = fp_param-object.
        UPDATE rsldpsel SET init_simu = space
                        WHERE logdpid = fp_param-object.
        COMMIT WORK.
      ELSE.
* Set update mode (init without DT)
        READ TABLE lt_param WITH KEY = 'INITNODT' TRANSPORTING NO FIELDS.
        IF sy-subrc = 0.
          UPDATE rssdbatch SET updmode = 'C'
                           WHERE logid = fp_param-object.
          UPDATE rsldpsel SET init_simu = c_true
                          WHERE logdpid = fp_param-object.
          COMMIT WORK.
        ENDIF.
      ENDIF.
    ENDIF.
  ENDIF.

* Set autoswitch flag
  READ TABLE lt_param WITH KEY = 'AUTOSWITCH' TRANSPORTING NO FIELDS.
  IF sy-subrc = 0.
    UPDATE rsldpsel SET inittodelta = c_true
                    WHERE logdpid = fp_param-object.
    COMMIT WORK.
  ELSE.
* Unset autoswitch flag
    READ TABLE lt_param WITH KEY = 'NOSWITCH' TRANSPORTING NO FIELDS.
    IF sy-subrc = 0.
      UPDATE rsldpsel SET inittodelta = space
                      WHERE logdpid = fp_param-object.
      COMMIT WORK.
    ENDIF.
  ENDIF.

* Set Fullrepair flag
  READ TABLE lt_param WITH KEY = 'REPAIR' TRANSPORTING NO FIELDS.
  IF sy-subrc = 0.
    UPDATE rsldpsel SET repair_full = c_true
                    WHERE logdpid = fp_param-object.
    COMMIT WORK.
  ELSE.
* Unset Fullrepair flag
    READ TABLE lt_param WITH KEY = 'NOREPAIR' TRANSPORTING NO FIELDS.
    IF sy-subrc = 0.
      UPDATE rsldpsel SET repair_full = space
                      WHERE logdpid = fp_param-object.
      COMMIT WORK.
    ENDIF.
  ENDIF.

ENDFORM. "CHANGE_IP_MODE

*&---------------------------------------------------------------------*
*&      Form  CHANGE_IP_SEL
*&---------------------------------------------------------------------*
*       Subroutine to perform process CHANGE_IP_SEL
*       Modify infopackage selection
*----------------------------------------------------------------------*
*      -->FP_PARAM   Line of the file
*      <--FP_SUBRC   Return code (<> 0 if error during process)
*----------------------------------------------------------------------*
FORM change_ip_sel USING fp_param LIKE s_param              "#EC CALLED
                   CHANGING fp_subrc TYPE i.
  DATA : ls_sel TYPE rsldpsel,
         ls_sel_ref LIKE ls_sel,
         lt_sel_new LIKE TABLE OF ls_sel,
         lt_sel_old LIKE TABLE OF ls_sel,
         l_param TYPE string,
         lt_param TYPE TABLE OF string,
         l_selupdic TYPE rsldpsel-selupdic,
         l_index TYPE i.

  IF fp_param-object IS INITIAL.
    RETURN.
  ENDIF.

* Get existing parameters for processed infopackage
  SELECT *
         INTO TABLE lt_sel_old
         FROM rsldpsel
         WHERE logdpid = fp_param-object
         AND objvers = c_version_active.
* If no entry in selection table, ip is not correct, exit with error
  IF sy-subrc NE 0.
    fp_subrc = 8.
    RETURN.
  ENDIF.

* Prepare selection line
* The db table contain some of non-selection parameters on each
* selection line, like "repair" or "load to PSA"
  READ TABLE lt_sel_old INTO ls_sel_ref INDEX 1.
  CLEAR : ls_sel_ref-lnr,
          ls_sel_ref-fieldname,
          ls_sel_ref-iobjnm,
          ls_sel_ref-sign,
          ls_sel_ref-opt,
          ls_sel_ref-low,
          ls_sel_ref-high,
          ls_sel_ref-selupdic, "target
          ls_sel_ref-vartyp, "for abap & olap
          ls_sel_ref-bex_variable, "for olap
          ls_sel_ref-periv, "for olap
          ls_sel_ref-description. "for abap

* Fill selection table with input parameters
  l_param = fp_param-param.
  SPLIT l_param AT c_separator_param INTO TABLE lt_param.
  LOOP AT lt_param INTO l_param.
* Skip empty line
    IF l_param IS INITIAL.
      CONTINUE.
    ENDIF.

* Keep all non-selection information
    ls_sel = ls_sel_ref.

* Increment line counter
    ls_sel-lnr = sy-tabix.

* Get selection condition
    SPLIT l_param AT c_separator_cond INTO ls_sel-iobjnm
                                           ls_sel-fieldname
                                           ls_sel-low
                                           ls_sel-high.
    ls_sel-sign = 'I'.
    IF ls_sel-high IS INITIAL.
      ls_sel-opt = 'EQ'.
    ELSE.
      ls_sel-opt = 'BT'.
    ENDIF.

    APPEND ls_sel TO lt_sel_new.
  ENDLOOP.

* If no selection choosen, fill 1 lines with non-selection parameters
  IF lt_sel_new IS INITIAL.
    ls_sel = ls_sel_ref.
    ls_sel-lnr = 1.
    APPEND ls_sel TO lt_sel_new.
  ENDIF.

* If list of target choosen, fill 1 target per line
  DELETE lt_sel_old WHERE selupdic = space.
  SORT lt_sel_old BY selupdic.
  DELETE ADJACENT DUPLICATES FROM lt_sel_old COMPARING selupdic.
  LOOP AT lt_sel_old INTO ls_sel.
    l_index = sy-tabix.
    l_selupdic = ls_sel-selupdic.
    READ TABLE lt_sel_new INTO ls_sel INDEX l_index.
    IF sy-subrc = 0.
      ls_sel-selupdic = l_selupdic.
      MODIFY lt_sel_new FROM ls_sel INDEX l_index TRANSPORTING selupdic.
    ELSE.
      ls_sel = ls_sel_ref.
      ls_sel-lnr = l_index.
      ls_sel-selupdic = l_selupdic.
      APPEND ls_sel TO lt_sel_new.
    ENDIF.
  ENDLOOP.

* Finally, update db
  DELETE FROM rsldpsel
         WHERE logdpid = fp_param-object
         AND objvers = c_version_active.
  INSERT rsldpsel FROM TABLE lt_sel_new.
  CALL FUNCTION 'DB_COMMIT'.
  COMMIT WORK AND WAIT.

ENDFORM.                    "change_ip_sel

*&---------------------------------------------------------------------*
*&      Form  DBSTAT
*&---------------------------------------------------------------------*
*       Subroutine to perform process DBSTAT
*       Run Index creation and/or Statistics generation for cube/table
*----------------------------------------------------------------------*
*      -->FP_PARAM   Line of the file
*      <--FP_SUBRC   Return code (<> 0 if error during process)
*----------------------------------------------------------------------*
FORM dbstat USING fp_param LIKE s_param                     "#EC CALLED
                    CHANGING fp_subrc TYPE i.
  DATA : lt_file LIKE RANGE OF rsdcube-infocube,
         lt_stat LIKE RANGE OF rsdcube-infocube,
         lt_index LIKE RANGE OF rsdcube-infocube,
         ls_file LIKE LINE OF lt_file,
         lw_param TYPE string,
         lw_type(1) TYPE c.

  ls_file = 'IEQ'.
  ls_file-low = fp_param-object.
  APPEND ls_file TO lt_file.

  lw_param = fp_param-param.
  TRANSLATE lw_param TO UPPER CASE.
  FIND FIRST OCCURRENCE OF 'STAT' IN lw_param.
  IF sy-subrc = 0.
    APPEND ls_file TO lt_stat.
  ENDIF.

  FIND FIRST OCCURRENCE OF 'INDEX' IN lw_param.
  IF sy-subrc = 0.
    APPEND ls_file TO lt_index.
  ENDIF.

  SELECT SINGLE infocube
                     INTO s_param-object
                     FROM rsdcube
                     WHERE infocube = s_param-object
                     AND objvers = c_version_active
                     AND ( cubetype = 'A' OR cubetype = 'B' ).
  IF sy-subrc = 0.
    lw_type = 'I'.
  ELSE.
    CLEAR lw_type.
  ENDIF.

  SUBMIT rsstat1 WITH file  IN lt_file "liste des cubes/tables a traiter
                 WITH stat  IN lt_stat "liste des cubes/tables pour stat
                 WITH index IN lt_index "liste des cubes/tables pour index
                 WITH type  EQ lw_type "I = cube / A = aggr / other =table
                 WITH rnr   EQ space
                 AND RETURN.

ENDFORM. "DBSTAT

*&---------------------------------------------------------------------*
*&      Form  COMPRESS_EMAIL
*&---------------------------------------------------------------------*
*       Compress email content by removing all unused spaces
*       Divide by 4 the email size
*----------------------------------------------------------------------*
*      <->FT_CONTENT  Content of the email to compress
*----------------------------------------------------------------------*
FORM compress_email  CHANGING ft_content TYPE soli_tab.
  DATA : lw_content TYPE string,
         ls_content LIKE LINE OF ft_content,
         lw_length TYPE i,
         lw_offset TYPE i,
         lw_count TYPE i,
         lw_length_limit TYPE i.

* concatenate all lines into a string
  LOOP AT ft_content INTO ls_content.
    CONCATENATE lw_content ls_content INTO lw_content
                SEPARATED BY space.
  ENDLOOP.

* In HTML, double space is ignored
* Condense to remove all unused spaces
  CONDENSE lw_content.

* Rebuild the content of the email table
  lw_length = strlen( lw_content ).
  lw_length_limit = 255.
  lw_offset = 0.
  REFRESH ft_content.
  WHILE lw_offset LT lw_length.
    lw_count = lw_length - lw_offset.
    IF lw_count GT lw_length_limit.
      ls_content = lw_content+lw_offset(lw_length_limit).
      APPEND ls_content TO ft_content.
      lw_offset = lw_offset + lw_length_limit.
    ELSE.
      ls_content = lw_content+lw_offset(lw_count).
      APPEND ls_content TO ft_content.
      lw_offset = lw_length.
    ENDIF.
  ENDWHILE.
ENDFORM.                    " COMPRESS_EMAIL

*FUNCTION ZRSPC_SEND_MAIL.
**"----------------------------------------------------------------------
**"*"Local Interface:
**"  IMPORTING
**"     VALUE(I_SHARED) TYPE  CHAR30
**"     VALUE(I_RUNID) TYPE  CHAR14
**"----------------------------------------------------------------------
*  DATA : BEGIN OF ls_param,
*           process TYPE string,
*           object TYPE string,
*           param  TYPE string,
*           comment TYPE string,
*           state(4) TYPE c,
*           line TYPE i,
*           start_date TYPE d,
*           start_time TYPE t,
*           end_date TYPE d,
*           end_time TYPE t,
*           exec_time TYPE t,
*           selkz(1) TYPE c,
*         END OF ls_param,
*         BEGIN OF s_shared,
*           param LIKE TABLE OF ls_param,
*           jobname TYPE tbtcjob-jobname,
*           jobcount TYPE tbtcm-jobcount,
*           mail(1) TYPE c,
*           nostop(1) TYPE c,
*           mail_time TYPE i,
*           runid(14) TYPE c,
*         END OF s_shared.
*  DATA : lt_content TYPE soli_tab,
*         ls_userdet TYPE rsplppm_s_userdetails,
*         lw_state(8) TYPE c,
*         lw_subject TYPE so_obj_des,
*         lo_mail TYPE REF TO cl_bcs, "Mail object
*         lo_content TYPE REF TO cl_document_bcs, "Mail content
*         lo_sender TYPE REF TO cl_sapuser_bcs, "Mail sender
*         lo_recipient TYPE REF TO if_recipient_bcs, "Mail recipient
*         lo_bcs TYPE REF TO cx_bcs, "Mail exception
*         lw_message(100) TYPE c.
*  DATA : lw_count TYPE i,
*         lw_time TYPE t.
*
*  CONSTANTS : c_state_skip LIKE ls_param-state VALUE '@03@',
*              c_state_ok  LIKE ls_param-state VALUE '@5B@',
*              c_state_ko  LIKE ls_param-state VALUE '@5C@',
*              c_state_run LIKE ls_param-state VALUE '@5D@',
*              c_state_abort LIKE ls_param-state VALUE '@8N@'.
*
** Macro to write HTML
*  DEFINE c.
*    append &1 to lt_content.
*  END-OF-DEFINITION.
*
*  IMPORT s_shared FROM SHARED BUFFER indx(st) ID i_shared.
*  DO.
*    WAIT UP TO s_shared-mail_time SECONDS.
*
** Get current run
*    IMPORT s_shared FROM SHARED BUFFER indx(st) ID i_shared.
*
** If current run is not the run watched, exit
*    IF s_shared-runid NE i_runid.
*      MESSAGE x000(38).
*      EXIT.
*    ENDIF.
*
** Get run status
** Check if runing process is found
*    READ TABLE s_shared-param WITH KEY state = c_state_run
*               TRANSPORTING NO FIELDS.
*    IF sy-subrc NE 0.
** Check if error/abort found => exit
*      READ TABLE s_shared-param WITH KEY state = c_state_ko
*                                TRANSPORTING NO FIELDS.
*      IF sy-subrc = 0.
*        EXIT.
*      ENDIF.
*      READ TABLE s_shared-param WITH KEY state = c_state_abort
*                                TRANSPORTING NO FIELDS.
*      IF sy-subrc = 0.
*        EXIT.
*      ENDIF.
** Check if empty process, will run soon. If not => finished : exit
*      READ TABLE s_shared-param WITH KEY state = space
*                                TRANSPORTING NO FIELDS.
*      IF sy-subrc NE 0.
*        EXIT.
*      ENDIF.
*    ENDIF.
*
** Write mail content
*    REFRESH lt_content.
*    CLEAR lw_count.
*    c '<html>'.
*    c '<head>'.
*    c '<meta http-equiv="content-type"'.
*    c ' content="text/html; charset=utf-8">'.
*    c '<title>Automate action - LOG</title>'.
*    c '<style type="text/css">'.
*    c 'table{padding:0;margin:0;}'.
*    c 'strong{font-weight:bold;color:#FF6600;}'.
*    c '</style>'.
*    c '</head>'.
*    c '<body>'.
*    c '<p>Log for job <strong>'.
*    c s_shared-jobname.
*    c '</strong></p><table cellpadding=0 cellspacing=0 border=0 width=100%>'.
*    c '<tr><th>Step</th><th>Process</th><th>Object</th>'.
*    c '<th>Parameters</th><th>Comment</th><th>State</th>'.
*    c '<th>Exec Time</th></tr>'.
*    LOOP AT s_shared-param INTO ls_param.
** Process Success
*      IF ls_param-state = c_state_ok. "green
*        c '<tr bgcolor=#66CC66><td>&nbsp;'.
*        lw_state = 'OK'.
** Process skiped
*      ELSEIF ls_param-state = c_state_skip.
*        c '<tr bgcolor=#66CCFF><td>&nbsp;'. "blue
*        lw_state = 'SKIP'.
** Process in error
*      ELSEIF ls_param-state = c_state_ko
*          OR ls_param-state = c_state_abort.
*        c '<tr bgcolor=#FF6666><td>&nbsp;'. "red
*        lw_state = 'KO'.
*      ELSEIF ls_param-state = c_state_run.
*        c '<tr bgcolor=#FFFF99><td>&nbsp;'. "yellow
*        lw_state = 'RUN'.
** For runing process, calculate current execution time
*        IF ls_param-exec_time IS INITIAL.
*          ls_param-exec_time = ( sy-datum - ls_param-start_date ) *  86400
*                               + sy-uzeit - ls_param-start_time.
*        ENDIF.
** Not processed - Append for process after a process in error
*      ELSE.
*        c '<tr><td>&nbsp;'.
*        lw_state = ''.
*      ENDIF.
*      c ls_param-line.
*      c '</td><td>'.
*      IF ls_param-process(1) = '@'.
*        ls_param-process = ls_param-process+5.
*      ENDIF.
*      c ls_param-process.
*      c '</td><td>&nbsp;'.
*      c ls_param-object.
*      c '</td><td>&nbsp;'.
*      c ls_param-param.
*      c '</td><td>&nbsp;'.
*      c ls_param-comment.
*      c '</td><td>&nbsp;'.
*      c lw_state.
*      c '</td><td>&nbsp;'.
*      WRITE ls_param-exec_time TO lw_state.
*      c lw_state.
*      c '</td></tr>'.
*      lw_count = lw_count + ls_param-exec_time.
*    ENDLOOP.
** Add a total line
*    c '<tr bgcolor=#FFFF66 style="padding-top:10px;"><td>&nbsp;</td>'.
*    c '<td colspan=5><b>Total execution time</b></td><td>&nbsp;<b>'.
*
** Calculate total execution time
*    CLEAR lw_message.
*    lw_time = lw_count.
*    IF lw_count GE 86400.
*      lw_count = lw_count DIV 86400.
*      lw_message = lw_count.
*      CONCATENATE lw_message 'd' INTO lw_message.
*      CONDENSE lw_message NO-GAPS.
*      WRITE lw_time TO lw_message+3.
*    ELSE.
*      WRITE lw_time TO lw_message.
*    ENDIF.
*
*    c lw_message.
*    c '</b></td></tr>'.
*    c '</table>'.
*
** Get the email of current user
*    CLEAR ls_userdet.
*    CALL FUNCTION 'RSPLPPM_GET_USERDETAILS'
*      EXPORTING
*        i_user          = sy-uname
*      IMPORTING
*        e_s_userdetails = ls_userdet.
*    IF ls_userdet-email IS INITIAL.
*      MESSAGE 'Cannot send email as recipient have not email defined'
*               TYPE 'E'.
*    ENDIF.
*
** Remove all unused spaces
*  PERFORM compress_email in program ZRSPC
*                         CHANGING lt_content.
*
** Catch object errors
*    TRY.
** Create mail object
*        lo_mail = cl_bcs=>create_persistent( ).
*        lw_subject = '[' && sy-sysid && ']' && ' Chain BW Process - Log (Running)'.
*
** Create mail content object
*        CALL METHOD cl_document_bcs=>create_document
*          EXPORTING
*            i_type    = 'HTM'
*            i_subject = lw_subject
*            i_text    = lt_content
*          RECEIVING
*            result    = lo_content.
*
** Link the mail content object to the mail object
*        CALL METHOD lo_mail->set_document
*          EXPORTING
*            i_document = lo_content.
*
** Define sender as current user
** It require that current user have an email defined
*        lo_sender = cl_sapuser_bcs=>create( sy-uname ).
*        CALL METHOD lo_mail->set_sender
*          EXPORTING
*            i_sender = lo_sender.
*
** Define receiver list
*        lo_recipient =
*        cl_cam_address_bcs=>create_internet_address( ls_userdet-email ).
*
** Add receiver to the receiver list
*        CALL METHOD lo_mail->add_recipient
*          EXPORTING
*            i_recipient = lo_recipient.
*
** Define mail attributes
*        CALL METHOD lo_mail->set_status_attributes
*          EXPORTING
*            i_requested_status = 'N'
*            i_status_mail      = 'N'.
*
** Set mail to be immediatly send (no batch wait)
*        lo_mail->set_send_immediately( 'X' ).
*
** Send the mail
*        CALL METHOD lo_mail->send( ).
*        COMMIT WORK.
*        FREE lo_mail.
*
** Any Exception during process ?
*      CATCH cx_bcs INTO lo_bcs.
*        lw_message = lo_bcs->get_text( ).
*        MESSAGE lw_message TYPE 'E'.
*    ENDTRY.
*  ENDDO.
*
*ENDFUNCTION.